// Copyright (c) 2017, 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.

// @dart=2.10

import 'dart:async';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:collection/collection.dart';
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';
import 'package:stack_trace/stack_trace.dart';

import '../dart.dart';
import '../entrypoint.dart';
import '../io.dart';
import '../log.dart' as log;
import '../utils.dart';
import '../validator.dart';

/// Validates that Dart source files only import declared dependencies.
class StrictDependenciesValidator extends Validator {
  final AnalysisContextManager analysisContextManager =
      AnalysisContextManager();

  StrictDependenciesValidator(Entrypoint entrypoint) : super(entrypoint) {
    var packagePath = p.normalize(p.absolute(entrypoint.root.dir));
    analysisContextManager.createContextsForDirectory(packagePath);
  }

  /// Lazily returns all dependency uses in [files].
  ///
  /// Files that do not parse and directives that don't import or export
  /// `package:` URLs are ignored.
  Iterable<_Usage> _findPackages(Iterable<String> files) sync* {
    for (var file in files) {
      List<UriBasedDirective> directives;
      var contents = readTextFile(file);
      try {
        directives = analysisContextManager.parseImportsAndExports(file);
      } on AnalyzerErrorGroup catch (e, s) {
        // Ignore files that do not parse.
        log.fine(getErrorMessage(e));
        log.fine(Chain.forTrace(s).terse);
        continue;
      }

      for (var directive in directives) {
        Uri url;
        try {
          url = Uri.parse(directive.uri.stringValue);
        } on FormatException catch (_) {
          // Ignore a format exception. [url] will be null, and we'll emit an
          // "Invalid URL" warning below.
        }

        // If the URL could not be parsed or it is a `package:` URL AND there
        // are no segments OR any segment are empty, it's invalid.
        if (url == null ||
            (url.scheme == 'package' &&
                (url.pathSegments.length < 2 ||
                    url.pathSegments.any((s) => s.isEmpty)))) {
          errors.add(
              _Usage.errorMessage('Invalid URL.', file, contents, directive));
        } else if (url.scheme == 'package') {
          yield _Usage(file, contents, directive, url);
        }
      }
    }
  }

  @override
  Future validate() async {
    var dependencies = entrypoint.root.dependencies.keys.toSet()
      ..add(entrypoint.root.name);
    var devDependencies = MapKeySet(entrypoint.root.devDependencies);
    _validateLibBin(dependencies, devDependencies);
    _validateBenchmarkTestTool(dependencies, devDependencies);
  }

  /// Validates that no Dart files in `lib/` or `bin/` have dependencies that
  /// aren't in [deps].
  ///
  /// The [devDeps] are used to generate special warnings for files that import
  /// dev dependencies.
  void _validateLibBin(Set<String> deps, Set<String> devDeps) {
    for (var usage in _usagesBeneath(['lib', 'bin'])) {
      if (!deps.contains(usage.package)) {
        if (devDeps.contains(usage.package)) {
          errors.add(usage.dependencyMisplaceMessage());
        } else {
          errors.add(usage.dependencyMissingMessage());
        }
      }
    }
  }

  /// Validates that no Dart files in `benchmark/`, `test/` or
  /// `tool/` have dependencies that aren't in [deps] or [devDeps].
  void _validateBenchmarkTestTool(Set<String> deps, Set<String> devDeps) {
    var directories = ['benchmark', 'test', 'tool'];
    for (var usage in _usagesBeneath(directories)) {
      if (!deps.contains(usage.package) && !devDeps.contains(usage.package)) {
        warnings.add(usage.dependenciesMissingMessage());
      }
    }
  }

  Iterable<_Usage> _usagesBeneath(List<String> paths) => _findPackages(paths
      .map((path) => entrypoint.root.listFiles(beneath: path))
      .expand((files) => files)
      .where((String file) => p.extension(file) == '.dart'));
}

/// A parsed import or export directive in a D source file.
class _Usage {
  /// Returns a formatted error message highlighting [directive] in [file].
  static String errorMessage(String message, String file, String contents,
      UriBasedDirective directive) {
    return SourceFile.fromString(contents, url: file)
        .span(directive.offset, directive.offset + directive.length)
        .message(message);
  }

  /// The path to the file from which [_directive] was parsed.
  final String _file;

  /// The contents of [_file].
  final String _contents;

  /// The URI parsed from [_directive].
  final Uri _url;

  /// The directive that uses [_url].
  final UriBasedDirective _directive;

  _Usage(this._file, this._contents, this._directive, this._url);

  /// The name of the package referred to by this usage..
  String get package => _url.pathSegments.first;

  /// Returns a message associated with [_directive].
  ///
  /// We assume that normally all directives are valid and we won't see an error
  /// message, so we create the SourceFile lazily to avoid parsing line endings
  /// in the case of only valid directives.
  String _toMessage(String message) =>
      errorMessage(message, _file, _contents, _directive);

  /// Returns an error message saying the package is not listed in `dependencies`.
  String dependencyMissingMessage() =>
      _toMessage('This package does not have $package in the `dependencies` '
          'section of `pubspec.yaml`.');

  /// Returns an error message saying the package is not listed in `dependencies`
  ///  or `dev_dependencies`.
  String dependenciesMissingMessage() =>
      _toMessage('This package does not have $package in the `dependencies` '
          'or `dev_dependencies` section of `pubspec.yaml`.');

  /// Returns an error message saying the package should be in `dependencies`.
  String dependencyMisplaceMessage() {
    var shortFile = p.split(p.relative(_file)).first;
    return _toMessage(
        '$package is in the `dev_dependencies` section of `pubspec.yaml`. '
        'Packages used in $shortFile/ must be declared in the `dependencies` '
        'section.');
  }
}
