// 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:io' show File;
import 'dart:typed_data' show Uint8List;

import 'package:_fe_analyzer_shared/src/parser/listener.dart' show Listener;
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
    show FormalParameterKind, MemberKind, Parser;
import 'package:_fe_analyzer_shared/src/scanner/abstract_scanner.dart'
    show ScannerConfiguration;
import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart'
    show Utf8BytesScanner;
import 'package:front_end/src/base/command_line_reporting.dart'
    as command_line_reporting;
import 'package:front_end/src/source/diet_parser.dart'
    show useImplicitCreationExpressionInCfe;
import 'package:kernel/kernel.dart';
import 'package:package_config/package_config.dart';
import 'package:testing/testing.dart'
    show Chain, ChainContext, Result, Step, TestDescription;

import 'utils/suite_utils.dart';
import 'testing_utils.dart' show checkEnvironment, filterList;

void main([List<String> arguments = const []]) => internalMain(createContext,
    arguments: arguments,
    displayName: "lint suite",
    configurationPath: "../testing.json");

Future<Context> createContext(Chain suite, Map<String, String> environment) {
  const Set<String> knownEnvironmentKeys = {"onlyInGit"};
  checkEnvironment(environment, knownEnvironmentKeys);

  bool onlyInGit = environment["onlyInGit"] != "false";
  return new Future.value(new Context(onlyInGit: onlyInGit));
}

class LintTestDescription extends TestDescription {
  @override
  final String shortName;
  @override
  final Uri uri;
  final LintTestCache cache;
  final LintListener listener;

  LintTestDescription(this.shortName, this.uri, this.cache, this.listener) {
    this.listener.description = this;
    this.listener.uri = uri;
  }

  String getErrorMessage(int offset, int squigglyLength, String message) {
    cache.source ??= new Source(cache.lineStarts, cache.rawBytes!, uri, uri);
    Location location = cache.source!.getLocation(uri, offset);
    return command_line_reporting.formatErrorMessage(
        cache.source!.getTextLine(location.line),
        location,
        squigglyLength,
        uri.toString(),
        message);
  }
}

class LintTestCache {
  Uint8List? rawBytes;
  late List<int> lineStarts;
  Source? source;
  Token? firstToken;
  PackageConfig? packages;
}

class Context extends ChainContext {
  final bool onlyInGit;
  Context({required this.onlyInGit});

  @override
  final List<Step> steps = const <Step>[
    const LintStep(),
  ];

  @override
  Future<List<LintTestDescription>> list(Chain suite) async {
    String rootString = "${suite.root}";
    Uri apiUnstableUri =
        Uri.base.resolve("pkg/front_end/lib/src/api_unstable/");
    String apiUnstableString = apiUnstableUri.toString();

    List<LintTestDescription> result = [];
    for (TestDescription description
        in await filterList(suite, onlyInGit, await super.list(suite))) {
      String baseName = "${description.uri}".substring(rootString.length);
      baseName = baseName.substring(0, baseName.length - ".dart".length);
      LintTestCache cache = new LintTestCache();

      result.add(new LintTestDescription(
        "$baseName/ExplicitType",
        description.uri,
        cache,
        new ExplicitTypeLintListener(),
      ));

      result.add(new LintTestDescription(
        "$baseName/ImportsTwice",
        description.uri,
        cache,
        new ImportsTwiceLintListener(),
      ));

      if (!description.uri.toString().startsWith(apiUnstableString)) {
        result.add(new LintTestDescription(
          "$baseName/Exports",
          description.uri,
          cache,
          new ExportsLintListener(),
        ));
      }
    }
    return result;
  }
}

class LintStep extends Step<LintTestDescription, LintTestDescription, Context> {
  const LintStep();

  @override
  String get name => "lint";

  @override
  Future<Result<LintTestDescription>> run(
      LintTestDescription description, Context context) async {
    if (description.cache.rawBytes == null) {
      File f = new File.fromUri(description.uri);
      Uint8List bytes = description.cache.rawBytes = f.readAsBytesSync();
      Utf8BytesScanner scanner = new Utf8BytesScanner(
        bytes,
        configuration: const ScannerConfiguration(enableTripleShift: true),
        includeComments: true,
        languageVersionChanged: (scanner, languageVersion) {
          // Nothing - but don't overwrite the previous settings.
        },
      );
      description.cache.firstToken = scanner.tokenize();
      description.cache.lineStarts = scanner.lineStarts;

      Uri packageConfig =
          description.uri.resolve(".dart_tool/package_config.json");
      while (true) {
        if (new File.fromUri(packageConfig).existsSync()) {
          break;
        }
        // Stupid bailout.
        if (packageConfig.pathSegments.length < Uri.base.pathSegments.length) {
          break;
        }
        packageConfig =
            packageConfig.resolve("../../.dart_tool/package_config.json");
      }

      File packageConfigUri = new File.fromUri(packageConfig);
      if (packageConfigUri.existsSync()) {
        description.cache.packages = await loadPackageConfigUri(packageConfig);
      }
    }

    if (description.cache.firstToken == null) {
      return crash(description, StackTrace.current);
    }

    Parser parser = new Parser(description.listener,
        useImplicitCreationExpression: useImplicitCreationExpressionInCfe,
        allowPatterns: true,
        enableFeatureEnhancedParts: true);
    parser.parseUnit(description.cache.firstToken!);

    if (description.listener.problems.isEmpty) {
      return pass(description);
    }
    return fail(description, description.listener.problems.join("\n\n"));
  }
}

class LintListener extends Listener {
  List<String> problems = <String>[];
  late final LintTestDescription description;
  @override
  late final Uri uri;

  void onProblem(int offset, int squigglyLength, String message) {
    problems.add(description.getErrorMessage(offset, squigglyLength, message));
  }
}

class ExplicitTypeLintListener extends LintListener {
  List<LatestType> _latestTypes = <LatestType>[];

  @override
  void beginVariablesDeclaration(
      Token token, Token? lateToken, Token? varFinalOrConst) {
    if (!_latestTypes.last.type) {
      onProblem(
          varFinalOrConst!.offset, varFinalOrConst.length, "No explicit type.");
    }
  }

  @override
  void handleType(Token beginToken, Token? questionMark) {
    _latestTypes.add(new LatestType(beginToken, true));
  }

  @override
  void handleNoType(Token lastConsumed) {
    _latestTypes.add(new LatestType(lastConsumed, false));
  }

  @override
  void endFunctionType(Token functionToken, Token? questionMark) {
    _latestTypes.add(new LatestType(functionToken, true));
  }

  @override
  void endTopLevelFields(
      Token? augmentToken,
      Token? externalToken,
      Token? staticToken,
      Token? covariantToken,
      Token? lateToken,
      Token? varFinalOrConst,
      int count,
      Token beginToken,
      Token endToken) {
    if (!_latestTypes.last.type) {
      onProblem(beginToken.offset, beginToken.length, "No explicit type.");
    }
    _latestTypes.removeLast();
  }

  @override
  void endClassFields(
      Token? abstractToken,
      Token? augmentToken,
      Token? externalToken,
      Token? staticToken,
      Token? covariantToken,
      Token? lateToken,
      Token? varFinalOrConst,
      int count,
      Token beginToken,
      Token endToken) {
    if (!_latestTypes.last.type) {
      onProblem(
          varFinalOrConst!.offset, varFinalOrConst.length, "No explicit type.");
    }
    _latestTypes.removeLast();
  }

  @override
  void endFormalParameter(
      Token? thisKeyword,
      Token? superKeyword,
      Token? periodAfterThisOrSuper,
      Token nameToken,
      Token? initializerStart,
      Token? initializerEnd,
      FormalParameterKind kind,
      MemberKind memberKind) {
    _latestTypes.removeLast();
  }
}

class LatestType {
  final Token token;
  bool type;

  LatestType(this.token, this.type);
}

class ImportsTwiceLintListener extends LintListener {
  Map<Uri, Set<String?>> seenImports = {};

  Token? seenAsKeyword;

  @override
  void handleImportPrefix(Token? deferredKeyword, Token? asKeyword) {
    seenAsKeyword = asKeyword;
  }

  @override
  void endImport(Token importKeyword, Token? augmentToken, Token? semicolon) {
    Token importUriToken = importKeyword.next!;
    String importUri = importUriToken.lexeme;
    if (importUri.startsWith("r")) {
      importUri = importUri.substring(2, importUri.length - 1);
    } else {
      importUri = importUri.substring(1, importUri.length - 1);
    }
    Uri resolved = uri.resolve(importUri);
    if (resolved.isScheme("package")) {
      if (description.cache.packages != null) {
        resolved = description.cache.packages!.resolve(resolved)!;
      }
    }
    String? asName = seenAsKeyword?.lexeme;
    Set<String?> asNames = seenImports[resolved] ??= {};
    if (!asNames.add(asName)) {
      if (asName != null) {
        onProblem(importUriToken.offset, importUriToken.lexeme.length,
            "Uri '$resolved' already imported once as '${asName}'.");
      } else {
        onProblem(importUriToken.offset, importUriToken.lexeme.length,
            "Uri '$resolved' already imported once.");
      }
    }
  }
}

class ExportsLintListener extends LintListener {
  @override
  void endExport(Token exportKeyword, Token semicolon) {
    Token exportUriToken = exportKeyword.next!;
    String exportUri = exportUriToken.lexeme;
    if (exportUri.startsWith("r")) {
      exportUri = exportUri.substring(2, exportUri.length - 1);
    } else {
      exportUri = exportUri.substring(1, exportUri.length - 1);
    }
    Uri resolved = uri.resolve(exportUri);

    if (resolved.isScheme("package") && resolved.path.startsWith('kernel/')) {
      // Exporting from `package:kernel` is allowed.
      return;
    }

    // Allowlist specific exports.
    if (resolved.isScheme('package') &&
        ['_fe_analyzer_shared/src/macros/uri.dart'].contains(resolved.path)) {
      return;
    }

    if (resolved.isScheme("package")) {
      if (description.cache.packages != null) {
        resolved = description.cache.packages!.resolve(resolved)!;
      }
    }
    onProblem(exportUriToken.offset, exportUriToken.lexeme.length,
        "Exports disallowed internally.");
  }
}
