// Copyright (c) 2022, 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:typed_data';

// ignore: implementation_imports
import 'package:_js_interop_checks/src/transformations/static_interop_class_eraser.dart';
import 'package:collection/collection.dart';
// ignore: implementation_imports
import 'package:front_end/src/api_unstable/dart2js.dart' as fe;
import 'package:kernel/ast.dart' as ir;
import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
import 'package:kernel/class_hierarchy.dart' as ir;
import 'package:kernel/core_types.dart' as ir;
import 'package:kernel/kernel.dart' hide LibraryDependency, Combinator;
import 'package:kernel/target/targets.dart' hide DiagnosticReporter;
import 'package:kernel/type_environment.dart' as ir;
import 'package:kernel/verifier.dart';

import '../../compiler_api.dart' as api;
import '../common.dart';
import '../diagnostics/diagnostic_listener.dart';
import '../environment.dart';
import '../ir/annotations.dart';
import '../ir/constants.dart';
import '../kernel/dart2js_target.dart'
    show
        Dart2jsConstantsBackend,
        Dart2jsDartLibrarySupport,
        Dart2jsTarget,
        implicitlyUsedLibraries;
import '../kernel/front_end_adapter.dart';
import '../kernel/transformations/global/transform.dart' as global_transforms;
import '../options.dart';

class Input {
  final CompilerOptions options;
  final api.CompilerInput compilerInput;
  final DiagnosticReporter reporter;

  /// Shared state between compilations. Only used when loading from source.
  final fe.InitializedCompilerState? initializedCompilerState;

  // TODO(johnniwinther): Remove this when #34942 is fixed.
  /// Force in-memory serialization/deserialization of the loaded component.
  ///
  /// This is used for testing.
  final bool forceSerialization;

  Input(
    this.options,
    this.compilerInput,
    this.reporter,
    this.initializedCompilerState,
    this.forceSerialization,
  );
}

/// Result of invoking the CFE to produce the kernel IR.
class Output {
  final ir.Component component;

  /// The [Uri] of the root library containing main.
  /// Note: rootLibraryUri will be null for some modules, for example in the
  /// case of dependent libraries processed modularly.
  final Uri? rootLibraryUri;

  /// Returns the [Uri]s of all libraries that have been loaded that are
  /// reachable from the [rootLibraryUri].
  ///
  /// Note that [component] may contain some libraries that are excluded here.
  final List<Uri>? libraries;

  final fe.InitializedCompilerState? initializedCompilerState;

  Output withNewComponent(ir.Component component) =>
      Output(component, rootLibraryUri, libraries, initializedCompilerState);

  Output(
    this.component,
    this.rootLibraryUri,
    this.libraries,
    this.initializedCompilerState,
  );
}

Library _findEntryLibrary(Component component, Uri entryUri) {
  final entryLibrary = component.libraries.firstWhereOrNull(
    (l) => l.fileUri == entryUri,
  );
  if (entryLibrary == null) {
    throw ArgumentError('Entry uri $entryUri not found in dill.');
  }
  return entryLibrary;
}

ir.Reference _findMainMethod(Library entryLibrary) {
  var mainMethod = entryLibrary.procedures.firstWhereOrNull(
    (p) => p.name.text == 'main',
  );

  // In some cases, a main method is defined in another file, and then
  // exported. In these cases, we search for the main method in
  // [additionalExports].
  ir.Reference? mainMethodReference;
  if (mainMethod == null) {
    mainMethodReference = entryLibrary.additionalExports.firstWhereOrNull(
      (p) => p.canonicalName?.name == 'main',
    );
  } else {
    mainMethodReference = mainMethod.reference;
  }
  if (mainMethodReference == null) {
    throw ArgumentError(
      'Entry uri ${entryLibrary.fileUri} has no main method.',
    );
  }
  return mainMethodReference;
}

String _getPlatformFilename(String targetName) => "${targetName}_platform.dill";

class _LoadFromKernelResult {
  final ir.Component? component;
  final Library? entryLibrary;

  _LoadFromKernelResult(this.component, this.entryLibrary);
}

void _simplifyConstConditionals(
  ir.Component component,
  CompilerOptions options,
  ir.ClassHierarchy classHierarchy,
  DiagnosticReporter reporter,
) {
  void reportMessage(
    fe.LocatedMessage message,
    List<fe.LocatedMessage>? context,
  ) {
    reportLocatedMessage(reporter, message, context);
  }

  bool shouldNotInline(ir.TreeNode node) {
    if (node is! ir.Annotatable) {
      return false;
    }
    return computePragmaAnnotationDataFromIr(node).any(
      (PragmaAnnotationData pragma) =>
          pragma == const PragmaAnnotationData('noInline') ||
          pragma == const PragmaAnnotationData('never-inline'),
    );
  }

  fe.ConstConditionalSimplifier(
    const Dart2jsDartLibrarySupport(),
    const Dart2jsConstantsBackend(supportsUnevaluatedConstants: false),
    component,
    reportMessage,
    environmentDefines: options.environment,
    classHierarchy: classHierarchy,
    shouldNotInline: shouldNotInline,
    removeAsserts: !options.enableUserAssertions,
  ).run();
}

// Perform any backend-specific transforms here that can be done on both
// serialized components and components from source.
void _doTransformsOnKernelLoad(
  Component component,
  CompilerOptions options,
  DiagnosticReporter reporter,
) {
  if (options.stage.shouldRunGlobalTransforms) {
    ir.CoreTypes coreTypes = ir.CoreTypes(component);
    // Ignore ambiguous supertypes.
    final classHierarchy = ir.ClassHierarchy(
      component,
      coreTypes,
      onAmbiguousSupertypes: (_, _, _) {},
    );
    ir.TypeEnvironment typeEnvironment = ir.TypeEnvironment(
      coreTypes,
      classHierarchy,
    );
    final constantsEvaluator = Dart2jsConstantEvaluator(
      component,
      typeEnvironment,
      (fe.LocatedMessage message, List<fe.LocatedMessage>? context) =>
          reportLocatedMessage(reporter, message, context),
      environment: Environment(options.environment),
    );
    StaticInteropClassEraser(coreTypes).visitComponent(component);
    global_transforms.transformLibraries(
      component.libraries,
      constantsEvaluator,
      coreTypes,
      options,
    );
    _simplifyConstConditionals(component, options, classHierarchy, reporter);
  }
}

Future<_LoadFromKernelResult> _loadFromKernel(
  CompilerOptions options,
  api.CompilerInput compilerInput,
  String targetName,
  DiagnosticReporter reporter,
) async {
  Library? entryLibrary;
  var resolvedUri = options.compilationTarget;
  ir.Component component = ir.Component();

  Future<void> read(Uri uri) async {
    api.Input<Uint8List> input = await compilerInput.readFromUri(
      uri,
      inputKind: api.InputKind.binary,
    );
    BinaryBuilder(input.data).readComponent(component);
  }

  await read(resolvedUri);

  if (options.platformBinaries != null &&
      options.stage.shouldReadPlatformBinaries) {
    var platformUri = options.platformBinaries?.resolve(
      _getPlatformFilename(targetName),
    );
    // TODO(joshualitt): Change how we detect this case so it is less
    // brittle.
    if (platformUri != resolvedUri) await read(platformUri!);
  }

  // Concatenate dills.
  if (options.dillDependencies != null) {
    for (Uri dependency in options.dillDependencies!) {
      await read(dependency);
    }
  }

  if (options.entryUri != null) {
    entryLibrary = _findEntryLibrary(component, options.entryUri!);
    var mainMethod = _findMainMethod(entryLibrary);
    component.setMainMethodAndMode(mainMethod, true);
  }

  _doTransformsOnKernelLoad(component, options, reporter);
  registerSources(component, compilerInput);
  return _LoadFromKernelResult(component, entryLibrary);
}

class _LoadFromSourceResult {
  final ir.Component? component;
  final fe.InitializedCompilerState initializedCompilerState;

  _LoadFromSourceResult(this.component, this.initializedCompilerState);
}

Future<_LoadFromSourceResult> _loadFromSource(
  CompilerOptions options,
  api.CompilerInput compilerInput,
  DiagnosticReporter reporter,
  fe.InitializedCompilerState? initializedCompilerState,
  String targetName,
) async {
  bool verbose = false;
  bool cfeConstants = options.features.cfeConstants.isEnabled;
  Map<String, String>? environment = cfeConstants ? options.environment : null;
  Target target = Dart2jsTarget(
    targetName,
    TargetFlags(),
    options: options,
    supportsUnevaluatedConstants: !cfeConstants,
  );
  fe.FileSystem fileSystem = CompilerFileSystem(compilerInput);
  fe.Verbosity verbosity = options.verbosity;
  void onDiagnostic(fe.DiagnosticMessage message) {
    if (fe.Verbosity.shouldPrint(verbosity, message)) {
      reportFrontEndMessage(reporter, message);
    }
  }

  List<Uri> sources = [options.compilationTarget];

  List<Uri> dependencies = [];
  if (options.platformBinaries != null) {
    dependencies.add(
      options.platformBinaries!.resolve(_getPlatformFilename(targetName)),
    );
  }
  if (options.dillDependencies != null) {
    dependencies.addAll(options.dillDependencies!);
  }

  initializedCompilerState = fe.initializeCompiler(
    initializedCompilerState,
    target,
    options.librariesSpecificationUri,
    dependencies,
    options.packageConfig,
    explicitExperimentalFlags: options.explicitExperimentalFlags,
    environmentDefines: environment,
    invocationModes: options.cfeInvocationModes,
    verbosity: verbosity,
  );
  ir.Component? component = await fe.compile(
    initializedCompilerState,
    verbose,
    fileSystem,
    onDiagnostic,
    sources,
  );

  if (component != null) {
    assert(() {
      verifyComponent(
        target,
        VerificationStage.afterModularTransformations,
        component,
      );
      return true;
    }());

    _doTransformsOnKernelLoad(component, options, reporter);

    registerSources(component, compilerInput);
  }

  return _LoadFromSourceResult(component, initializedCompilerState);
}

Output _createOutput(
  CompilerOptions options,
  DiagnosticReporter reporter,
  Library? entryLibrary,
  ir.Component component,
  fe.InitializedCompilerState? initializedCompilerState,
) {
  Uri? rootLibraryUri;
  Iterable<ir.Library> libraries = component.libraries;
  if (component.mainMethod == null) {
    // TODO(sigmund): move this so that we use the same error template
    // from the CFE.
    reporter.reportError(
      reporter.createMessage(noLocationSpannable, MessageKind.generic, {
        'text': "No 'main' method found.",
      }),
    );
  }

  // If we are building from dill and are passed an [entryUri], then we use
  // that to find the appropriate [entryLibrary]. Otherwise, we fallback to
  // the [enclosingLibrary] of the [mainMethod].
  // NOTE: Under some circumstances, the [entryLibrary] exports the
  // [mainMethod] from another library, and thus the [enclosingLibrary] of
  // the [mainMethod] may not be the same as the [entryLibrary].
  var root = entryLibrary ?? component.mainMethod!.enclosingLibrary;
  rootLibraryUri = root.importUri;

  // Filter unreachable libraries: [Component] was built by linking in the
  // entire SDK libraries, not all of them are used. We include anything
  // that is reachable from `main`. Note that all internal libraries that
  // the compiler relies on are reachable from `dart:core`.
  var seen = <Library>{};
  void search(ir.Library current) {
    if (!seen.add(current)) return;
    for (ir.LibraryDependency dep in current.dependencies) {
      search(dep.targetLibrary);
    }
  }

  search(root);

  // Libraries dependencies do not show implicit imports to certain internal
  // libraries.
  const Set<String> alwaysInclude = {
    'dart:_internal',
    'dart:core',
    'dart:async',
    ...implicitlyUsedLibraries,
  };
  for (String uri in alwaysInclude) {
    Library library = component.libraries.firstWhere((lib) {
      return '${lib.importUri}' == uri;
    });
    search(library);
  }

  libraries = libraries.where(seen.contains);
  return Output(
    component,
    rootLibraryUri,
    libraries.map((lib) => lib.importUri).toList(),
    initializedCompilerState,
  );
}

/// Loads an entire Kernel [Component] from a file on disk.
Future<Output?> run(Input input) async {
  CompilerOptions options = input.options;
  api.CompilerInput compilerInput = input.compilerInput;
  DiagnosticReporter reporter = input.reporter;

  String targetName = options.compileForServer ? "dart2js_server" : "dart2js";

  Library? entryLibrary;
  ir.Component? component;
  fe.InitializedCompilerState? initializedCompilerState =
      input.initializedCompilerState;
  if (options.shouldLoadFromDill) {
    _LoadFromKernelResult result = await _loadFromKernel(
      options,
      compilerInput,
      targetName,
      reporter,
    );
    component = result.component;
    entryLibrary = result.entryLibrary;
  } else {
    _LoadFromSourceResult result = await _loadFromSource(
      options,
      compilerInput,
      reporter,
      input.initializedCompilerState,
      targetName,
    );
    component = result.component;
    initializedCompilerState = result.initializedCompilerState;
  }
  if (component == null) return null;
  if (input.forceSerialization) {
    // TODO(johnniwinther): Remove this when #34942 is fixed.
    Uint8List data = fe.serializeComponent(component);
    component = ir.Component();
    BinaryBuilder(data).readComponent(component);
    // Ensure we use the new deserialized entry point library.
    entryLibrary = _findEntryLibrary(component, options.entryUri!);
  }
  return _createOutput(
    options,
    reporter,
    entryLibrary,
    component,
    initializedCompilerState,
  );
}

/// Registers with the dart2js compiler all sources embedded in a kernel
/// component. This may include sources that were read from disk directly as
/// files, but also sources that were embedded in binary `.dill` files (like the
/// platform kernel file).
///
/// This registration improves how locations are presented when errors
/// or crashes are reported by the dart2js compiler.
void registerSources(ir.Component component, api.CompilerInput compilerInput) {
  component.uriToSource.forEach((uri, source) {
    compilerInput.registerUtf8ContentsForDiagnostics(uri, source.source);
  });
}
