// Copyright (c) 2021, 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:convert' show jsonDecode;
import 'dart:io' show File;

import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;
import 'package:front_end/src/api_prototype/compiler_options.dart';
import 'package:front_end/src/api_prototype/incremental_kernel_generator.dart';
import 'package:front_end/src/api_prototype/memory_file_system.dart';
import 'package:front_end/src/fasta/util/outline_extractor.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/src/equivalence.dart';
import 'package:testing/testing.dart'
    show Chain, ChainContext, ExpectationSet, Result, Step, TestDescription;

import 'fasta/suite_utils.dart';
import 'fasta/testing/environment_keys.dart';
import 'incremental_suite.dart' as helper;
import 'testing_utils.dart' show checkEnvironment;
import 'utils/kernel_chain.dart' show MatchContext;

const String EXPECTATIONS = '''
[
  {
    "name": "ExpectationFileMismatch",
    "group": "Fail"
  },
  {
    "name": "ExpectationFileMissing",
    "group": "Fail"
  }
]
''';

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

Future<Context> createContext(
    Chain suite, Map<String, String> environment) async {
  const Set<String> knownEnvironmentKeys = {
    EnvironmentKeys.updateExpectations,
  };
  checkEnvironment(environment, knownEnvironmentKeys);

  bool updateExpectations =
      environment[EnvironmentKeys.updateExpectations] == "true";

  return new Context(suite.name, updateExpectations);
}

class Context extends ChainContext with MatchContext {
  @override
  final bool updateExpectations;

  @override
  String get updateExpectationsOption =>
      '${EnvironmentKeys.updateExpectations}=true';

  @override
  bool get canBeFixWithUpdateExpectations => true;

  final String suiteName;

  Context(this.suiteName, this.updateExpectations);

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

  @override
  final ExpectationSet expectationSet =
      new ExpectationSet.fromJsonList(jsonDecode(EXPECTATIONS));
}

class OutlineExtractorStep
    extends Step<TestDescription, TestDescription, Context> {
  const OutlineExtractorStep();

  @override
  String get name => "OutlineExtractorStep";

  @override
  Future<Result<TestDescription>> run(
      TestDescription description, Context context) async {
    Uri? packages = description.uri.resolve(".dart_tool/package_config.json");
    if (!new File.fromUri(packages).existsSync()) {
      packages = null;
    }
    Map<Uri, String> result =
        await extractOutline([description.uri], packages: packages);
    StringBuffer sb = new StringBuffer();
    Uri uri = description.uri;
    Uri base = uri.resolve(".");
    Uri dartBase = Uri.base;

    for (MapEntry<Uri, String> entry in result.entries) {
      sb.writeln("${entry.key}:");
      sb.writeln(entry.value);
      sb.writeln("\n\n");
    }

    String actual = sb.toString();
    actual = actual.replaceAll("$base", "org-dartlang-testcase:///");
    actual = actual.replaceAll("$dartBase", "org-dartlang-testcase-sdk:///");
    actual = actual.replaceAll("\\n", "\n");

    return context.match<TestDescription>(
      ".outline_extracted",
      actual,
      description.uri,
      description,
    );
  }
}

class CompileAndCompareStep
    extends Step<TestDescription, TestDescription, Context> {
  const CompileAndCompareStep();

  @override
  String get name => "CompileAndCompare";

  @override
  Future<Result<TestDescription>> run(
      TestDescription description, Context context) async {
    Uri? packages = description.uri.resolve(".dart_tool/package_config.json");
    if (!new File.fromUri(packages).existsSync()) {
      packages = null;
    }
    Map<Uri, String> processedFiles =
        await extractOutline([description.uri], packages: packages);

    void onDiagnostic(DiagnosticMessage message) {
      if (message.severity == Severity.error ||
          message.severity == Severity.warning) {
        throw ("Unexpected error: ${message.plainTextFormatted.join('\n')}");
      }
    }

    Library lib1;
    {
      CompilerOptions options = helper.getOptions();
      options.onDiagnostic = onDiagnostic;
      options.packagesFileUri = packages;
      helper.TestIncrementalCompiler compiler =
          new helper.TestIncrementalCompiler(options, description.uri,
              /* initializeFrom = */ null, /* outlineOnly = */ true);
      IncrementalCompilerResult c = await compiler.computeDelta();
      lib1 = c.component.libraries
          .firstWhere((element) => element.fileUri == description.uri);
    }
    Library lib2;
    {
      CompilerOptions options = helper.getOptions();
      options.onDiagnostic = onDiagnostic;
      options.packagesFileUri = packages;
      MemoryFileSystem mfs = new MemoryFileSystem(Uri.base);
      if (packages != null) {
        mfs.entityForUri(packages).writeAsBytesSync(
            await options.fileSystem.entityForUri(packages).readAsBytes());
      }
      if (options.sdkSummary != null) {
        mfs.entityForUri(options.sdkSummary!).writeAsBytesSync(await options
            .fileSystem
            .entityForUri(options.sdkSummary!)
            .readAsBytes());
      }
      if (options.librariesSpecificationUri != null) {
        mfs.entityForUri(options.librariesSpecificationUri!).writeAsBytesSync(
            await options.fileSystem
                .entityForUri(options.librariesSpecificationUri!)
                .readAsBytes());
      }
      for (MapEntry<Uri, String> entry in processedFiles.entries) {
        mfs.entityForUri(entry.key).writeAsStringSync(entry.value);
      }
      options.fileSystem = mfs;
      helper.TestIncrementalCompiler compiler =
          new helper.TestIncrementalCompiler(options, description.uri,
              /* initializeFrom = */ null, /* outlineOnly = */ true);
      IncrementalCompilerResult c = await compiler.computeDelta();
      lib2 = c.component.libraries
          .firstWhere((element) => element.fileUri == description.uri);
    }
    EquivalenceResult result =
        checkEquivalence(lib1, lib2, strategy: const Strategy());

    if (result.isEquivalent) {
      return new Result<TestDescription>.pass(description);
    } else {
      print("Bad:");
      print(result);
      return new Result<TestDescription>.fail(
          description, /* error = */ result);
    }
  }
}

class Strategy extends EquivalenceStrategy {
  const Strategy();

  @override
  bool checkTreeNode_fileOffset(
      EquivalenceVisitor visitor, TreeNode node, TreeNode other) {
    return true;
  }

  @override
  bool checkAssertStatement_conditionStartOffset(
      EquivalenceVisitor visitor, AssertStatement node, AssertStatement other) {
    return true;
  }

  @override
  bool checkAssertStatement_conditionEndOffset(
      EquivalenceVisitor visitor, AssertStatement node, AssertStatement other) {
    return true;
  }

  @override
  bool checkClass_startFileOffset(
      EquivalenceVisitor visitor, Class node, Class other) {
    return true;
  }

  @override
  bool checkClass_fileEndOffset(
      EquivalenceVisitor visitor, Class node, Class other) {
    return true;
  }

  @override
  bool checkProcedure_fileStartOffset(
      EquivalenceVisitor visitor, Procedure node, Procedure other) {
    return true;
  }

  @override
  bool checkConstructor_startFileOffset(
      EquivalenceVisitor visitor, Constructor node, Constructor other) {
    return true;
  }

  @override
  bool checkMember_fileEndOffset(
      EquivalenceVisitor visitor, Member node, Member other) {
    return true;
  }

  @override
  bool checkFunctionNode_fileEndOffset(
      EquivalenceVisitor visitor, FunctionNode node, FunctionNode other) {
    return true;
  }

  @override
  bool checkBlock_fileEndOffset(
      EquivalenceVisitor visitor, Block node, Block other) {
    return true;
  }

  @override
  bool checkLibrary_additionalExports(
      EquivalenceVisitor visitor, Library node, Library other) {
    return visitor.checkSets(
        node.additionalExports.toSet(),
        other.additionalExports.toSet(),
        visitor.matchReferences,
        visitor.checkReferences,
        'additionalExports');
  }

  @override
  bool checkClass_procedures(
      EquivalenceVisitor visitor, Class node, Class other) {
    // Check procedures as a set instead of a list to allow for reordering.
    List<Procedure> a = node.procedures.toList();
    int sorter(Procedure x, Procedure y) {
      int result = x.name.text.compareTo(y.name.text);
      if (result != 0) return result;
      result = x.kind.index - y.kind.index;
      if (result != 0) return result;
      // other stuff?
      return 0;
    }

    a.sort(sorter);
    List<Procedure> b = other.procedures.toList();
    b.sort(sorter);
    // return visitor.checkSets(a.toSet(), b.toSet(),
    //     visitor.matchNamedNodes, visitor.checkNodes, 'procedures');

    return visitor.checkLists(a, b, visitor.checkNodes, 'procedures');
  }
}
