// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:io' show File, Platform;

import 'package:analysis_server_client/handler/connection_handler.dart';
import 'package:analysis_server_client/handler/notification_handler.dart';
import 'package:analysis_server_client/listener/server_listener.dart';
import 'package:analysis_server_client/protocol.dart';
import 'package:analysis_server_client/server.dart';
import 'package:cli_util/cli_logging.dart';
import 'package:dartfix/handler/analysis_complete_handler.dart';
import 'package:dartfix/listener/bad_message_listener.dart';
import 'package:dartfix/src/context.dart';
import 'package:dartfix/src/options.dart';
import 'package:dartfix/src/util.dart';
import 'package:pub_semver/pub_semver.dart';

class Driver {
  Context context;
  _Handler handler;
  Logger logger;
  Server server;

  bool force;
  bool overwrite;
  List<String> targets;
  EditDartfixResult result;

  Ansi get ansi => logger.ansi;

  Future start(
    List<String> args, {
    Context testContext,
    Logger testLogger,
  }) async {
    final Options options = Options.parse(args, testContext, testLogger);

    force = options.force;
    overwrite = options.overwrite;
    targets = options.targets;
    context = testContext ?? options.context;
    logger = testLogger ?? options.logger;
    server = new Server(listener: new _Listener(logger));
    handler = new _Handler(this);

    // Start showing progress before we start the analysis server.
    Progress progress;
    if (options.showHelp) {
      progress = logger.progress('${ansi.emphasized('Listing fixes')}');
    } else {
      progress = logger.progress('${ansi.emphasized('Calculating fixes')}');
    }

    if (!await startServer(options)) {
      context.exit(15);
    }

    if (!checkSupported(options)) {
      await server.stop();
      context.exit(1);
    }

    if (options.showHelp) {
      try {
        await showListOfFixes(progress: progress);
      } finally {
        await server.stop();
      }
      context.exit(0);
    }

    Future serverStopped;
    try {
      await setupFixesAnalysis(options);
      result = await requestFixes(options, progress: progress);
      serverStopped = server.stop();
      await applyFixes();
      await serverStopped;
    } finally {
      // If we didn't already try to stop the server, then stop it now.
      if (serverStopped == null) {
        await server.stop();
      }
    }
  }

  Future<bool> startServer(Options options) async {
    if (options.verbose) {
      logger.trace('Dart SDK version ${Platform.version}');
      logger.trace('  ${Platform.resolvedExecutable}');
      logger.trace('dartfix');
      logger.trace('  ${Platform.script.toFilePath()}');
    }
    // Automatically run analysis server from source
    // if this command line tool is being run from source within the SDK repo.
    String serverPath = findServerPath();
    await server.start(
      clientId: 'dartfix',
      clientVersion: 'unspecified',
      sdkPath: options.sdkPath,
      serverPath: serverPath,
    );
    server.listenToOutput(notificationProcessor: handler.handleEvent);
    return handler.serverConnected(timeLimit: const Duration(seconds: 30));
  }

  /// Check if the specified options is supported by the version of analysis
  /// server being run and return `true` if they are.
  /// Display an error message and return `false` if not.
  bool checkSupported(Options options) {
    if (handler.serverProtocolVersion.compareTo(new Version(1, 22, 2)) >= 0) {
      return true;
    }
    if (options.excludeFixes.isNotEmpty) {
      unsupportedOption(excludeOption);
      return false;
    }
    if (options.includeFixes.isNotEmpty) {
      unsupportedOption(includeOption);
      return false;
    }
    if (options.requiredFixes) {
      unsupportedOption(requiredOption);
      return false;
    }
    if (options.showHelp) {
      return false;
    }
    return true;
  }

  void unsupportedOption(String option) {
    final version = handler.serverProtocolVersion.toString();
    logger.stderr('''
The --$option option is not supported by analysis server version $version.
Please upgrade to a newer version of the Dart SDK to use this option.''');
  }

  Future<Progress> setupFixesAnalysis(
    Options options, {
    Progress progress,
  }) async {
    logger.trace('');
    logger.trace('Setup analysis');
    await server.send(SERVER_REQUEST_SET_SUBSCRIPTIONS,
        new ServerSetSubscriptionsParams([ServerService.STATUS]).toJson());
    await server.send(
        ANALYSIS_REQUEST_SET_ANALYSIS_ROOTS,
        new AnalysisSetAnalysisRootsParams(
          options.targets,
          const [],
        ).toJson());
    return progress;
  }

  Future<EditDartfixResult> requestFixes(
    Options options, {
    Progress progress,
  }) async {
    logger.trace('Requesting fixes');
    Future isAnalysisComplete = handler.analysisComplete();

    final params = new EditDartfixParams(options.targets);
    if (options.excludeFixes.isNotEmpty) {
      params.excludedFixes = options.excludeFixes;
    }
    if (options.includeFixes.isNotEmpty) {
      params.includedFixes = options.includeFixes;
    }
    if (options.requiredFixes) {
      params.includeRequiredFixes = true;
    }
    Map<String, dynamic> json =
        await server.send(EDIT_REQUEST_DARTFIX, params.toJson());

    // TODO(danrubel): This is imprecise signal for determining when all
    // analysis error notifications have been received. Consider adding a new
    // notification indicating that the server is idle (all requests processed,
    // all analysis complete, all notifications sent).
    await isAnalysisComplete;

    progress.finish(showTiming: true);
    ResponseDecoder decoder = new ResponseDecoder(null);
    return EditDartfixResult.fromJson(decoder, 'result', json);
  }

  Future applyFixes() async {
    showDescriptions('Recommended changes', result.suggestions);
    showDescriptions('Recommended changes that cannot be automatically applied',
        result.otherSuggestions);
    if (result.suggestions.isEmpty) {
      logger.stdout('');
      logger.stdout(result.otherSuggestions.isNotEmpty
          ? 'None of the recommended changes can be automatically applied.'
          : 'No recommended changes.');
      return;
    }
    logger.stdout('');
    logger.stdout(ansi.emphasized('Files to be changed:'));
    for (SourceFileEdit fileEdit in result.edits) {
      logger.stdout('  ${relativePath(fileEdit.file)}');
    }
    if (shouldApplyChanges(result)) {
      for (SourceFileEdit fileEdit in result.edits) {
        final file = new File(fileEdit.file);
        String code = file.existsSync() ? file.readAsStringSync() : '';
        code = SourceEdit.applySequence(code, fileEdit.edits);
        await file.writeAsString(code);
      }
      logger.stdout(ansi.emphasized('Changes applied.'));
    }
  }

  void showDescriptions(String title, List<DartFixSuggestion> suggestions) {
    if (suggestions.isNotEmpty) {
      logger.stdout('');
      logger.stdout(ansi.emphasized('$title:'));
      List<DartFixSuggestion> sorted = new List.from(suggestions)
        ..sort(compareSuggestions);
      for (DartFixSuggestion suggestion in sorted) {
        final msg = new StringBuffer();
        msg.write('  ${toSentenceFragment(suggestion.description)}');
        final loc = suggestion.location;
        if (loc != null) {
          msg.write(' • ${relativePath(loc.file)}');
          msg.write(' • ${loc.startLine}:${loc.startColumn}');
        }
        logger.stdout(msg.toString());
      }
    }
  }

  bool shouldApplyChanges(EditDartfixResult result) {
    logger.stdout('');
    if (result.hasErrors) {
      logger.stdout('WARNING: The analyzed source contains errors'
          ' that may affect the accuracy of these changes.');
      logger.stdout('');
      if (!force) {
        logger.stdout('Rerun with --$forceOption to apply these changes.');
        return false;
      }
    } else if (!overwrite && !force) {
      logger.stdout('Rerun with --$overwriteOption to apply these changes.');
      return false;
    }
    return true;
  }

  String relativePath(String filePath) {
    for (String target in targets) {
      if (filePath.startsWith(target)) {
        return filePath.substring(target.length + 1);
      }
    }
    return filePath;
  }

  Future<EditGetDartfixInfoResult> showListOfFixes({Progress progress}) async {
    Map<String, dynamic> json = await server.send(
        EDIT_REQUEST_GET_DARTFIX_INFO, new EditGetDartfixInfoParams().toJson());
    progress?.finish(showTiming: true);
    ResponseDecoder decoder = new ResponseDecoder(null);
    final result = EditGetDartfixInfoResult.fromJson(decoder, 'result', json);

    final fixes = new List<DartFix>.from(result.fixes)
      ..sort((f1, f2) => f1.name.compareTo(f2.name));

    logger.stdout('''

These fixes are automatically applied unless at least one
--$includeOption option is specified and --$requiredOption is not specified.
They may be individually disabled using --$excludeOption.''');

    fixes.where((fix) => fix.isRequired).forEach(showFix);

    logger.stdout('''

These fixes are NOT automatically applied, but may be enabled using --$includeOption.''');

    fixes.where((fix) => !fix.isRequired).forEach(showFix);

    return result;
  }

  void showFix(DartFix fix) {
    logger.stdout('''

* ${fix.name}''');
    if (fix.description != null) {
      for (String line in indentAndWrapDescription(fix.description)) {
        logger.stdout(line);
      }
    }
  }

  List<String> indentAndWrapDescription(String description) =>
      description.split('\n').map((line) => '    $line').toList();
}

class _Listener with ServerListener, BadMessageListener {
  final Logger logger;
  final bool verbose;

  _Listener(this.logger) : verbose = logger.isVerbose;

  @override
  void log(String prefix, String details) {
    if (verbose) {
      logger.trace('$prefix $details');
    }
  }
}

class _Handler
    with NotificationHandler, ConnectionHandler, AnalysisCompleteHandler {
  final Driver driver;
  final Logger logger;
  final Server server;
  Version serverProtocolVersion;

  _Handler(this.driver)
      : logger = driver.logger,
        server = driver.server;

  @override
  bool checkServerProtocolVersion(Version version) {
    serverProtocolVersion = version;
    return super.checkServerProtocolVersion(version);
  }

  @override
  void onFailedToConnect() {
    logger.stderr('Failed to connect to server');
  }

  @override
  void onProtocolNotSupported(Version version) {
    logger.stderr('Expected protocol version $PROTOCOL_VERSION,'
        ' but found $version');
    final expectedVersion = Version.parse(PROTOCOL_VERSION);
    if (version > expectedVersion) {
      logger.stdout('''
This version of dartfix is incompatible with the current Dart SDK. 
Try installing a newer version of dartfix by running

    pub global activate dartfix
''');
    } else {
      logger.stdout('''
This version of dartfix is too new to be used with the current Dart SDK.
Try upgrading the Dart SDK to a newer version
or installing an older version of dartfix using

    pub global activate dartfix <version>
''');
    }
  }

  @override
  void onServerError(ServerErrorParams params) {
    if (params.isFatal) {
      logger.stderr('Fatal Server Error: ${params.message}');
    } else {
      logger.stderr('Server Error: ${params.message}');
    }
    if (params.stackTrace != null) {
      logger.stderr(params.stackTrace);
    }
    super.onServerError(params);
  }

  @override
  void onAnalysisErrors(AnalysisErrorsParams params) {
    List<AnalysisError> errors = params.errors;
    bool foundAtLeastOneError = false;
    for (AnalysisError error in errors) {
      if (shouldShowError(error)) {
        if (!foundAtLeastOneError) {
          foundAtLeastOneError = true;
          logger.stdout('${driver.relativePath(params.file)}:');
        }
        Location loc = error.location;
        logger.stdout('  ${toSentenceFragment(error.message)}'
            ' • ${loc.startLine}:${loc.startColumn}');
      }
    }
  }
}
