// 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';
import 'dart:typed_data';

import 'package:compiler/compiler_api.dart' as api;
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common/codegen.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/dump_info.dart';
import 'package:compiler/src/io/source_information.dart';
import 'package:compiler/src/js_model/js_world.dart';
import 'package:compiler/src/inferrer/types.dart';
import 'package:compiler/src/serialization/serialization.dart';
import 'package:compiler/src/serialization/strategies.dart';
import 'package:expect/expect.dart';
import 'package:kernel/ast.dart' as ir;
import 'package:compiler/src/util/memory_compiler.dart';
import '../helpers/text_helpers.dart';

/// Entries in dump info that naturally differ between compilations.
const List<String> dumpInfoExceptions = [
  '"compilationMoment":',
  '"compilationDuration":',
  '"toJsonDuration":',
  '"ramUsage":',
];

Future<void> generateJavaScriptCode(
  Compiler compiler,
  GlobalTypeInferenceResults globalTypeInferenceResults,
) async {
  final codegenInputs = compiler.initializeCodegen(globalTypeInferenceResults);
  final codegenResults = OnDemandCodegenResults(
    codegenInputs,
    compiler.backendStrategy.functionCompiler,
  );
  final programSize = compiler.runCodegenEnqueuer(
    codegenResults,
    globalTypeInferenceResults.inferredData,
    SourceLookup(compiler.componentForTesting),
    globalTypeInferenceResults.closedWorld,
  );
  if (compiler.options.stage.emitsDumpInfo) {
    await compiler.runDumpInfo(
      codegenResults,
      globalTypeInferenceResults,
      DumpInfoProgramData.fromEmitterResults(
        compiler.backendStrategy.emitterTask,
        compiler.dumpInfoRegistry,
        codegenResults,
        programSize,
      ),
    );
  }
}

Future<void> finishCompileAndCompare(
  Map<api.OutputType, Map<String, String>> expectedOutput,
  OutputCollector actualOutputCollector,
  Compiler compiler,
  SerializationStrategy strategy, {
  bool stoppedAfterClosedWorld = false,
  bool stoppedAfterTypeInference = false,
}) async {
  if (stoppedAfterClosedWorld) {
    JClosedWorld closedWorld = compiler.backendClosedWorldForTesting!;
    var newClosedWorld = cloneClosedWorld(compiler, closedWorld, strategy);
    compiler.performGlobalTypeInference(newClosedWorld);
  }

  if (stoppedAfterClosedWorld || stoppedAfterTypeInference) {
    GlobalTypeInferenceResults globalInferenceResults =
        compiler.globalInference.resultsForTesting!;
    GlobalTypeInferenceResults newGlobalInferenceResults =
        cloneInferenceResults(compiler, globalInferenceResults, strategy);
    await generateJavaScriptCode(compiler, newGlobalInferenceResults);
  }
  var actualOutput = actualOutputCollector.clear();
  Expect.setEquals(
    expectedOutput.keys,
    actualOutput.keys,
    "Output type mismatch.",
  );

  void check(api.OutputType outputType, Map<String, String> fileMap) {
    Map<String, String> newFileMap = actualOutput[outputType]!;
    Expect.setEquals(
      fileMap.keys,
      newFileMap.keys,
      "File mismatch for output type $outputType.",
    );
    fileMap.forEach((String fileName, String code) {
      String newCode = newFileMap[fileName]!;
      bool Function(int, List<String>, List<String>)? filter;
      if (outputType == api.OutputType.dumpInfo) {
        filter = (int index, List<String> lines1, List<String> lines2) {
          if (index <= lines1.length && index <= lines2.length) {
            String line1 = lines1[index];
            String line2 = lines2[index];
            for (String exception in dumpInfoExceptions) {
              if (line1.trim().startsWith(exception) &&
                  line2.trim().startsWith(exception)) {
                return true;
              }
            }
          }
          return false;
        };
      }
      int? failureLine = checkEqualContentAndShowDiff(
        code,
        newCode,
        filter: filter,
      );
      Expect.isNull(
        failureLine,
        "Output mismatch at line $failureLine in "
        "file '${fileName}' of type ${outputType}.",
      );
    });
  }

  expectedOutput.forEach(check);
}

runTest({
  Uri? entryPoint,
  Map<String, String> memorySourceFiles = const <String, String>{},
  Uri? packageConfig,
  Uri? librariesSpecificationUri,
  required List<String> options,
  SerializationStrategy strategy = const BytesInMemorySerializationStrategy(),
  bool useDataKinds = false,
}) async {
  var commonOptions = options + ['--out=out.js'];
  OutputCollector collector = OutputCollector();
  CompilationResult result = await runCompiler(
    entryPoint: entryPoint,
    memorySourceFiles: memorySourceFiles,
    packageConfig: packageConfig,
    librariesSpecificationUri: librariesSpecificationUri,
    options: commonOptions,
    outputProvider: collector,
    beforeRun: (Compiler compiler) {
      compiler.forceSerializationForTesting = true;
    },
  );
  Expect.isTrue(result.isSuccess);
  Map<api.OutputType, Map<String, String>> expectedOutput = collector.clear();

  OutputCollector collector2 = OutputCollector();
  CompilationResult result2 = await runCompiler(
    entryPoint: entryPoint,
    memorySourceFiles: memorySourceFiles,
    packageConfig: packageConfig,
    librariesSpecificationUri: librariesSpecificationUri,
    options: commonOptions,
    outputProvider: collector2,
    beforeRun: (Compiler compiler) {
      compiler.forceSerializationForTesting = true;
      compiler.stopAfterClosedWorldForTesting = true;
    },
  );
  Expect.isTrue(result2.isSuccess);

  Directory dir = await Directory.systemTemp.createTemp(
    'serialization_test_helper',
  );
  final cfeDillFileUri = dir.uri.resolve('cfe.dill');

  OutputCollector cfeDillCollector = OutputCollector();
  CompilationResult resultCfeDill = await runCompiler(
    entryPoint: entryPoint,
    memorySourceFiles: memorySourceFiles,
    packageConfig: packageConfig,
    librariesSpecificationUri: librariesSpecificationUri,
    outputProvider: cfeDillCollector,
    options: options + ['--out=$cfeDillFileUri', '${Flags.stage}=cfe'],
  );
  Expect.isTrue(resultCfeDill.isSuccess);
  Expect.isTrue(cfeDillCollector.binaryOutputMap.containsKey(cfeDillFileUri));

  File(
    cfeDillFileUri.path,
  ).writeAsBytesSync(cfeDillCollector.binaryOutputMap[cfeDillFileUri]!.list);

  var closedWorldUri = Uri.parse('world.data');
  OutputCollector collector3a = OutputCollector();
  CompilationResult result3a = await runCompiler(
    entryPoint: entryPoint,
    memorySourceFiles: memorySourceFiles,
    packageConfig: packageConfig,
    librariesSpecificationUri: librariesSpecificationUri,
    options:
        options +
        [
          '${Flags.inputDill}=$cfeDillFileUri',
          '${Flags.closedWorldUri}=$closedWorldUri',
          '${Flags.stage}=closed-world',
        ],
    outputProvider: collector3a,
    beforeRun: (Compiler compiler) {
      compiler.forceSerializationForTesting = true;
    },
  );
  Expect.isTrue(result3a.isSuccess);
  Expect.isTrue(collector3a.binaryOutputMap.containsKey(closedWorldUri));

  final closedWorldFileUri = dir.uri.resolve('world.data');
  final globalDataUri = Uri.parse('global.data');
  final closedWorldBytes = collector3a.binaryOutputMap[closedWorldUri]!.list;
  File(closedWorldFileUri.path).writeAsBytesSync(closedWorldBytes);
  OutputCollector collector3b = OutputCollector();
  CompilationResult result3b = await runCompiler(
    entryPoint: entryPoint,
    memorySourceFiles: memorySourceFiles,
    packageConfig: packageConfig,
    librariesSpecificationUri: librariesSpecificationUri,
    options:
        commonOptions +
        [
          '${Flags.inputDill}=$cfeDillFileUri',
          '${Flags.closedWorldUri}=$closedWorldFileUri',
          '${Flags.globalInferenceUri}=$globalDataUri',
          '${Flags.stage}=global-inference',
        ],
    outputProvider: collector3b,
    beforeRun: (Compiler compiler) {
      compiler.forceSerializationForTesting = true;
      compiler.stopAfterGlobalTypeInferenceForTesting = true;
    },
  );
  Expect.isTrue(result3b.isSuccess);
  Expect.isTrue(collector3b.binaryOutputMap.containsKey(globalDataUri));

  final globalDataFileUri = dir.uri.resolve('global.data');

  // We must write the global data bytes before calling
  // `finishCompileAndCompare` below as that clears the collector.

  final globalDataBytes = collector3b.binaryOutputMap[globalDataUri]!.list;
  File(globalDataFileUri.path).writeAsBytesSync(globalDataBytes);

  await finishCompileAndCompare(
    expectedOutput,
    collector2,
    result2.compiler!,
    strategy,
    stoppedAfterClosedWorld: true,
  );
  await finishCompileAndCompare(
    expectedOutput,
    collector3b,
    result3b.compiler!,
    strategy,
    stoppedAfterTypeInference: true,
  );

  final jsOutUri = Uri.parse('out.js');
  OutputCollector collector4 = OutputCollector();
  CompilationResult result4 = await runCompiler(
    entryPoint: entryPoint,
    memorySourceFiles: memorySourceFiles,
    packageConfig: packageConfig,
    librariesSpecificationUri: librariesSpecificationUri,
    options:
        commonOptions +
        [
          '${Flags.inputDill}=$cfeDillFileUri',
          '${Flags.closedWorldUri}=$closedWorldFileUri',
          '${Flags.globalInferenceUri}=$globalDataFileUri',
          '${Flags.stage}=codegen-emit-js',
          '--out=$jsOutUri',
        ],
    outputProvider: collector4,
    beforeRun: (Compiler compiler) {
      compiler.forceSerializationForTesting = true;
    },
  );
  Expect.isTrue(result4.isSuccess);

  await dir.delete(recursive: true);
}

void checkData(List<int> data, List<int> newData) {
  Expect.equals(
    data.length,
    newData.length,
    "Reserialization data length mismatch.",
  );
  for (int i = 0; i < data.length; i++) {
    if (data[i] != newData[i]) {
      print('Reserialization data mismatch at offset $i:');
      for (int j = i - 50; j < i + 50; j++) {
        if (0 <= j && j <= data.length) {
          String text;
          if (data[j] == newData[j]) {
            text = '${data[j]}';
          } else {
            text = '${data[j]} <> ${newData[j]}';
          }
          print('${j == i ? '> ' : '  '}$j: $text');
        }
      }
      break;
    }
  }
  Expect.listEquals(data, newData);
}

JClosedWorld cloneClosedWorld(
  Compiler compiler,
  JClosedWorld closedWorld,
  SerializationStrategy strategy,
) {
  SerializationIndices indices = SerializationIndices();
  ir.Component component = closedWorld.elementMap.programEnv.mainComponent;
  Uint8List irData = strategy.serializeComponent(component);
  final closedWorldData =
      strategy.serializeClosedWorld(closedWorld, compiler.options, indices)
          as List<int>;
  print('data size: ${closedWorldData.length}');

  ir.Component newComponent = strategy.deserializeComponent(irData);
  var newClosedWorld = strategy.deserializeClosedWorld(
    compiler.options,
    compiler.reporter,
    compiler.abstractValueStrategy,
    newComponent,
    closedWorldData,
    indices,
  );
  indices = SerializationIndices();
  final newClosedWorldData =
      strategy.serializeClosedWorld(newClosedWorld, compiler.options, indices)
          as List<int>;
  checkData(closedWorldData, newClosedWorldData);
  return newClosedWorld;
}

/// Tests that cloned inference results serialize to the same data.
///
/// Does 3 round trips to serialize/deserialize the provided data. The first
/// round normalizes the data as some information might be dropped in the
/// serialization/deserialization process. The second and third rounds are
/// compared for consistency.
GlobalTypeInferenceResults cloneInferenceResults(
  Compiler compiler,
  GlobalTypeInferenceResults results,
  SerializationStrategy strategy,
) {
  SerializationIndices indices = SerializationIndices(testMode: true);
  Uint8List irData = strategy.unpackAndSerializeComponent(results);
  final closedWorldData =
      strategy.serializeClosedWorld(
            results.closedWorld,
            compiler.options,
            indices,
          )
          as List<int>;
  ir.Component newComponent = strategy.deserializeComponent(irData);
  var newClosedWorld = strategy.deserializeClosedWorld(
    compiler.options,
    compiler.reporter,
    compiler.abstractValueStrategy,
    newComponent,
    closedWorldData,
    indices,
  );
  indices = SerializationIndices(testMode: true);
  final worldData =
      strategy.serializeGlobalTypeInferenceResults(
            results,
            compiler.options,
            indices,
          )
          as List<int>;
  print('data size: ${worldData.length}');
  GlobalTypeInferenceResults initialResults = strategy
      .deserializeGlobalTypeInferenceResults(
        compiler.options,
        compiler.reporter,
        compiler.environment,
        compiler.abstractValueStrategy,
        newComponent,
        newClosedWorld,
        worldData,
        indices,
      );
  indices = SerializationIndices(testMode: true);
  final initialWorldData =
      strategy.serializeGlobalTypeInferenceResults(
            initialResults,
            compiler.options,
            indices,
          )
          as List<int>;
  GlobalTypeInferenceResults finalResults = strategy
      .deserializeGlobalTypeInferenceResults(
        compiler.options,
        compiler.reporter,
        compiler.environment,
        compiler.abstractValueStrategy,
        newComponent,
        newClosedWorld,
        worldData,
        indices,
      );
  indices = SerializationIndices(testMode: true);
  final finalWorldData =
      strategy.serializeGlobalTypeInferenceResults(
            finalResults,
            compiler.options,
            indices,
          )
          as List<int>;
  checkData(initialWorldData, finalWorldData);
  return finalResults;
}
