// 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/fasta/command_line_reporting.dart'
    as command_line_reporting;
import 'package:front_end/src/fasta/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 'fasta/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) async {
  const Set<String> knownEnvironmentKeys = {"onlyInGit"};
  checkEnvironment(environment, knownEnvironmentKeys);

  bool onlyInGit = environment["onlyInGit"] != "false";
  return 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 {
  List<int>? 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);
      description.cache.rawBytes = f.readAsBytesSync();

      Uint8List bytes = new Uint8List(description.cache.rawBytes!.length + 1);
      bytes.setRange(
          0, description.cache.rawBytes!.length, description.cache.rawBytes!);

      Utf8BytesScanner scanner = new Utf8BytesScanner(
        bytes,
        configuration: const ScannerConfiguration(
            enableExtensionMethods: true,
            enableNonNullable: true,
            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);
    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;
    }

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