// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @dart = 2.8

import 'package:args/args.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'package:yaml/yaml.dart' as yaml;

import '../artifacts.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/platform.dart';
import '../base/terminal.dart';
import '../base/utils.dart';
import '../cache.dart';
import '../globals_null_migrated.dart' as globals;

/// Common behavior for `flutter analyze` and `flutter analyze --watch`
abstract class AnalyzeBase {
  AnalyzeBase(this.argResults, {
    @required this.repoRoots,
    @required this.repoPackages,
    @required this.fileSystem,
    @required this.logger,
    @required this.platform,
    @required this.processManager,
    @required this.terminal,
    @required this.artifacts,
  });

  /// The parsed argument results for execution.
  final ArgResults argResults;
  @protected
  final List<String> repoRoots;
  @protected
  final List<Directory> repoPackages;
  @protected
  final FileSystem fileSystem;
  @protected
  final Logger logger;
  @protected
  final ProcessManager processManager;
  @protected
  final Platform platform;
  @protected
  final Terminal terminal;
  @protected
  final Artifacts artifacts;

  /// Called by [AnalyzeCommand] to start the analysis process.
  Future<void> analyze();

  void dumpErrors(Iterable<String> errors) {
    if (argResults['write'] != null) {
      try {
        final RandomAccessFile resultsFile = fileSystem.file(argResults['write']).openSync(mode: FileMode.write);
        try {
          resultsFile.lockSync();
          resultsFile.writeStringSync(errors.join('\n'));
        } finally {
          resultsFile.close();
        }
      } on Exception catch (e) {
        logger.printError('Failed to save output to "${argResults['write']}": $e');
      }
    }
  }

  void writeBenchmark(Stopwatch stopwatch, int errorCount) {
    const String benchmarkOut = 'analysis_benchmark.json';
    final Map<String, dynamic> data = <String, dynamic>{
      'time': stopwatch.elapsedMilliseconds / 1000.0,
      'issues': errorCount,
    };
    fileSystem.file(benchmarkOut).writeAsStringSync(toPrettyJson(data));
    logger.printStatus('Analysis benchmark written to $benchmarkOut ($data).');
  }

  bool get isFlutterRepo => argResults['flutter-repo'] as bool;
  String get sdkPath => argResults['dart-sdk'] as String ?? artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path;
  bool get isBenchmarking => argResults['benchmark'] as bool;
  String get protocolTrafficLog => argResults['protocol-traffic-log'] as String;

  /// Generate an analysis summary for both [AnalyzeOnce], [AnalyzeContinuously].
  static String generateErrorsMessage({
    @required int issueCount,
    int issueDiff,
    int files,
    @required String seconds,
  }) {
    final StringBuffer errorsMessage = StringBuffer(issueCount > 0
      ? '$issueCount ${pluralize('issue', issueCount)} found.'
      : 'No issues found!');

    // Only [AnalyzeContinuously] has issueDiff message.
    if (issueDiff != null) {
      if (issueDiff > 0) {
        errorsMessage.write(' ($issueDiff new)');
      } else if (issueDiff < 0) {
        errorsMessage.write(' (${-issueDiff} fixed)');
      }
    }

    // Only [AnalyzeContinuously] has files message.
    if (files != null) {
      errorsMessage.write(' • analyzed $files ${pluralize('file', files)}');
    }
    errorsMessage.write(' (ran in ${seconds}s)');
    return errorsMessage.toString();
  }
}

class PackageDependency {
  // This is a map from dependency targets (lib directories) to a list
  // of places that ask for that target (.packages or pubspec.yaml files)
  Map<String, List<String>> values = <String, List<String>>{};
  String canonicalSource;
  void addCanonicalCase(String packagePath, String pubSpecYamlPath) {
    assert(canonicalSource == null);
    add(packagePath, pubSpecYamlPath);
    canonicalSource = pubSpecYamlPath;
  }
  void add(String packagePath, String sourcePath) {
    values.putIfAbsent(packagePath, () => <String>[]).add(sourcePath);
  }
  bool get hasConflict => values.length > 1;
  bool get hasConflictAffectingFlutterRepo {
    assert(globals.fs.path.isAbsolute(Cache.flutterRoot));
    for (final List<String> targetSources in values.values) {
      for (final String source in targetSources) {
        assert(globals.fs.path.isAbsolute(source));
        if (globals.fs.path.isWithin(Cache.flutterRoot, source)) {
          return true;
        }
      }
    }
    return false;
  }
  void describeConflict(StringBuffer result) {
    assert(hasConflict);
    final List<String> targets = values.keys.toList();
    targets.sort((String a, String b) => values[b].length.compareTo(values[a].length));
    for (final String target in targets) {
      final int count = values[target].length;
      result.writeln('  $count ${count == 1 ? 'source wants' : 'sources want'} "$target":');
      bool canonical = false;
      for (final String source in values[target]) {
        result.writeln('    $source');
        if (source == canonicalSource) {
          canonical = true;
        }
      }
      if (canonical) {
        result.writeln('    (This is the actual package definition, so it is considered the canonical "right answer".)');
      }
    }
  }
  String get target => values.keys.single;
}

class PackageDependencyTracker {
  /// Packages whose source is defined in the vended SDK.
  static const List<String> _vendedSdkPackages = <String>['analyzer', 'front_end', 'kernel'];

  // This is a map from package names to objects that track the paths
  // involved (sources and targets).
  Map<String, PackageDependency> packages = <String, PackageDependency>{};

  PackageDependency getPackageDependency(String packageName) {
    return packages.putIfAbsent(packageName, () => PackageDependency());
  }

  /// Read the .packages file in [directory] and add referenced packages to [dependencies].
  void addDependenciesFromPackagesFileIn(Directory directory) {
    final String dotPackagesPath = globals.fs.path.join(directory.path, '.packages');
    final File dotPackages = globals.fs.file(dotPackagesPath);
    if (dotPackages.existsSync()) {
      // this directory has opinions about what we should be using
      final Iterable<String> lines = dotPackages
        .readAsStringSync()
        .split('\n')
        .where((String line) => !line.startsWith(RegExp(r'^ *#')));
      for (final String line in lines) {
        final int colon = line.indexOf(':');
        if (colon > 0) {
          final String packageName = line.substring(0, colon);
          final String packagePath = globals.fs.path.fromUri(line.substring(colon+1));
          // Ensure that we only add `analyzer` and dependent packages defined in the vended SDK (and referred to with a local
          // globals.fs.path. directive). Analyzer package versions reached via transitive dependencies (e.g., via `test`) are ignored
          // since they would produce spurious conflicts.
          if (!_vendedSdkPackages.contains(packageName) || packagePath.startsWith('..')) {
            add(packageName, globals.fs.path.normalize(globals.fs.path.absolute(directory.path, packagePath)), dotPackagesPath);
          }
        }
      }
    }
  }

  void addCanonicalCase(String packageName, String packagePath, String pubSpecYamlPath) {
    getPackageDependency(packageName).addCanonicalCase(packagePath, pubSpecYamlPath);
  }

  void add(String packageName, String packagePath, String dotPackagesPath) {
    getPackageDependency(packageName).add(packagePath, dotPackagesPath);
  }

  void checkForConflictingDependencies(Iterable<Directory> pubSpecDirectories, PackageDependencyTracker dependencies) {
    for (final Directory directory in pubSpecDirectories) {
      final String pubSpecYamlPath = globals.fs.path.join(directory.path, 'pubspec.yaml');
      final File pubSpecYamlFile = globals.fs.file(pubSpecYamlPath);
      if (pubSpecYamlFile.existsSync()) {
        // we are analyzing the actual canonical source for this package;
        // make sure we remember that, in case all the packages are actually
        // pointing elsewhere somehow.
        final dynamic pubSpecYaml = yaml.loadYaml(globals.fs.file(pubSpecYamlPath).readAsStringSync());
        if (pubSpecYaml is yaml.YamlMap) {
          final dynamic packageName = pubSpecYaml['name'];
          if (packageName is String) {
            final String packagePath = globals.fs.path.normalize(globals.fs.path.absolute(globals.fs.path.join(directory.path, 'lib')));
            dependencies.addCanonicalCase(packageName, packagePath, pubSpecYamlPath);
          } else {
            throwToolExit('pubspec.yaml is malformed. The name should be a String.');
          }
        } else {
          throwToolExit('pubspec.yaml is malformed.');
        }
      }
      dependencies.addDependenciesFromPackagesFileIn(directory);
    }

    // prepare a union of all the .packages files
    if (dependencies.hasConflicts) {
      final StringBuffer message = StringBuffer();
      message.writeln(dependencies.generateConflictReport());
      message.writeln('Make sure you have run "pub upgrade" in all the directories mentioned above.');
      if (dependencies.hasConflictsAffectingFlutterRepo) {
        message.writeln(
          'For packages in the flutter repository, try using "flutter update-packages" to do all of them at once.\n'
          'If you need to actually upgrade them, consider "flutter update-packages --force-upgrade". '
          '(This will update your pubspec.yaml files as well, so you may wish to do this on a separate branch.)'
        );
      }
      message.write(
        'If this does not help, to track down the conflict you can use '
        '"pub deps --style=list" and "pub upgrade --verbosity=solver" in the affected directories.'
      );
      throwToolExit(message.toString());
    }
  }

  bool get hasConflicts {
    return packages.values.any((PackageDependency dependency) => dependency.hasConflict);
  }

  bool get hasConflictsAffectingFlutterRepo {
    return packages.values.any((PackageDependency dependency) => dependency.hasConflictAffectingFlutterRepo);
  }

  String generateConflictReport() {
    assert(hasConflicts);
    final StringBuffer result = StringBuffer();
    for (final String package in packages.keys.where((String package) => packages[package].hasConflict)) {
      result.writeln('Package "$package" has conflicts:');
      packages[package].describeConflict(result);
    }
    return result.toString();
  }

  Map<String, String> asPackageMap() {
    final Map<String, String> result = <String, String>{};
    for (final String package in packages.keys) {
      result[package] = packages[package].target;
    }
    return result;
  }
}
