// Copyright (c) 2018, 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 'package:_fe_analyzer_shared/src/messages/diagnostic_message.dart'
    show DiagnosticMessage, getMessageCodeObject;

import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity;

import 'package:expect/expect.dart' show Expect;

import 'package:front_end/src/api_prototype/compiler_options.dart'
    show CompilerOptions;

import 'package:front_end/src/api_prototype/experimental_flags.dart'
    show ExperimentalFlag;

import 'package:front_end/src/api_prototype/incremental_kernel_generator.dart'
    show IncrementalCompilerResult;

import "package:front_end/src/api_prototype/memory_file_system.dart"
    show MemoryFileSystem;

import 'package:front_end/src/base/nnbd_mode.dart' show NnbdMode;

import 'package:front_end/src/base/processed_options.dart'
    show ProcessedOptions;

import 'package:front_end/src/compute_platform_binaries_location.dart'
    show computePlatformBinariesLocation;

import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;

import 'package:front_end/src/fasta/fasta_codes.dart'
    show
        Code,
        codeInitializeFromDillNotSelfContained,
        codeInitializeFromDillNotSelfContainedNoDump,
        codeInitializeFromDillUnknownProblem,
        codeInitializeFromDillUnknownProblemNoDump;

import 'package:front_end/src/fasta/incremental_compiler.dart'
    show IncrementalCompiler, RecorderForTesting;

import 'package:front_end/src/fasta/kernel/utils.dart' show serializeComponent;

import 'package:kernel/kernel.dart'
    show Component, Library, NonNullableByDefaultCompiledMode;

import 'incremental_suite.dart' show getOptions;

Future<Null> main() async {
  Tester tester = new Tester();
  await tester.initialize();
  await tester.test();
}

class Tester {
  late Uri sdkRoot;
  late Uri base;
  late Uri sdkSummary;
  late Uri initializeFrom;
  late Uri helperFile;
  late Uri helper2File;
  late Uri entryPoint;
  late Uri entryPointImportDartFoo;
  late Uri platformUri;
  late List<int> sdkSummaryData;
  late List<DiagnosticMessage> errorMessages;
  late List<DiagnosticMessage> warningMessages;
  late MemoryFileSystem fs;
  late CompilerOptions options;
  late IncrementalCompiler compiler;

  Future<void> compileExpectInitializeFailAndSpecificWarning(
      Code expectedWarningCode, bool writeFileOnCrashReport) async {
    errorMessages.clear();
    warningMessages.clear();
    options.writeFileOnCrashReport = writeFileOnCrashReport;
    compiler = new DeleteTempFilesIncrementalCompiler(
        new CompilerContext(
            new ProcessedOptions(options: options, inputs: [entryPoint])),
        initializeFrom);
    await compiler.computeDelta();
    if (compiler.initializedFromDillForTesting) {
      Expect.fail("Expected to not be able to initialized from dill, but did.");
    }
    if (errorMessages.isNotEmpty) {
      Expect.fail("Got unexpected errors: " + joinMessages(errorMessages));
    }
    if (warningMessages.length != 1) {
      Expect.fail("Got unexpected errors: Expected one, got this: " +
          joinMessages(warningMessages));
    }
    if (getMessageCodeObject(warningMessages[0]) != expectedWarningCode) {
      Expect.fail("Expected ${expectedWarningCode.name} but got " +
          joinMessages(warningMessages));
    }
  }

  Future<Component> compileExpectOk(
      bool initializedFromDill, Uri compileThis) async {
    errorMessages.clear();
    warningMessages.clear();
    options.writeFileOnCrashReport = false;
    compiler = new DeleteTempFilesIncrementalCompiler(
        new CompilerContext(
            new ProcessedOptions(options: options, inputs: [compileThis])),
        initializeFrom);
    IncrementalCompilerResult compilerResult = await compiler.computeDelta();
    Component component = compilerResult.component;

    if (compiler.initializedFromDillForTesting != initializedFromDill) {
      Expect.fail("Expected initializedFromDill to be $initializedFromDill "
          "but was ${compiler.initializedFromDillForTesting}");
    }
    if (errorMessages.isNotEmpty) {
      Expect.fail("Got unexpected errors: " + joinMessages(errorMessages));
    }
    if (warningMessages.isNotEmpty) {
      Expect.fail("Got unexpected warnings: " + joinMessages(warningMessages));
    }

    return component;
  }

  Future<void> initialize() async {
    sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
    base = Uri.parse("org-dartlang-test:///");
    sdkSummary = base.resolve("vm_platform.dill");
    initializeFrom = base.resolve("initializeFrom.dill");
    helperFile = base.resolve("helper.dart");
    helper2File = base.resolve("helper2.dart");
    entryPoint = base.resolve("small.dart");
    entryPointImportDartFoo = base.resolve("small_foo.dart");
    platformUri = sdkRoot.resolve("vm_platform_strong.dill");
    sdkSummaryData = await new File.fromUri(platformUri).readAsBytes();
    errorMessages = <DiagnosticMessage>[];
    warningMessages = <DiagnosticMessage>[];
    fs = new MemoryFileSystem(base);
    options = getOptions();

    options.fileSystem = fs;
    options.sdkRoot = null;
    options.sdkSummary = sdkSummary;
    options.omitPlatform = true;
    options.onDiagnostic = (DiagnosticMessage message) {
      if (message.severity == Severity.error) {
        errorMessages.add(message);
      } else if (message.severity == Severity.warning) {
        warningMessages.add(message);
      }
    };

    fs.entityForUri(sdkSummary).writeAsBytesSync(sdkSummaryData);
    fs.entityForUri(helperFile).writeAsStringSync("""
foo() {
    print("hello from foo");
}
""");
    fs.entityForUri(helper2File).writeAsStringSync("""
foo2() {
    print("hello from foo2");
}
""");
    fs.entityForUri(entryPoint).writeAsStringSync("""
import "helper.dart" as helper;
main() {
    helper.foo();
}
""");
    fs.entityForUri(entryPointImportDartFoo).writeAsStringSync("""
import "dart:foo" as helper;
main() {
    helper.foo2();
}
""");
  }

  Future<Null> test() async {
    compiler = new IncrementalCompiler(
        new CompilerContext(
            new ProcessedOptions(options: options, inputs: [entryPoint])),
        initializeFrom);

    IncrementalCompilerResult compilerGoodResult =
        await compiler.computeDelta();
    Component componentGood = compilerGoodResult.component;
    List<int> dataGood = serializeComponent(componentGood);
    fs.entityForUri(initializeFrom).writeAsBytesSync(dataGood);

    // Create fake "dart:foo" library.
    options.omitPlatform = false;
    compiler = new IncrementalCompiler(
        new CompilerContext(
            new ProcessedOptions(options: options, inputs: [helper2File])),
        initializeFrom);
    IncrementalCompilerResult compilerHelperResult =
        await compiler.computeDelta();
    Component componentHelper = compilerHelperResult.component;
    Library helper2Lib = componentHelper.libraries
        .firstWhere((lib) => lib.importUri == helper2File);
    helper2Lib.importUri = new Uri(scheme: "dart", path: "foo");
    List<int> sdkWithDartFoo = serializeComponent(componentHelper);
    options.omitPlatform = true;

    // Compile with our fake sdk with dart:foo should be ok.
    List<int> orgSdkBytes = await fs.entityForUri(sdkSummary).readAsBytes();
    fs.entityForUri(sdkSummary).writeAsBytesSync(sdkWithDartFoo);
    Component component = await compileExpectOk(true, entryPointImportDartFoo);
    fs.entityForUri(sdkSummary).writeAsBytesSync(orgSdkBytes);
    if (component.libraries.length != 1) {
      Expect.fail("Expected 1 library, got ${component.libraries.length}: "
          "${component.libraries}");
    }
    List<int> dataLinkedToSdkWithFoo = serializeComponent(component);

    // Initialize from good dill file should be ok.
    await compileExpectOk(true, entryPoint);

    // Create a partial dill file.
    compiler.invalidate(entryPoint);
    IncrementalCompilerResult compilerResult = await compiler.computeDelta();
    component = compilerResult.component;
    if (component.libraries.length != 1) {
      Expect.fail("Expected 1 library, got ${component.libraries.length}: "
          "${component.libraries}");
    }
    List<int> data = serializeComponent(component);
    fs.entityForUri(initializeFrom).writeAsBytesSync(data);

    // Initializing from partial dill should not be ok.
    await compileExpectInitializeFailAndSpecificWarning(
        codeInitializeFromDillNotSelfContained, true);
    await compileExpectInitializeFailAndSpecificWarning(
        codeInitializeFromDillNotSelfContainedNoDump, false);

    // Create a invalid dill file to load from: Should not be ok.
    data = new List<int>.filled(42, 42);
    fs.entityForUri(initializeFrom).writeAsBytesSync(data);
    await compileExpectInitializeFailAndSpecificWarning(
        codeInitializeFromDillUnknownProblem, true);
    await compileExpectInitializeFailAndSpecificWarning(
        codeInitializeFromDillUnknownProblemNoDump, false);

    // Create a dill with a reference to a non-existing sdk thing:
    // Should be ok (for now), but we shouldn't actually initialize from dill.
    fs.entityForUri(initializeFrom).writeAsBytesSync(dataLinkedToSdkWithFoo);
    await compileExpectOk(false, entryPoint);

    // Try to initialize from a dill which contains mixed compilation modes:
    // Should be ok, but we shouldn't actually initialize from dill.
    List<int> mixedPart1;
    {
      // Create a component that is compiled without NNBD.
      Map<ExperimentalFlag, bool>? prevTesting =
          options.defaultExperimentFlagsForTesting;
      options.defaultExperimentFlagsForTesting = {
        ExperimentalFlag.nonNullable: false
      };
      NnbdMode prevNnbd = options.nnbdMode;
      options.nnbdMode = NnbdMode.Weak;
      compiler = new IncrementalCompiler(
          new CompilerContext(
              new ProcessedOptions(options: options, inputs: [helper2File])),
          null);

      IncrementalCompilerResult result = await compiler.computeDelta();
      Component c = result.component;
      c.setMainMethodAndMode(
          null, false, NonNullableByDefaultCompiledMode.Weak);
      mixedPart1 = serializeComponent(c);
      options.defaultExperimentFlagsForTesting = prevTesting;
      options.nnbdMode = prevNnbd;
    }

    List<int> mixedPart2;
    {
      // Create a component that is compiled with strong NNBD.
      Map<ExperimentalFlag, bool>? prevTesting =
          options.defaultExperimentFlagsForTesting;
      options.defaultExperimentFlagsForTesting = {
        ExperimentalFlag.nonNullable: true
      };
      NnbdMode prevNnbd = options.nnbdMode;
      options.nnbdMode = NnbdMode.Strong;
      compiler = new IncrementalCompiler(
          new CompilerContext(
              new ProcessedOptions(options: options, inputs: [helperFile])),
          null);
      IncrementalCompilerResult result = await compiler.computeDelta();
      Component c = result.component;
      c.setMainMethodAndMode(
          null, false, NonNullableByDefaultCompiledMode.Strong);
      mixedPart2 = serializeComponent(c);
      options.defaultExperimentFlagsForTesting = prevTesting;
      options.nnbdMode = prevNnbd;
    }

    // Now mix the two components together and try to initialize from them.
    // We expect the compilation to be OK but that the dill is not actually
    // used to initialize from (as it's invalid because of the mixed mode).
    List<int> mixed = [];
    mixed.addAll(mixedPart1);
    mixed.addAll(mixedPart2);
    fs.entityForUri(initializeFrom).writeAsBytesSync(mixed);
    await compileExpectOk(false, entryPoint);
  }
}

class DeleteTempFilesIncrementalCompiler extends IncrementalCompiler {
  DeleteTempFilesIncrementalCompiler(CompilerContext context,
      [Uri? initializeFromDillUri])
      : super(context, initializeFromDillUri);

  @override
  final RecorderForTesting recorderForTesting =
      const DeleteTempFilesRecorderForTesting();
}

class DeleteTempFilesRecorderForTesting extends RecorderForTesting {
  const DeleteTempFilesRecorderForTesting();

  @override
  void recordTemporaryFile(Uri uri) {
    File f = new File.fromUri(uri);
    if (f.existsSync()) f.deleteSync();
  }
}

String joinMessages(List<DiagnosticMessage> messages) {
  return messages.map((m) => m.plainTextFormatted.join("\n")).join("\n");
}
