// 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 'package:expect/expect.dart' show Expect;

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

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

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

import 'package:kernel/kernel.dart' show Component;

import 'package:kernel/text/ast_to_text.dart'
    show globalDebuggingNames, NameSystem;

import 'package:testing/testing.dart'
    show Chain, ChainContext, Result, Step, TestDescription, runMe;

import 'incremental_utils.dart' as util;

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

Future<Context> createContext(Chain suite, Map<String, String> environment) {
  return new Future.value(new Context());
}

class Context extends ChainContext {
  @override
  final List<Step> steps = const <Step>[
    const RunTest(),
  ];

  // Override special handling of negative tests.
  @override
  Result processTestResult(
      TestDescription description, Result result, bool last) {
    return result;
  }

  IncrementalKernelGenerator? compiler;
}

CompilerOptions getOptions() {
  final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
  var options = new CompilerOptions()
    ..sdkRoot = sdkRoot
    ..librariesSpecificationUri = Uri.base.resolve("sdk/lib/libraries.json")
    ..omitPlatform = true
    ..onDiagnostic = (DiagnosticMessage message) {
      // Ignored.
    };
  options.sdkSummary = sdkRoot.resolve("vm_platform_strong.dill");
  return options;
}

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

  @override
  String get name => "run test";

  @override
  Future<Result<TestDescription>> run(
      TestDescription description, Context context) async {
    Uri uri = description.uri;

    // "One shot compile"
    bool oneShotFailed = false;
    late List<int> oneShotSerialized;
    try {
      IncrementalKernelGenerator compiler =
          new IncrementalKernelGenerator(getOptions(), [uri]);
      oneShotSerialized =
          util.postProcess((await compiler.computeDelta()).component);
    } catch (e) {
      oneShotFailed = true;
    }

    // Bulk
    bool bulkFailed = false;
    late List<int> bulkSerialized;
    try {
      globalDebuggingNames = new NameSystem();
      if (context.compiler == null) {
        context.compiler = new IncrementalKernelGenerator(getOptions(), [uri]);
      }
      IncrementalCompilerResult compilerResult = await context.compiler!
          .computeDelta(entryPoints: [uri], fullComponent: true);
      Component bulkCompiledComponent = compilerResult.component;
      bulkSerialized = util.postProcess(bulkCompiledComponent);
    } catch (e) {
      bulkFailed = true;
      context.compiler = null;
    }

    // Compile again - the serialized output should be the same.
    bool bulk2Failed = false;
    late List<int> bulkSerialized2;
    try {
      globalDebuggingNames = new NameSystem();
      if (context.compiler == null) {
        context.compiler = new IncrementalKernelGenerator(getOptions(), [uri]);
      }
      IncrementalCompilerResult compilerResult = await context.compiler!
          .computeDelta(entryPoints: [uri], fullComponent: true);
      Component bulkCompiledComponent = compilerResult.component;
      bulkSerialized2 = util.postProcess(bulkCompiledComponent);
    } catch (e) {
      bulk2Failed = true;
      context.compiler = null;
    }

    if (bulkFailed || oneShotFailed) {
      if (bulkFailed != oneShotFailed) {
        throw "Bulk-compiler failed: $bulkFailed; "
            "one-shot failed: $oneShotFailed";
      }
    } else {
      checkIsEqual(oneShotSerialized, bulkSerialized);
    }

    if (bulkFailed || bulk2Failed) {
      if (bulkFailed != bulk2Failed) {
        throw "Bulk-compiler failed: $bulkFailed; "
            "second bulk-compile failed: $bulk2Failed";
      }
    } else {
      checkIsEqual(bulkSerialized, bulkSerialized2);
    }

    return pass(description);
  }

  void checkIsEqual(List<int> a, List<int> b) {
    int length = a.length;
    if (b.length < length) {
      length = b.length;
    }
    for (int i = 0; i < length; ++i) {
      if (a[i] != b[i]) {
        Expect.fail("Data differs at byte ${i + 1}.");
      }
    }
    Expect.equals(a.length, b.length);
  }
}
