// 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:async';
import 'dart:io';
import 'dart:math';

import 'package:expect/expect.dart';
import 'package:path/path.dart' as p;

class Result {
  final String cmdline;
  final ProcessResult processResult;

  Result(this.cmdline, this.processResult);

  String get output => processResult.stdout.trim();
}

void reportError(Result result, String msg) {
  print('running ${result.cmdline}:');
  if (result.processResult.stdout.isNotEmpty) {
    print('''

Command stdout:
${result.processResult.stdout}''');
  }

  if (result.processResult.stderr.isNotEmpty) {
    print('''

Command stderr:
${result.processResult.stderr}''');
  }

  Expect.fail(msg);
}

void expectOutput(String what, Result result) {
  if (result.output != what) {
    reportError(
        result,
        'Expected test to print \'${what}\' to stdout. '
        'Actual: ${result.output}');
  }
}

final String scriptSuffix = Platform.isWindows ? ".bat" : "";
final String executableSuffix = Platform.isWindows ? ".exe" : "";
final String buildDir = p.dirname(Platform.executable);
final String platformDill = p.join(buildDir, "vm_platform_strong.dill");
final String genSnapshot = p.join(buildDir, "gen_snapshot${executableSuffix}");
final String dart = p.join(buildDir, "dart${executableSuffix}");
final String dartPrecompiledRuntime =
    p.join(buildDir, "dart_precompiled_runtime${executableSuffix}");
final String genKernel = p.join("pkg", "vm", "bin", "gen_kernel.dart");
final String checkedInDartVM =
    p.join("tools", "sdks", "dart-sdk", "bin", "dart${executableSuffix}");

Future<Result> runDart(String prefix, List<String> arguments,
    {bool printOut: true}) {
  final augmentedArguments = <String>[]
    ..addAll(Platform.executableArguments)
    ..add('--verbosity=warning')
    ..addAll(arguments);
  return runBinary(prefix, Platform.executable, augmentedArguments,
      printOut: printOut);
}

Future<Result> runGenKernel(String prefix, List<String> arguments) {
  final augmentedArguments = <String>[
    "--platform",
    platformDill,
    ...Platform.executableArguments.where((arg) =>
        arg.startsWith('--enable-experiment=') ||
        arg == '--sound-null-safety' ||
        arg == '--no-sound-null-safety'),
    ...arguments,
  ];
  return runGenKernelWithoutStandardOptions(prefix, augmentedArguments);
}

Future<Result> runGenKernelWithoutStandardOptions(
    String prefix, List<String> arguments) {
  return runBinary(prefix, checkedInDartVM, [genKernel, ...arguments]);
}

Future<Result> runGenSnapshot(String prefix, List<String> arguments) {
  return runBinary(prefix, genSnapshot, arguments);
}

Future<Result> runBinary(String prefix, String binary, List<String> arguments,
    {Map<String, String>? environment,
    bool runInShell: false,
    bool printOut: true}) async {
  print("+ $binary " + arguments.join(" "));
  final processResult = await Process.run(binary, arguments,
      environment: environment, runInShell: runInShell);
  final result =
      new Result('[$prefix] ${binary} ${arguments.join(' ')}', processResult);

  if (printOut && processResult.stdout.isNotEmpty) {
    print('''

Command stdout:
${processResult.stdout}''');
  }

  if (printOut && processResult.stderr.isNotEmpty) {
    print('''

Command stderr:
${processResult.stderr}''');
  }

  if (result.processResult.exitCode != 0) {
    reportError(result,
        '[$prefix] Process finished with non-zero exit code ${result.processResult.exitCode}');
  }
  return result;
}

withTempDir(Future fun(String dir)) async {
  final Directory tempDir = Directory.systemTemp.createTempSync();
  try {
    return await fun(tempDir.path);
  } finally {
    tempDir.deleteSync(recursive: true);
  }
}

checkDeterministicSnapshot(String snapshotKind, String expectedStdout) async {
  await withTempDir((String temp) async {
    final snapshot1Path = p.join(temp, 'snapshot1');
    final snapshot2Path = p.join(temp, 'snapshot2');

    print("Version ${Platform.version}");

    final generate1Result = await runDart('GENERATE SNAPSHOT 1', [
      '--deterministic',
      '--trace_class_finalization',
      '--trace_type_finalization',
      '--trace_compiler',
      '--verbose_gc',
      '--verbosity=warning',
      '--snapshot=$snapshot1Path',
      '--snapshot-kind=$snapshotKind',
      Platform.script.toFilePath(),
      '--child',
    ]);
    expectOutput(expectedStdout, generate1Result);

    final generate2Result = await runDart('GENERATE SNAPSHOT 2', [
      '--deterministic',
      '--trace_class_finalization',
      '--trace_type_finalization',
      '--trace_compiler',
      '--verbose_gc',
      '--verbosity=warning',
      '--snapshot=$snapshot2Path',
      '--snapshot-kind=$snapshotKind',
      Platform.script.toFilePath(),
      '--child',
    ]);
    expectOutput(expectedStdout, generate2Result);

    var snapshot1Bytes = await new File(snapshot1Path).readAsBytes();
    var snapshot2Bytes = await new File(snapshot2Path).readAsBytes();

    var minLength = min(snapshot1Bytes.length, snapshot2Bytes.length);
    for (var i = 0; i < minLength; i++) {
      if (snapshot1Bytes[i] != snapshot2Bytes[i]) {
        Expect.fail("Snapshots differ at byte $i");
      }
    }
    Expect.equals(snapshot1Bytes.length, snapshot2Bytes.length);
  });
}

runAppJitTest(Uri testScriptUri,
    {Future<Result> Function(String snapshotPath)? runSnapshot}) async {
  runSnapshot ??=
      (snapshotPath) => runDart('RUN FROM SNAPSHOT', [snapshotPath]);

  await withTempDir((String temp) async {
    final snapshotPath = p.join(temp, 'app.jit');
    final testPath = testScriptUri.toFilePath();

    final trainingResult = await runDart('TRAINING RUN', [
      '--snapshot=$snapshotPath',
      '--snapshot-kind=app-jit',
      '--verbosity=warning',
      testPath,
      '--train'
    ]);
    expectOutput("OK(Trained)", trainingResult);
    final runResult = await runSnapshot!(snapshotPath);
    expectOutput("OK(Run)", runResult);
  });
}
