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

library kernel.transformations.value_class;

import 'package:kernel/type_environment.dart';

import '../ast.dart';
import '../kernel.dart';
import '../core_types.dart' show CoreTypes;
import '../class_hierarchy.dart' show ClassHierarchy;
import './scanner.dart';

class ValueClassScanner extends ClassScanner<Null> {
  ValueClassScanner() : super(null);

  bool predicate(Class node) => isValueClass(node);
}

class JenkinsClassScanner extends ClassScanner<Procedure> {
  JenkinsClassScanner(Scanner<Procedure, TreeNode?> next) : super(next);

  bool predicate(Class node) {
    return node.name == "JenkinsSmiHash";
  }
}

class HashCombineMethodsScanner extends ProcedureScanner<Null> {
  HashCombineMethodsScanner() : super(null);

  bool predicate(Procedure node) {
    return node.name.text == "combine" || node.name.text == "finish";
  }
}

class AllMemberScanner extends MemberScanner<InstanceInvocationExpression> {
  AllMemberScanner(Scanner<InstanceInvocationExpression, TreeNode?> next)
      : super(next);

  bool predicate(Member member) => true;
}

// Scans and matches all copyWith invocations were the receiver is _ as dynamic
// It will filter out the results that are not value classes afterwards
class ValueClassCopyWithScanner extends MethodInvocationScanner<Null> {
  ValueClassCopyWithScanner() : super(null);

  // The matching construct followed in unit-tests is:
  // @valueClass V {}
  // V v;
  // (v as dynamic).copyWith() as V
  bool predicate(InstanceInvocationExpression node) {
    return node.name.text == "copyWith" &&
        _isValueClassAsConstruct(node.receiver);
  }

  bool _isValueClassAsConstruct(Expression node) {
    return node is AsExpression && node.type is DynamicType;
  }
}

void transformComponent(Component node, CoreTypes coreTypes,
    ClassHierarchy hierarchy, TypeEnvironment typeEnvironment,
    {required bool useNewMethodInvocationEncoding}) {
  ValueClassScanner scanner = new ValueClassScanner();
  ScanResult<Class, Null> valueClasses = scanner.scan(node);
  for (Class valueClass in valueClasses.targets.keys) {
    transformValueClass(valueClass, coreTypes, hierarchy, typeEnvironment,
        useNewMethodInvocationEncoding: useNewMethodInvocationEncoding);
  }

  treatCopyWithCallSites(node, coreTypes, typeEnvironment, hierarchy,
      useNewMethodInvocationEncoding: useNewMethodInvocationEncoding);

  for (Class valueClass in valueClasses.targets.keys) {
    removeValueClassAnnotation(valueClass);
  }
}

void transformValueClass(Class cls, CoreTypes coreTypes,
    ClassHierarchy hierarchy, TypeEnvironment typeEnvironment,
    {required bool useNewMethodInvocationEncoding}) {
  Constructor? syntheticConstructor = null;
  for (Constructor constructor in cls.constructors) {
    if (constructor.isSynthetic) {
      syntheticConstructor = constructor;
    }
  }

  List<VariableDeclaration> allVariables = queryAllInstanceVariables(cls);
  List<VariableDeclaration> allVariablesList = allVariables.toList();
  allVariablesList.sort((a, b) => a.name!.compareTo(b.name!));

  addConstructor(cls, coreTypes, syntheticConstructor!);
  addEqualsOperator(cls, coreTypes, hierarchy, allVariablesList,
      useNewMethodInvocationEncoding: useNewMethodInvocationEncoding);
  addHashCode(cls, coreTypes, hierarchy, allVariablesList,
      useNewMethodInvocationEncoding: useNewMethodInvocationEncoding);
  addToString(cls, coreTypes, hierarchy, allVariablesList,
      useNewMethodInvocationEncoding: useNewMethodInvocationEncoding);
  addCopyWith(cls, coreTypes, hierarchy, allVariablesList, syntheticConstructor,
      typeEnvironment);
}

void addConstructor(
    Class cls, CoreTypes coreTypes, Constructor syntheticConstructor) {
  Constructor? superConstructor = null;
  for (Constructor constructor in cls.superclass!.constructors) {
    if (constructor.name.text == "") {
      superConstructor = constructor;
    }
  }
  List<VariableDeclaration> superParameters = superConstructor!
      .function.namedParameters
      .map<VariableDeclaration>((e) => VariableDeclaration(e.name, type: e.type)
        ..parent = syntheticConstructor.function)
      .toList();
  Map<String, VariableDeclaration> ownFields = Map.fromIterable(cls.fields,
      key: (f) => f.name.text,
      value: (f) =>
          VariableDeclaration(f.name.text, type: f.type, isRequired: true)
            ..parent = syntheticConstructor.function);

  List<Initializer> initializersConstructor = cls.fields
      .map<Initializer>((f) =>
          FieldInitializer(f, VariableGet(ownFields[f.name.text]!))
            ..parent = syntheticConstructor)
      .toList();

  initializersConstructor.add(SuperInitializer(superConstructor,
      Arguments(superParameters.map((f) => VariableGet(f)).toList()))
    ..parent = syntheticConstructor);

  syntheticConstructor.function.namedParameters
    ..clear()
    ..addAll(ownFields.values)
    ..addAll(superParameters);
  syntheticConstructor.initializers = initializersConstructor;
}

void addEqualsOperator(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy,
    List<VariableDeclaration> allVariablesList,
    {required bool useNewMethodInvocationEncoding}) {
  List<VariableDeclaration> allVariables = allVariablesList.toList();
  for (Procedure procedure in cls.procedures) {
    if (procedure.kind == ProcedureKind.Operator &&
        procedure.name.text == "==") {
      // ==operator is already implemented, spec is to do nothing
      return;
    }
  }
  DartType returnType = coreTypes.boolRawType(cls.enclosingLibrary.nonNullable);
  DartType myType = coreTypes.thisInterfaceType(cls, Nullability.nonNullable);

  VariableDeclaration other = VariableDeclaration("other",
      type: coreTypes.objectRawType(Nullability.nonNullable));

  Map<VariableDeclaration, Member> targetsEquals = new Map();
  Map<VariableDeclaration, Member> targets = new Map();
  for (VariableDeclaration variable in allVariables) {
    Member target = coreTypes.objectEquals;
    Member targetEquals = coreTypes.objectEquals;
    DartType fieldsType = variable.type;
    if (fieldsType is InterfaceType) {
      targetEquals =
          hierarchy.getInterfaceMember(fieldsType.classNode, Name("=="))!;
      target = hierarchy.getInterfaceMember(cls, Name(variable.name!))!;
    }
    targetsEquals[variable] = targetEquals;
    targets[variable] = target;
  }

  Procedure equalsOperator = Procedure(
      Name("=="),
      ProcedureKind.Operator,
      FunctionNode(
          ReturnStatement(allVariables
              .map((f) => _createEquals(
                  _createGet(ThisExpression(), Name(f.name!),
                      interfaceTarget: targets[f],
                      useNewMethodInvocationEncoding:
                          useNewMethodInvocationEncoding),
                  _createGet(VariableGet(other, myType), Name(f.name!),
                      interfaceTarget: targets[f],
                      useNewMethodInvocationEncoding:
                          useNewMethodInvocationEncoding),
                  interfaceTarget: targetsEquals[f] as Procedure,
                  useNewMethodInvocationEncoding:
                      useNewMethodInvocationEncoding))
              .fold(
                  IsExpression(VariableGet(other), myType),
                  (previousValue, element) => LogicalExpression(
                      previousValue!, LogicalExpressionOperator.AND, element))),
          returnType: returnType,
          positionalParameters: [other]),
      fileUri: cls.fileUri)
    ..fileOffset = cls.fileOffset;
  cls.addProcedure(equalsOperator);
}

void addHashCode(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy,
    List<VariableDeclaration> allVariablesList,
    {required bool useNewMethodInvocationEncoding}) {
  List<VariableDeclaration> allVariables = allVariablesList.toList();
  for (Procedure procedure in cls.procedures) {
    if (procedure.kind == ProcedureKind.Getter &&
        procedure.name.text == "hashCode") {
      // hashCode getter is already implemented, spec is to do nothing
      return;
    }
  }
  DartType returnType = coreTypes.intRawType(cls.enclosingLibrary.nonNullable);

  Procedure? hashCombine, hashFinish;
  HashCombineMethodsScanner hashCombineMethodsScanner =
      new HashCombineMethodsScanner();
  JenkinsClassScanner jenkinsScanner =
      new JenkinsClassScanner(hashCombineMethodsScanner);
  ScanResult<Class, Procedure> hashMethodsResult =
      jenkinsScanner.scan(cls.enclosingLibrary.enclosingComponent!);
  for (Class clazz in hashMethodsResult.targets.keys) {
    for (Procedure procedure
        in hashMethodsResult.targets[clazz]!.targets.keys) {
      if (procedure.name.text == "combine") {
        hashCombine = procedure;
      }
      if (procedure.name.text == "finish") {
        hashFinish = procedure;
      }
    }
  }

  Map<VariableDeclaration, Member> targetsHashcode = new Map();
  Map<VariableDeclaration, Member> targets = new Map();
  for (VariableDeclaration variable in allVariables) {
    Member target = coreTypes.objectEquals;
    Member targetHashcode = coreTypes.objectEquals;
    DartType fieldsType = variable.type;
    if (fieldsType is InterfaceType) {
      targetHashcode =
          hierarchy.getInterfaceMember(fieldsType.classNode, Name("hashCode"))!;
      target = hierarchy.getInterfaceMember(cls, Name(variable.name!))!;
    }
    targetsHashcode[variable] = targetHashcode;
    targets[variable] = target;
  }
  cls.addProcedure(Procedure(
      Name("hashCode"),
      ProcedureKind.Getter,
      FunctionNode(
          ReturnStatement(StaticInvocation(
              hashFinish!,
              Arguments([
                allVariables
                    .map((f) => (_createGet(
                        _createGet(ThisExpression(), Name(f.name!),
                            interfaceTarget: targets[f],
                            useNewMethodInvocationEncoding:
                                useNewMethodInvocationEncoding),
                        Name("hashCode"),
                        interfaceTarget: targetsHashcode[f],
                        useNewMethodInvocationEncoding:
                            useNewMethodInvocationEncoding)))
                    .fold(
                        _createGet(
                            StringLiteral(
                                cls.enclosingLibrary.importUri.toString() +
                                    cls.name),
                            Name("hashCode"),
                            interfaceTarget: hierarchy.getInterfaceMember(
                                coreTypes.stringClass, Name("hashCode")),
                            useNewMethodInvocationEncoding:
                                useNewMethodInvocationEncoding),
                        (previousValue, element) => StaticInvocation(
                            hashCombine!, Arguments([previousValue, element])))
              ]))),
          returnType: returnType),
      fileUri: cls.fileUri)
    ..fileOffset = cls.fileOffset);
}

void addToString(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy,
    List<VariableDeclaration> allVariablesList,
    {required bool useNewMethodInvocationEncoding}) {
  List<Expression> wording = [StringLiteral("${cls.name}(")];

  for (VariableDeclaration variable in allVariablesList) {
    wording.add(StringLiteral("${variable.name}: "));
    Member? variableTarget =
        hierarchy.getInterfaceMember(cls, Name(variable.name!));
    Procedure toStringTarget = hierarchy.getInterfaceMember(
        variable.type is InterfaceType
            ? (variable.type as InterfaceType).classNode
            : coreTypes.objectClass,
        Name("toString")) as Procedure;
    wording.add(_createInvocation(
        _createGet(ThisExpression(), Name(variable.name!),
            interfaceTarget: variableTarget,
            useNewMethodInvocationEncoding: useNewMethodInvocationEncoding),
        Name("toString"),
        Arguments([]),
        interfaceTarget: toStringTarget,
        useNewMethodInvocationEncoding: useNewMethodInvocationEncoding));
    wording.add(StringLiteral(", "));
  }
  if (allVariablesList.length != 0) {
    wording[wording.length - 1] = StringLiteral(")");
  } else {
    wording.add(StringLiteral(")"));
  }
  DartType returnType =
      coreTypes.stringRawType(cls.enclosingLibrary.nonNullable);
  cls.addProcedure(Procedure(
      Name("toString"),
      ProcedureKind.Method,
      FunctionNode(ReturnStatement(StringConcatenation(wording)),
          returnType: returnType),
      fileUri: cls.fileUri)
    ..fileOffset = cls.fileOffset);
}

void addCopyWith(
    Class cls,
    CoreTypes coreTypes,
    ClassHierarchy hierarchy,
    List<VariableDeclaration> allVariablesList,
    Constructor syntheticConstructor,
    TypeEnvironment typeEnvironment) {
  List<VariableDeclaration> allVariables = allVariablesList.toList();

  Map<VariableDeclaration, Member> targetsEquals = new Map();
  Map<VariableDeclaration, Member> targets = new Map();
  for (VariableDeclaration variable in allVariables) {
    Member target = coreTypes.objectEquals;
    Member targetEquals = coreTypes.objectEquals;
    DartType fieldsType = variable.type;
    if (fieldsType is InterfaceType) {
      targetEquals =
          hierarchy.getInterfaceMember(fieldsType.classNode, Name("=="))!;
      target = hierarchy.getInterfaceMember(cls, Name(variable.name!))!;
    }
    targetsEquals[variable] = targetEquals;
    targets[variable] = target;
  }

  cls.addProcedure(Procedure(
      Name("copyWith"),
      ProcedureKind.Method,
      FunctionNode(
          ReturnStatement(ConstructorInvocation(
              syntheticConstructor,
              Arguments([],
                  named: allVariables
                      .map((f) => NamedExpression(f.name!, VariableGet(f)))
                      .toList()))),
          namedParameters: allVariables),
      fileUri: cls.fileUri)
    ..fileOffset = cls.fileOffset);
}

List<VariableDeclaration> queryAllInstanceVariables(Class cls) {
  Constructor? superConstructor = null;
  for (Constructor constructor in cls.superclass!.constructors) {
    if (constructor.name.text == "") {
      superConstructor = constructor;
    }
  }
  return superConstructor!.function.namedParameters
      .map<VariableDeclaration>(
          (f) => VariableDeclaration(f.name, type: f.type))
      .toList()
        ..addAll(cls.fields.map<VariableDeclaration>(
            (f) => VariableDeclaration(f.name.text, type: f.type)));
}

void removeValueClassAnnotation(Class cls) {
  int? valueClassAnnotationIndex;
  for (int annotationIndex = 0;
      annotationIndex < cls.annotations.length;
      annotationIndex++) {
    Expression annotation = cls.annotations[annotationIndex];
    if (annotation is ConstantExpression &&
        annotation.constant is StringConstant) {
      StringConstant constant = annotation.constant as StringConstant;
      if (constant.value == 'valueClass') {
        valueClassAnnotationIndex = annotationIndex;
      }
    }
  }
  cls.annotations.removeAt(valueClassAnnotationIndex!);
}

void treatCopyWithCallSites(Component component, CoreTypes coreTypes,
    TypeEnvironment typeEnvironment, ClassHierarchy hierarchy,
    {required bool useNewMethodInvocationEncoding}) {
  ValueClassCopyWithScanner valueCopyWithScanner =
      new ValueClassCopyWithScanner();
  AllMemberScanner copyWithScanner = AllMemberScanner(valueCopyWithScanner);
  ScanResult<Member, InstanceInvocationExpression> copyWithCallSites =
      copyWithScanner.scan(component);
  for (Member memberWithCopyWith in copyWithCallSites.targets.keys) {
    Map<InstanceInvocationExpression, ScanResult<TreeNode?, TreeNode?>?>?
        targets = copyWithCallSites.targets[memberWithCopyWith]?.targets;
    if (targets != null) {
      StaticTypeContext staticTypeContext =
          StaticTypeContext(memberWithCopyWith, typeEnvironment);
      for (InstanceInvocationExpression copyWithCall in targets.keys) {
        AsExpression receiver = copyWithCall.receiver as AsExpression;

        Expression valueClassInstance = receiver.operand;
        DartType valueClassType =
            valueClassInstance.getStaticType(staticTypeContext);
        if (valueClassType is InterfaceType) {
          Class valueClass = valueClassType.classNode;
          if (isValueClass(valueClass)) {
            treatCopyWithCallSite(
                valueClass, copyWithCall, coreTypes, hierarchy,
                useNewMethodInvocationEncoding: useNewMethodInvocationEncoding);
          }
        }
      }
    }
  }
}

void treatCopyWithCallSite(
    Class valueClass,
    InstanceInvocationExpression copyWithCall,
    CoreTypes coreTypes,
    ClassHierarchy hierarchy,
    {required bool useNewMethodInvocationEncoding}) {
  Map<String, Expression> preTransformationArguments = new Map();
  for (NamedExpression argument in copyWithCall.arguments.named) {
    preTransformationArguments[argument.name] = argument.value;
  }
  Constructor? syntheticConstructor;
  for (Constructor constructor in valueClass.constructors) {
    if (constructor.isSynthetic) {
      syntheticConstructor = constructor;
    }
  }
  List<VariableDeclaration> allArguments =
      syntheticConstructor!.function.namedParameters;

  VariableDeclaration letVariable =
      VariableDeclaration.forValue(copyWithCall.receiver);
  Arguments postTransformationArguments = Arguments.empty();
  for (VariableDeclaration argument in allArguments) {
    if (preTransformationArguments.containsKey(argument.name)) {
      postTransformationArguments.named.add(NamedExpression(
          argument.name!, preTransformationArguments[argument.name]!)
        ..parent = postTransformationArguments);
    } else {
      postTransformationArguments.named.add(NamedExpression(
          argument.name!,
          _createGet(VariableGet(letVariable), Name(argument.name!),
              useNewMethodInvocationEncoding: useNewMethodInvocationEncoding))
        ..parent = postTransformationArguments);
    }
  }
  copyWithCall.replaceWith(Let(
      letVariable,
      _createInvocation(VariableGet(letVariable), Name("copyWith"),
          postTransformationArguments,
          useNewMethodInvocationEncoding: useNewMethodInvocationEncoding)));
}

bool isValueClass(Class node) {
  for (Expression annotation in node.annotations) {
    if (annotation is ConstantExpression &&
        annotation.constant is StringConstant) {
      StringConstant constant = annotation.constant as StringConstant;
      if (constant.value == "valueClass") {
        return true;
      }
    }
  }
  return false;
}

// TODO(johnniwinther): Ensure correct invocation function type and instance
// access kind on InstanceInvocation.
Expression _createInvocation(
    Expression receiver, Name name, Arguments arguments,
    {Procedure? interfaceTarget,
    required bool useNewMethodInvocationEncoding}) {
  if (useNewMethodInvocationEncoding) {
    if (interfaceTarget != null) {
      return InstanceInvocation(
          InstanceAccessKind.Instance, receiver, name, arguments,
          interfaceTarget: interfaceTarget,
          functionType: interfaceTarget.getterType as FunctionType);
    } else {
      return DynamicInvocation(
          DynamicAccessKind.Dynamic, receiver, name, arguments);
    }
  } else {
    return MethodInvocation(receiver, name, arguments, interfaceTarget);
  }
}

Expression _createEquals(Expression left, Expression right,
    {required Procedure interfaceTarget,
    required bool useNewMethodInvocationEncoding}) {
  if (useNewMethodInvocationEncoding) {
    return EqualsCall(left, right,
        interfaceTarget: interfaceTarget,
        functionType: interfaceTarget.getterType as FunctionType);
  } else {
    return MethodInvocation(left, Name('=='), Arguments([right]));
  }
}

// TODO(johnniwinther): Ensure correct result type on InstanceGet.
Expression _createGet(Expression receiver, Name name,
    {Member? interfaceTarget, required bool useNewMethodInvocationEncoding}) {
  if (useNewMethodInvocationEncoding) {
    if (interfaceTarget != null) {
      return InstanceGet(InstanceAccessKind.Instance, receiver, name,
          interfaceTarget: interfaceTarget,
          resultType: interfaceTarget.getterType);
    } else {
      return DynamicGet(DynamicAccessKind.Dynamic, receiver, name);
    }
  } else {
    return PropertyGet(receiver, name, interfaceTarget);
  }
}
