// Copyright (c) 2019, 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:convert' show jsonDecode, JsonEncoder;

import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:cli_util/cli_logging.dart';
import 'package:meta/meta.dart';
import 'package:nnbd_migration/nnbd_migration.dart';
import 'package:nnbd_migration/src/front_end/charcodes.dart';
import 'package:nnbd_migration/src/front_end/dartfix_listener.dart';
import 'package:nnbd_migration/src/front_end/instrumentation_listener.dart';
import 'package:nnbd_migration/src/front_end/migration_state.dart';
import 'package:nnbd_migration/src/front_end/migration_summary.dart';
import 'package:nnbd_migration/src/preview/http_preview_server.dart';
import 'package:nnbd_migration/src/utilities/json.dart' as json;
import 'package:pub_semver/pub_semver.dart';
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';

/// [NonNullableFix] visits each named type in a resolved compilation unit
/// and determines whether the associated variable or parameter can be null
/// then adds or removes a '?' trailing the named type as appropriate.
class NonNullableFix {
  static final List<HttpPreviewServer?> _allServers = [];

  final Version _intendedMinimumSdkVersion;

  /// The internet address the server should bind to.  Should be suitable for
  /// passing to HttpServer.bind, i.e. either a [String] or an
  /// [InternetAddress].
  final Object? bindAddress;

  final Logger _logger;

  final int? preferredPort;

  final DartFixListener listener;

  /// The root of the included paths.
  ///
  /// The included paths may contain absolute and relative paths, non-canonical
  /// paths, and directory and file paths. The "root" is the deepest directory
  /// which all included paths share.
  final String includedRoot;

  /// If non-null, the path to which a machine-readable summary of migration
  /// results should be written.
  final String? summaryPath;

  final ResourceProvider resourceProvider;

  final LineInfo Function(String) _getLineInfo;

  /// The HTTP server that serves the preview tool.
  HttpPreviewServer? _server;

  String? authToken;

  InstrumentationListener? instrumentationListener;

  NullabilityMigrationAdapter? adapter;

  NullabilityMigration? migration;

  late Future<MigrationState> Function() rerunFunction;

  /// A list of the URLs corresponding to the included roots.
  List<String>? previewUrls;

  /// A function which returns whether a file at a given path should be
  /// migrated.
  final bool Function(String?) shouldBeMigratedFunction;

  /// The set of files which are being considered for migration.
  Iterable<String>? pathsToProcess;

  /// Completes when the server has been shutdown.
  late Completer<void> serverIsShutdown;

  NonNullableFix(this.listener, this.resourceProvider, this._getLineInfo,
      this.bindAddress, this._logger, this.shouldBeMigratedFunction,
      {List<String> included = const [],
      this.preferredPort,
      this.summaryPath,
      required String sdkPath})
      : includedRoot =
            _getIncludedRoot(included, listener.server!.resourceProvider),
        _intendedMinimumSdkVersion =
            _computeIntendedMinimumSdkVersion(resourceProvider, sdkPath) {
    reset();
  }

  bool get isPreviewServerRunning => _server != null;

  /// In the package_config.json file, the patch number is omitted.
  String get _intendedLanguageVersion =>
      '${_intendedMinimumSdkVersion.major}.${_intendedMinimumSdkVersion.minor}';

  String get _intendedSdkVersionConstraint =>
      '>=$_intendedMinimumSdkVersion <3.0.0';

  InstrumentationListener createInstrumentationListener(
          {MigrationSummary? migrationSummary}) =>
      InstrumentationListener(migrationSummary: migrationSummary);

  Future<void> finalizeUnit(ResolvedUnitResult result) async {
    migration!.finalizeInput(result);
  }

  Future<MigrationState> finish() async {
    var neededPackages = migration!.finish();
    final state = MigrationState(migration, includedRoot, listener,
        instrumentationListener, neededPackages, shouldBeMigratedFunction);
    await state.refresh(_logger, pathsToProcess);
    return state;
  }

  Future<void> prepareUnit(ResolvedUnitResult result) async {
    migration!.prepareInput(result);
  }

  /// Processes the non-source files of the package rooted at [pkgFolder].
  ///
  /// This means updating the pubspec.yaml file, the package_config.json
  /// file, and the analysis_options.yaml file, each only if necessary.
  ///
  /// [neededPackages] is a map whose keys are the names of packages that should
  /// be depended upon by the package's pubspec, and whose values are the
  /// minimum required versions of those packages.
  void processPackage(Folder pkgFolder, Map<String, Version> neededPackages) {
    var pubspecFile = pkgFolder.getChildAssumingFile('pubspec.yaml');
    if (!pubspecFile.exists) {
      // If the pubspec file cannot be found, we do not attempt to change the
      // Package Config file, nor the analysis options file.
      return;
    }

    _YamlFile pubspec;
    try {
      pubspec = _YamlFile._parseFrom(pubspecFile);
    } on FileSystemException catch (e) {
      _processPubspecException('read', pubspecFile.path, e);
      return;
    } on FormatException catch (e) {
      _processPubspecException('parse', pubspecFile.path, e);
      return;
    }

    var updated = _processPubspec(pubspec, neededPackages);
    if (updated) {
      _processConfigFile(pkgFolder, pubspec);
    }
  }

  Future<void> processUnit(ResolvedUnitResult result) async {
    migration!.processInput(result);
  }

  Future<MigrationState> rerun() async {
    reset();
    var state = await rerunFunction();
    return state;
  }

  void reset() {
    instrumentationListener = createInstrumentationListener(
        migrationSummary: summaryPath == null
            ? null
            : MigrationSummary(summaryPath, resourceProvider, includedRoot));
    adapter = NullabilityMigrationAdapter(listener);
    migration = NullabilityMigration(adapter, _getLineInfo,
        permissive: true, instrumentation: instrumentationListener);
  }

  void shutdownServer() {
    if (_server != null) {
      _server!.close();
      _server = null;
      serverIsShutdown.complete();
    }
  }

  Future<void> startPreviewServer(
      MigrationState state, void Function() applyHook) async {
    // This method may be called multiple times, for example during a re-run.
    // But the preview server should only be started once.
    if (_server == null) {
      var wrappedApplyHookWithShutdown = () {
        shutdownServer();
        applyHook();
      };
      _server = HttpPreviewServer(state, rerun, wrappedApplyHookWithShutdown,
          bindAddress, preferredPort, _logger);
      _server!.serveHttp();
      _allServers.add(_server);
      var serverHostname = await _server!.boundHostname;
      var serverPort = await _server!.boundPort;
      authToken = await _server!.authToken;
      serverIsShutdown = Completer();

      previewUrls = [
        // TODO(jcollins-g): Change protocol to only return a single string.
        Uri(
            scheme: 'http',
            host: serverHostname,
            port: serverPort,
            path: state.pathMapper!.map(includedRoot),
            queryParameters: {'authToken': authToken}).toString()
      ];
    }
  }

  /// Updates the Package Config file to specify a minimum Dart SDK version
  /// which supports null safety.
  void _processConfigFile(Folder pkgFolder, _YamlFile pubspec) {
    var packageName = pubspec._getName();
    if (packageName == null) {
      return;
    }

    var packageConfigFile = pkgFolder
        .getChildAssumingFolder('.dart_tool')
        .getChildAssumingFile('package_config.json');

    if (!packageConfigFile.exists) {
      _processPackageConfigException(
          'Warning: Could not find the package configuration file.',
          packageConfigFile.path);
      return;
    }
    try {
      var configText = packageConfigFile.readAsStringSync();
      var configMap = json.expectType<Map>(jsonDecode(configText), 'root');
      json.expectKey(configMap, 'configVersion');
      var configVersion =
          json.expectType<int>(configMap['configVersion'], 'configVersion');
      if (configVersion != 2) {
        _processPackageConfigException(
            'Warning: Unexpected package configuration file version '
            '$configVersion (expected version 2). Cannot update this file.',
            packageConfigFile.path);
        return;
      }
      json.expectKey(configMap, 'packages');
      var packagesList =
          json.expectType<List>(configMap['packages'], 'packages');
      for (var package in packagesList) {
        var packageMap = json.expectType<Map>(package, 'package');
        json.expectKey(packageMap, 'name');
        var name = json.expectType<String>(packageMap['name'], 'name');
        if (name != packageName) {
          continue;
        }
        json.expectKey(packageMap, 'languageVersion');
        packageMap['languageVersion'] = _intendedLanguageVersion;
        // Pub appears to always use a two-space indent. This will minimize the
        // diff between the previous text and the new text.
        var newText = JsonEncoder.withIndent('  ').convert(configMap) + '\n';

        // TODO(srawlins): This is inelegant. We add an "edit" which replaces
        // the entire content of the package config file with new content, while
        // it is likely that only 1 character has changed. I do not know of a
        // JSON parser that yields SourceSpans, so that I may know the proper
        // index. One idea, another hack, would be to write a magic string in
        // place of the version number, encode to JSON, and find the index of
        // the magic string.
        var line = 0;
        var offset = 0;
        var edit = SourceEdit(offset, configText.length, newText);
        listener.addSourceFileEdit(
            'enable Null Safety language feature',
            Location(
                packageConfigFile.path, offset, newText.length, line, 0, 0, 0),
            SourceFileEdit(packageConfigFile.path, 0, edits: [edit]));
      }
    } on FormatException catch (e) {
      _processPackageConfigException(
          'Warning: Encountered an error parsing the package configuration '
          'file: $e\n\nCannot update this file.',
          packageConfigFile.path);
    }
  }

  void _processPackageConfigException(String prefix, String packageConfigPath,
      [Object error = '']) {
    // TODO(#42138): This should use [listener.addRecommendation] when that
    // function is implemented.
    print('''$prefix
  $packageConfigPath
  $error

  Be sure to run `pub get` before examining the results of the migration.
''');
  }

  /// Updates the pubspec.yaml file to specify a minimum Dart SDK version which
  /// supports null safety.
  ///
  /// Return value indicates whether the user's `package_config.json` file
  /// should be updated.
  bool _processPubspec(_YamlFile pubspec, Map<String, Version> neededPackages) {
    bool packageConfigNeedsUpdate = false;
    bool packageDepsUpdated = false;
    var pubspecMap = pubspec.content;
    YamlNode? environmentOptions;
    if (pubspecMap is YamlMap) {
      environmentOptions = pubspecMap.nodes['environment'];
    }
    if (environmentOptions == null) {
      var start = SourceLocation(0, line: 0, column: 0);
      var content = '''
environment:
  sdk: '$_intendedSdkVersionConstraint'
''';
      pubspec._insertAfterParent(
          SourceSpan(start, start, ''), content, listener);
      packageConfigNeedsUpdate = true;
    } else if (environmentOptions is YamlMap) {
      if (_updatePubspecConstraint(pubspec, environmentOptions, 'sdk',
          "'$_intendedSdkVersionConstraint'", _intendedMinimumSdkVersion)) {
        packageConfigNeedsUpdate = true;
      }
    } else {
      // Odd malformed pubspec.  Leave it alone, but go ahead and update the
      // package_config.json file.
      packageConfigNeedsUpdate = true;
    }
    if (neededPackages.isNotEmpty) {
      YamlNode? dependencies;
      if (pubspecMap is YamlMap) {
        dependencies = pubspecMap.nodes['dependencies'];
      }
      if (dependencies == null) {
        var depLines = [
          for (var entry in neededPackages.entries)
            '  ${entry.key}: ^${entry.value}'
        ];
        var start = SourceLocation(0, line: 0, column: 0);
        var content = '''
dependencies:
${depLines.join('\n')}
''';
        pubspec._insertAfterParent(
            SourceSpan(start, start, ''), content, listener);
        packageDepsUpdated = true;
      } else if (dependencies is YamlMap) {
        for (var neededPackage in neededPackages.entries) {
          if (_updatePubspecConstraint(pubspec, dependencies, neededPackage.key,
              '^${neededPackage.value}', neededPackage.value)) {
            packageDepsUpdated = true;
          }
        }
      }
    }
    if (packageDepsUpdated) {
      listener.reportPubGetNeeded(neededPackages);
    }

    return packageConfigNeedsUpdate;
  }

  void _processPubspecException(String action, String pubspecPath, error) {
    listener.client.onFatalError('''Failed to $action pubspec file
  $pubspecPath
  $error

  Manually update this file to enable the Null Safety language feature by
  adding:

    environment:
      sdk: '$_intendedSdkVersionConstraint';
''');
    throw StateError('listener.reportFatalError should never return');
  }

  /// Updates a constraint in the given [pubspec] file.  If [key] is found in
  /// [map], and the corresponding value does has a minimum less than
  /// [minimumVersion], it is updated to [fullVersionConstraint].  If it is not
  /// found, then an entry is added.
  ///
  /// Return value indicates whether a change was made.
  bool _updatePubspecConstraint(_YamlFile pubspec, YamlMap map, String key,
      String fullVersionConstraint, Version minimumVersion) {
    var node = map.nodes[key];
    if (node == null) {
      var content = '''

  $key: $fullVersionConstraint''';
      pubspec._insertAfterParent(map.span, content, listener);
      return true;
    } else if (node is YamlScalar) {
      VersionConstraint currentConstraint;
      if (node.value is String) {
        currentConstraint = VersionConstraint.parse(node.value as String);
        var invalidVersionMessage =
            'The current SDK constraint in pubspec.yaml is invalid. A '
            'minimum version, such as ">=2.7.0", is required when launching '
            "'dart migrate'.";
        if (currentConstraint is Version) {
          // In this case, the constraint is an exact version, like 2.0.0.
          _logger.stderr(invalidVersionMessage);
          return false;
        } else if (currentConstraint is VersionRange) {
          if (currentConstraint.min == null) {
            _logger.stderr(invalidVersionMessage);
            return false;
          } else if (currentConstraint.min! >= minimumVersion) {
            // The current version constraint is already up to date.  Do not
            // edit.
            return false;
          } else {
            // TODO(srawlins): This overwrites the current maximum version. In
            // the uncommon situation that there is a special maximum, it should
            // not.
            pubspec._replaceSpan(node.span, fullVersionConstraint, listener);
            return true;
          }
        } else {
          // The constraint is something different, like a union, like
          // '>=1.0.0 <2.0.0 >=3.0.0 <4.0.0', which is not valid.
          _logger.stderr(invalidVersionMessage);
          return false;
        }
      } else {
        // Something is odd with the constraint we've found in pubspec.yaml;
        // Best to leave it alone.
        return false;
      }
    } else {
      // Something is odd with the format of pubspec.yaml; best to leave it
      // alone.
      return false;
    }
  }

  /// Allows unit tests to shut down any rogue servers that have been started,
  /// so that unit testing can complete.
  @visibleForTesting
  static void shutdownAllServers() {
    for (var server in _allServers) {
      try {
        server!.close();
      } catch (_) {}
    }
    _allServers.clear();
  }

  static Version _computeIntendedMinimumSdkVersion(
      ResourceProvider resourceProvider, String sdkPath) {
    var versionFile = resourceProvider
        .getFile(resourceProvider.pathContext.join(sdkPath, 'version'));
    if (!versionFile.exists) {
      throw StateError(
          'Could not find SDK version file at ${versionFile.path}');
    }
    var sdkVersionString = versionFile.readAsStringSync().trim();
    var sdkVersion = Version.parse(sdkVersionString);
    // Ideally, we would like to set the user's minimum SDK constraint to the
    // version in which null safety was released to stable.  But we only want to
    // do so if we are sure that stable release exists.  An easy way to check
    // that is to see if the current SDK version is greater than or equal to the
    // stable release of null safety.
    var nullSafetyStableReleaseVersion = Feature.non_nullable.releaseVersion!;
    if (sdkVersion >= nullSafetyStableReleaseVersion) {
      // It is, so we can use it as the minimum SDK constraint.
      return nullSafetyStableReleaseVersion;
    } else {
      // It isn't.  This either means that null safety hasn't been released to
      // stable yet (in which case it's definitely not safe to use
      // `nullSafetyStableReleaseVersion` as a minimum SDK constraint), or it
      // has been released but the user hasn't upgraded to it (in which case we
      // don't want to use it as a minimum SDK constraint anyway, because we
      // don't want to force the user to upgrade their SDK in order to be able
      // to use their own package).  Our next best option is to use the user's
      // current SDK version as a minimum SDK constraint, assuming it's a proper
      // beta release version.
      if (sdkVersionString.contains('beta')) {
        // It is, so we can use it.
        return sdkVersion;
      } else {
        // It isn't.  The user is probably either on a bleeding edge version of
        // the SDK (e.g. `2.12.0-edge.<SHA>`), a dev version
        // (e.g. `2.12.0-X.Y.dev`), or an internally built version
        // (e.g. `2.12.0-<large number>`).  All of these version numbers are
        // unsafe for the user to use as their minimum SDK constraint, because
        // if they published their package, it wouldn't be usable with the
        // latest beta release.  So just fall back on using a version of
        // `<stable release>-0`.
        return Version.parse('$nullSafetyStableReleaseVersion-0');
      }
    }
  }

  /// Get the "root" of all [included] paths. See [includedRoot] for its
  /// definition.
  static String _getIncludedRoot(
      List<String> included, ResourceProvider provider) {
    var context = provider.pathContext;
    // This step looks like it may be expensive (`getResource`, splitting up
    // all of the paths, comparing parts, joining one path back together). In
    // practice, this should be cheap because typically only one path is given
    // to dartfix.
    var rootParts = included
        .map((p) => context.normalize(context.absolute(p)))
        .map((p) => provider.getResource(p) is File ? context.dirname(p) : p)
        .map((p) => context.split(p))
        .reduce((value, parts) {
      var shorterPath = value.length < parts.length ? value : parts;
      var length = shorterPath.length;
      for (var i = 0; i < length; i++) {
        if (value[i] != parts[i]) {
          // [value] and [parts] are the same, only up to part [i].
          return value.sublist(0, i);
        }
      }
      // [value] and [parts] are the same up to the full length of the shorter
      // of the two, so just return that.
      return shorterPath;
    });
    return context.joinAll(rootParts);
  }
}

class NullabilityMigrationAdapter implements NullabilityMigrationListener {
  final DartFixListener listener;

  NullabilityMigrationAdapter(this.listener);

  @override
  void addEdit(Source source, SourceEdit edit) {
    listener.addEditWithoutSuggestion(source, edit);
  }

  @override
  void addSuggestion(String descriptions, Location location) {
    listener.addSuggestion(descriptions, location);
  }

  @override
  void reportException(
      Source? source, AstNode? node, Object exception, StackTrace stackTrace) {
    listener.client.onException('''
$exception at offset ${node!.offset} in $source ($node)

$stackTrace''');
  }
}

class _YamlFile {
  final String path;
  final String textContent;

  final YamlNode content;

  _YamlFile._(this.path, this.textContent, this.content);

  String? _getName() {
    YamlNode? packageNameNode;

    if (content is YamlMap) {
      packageNameNode = (content as YamlMap).nodes['name'];
    } else {
      return null;
    }

    if (packageNameNode is YamlScalar && packageNameNode.value is String) {
      return packageNameNode.value as String?;
    } else {
      return null;
    }
  }

  /// Inserts [content] into this file, immediately after [parentSpan].
  void _insertAfterParent(
      SourceSpan parentSpan, String content, DartFixListener listener) {
    var line = parentSpan.end.line;
    var offset = parentSpan.end.offset;
    // Walk [offset] and [line] back to the first non-whitespace character
    // before [offset].
    while (offset > 0) {
      var ch = textContent.codeUnitAt(offset - 1);
      if (ch == $space || ch == $cr) {
        --offset;
      } else if (ch == $lf) {
        --offset;
        --line;
      } else {
        break;
      }
    }
    var edit = SourceEdit(offset, 0, content);
    listener.addSourceFileEdit(
        'enable Null Safety language feature',
        Location(path, offset, content.length, line, 0, 0, 0),
        SourceFileEdit(path, 0, edits: [edit]));
  }

  void _replaceSpan(SourceSpan span, String content, DartFixListener listener) {
    var line = span.start.line;
    var offset = span.start.offset;
    var edit = SourceEdit(offset, span.length, content);
    listener.addSourceFileEdit(
        'enable Null Safety language feature',
        Location(path, offset, content.length, line, 0, 0, 0),
        SourceFileEdit(path, 0, edits: [edit]));
  }

  static _YamlFile _parseFrom(File file) {
    var textContent = file.readAsStringSync();
    var content = loadYaml(textContent);
    if (content is YamlNode) {
      return _YamlFile._(file.path, textContent, content);
    } else {
      throw FormatException('pubspec.yaml is not a YAML map.');
    }
  }
}
