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

import 'package:_fe_analyzer_shared/src/testing/features.dart';
import 'package:compiler/src/closure.dart';
import 'package:compiler/src/common.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/deferred_load/output_unit.dart'
    show OutputUnit, OutputUnitData;
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/ir/util.dart';
import 'package:compiler/src/js_model/element_map.dart';
import 'package:compiler/src/js_model/js_world.dart';
import 'package:compiler/src/js_emitter/startup_emitter/fragment_merger.dart';
import 'package:compiler/src/kernel/kernel_strategy.dart';
import 'package:expect/expect.dart';
import '../equivalence/id_equivalence.dart';
import '../equivalence/id_equivalence_helper.dart';
import 'package:compiler/src/constants/values.dart';

import 'package:kernel/ast.dart' as ir;

// For ease of testing and making our tests easier to read, we impose an
// artificial constraint of requiring every deferred import use a different
// named prefix per test. We enforce this constraint here by checking that no
// prefix name responds to two different libraries.
Map<String, Uri> importPrefixes = {};

String importPrefixString(OutputUnit unit) {
  List<String> importNames = [];
  for (ImportEntity import in unit.imports) {
    importNames.add(import.name);
    Expect.isTrue(import.isDeferred);

    if (importPrefixes.containsKey(import.name)) {
      var existing = importPrefixes[import.name];
      var current = import.enclosingLibraryUri;
      Expect.equals(
          existing,
          current,
          '\n    Duplicate prefix \'${import.name}\' used in both:\n'
          '     - $existing and\n'
          '     - $current.\n'
          '    We require using unique prefixes on these tests to make '
          'the expectations more readable.');
    }
    importPrefixes[import.name] = import.enclosingLibraryUri;
  }
  importNames.sort();
  return importNames.join(', ');
}

/// Create a consistent string representation of [OutputUnit]s for both
/// KImportEntities and ImportElements.
String outputUnitString(OutputUnit unit) {
  if (unit == null) return 'none';
  String sb = importPrefixString(unit);
  return '${unit.name}{$sb}';
}

Map<String, List<PreFragment>> buildPreFragmentMap(
    Map<String, List<FinalizedFragment>> fragmentsToLoad,
    List<PreFragment> preDeferredFragments) {
  Map<FinalizedFragment, PreFragment> fragmentMap = {};
  for (var preFragment in preDeferredFragments) {
    fragmentMap[preFragment.finalizedFragment] = preFragment;
  }
  Map<String, List<PreFragment>> preFragmentMap = {};
  fragmentsToLoad.forEach((loadId, fragments) {
    List<PreFragment> preFragments = [];
    for (var fragment in fragments) {
      preFragments.add(fragmentMap[fragment]);
    }
    preFragmentMap[loadId] = preFragments.toList();
  });
  return preFragmentMap;
}

class Tags {
  static const String cls = 'class_unit';
  static const String member = 'member_unit';
  static const String closure = 'closure_unit';
  static const String constants = 'constants';
  static const String type = 'type_unit';
  // The below tags appear in a single block comment in the main file.
  // To keep them appearing in sequential order we prefix characters.
  static const String preFragments = 'a_pre_fragments';
  static const String finalizedFragments = 'b_finalized_fragments';
  static const String steps = 'c_steps';
}

class OutputUnitDataComputer extends DataComputer<Features> {
  const OutputUnitDataComputer();

  /// OutputData for [member] as a kernel based element.
  ///
  /// At this point the compiler has already been run, so it is holding the
  /// relevant OutputUnits, we just need to extract that information from it. We
  /// fill [actualMap] with the data computed about what the resulting OutputUnit
  /// is.
  @override
  void computeMemberData(Compiler compiler, MemberEntity member,
      Map<Id, ActualData<Features>> actualMap,
      {bool verbose: false}) {
    JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
    JsToElementMap elementMap = closedWorld.elementMap;
    MemberDefinition definition = elementMap.getMemberDefinition(member);
    OutputUnitIrComputer(compiler.reporter, actualMap, elementMap,
            closedWorld.outputUnitData, closedWorld.closureDataLookup)
        .run(definition.node);
  }

  @override
  void computeClassData(Compiler compiler, ClassEntity cls,
      Map<Id, ActualData<Features>> actualMap,
      {bool verbose: false}) {
    JsClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
    JsToElementMap elementMap = closedWorld.elementMap;
    ClassDefinition definition = elementMap.getClassDefinition(cls);
    OutputUnitIrComputer(compiler.reporter, actualMap, elementMap,
            closedWorld.outputUnitData, closedWorld.closureDataLookup)
        .computeForClass(definition.node);
  }

  @override
  void computeLibraryData(Compiler compiler, LibraryEntity library,
      Map<Id, ActualData<Features>> actualMap,
      {bool verbose}) {
    KernelFrontendStrategy frontendStrategy = compiler.frontendStrategy;
    ir.Library node = frontendStrategy.elementMap.getLibraryNode(library);
    List<PreFragment> preDeferredFragments = compiler
        .backendStrategy.emitterTask.emitter.preDeferredFragmentsForTesting;
    Map<String, List<FinalizedFragment>> fragmentsToLoad =
        compiler.backendStrategy.emitterTask.emitter.finalizedFragmentsToLoad;
    Set<OutputUnit> omittedOutputUnits =
        compiler.backendStrategy.emitterTask.emitter.omittedOutputUnits;
    PreFragmentsIrComputer(compiler.reporter, actualMap, preDeferredFragments,
            fragmentsToLoad, omittedOutputUnits)
        .computeForLibrary(node);
  }

  @override
  DataInterpreter<Features> get dataValidator =>
      const FeaturesDataInterpreter();
}

class PreFragmentsIrComputer extends IrDataExtractor<Features> {
  final List<PreFragment> _preDeferredFragments;
  final Map<String, List<FinalizedFragment>> _fragmentsToLoad;
  final Set<OutputUnit> _omittedOutputUnits;

  PreFragmentsIrComputer(
      DiagnosticReporter reporter,
      Map<Id, ActualData<Features>> actualMap,
      this._preDeferredFragments,
      this._fragmentsToLoad,
      this._omittedOutputUnits)
      : super(reporter, actualMap);

  @override
  Features computeLibraryValue(Id id, ir.Library library) {
    var name = '${library.importUri.pathSegments.last}';
    Features features = new Features();
    if (!name.startsWith('main')) return features;

    // First build a list of pre fragments and their dependencies.
    int index = 1;
    Map<FinalizedFragment, int> finalizedFragmentIndices = {};
    Map<PreFragment, int> preFragmentIndices = {};
    Map<int, PreFragment> reversePreFragmentIndices = {};
    Map<int, FinalizedFragment> reverseFinalizedFragmentIndices = {};
    for (var preFragment in _preDeferredFragments) {
      if (!preFragmentIndices.containsKey(preFragment)) {
        var finalizedFragment = preFragment.finalizedFragment;
        preFragmentIndices[preFragment] = index;
        finalizedFragmentIndices[finalizedFragment] = index;
        reversePreFragmentIndices[index] = preFragment;
        reverseFinalizedFragmentIndices[index] = finalizedFragment;
        index++;
      }
    }

    for (int i = 1; i < index; i++) {
      var preFragment = reversePreFragmentIndices[i];
      List<String> needs = [];
      List<OutputUnit> supplied = [];
      List<String> usedBy = [];
      for (var dependent in preFragment.successors) {
        if (preFragmentIndices.containsKey(dependent)) {
          usedBy.add('p${preFragmentIndices[dependent]}');
        }
      }

      for (var dependency in preFragment.predecessors) {
        if (preFragmentIndices.containsKey(dependency)) {
          needs.add('p${preFragmentIndices[dependency]}');
        }
      }

      for (var emittedOutputUnit in preFragment.emittedOutputUnits) {
        supplied.add(emittedOutputUnit.outputUnit);
      }

      var suppliedString = '[${supplied.map(outputUnitString).join(', ')}]';
      features.addElement(Tags.preFragments,
          'p$i: {units: $suppliedString, usedBy: $usedBy, needs: $needs}');
    }

    // Now dump finalized fragments and load ids.
    for (int i = 1; i < index; i++) {
      var finalizedFragment = reverseFinalizedFragmentIndices[i];
      List<String> supplied = [];

      for (var codeFragment in finalizedFragment.codeFragments) {
        List<String> outputUnitStrings = [];
        for (var outputUnit in codeFragment.outputUnits) {
          if (!_omittedOutputUnits.contains(outputUnit)) {
            outputUnitStrings.add(outputUnitString(outputUnit));
          }
        }
        if (outputUnitStrings.isNotEmpty) {
          supplied.add(outputUnitStrings.join('+'));
        }
      }

      if (supplied.isNotEmpty) {
        var suppliedString = '[${supplied.join(', ')}]';
        features.addElement(Tags.finalizedFragments, 'f$i: $suppliedString');
      }
    }

    _fragmentsToLoad.forEach((loadId, finalizedFragments) {
      List<String> finalizedFragmentNeeds = [];
      for (var finalizedFragment in finalizedFragments) {
        assert(finalizedFragmentIndices.containsKey(finalizedFragment));
        finalizedFragmentNeeds
            .add('f${finalizedFragmentIndices[finalizedFragment]}');
      }
      features.addElement(
          Tags.steps, '$loadId=(${finalizedFragmentNeeds.join(', ')})');
    });

    return features;
  }
}

class OutputUnitIrComputer extends IrDataExtractor<Features> {
  final JsToElementMap _elementMap;
  final OutputUnitData _data;
  final ClosureData _closureDataLookup;

  Set<String> _constants = {};

  OutputUnitIrComputer(
      DiagnosticReporter reporter,
      Map<Id, ActualData<Features>> actualMap,
      this._elementMap,
      this._data,
      this._closureDataLookup)
      : super(reporter, actualMap);

  Features getMemberValue(
      String tag, MemberEntity member, Set<String> constants) {
    Features features = Features();
    features.add(tag,
        value: outputUnitString(_data.outputUnitForMemberForTesting(member)));
    for (var constant in constants) {
      features.addElement(Tags.constants, constant);
    }
    return features;
  }

  @override
  Features computeClassValue(Id id, ir.Class node) {
    var cls = _elementMap.getClass(node);
    Features features = Features();
    features.add(Tags.cls,
        value: outputUnitString(_data.outputUnitForClassForTesting(cls)));
    features.add(Tags.type,
        value: outputUnitString(_data.outputUnitForClassTypeForTesting(cls)));
    return features;
  }

  @override
  Features computeMemberValue(Id id, ir.Member node) {
    if (node is ir.Field && node.isConst) {
      ir.Expression initializer = node.initializer;
      ConstantValue constant = _elementMap.getConstantValue(node, initializer);
      if (constant is! PrimitiveConstantValue) {
        SourceSpan span = computeSourceSpanFromTreeNode(initializer);
        if (initializer is ir.ConstructorInvocation) {
          // Adjust the source-span to match the AST-based location. The kernel FE
          // skips the "const" keyword for the expression offset and any prefix in
          // front of the constructor. The "-6" is an approximation assuming that
          // there is just a single space after "const" and no prefix.
          // TODO(sigmund): offsets should be fixed in the FE instead.
          span = SourceSpan(span.uri, span.begin - 6, span.end - 6);
        }
        _registerValue(
            NodeId(span.begin, IdKind.node),
            Features.fromMap({
              Tags.member: outputUnitString(
                  _data.outputUnitForConstantForTesting(constant))
            }),
            node,
            span,
            actualMap,
            reporter);
      }
    }

    Features features =
        getMemberValue(Tags.member, _elementMap.getMember(node), _constants);
    _constants = {};
    return features;
  }

  @override
  visitConstantExpression(ir.ConstantExpression node) {
    ConstantValue constant = _elementMap.getConstantValue(null, node);
    if (constant is! PrimitiveConstantValue) {
      _constants.add('${constant.toStructuredText(_elementMap.types)}='
          '${outputUnitString(_data.outputUnitForConstant(constant))}');
    }
    return super.visitConstantExpression(node);
  }

  @override
  Features computeNodeValue(Id id, ir.TreeNode node) {
    if (node is ir.FunctionExpression || node is ir.FunctionDeclaration) {
      ClosureRepresentationInfo info = _closureDataLookup.getClosureInfo(node);
      return getMemberValue(Tags.closure, info.callMethod, const {});
    }
    return null;
  }
}

/// Set [actualMap] to hold a key of [id] with the computed data [value]
/// corresponding to [object] at location [sourceSpan]. We also perform error
/// checking to ensure that the same [id] isn't added twice.
void _registerValue<T>(Id id, T value, Object object, SourceSpan sourceSpan,
    Map<Id, ActualData<T>> actualMap, DiagnosticReporter reporter) {
  if (actualMap.containsKey(id)) {
    ActualData<T> existingData = actualMap[id];
    reportHere(reporter, sourceSpan,
        "Duplicate id ${id}, value=$value, object=$object");
    reportHere(
        reporter,
        sourceSpan,
        "Duplicate id ${id}, value=${existingData.value}, "
        "object=${existingData.object}");
    Expect.fail("Duplicate id $id.");
  }
  if (value != null) {
    actualMap[id] =
        ActualData<T>(id, value, sourceSpan.uri, sourceSpan.begin, object);
  }
}
