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

import 'dart:io' show Directory, Platform;

import 'package:_fe_analyzer_shared/src/testing/id.dart';
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart';
import 'package:front_end/src/kernel/hierarchy/hierarchy_builder.dart';
import 'package:front_end/src/kernel/hierarchy/hierarchy_node.dart';
import 'package:front_end/src/testing/id_extractor.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
import 'package:front_end/src/testing/id_testing_utils.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/type_algebra.dart';

const String cfeFromBuilderMarker = 'cfe:builder';

Future<void> main(List<String> args) async {
  Directory dataDir = new Directory.fromUri(Platform.script
      .resolve('../../../_fe_analyzer_shared/test/inheritance/data'));
  await runTests<String>(dataDir,
      args: args,
      createUriForFileName: createUriForFileName,
      onFailure: onFailure,
      runTest: runTestFor(const InheritanceDataComputer(), [
        new CfeTestConfig(cfeMarker, 'cfe with nnbd',
            librariesSpecificationUri: createUriForFileName('libraries.json'),
            compileSdk: true),
        new CfeTestConfig(cfeFromBuilderMarker, 'cfe from builder',
            librariesSpecificationUri: createUriForFileName('libraries.json'),
            compileSdk: true)
      ]));
}

class InheritanceDataComputer extends CfeDataComputer<String> {
  const InheritanceDataComputer();

  /// Function that computes a data mapping for [library].
  ///
  /// Fills [actualMap] with the data.
  @override
  void computeLibraryData(CfeTestResultData testResultData, Library library,
      Map<Id, ActualData<String>> actualMap,
      {bool? verbose}) {
    new InheritanceDataExtractor(testResultData, actualMap)
        .computeForLibrary(library);
  }

  @override
  void computeClassData(CfeTestResultData testResultData, Class cls,
      Map<Id, ActualData<String>> actualMap,
      {bool? verbose}) {
    new InheritanceDataExtractor(testResultData, actualMap)
        .computeForClass(cls);
  }

  @override
  bool get supportsErrors => true;

  @override
  String computeErrorData(
      CfeTestResultData testResultData, Id id, List<FormattedMessage> errors) {
    return errorsToText(errors, useCodes: true);
  }

  @override
  DataInterpreter<String> get dataValidator => const StringDataInterpreter();
}

class InheritanceDataExtractor extends CfeDataExtractor<String> {
  final CfeTestResultData _testResultData;

  InheritanceDataExtractor(
      this._testResultData, Map<Id, ActualData<String>> actualMap)
      : super(_testResultData.compilerResult, actualMap);

  CfeTestConfig get _config => _testResultData.config;

  InternalCompilerResult get _compilerResult => _testResultData.compilerResult;

  ClassHierarchy get _hierarchy => _compilerResult.classHierarchy!;

  CoreTypes get _coreTypes => _compilerResult.coreTypes!;

  ClassHierarchyBuilder get _classHierarchyBuilder =>
      _compilerResult.kernelTargetForTesting!.loader.hierarchyBuilder;

  @override
  void computeForClass(Class node) {
    super.computeForClass(node);
    if (node.isAnonymousMixin) return;
    // TODO(johnniwinther): Also compute member data from builders.
    Set<Name> getters = _hierarchy
        .getInterfaceMembers(node)
        .map((Member member) => member.name)
        .toSet();
    Set<Name> setters = _hierarchy
        .getInterfaceMembers(node, setters: true)
        .where((Member member) =>
            member is Procedure && member.kind == ProcedureKind.Setter ||
            member is Field && member.hasSetter)
        .map((Member member) => member.name)
        .toSet();

    void addMember(Name name, {required bool isSetter}) {
      Member member =
          _hierarchy.getInterfaceMember(node, name, setter: isSetter)!;
      if (member.enclosingClass == _coreTypes.objectClass) {
        return;
      }
      InterfaceType supertype = _hierarchy.getInterfaceTypeAsInstanceOfClass(
          _coreTypes.thisInterfaceType(node, node.enclosingLibrary.nonNullable),
          member.enclosingClass!)!;
      Substitution substitution = Substitution.fromInterfaceType(supertype);
      DartType? type;
      if (member is Procedure) {
        if (member.kind == ProcedureKind.Getter) {
          type = substitution.substituteType(member.function.returnType);
        } else if (member.kind == ProcedureKind.Setter) {
          type = substitution
              .substituteType(member.function.positionalParameters.single.type);
        } else {
          Nullability functionTypeNullability =
              member.enclosingLibrary.nonNullable;
          type = substitution.substituteType(
              member.function.computeThisFunctionType(functionTypeNullability));
        }
      } else if (member is Field) {
        type = substitution.substituteType(member.type);
      }
      if (type == null) {
        return;
      }

      String memberName = name.text;
      if (isSetter) {
        memberName += '=';
      }
      MemberId id = new MemberId.internal(memberName, className: node.name);

      TreeNode nodeWithOffset;
      if (member.enclosingClass == node) {
        nodeWithOffset = computeTreeNodeWithOffset(member)!;
      } else {
        nodeWithOffset = computeTreeNodeWithOffset(node)!;
      }

      registerValue(
          nodeWithOffset.location!.file,
          nodeWithOffset.fileOffset,
          id,
          typeToText(type, TypeRepresentation.analyzerNonNullableByDefault),
          member);
    }

    for (Name name in getters) {
      addMember(name, isSetter: false);
    }

    for (Name name in setters) {
      addMember(name, isSetter: true);
    }
  }

  @override
  String? computeClassValue(Id id, Class node) {
    if (node.isAnonymousMixin) return null;
    if (_config.marker == cfeMarker) {
      List<String> supertypes = <String>[];
      for (Class superclass in computeAllSuperclasses(node)) {
        Supertype supertype =
            _hierarchy.getClassAsInstanceOf(node, superclass)!;
        if (supertype.classNode.isAnonymousMixin) continue;
        supertypes.add(supertypeToText(
            supertype, TypeRepresentation.analyzerNonNullableByDefault));
      }
      supertypes.sort();
      return supertypes.join(',');
    } else if (_config.marker == cfeFromBuilderMarker) {
      ClassHierarchyNode classHierarchyNode =
          _classHierarchyBuilder.getNodeFromClass(node);
      Set<String> supertypes = <String>{};
      void addSupertype(Supertype supertype) {
        if (supertype.classNode.isAnonymousMixin) return;
        supertypes.add(supertypeToText(
            supertype, TypeRepresentation.analyzerNonNullableByDefault));
      }

      addSupertype(new Supertype(
          classHierarchyNode.classBuilder.cls,
          getAsTypeArguments(classHierarchyNode.classBuilder.cls.typeParameters,
              classHierarchyNode.classBuilder.libraryBuilder.library)));
      classHierarchyNode.superclasses.forEach(addSupertype);
      classHierarchyNode.interfaces.forEach(addSupertype);
      List<String> sorted = supertypes.toList()..sort();
      return sorted.join(',');
    }
    return null;
  }
}
