// Copyright (c) 2019, 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.

// @dart = 2.9

import "dart:convert" show json, utf8;

import "dart:io" show File, gzip;

import "package:kernel/ast.dart" show Component, DartType, Library;

import "package:kernel/class_hierarchy.dart" show ClassHierarchy;

import "package:kernel/core_types.dart" show CoreTypes;

import "package:kernel/target/targets.dart" show NoneTarget, TargetFlags;

import 'package:kernel/testing/type_parser_environment.dart'
    show TypeParserEnvironment, parseLibrary;

import "package:kernel/type_environment.dart"
    show SubtypeCheckMode, TypeEnvironment;

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

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

import "package:front_end/src/fasta/builder/class_builder.dart";

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

import "package:front_end/src/fasta/dill/dill_loader.dart" show DillLoader;

import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;

import "package:front_end/src/fasta/kernel/kernel_builder.dart"
    show ClassHierarchyBuilder;

import "package:front_end/src/fasta/ticker.dart" show Ticker;

class SubtypesBenchmark {
  final Library library;
  final List<SubtypeCheck> checks;

  SubtypesBenchmark(this.library, this.checks);
}

class SubtypeCheck {
  final DartType s;
  final DartType t;
  final bool isSubtype;

  SubtypeCheck(this.s, this.t, this.isSubtype);

  @override
  String toString() {
    return (new StringBuffer()
          ..write(s)
          ..write(isSubtype ? " <: " : " !<: ")
          ..write(t))
        .toString();
  }
}

SubtypesBenchmark parseBenchMark(String source) {
  Map<Object, Object> data = json.decode(source);
  List<Object> classes = data["classes"];
  Uri uri = Uri.parse("dart:core");
  TypeParserEnvironment environment = new TypeParserEnvironment(uri, uri);
  Library library =
      parseLibrary(uri, classes.join("\n"), environment: environment);
  List<Object> checks = data["checks"];
  List<SubtypeCheck> subtypeChecks = <SubtypeCheck>[];
  for (Map<Object, Object> check in checks) {
    String kind = check["kind"];
    List<Object> arguments = check["arguments"];
    String sSource = arguments[0];
    String tSource = arguments[1];
    if (sSource.contains("?")) continue;
    if (tSource.contains("?")) continue;
    if (sSource.contains("⊥")) continue;
    if (tSource.contains("⊥")) continue;
    TypeParserEnvironment localEnvironment = environment;
    if (arguments.length > 2) {
      List<Object> typeParametersSource = arguments[2];
      localEnvironment = environment
          .extendWithTypeParameters("${typeParametersSource.join(', ')}");
    }
    DartType s = localEnvironment.parseType(sSource);
    DartType t = localEnvironment.parseType(tSource);
    subtypeChecks.add(new SubtypeCheck(s, t, kind == "isSubtype"));
  }
  return new SubtypesBenchmark(library, subtypeChecks);
}

void performChecks(List<SubtypeCheck> checks, TypeEnvironment environment) {
  for (int i = 0; i < checks.length; i++) {
    SubtypeCheck check = checks[i];
    bool isSubtype = environment.isSubtypeOf(
        check.s, check.t, SubtypeCheckMode.ignoringNullabilities);
    if (isSubtype != check.isSubtype) {
      throw "Check failed: $check";
    }
  }
}

void performFastaChecks(
    List<SubtypeCheck> checks, ClassHierarchyBuilder hierarchy) {
  for (int i = 0; i < checks.length; i++) {
    SubtypeCheck check = checks[i];
    bool isSubtype = hierarchy.types
        .isSubtypeOf(check.s, check.t, SubtypeCheckMode.ignoringNullabilities);
    if (isSubtype != check.isSubtype) {
      throw "Check failed: $check";
    }
  }
}

Future<void> run(Uri benchmarkInput, String name) async {
  const int runs = 50;
  final Ticker ticker = new Ticker(isVerbose: false);
  Stopwatch kernelWatch = new Stopwatch();
  Stopwatch fastaWatch = new Stopwatch();
  List<int> bytes = await new File.fromUri(benchmarkInput).readAsBytes();
  if (bytes.length > 3) {
    if (bytes[0] == 0x1f && bytes[1] == 0x8b && bytes[2] == 0x08) {
      bytes = gzip.decode(bytes);
    }
  }
  SubtypesBenchmark bench = parseBenchMark(utf8.decode(bytes));
  bytes = null;
  ticker.logMs("Parsed benchmark file");
  Component c = new Component(libraries: [bench.library]);
  CoreTypes coreTypes = new CoreTypes(c);
  ClassHierarchy hierarchy = new ClassHierarchy(c, coreTypes);
  TypeEnvironment environment = new TypeEnvironment(coreTypes, hierarchy);

  final CompilerContext context = new CompilerContext(new ProcessedOptions(
      options: new CompilerOptions()
        ..packagesFileUri = Uri.base.resolve(".packages")));
  await context.runInContext<void>((_) async {
    DillTarget target = new DillTarget(
        ticker,
        await context.options.getUriTranslator(),
        new NoneTarget(new TargetFlags()));
    final DillLoader loader = target.loader;
    loader.appendLibraries(c);
    await target.buildOutlines();
    ClassBuilder objectClass =
        loader.coreLibrary.lookupLocalMember("Object", required: true);
    ClassHierarchyBuilder hierarchy =
        new ClassHierarchyBuilder(objectClass, loader, coreTypes);

    for (int i = 0; i < runs; i++) {
      kernelWatch.start();
      performChecks(bench.checks, environment);
      kernelWatch.stop();

      fastaWatch.start();
      performFastaChecks(bench.checks, hierarchy);
      fastaWatch.stop();

      if (i == 0) {
        print("SubtypeKernel${name}First(RuntimeRaw): "
            "${kernelWatch.elapsedMilliseconds} ms");
        print("SubtypeFasta${name}First(RuntimeRaw): "
            "${fastaWatch.elapsedMilliseconds} ms");
      }
    }
  });

  print("SubtypeKernel${name}Avg${runs}(RuntimeRaw): "
      "${kernelWatch.elapsedMilliseconds / runs} ms");
  print("SubtypeFasta${name}Avg${runs}(RuntimeRaw): "
      "${fastaWatch.elapsedMilliseconds / runs} ms");
}

main() => run(Uri.base.resolve("type_checks.json"), "***");
