// 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.

/// Defines wrapper class around incremental compiler to support
/// the flow, where incremental deltas can be rejected by VM.
import 'dart:async';
import 'dart:developer';

import 'package:front_end/src/api_unstable/vm.dart';
import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
import 'package:kernel/core_types.dart' show CoreTypes;
import 'package:kernel/kernel.dart';

const String kDebugProcedureName = ":Eval";

/// Wrapper around [IncrementalKernelGenerator] that keeps track of rejected
/// deltas and combines them together into resultant program until it is
/// accepted.
class IncrementalCompiler {
  late IncrementalKernelGenerator _generator;
  IncrementalSerializer? incrementalSerializer;

  // Component that reflect the state that was most recently accepted by the
  // client. Is [null], if no compilation results were accepted by the client.
  Component? _lastKnownGood;
  late List<Component> _pendingDeltas;
  CompilerOptions _compilerOptions;
  bool initialized = false;
  bool fullComponent = false;
  Uri? initializeFromDillUri;
  Uri _entryPoint;
  final bool forExpressionCompilationOnly;

  Uri get entryPoint => _entryPoint;
  IncrementalKernelGenerator get generator => _generator;
  Component? get lastKnownGoodComponent => _lastKnownGood;

  IncrementalCompiler(this._compilerOptions, this._entryPoint,
      {this.initializeFromDillUri, bool incrementalSerialization: true})
      : forExpressionCompilationOnly = false {
    if (incrementalSerialization) {
      incrementalSerializer = new IncrementalSerializer();
    }
    _generator = new IncrementalKernelGenerator(_compilerOptions, _entryPoint,
        initializeFromDillUri, false, incrementalSerializer);
    _pendingDeltas = <Component>[];
  }

  IncrementalCompiler.forExpressionCompilationOnly(
      Component component, this._compilerOptions, this._entryPoint)
      : forExpressionCompilationOnly = true {
    _generator = new IncrementalKernelGenerator.forExpressionCompilationOnly(
        _compilerOptions, _entryPoint, component);
    _pendingDeltas = <Component>[];
  }

  /// Recompiles invalidated files, produces incremental component.
  ///
  /// If [entryPoint] is specified, that points to new entry point for the
  /// compilation. Otherwise, previously set entryPoint is used.
  Future<Component> compile({Uri? entryPoint}) async {
    final task = new TimelineTask();
    try {
      task.start("IncrementalCompiler.compile");
      _entryPoint = entryPoint ?? _entryPoint;
      List<Uri>? entryPoints;
      if (entryPoint != null) entryPoints = [entryPoint];
      Component component = await _generator.computeDelta(
          entryPoints: entryPoints, fullComponent: fullComponent);
      initialized = true;
      fullComponent = false;
      _pendingDeltas.add(component);
      return _combinePendingDeltas(false);
    } finally {
      task.finish();
    }
  }

  _combinePendingDeltas(bool includePlatform) {
    Procedure? mainMethod;
    NonNullableByDefaultCompiledMode compilationMode =
        NonNullableByDefaultCompiledMode.Invalid;
    Map<Uri, Library> combined = <Uri, Library>{};
    Map<Uri, Source> uriToSource = new Map<Uri, Source>();
    for (Component delta in _pendingDeltas) {
      if (delta.mainMethod != null) {
        mainMethod = delta.mainMethod;
      }
      compilationMode = delta.mode;
      uriToSource.addAll(delta.uriToSource);
      for (Library library in delta.libraries) {
        bool isPlatform =
            library.importUri.scheme == "dart" && !library.isSynthetic;
        if (!includePlatform && isPlatform) continue;
        combined[library.importUri] = library;
      }
    }

    // TODO(vegorov) this needs to merge metadata repositories from deltas.
    return new Component(
        libraries: combined.values.toList(), uriToSource: uriToSource)
      ..setMainMethodAndMode(mainMethod?.reference, true, compilationMode);
  }

  CoreTypes? getCoreTypes() => _generator.getCoreTypes();
  ClassHierarchy? getClassHierarchy() => _generator.getClassHierarchy();

  /// This lets incremental compiler know that results of last [compile] call
  /// were accepted, don't need to be included into subsequent [compile] calls
  /// results.
  accept() {
    if (forExpressionCompilationOnly) {
      throw new StateError("Incremental compiler created for expression "
          "compilation only; cannot accept");
    }
    Map<Uri, Library> combined = <Uri, Library>{};
    Map<Uri, Source> uriToSource = <Uri, Source>{};

    Component? lastKnownGood = _lastKnownGood;
    if (lastKnownGood != null) {
      // TODO(aam): Figure out how to skip no-longer-used libraries from
      // [_lastKnownGood] libraries.
      for (Library library in lastKnownGood.libraries) {
        combined[library.importUri] = library;
      }
      uriToSource.addAll(lastKnownGood.uriToSource);
    }

    Component candidate = _combinePendingDeltas(true);
    for (Library library in candidate.libraries) {
      combined[library.importUri] = library;
    }
    uriToSource.addAll(candidate.uriToSource);

    _lastKnownGood = lastKnownGood = new Component(
      libraries: combined.values.toList(),
      uriToSource: uriToSource,
    )..setMainMethodAndMode(
        candidate.mainMethod?.reference, true, candidate.mode);
    for (final repo in candidate.metadata.values) {
      lastKnownGood.addMetadataRepository(repo);
    }
    _pendingDeltas.clear();
  }

  /// This lets incremental compiler know that results of last [compile] call
  /// were rejected. Subsequent [compile] or [compileExpression] calls need to
  /// be processed without changes picked up by rejected [compile] call.
  reject() async {
    if (forExpressionCompilationOnly) {
      throw new StateError("Incremental compiler created for expression "
          "compilation only; cannot reject");
    }
    _pendingDeltas.clear();
    // Need to reset and warm up compiler so that expression evaluation requests
    // are processed in that known good state.
    if (incrementalSerializer != null) {
      incrementalSerializer = new IncrementalSerializer();
    }
    // Make sure the last known good component is linked to itself, i.e. if the
    // rejected delta was an "advanced incremental recompilation" that updated
    // old libraries to point to a new library (that we're now rejecting), make
    // sure it's "updated back".
    // Note that if accept was never called [_lastKnownGood] is null (and
    // loading from it below is basically nonsense, it will just start over).
    _lastKnownGood?.relink();

    _generator = new IncrementalKernelGenerator.fromComponent(_compilerOptions,
        _entryPoint, _lastKnownGood, false, incrementalSerializer);
    await _generator.computeDelta(entryPoints: [_entryPoint]);
  }

  /// This tells incremental compiler that it needs rescan [uri] file during
  /// next [compile] call.
  invalidate(Uri uri) {
    _generator.invalidate(uri);
  }

  resetDeltaState() {
    _pendingDeltas.clear();
    fullComponent = true;
  }

  Future<Procedure?> compileExpression(
      String expression,
      List<String> definitions,
      List<String> typeDefinitions,
      String libraryUri,
      String? klass,
      bool isStatic) {
    Map<String, DartType> completeDefinitions = {};
    for (String name in definitions) {
      if (!isLegalIdentifier(name)) continue;
      completeDefinitions[name] = new DynamicType();
    }

    List<TypeParameter> typeParameters = [];
    for (String name in typeDefinitions) {
      if (!isLegalIdentifier(name)) continue;
      typeParameters.add(new TypeParameter(name, new DynamicType()));
    }

    Uri library = Uri.parse(libraryUri);

    return _generator.compileExpression(expression, completeDefinitions,
        typeParameters, kDebugProcedureName, library, klass, isStatic);
  }
}
