// 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 'package:_fe_analyzer_shared/src/macros/api.dart' as macro;
import 'package:_fe_analyzer_shared/src/macros/executor.dart' as macro;
import 'package:_fe_analyzer_shared/src/macros/executor/introspection_impls.dart'
    as macro;
import 'package:_fe_analyzer_shared/src/macros/executor/multi_executor.dart';
import 'package:_fe_analyzer_shared/src/macros/executor/protocol.dart' as macro;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/summary2/library_builder.dart';
import 'package:analyzer/src/summary2/link.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
import 'package:analyzer/src/summary2/macro_application_error.dart';
import 'package:analyzer/src/summary2/macro_declarations.dart';
import 'package:analyzer/src/util/performance/operation_performance.dart';

class LibraryMacroApplier {
  final DeclarationBuilder declarationBuilder;
  final LibraryBuilder libraryBuilder;
  final MultiMacroExecutor macroExecutor;

  final List<_MacroTarget> _targets = [];

  late final macro.IdentifierResolver _identifierResolver =
      _IdentifierResolver(_linker.elementFactory, declarationBuilder);

  late final macro.TypeDeclarationResolver _typeDeclarationResolver =
      _TypeDeclarationResolver(declarationBuilder);

  late final macro.TypeIntrospector _typeIntrospector =
      _TypeIntrospector(declarationBuilder);

  late final macro.TypeResolver _typeResolver = _TypeResolver(
    typeSystem: libraryBuilder.element.typeSystem,
  );

  LibraryMacroApplier({
    required this.macroExecutor,
    required this.declarationBuilder,
    required this.libraryBuilder,
  });

  Linker get _linker => libraryBuilder.linker;

  /// Fill [_targets]s with macro applications.
  Future<void> buildApplications({
    required OperationPerformanceImpl performance,
  }) async {
    final collector = _MacroTargetElementCollector();
    libraryBuilder.element.accept(collector);

    for (final targetElement in collector.targets) {
      final targetNode = _linker.elementNodes[targetElement];
      // TODO(scheglov) support other declarations
      if (targetNode is ClassDeclaration) {
        await performance.runAsync(
          'forClassDeclaration',
          (performance) async {
            await _buildApplications(
              targetElement,
              targetNode.metadata,
              macro.DeclarationKind.clazz,
              () => declarationBuilder.fromNode.classDeclaration(targetNode),
              performance: performance,
            );
          },
        );
      }
    }
  }

  Future<String?> executeDeclarationsPhase() async {
    final results = <macro.MacroExecutionResult>[];
    for (final target in _targets) {
      for (final application in target.applications) {
        if (application.shouldExecute(macro.Phase.declarations)) {
          await _runWithCatchingExceptions(
            () async {
              final result = await application.executeDeclarationsPhase();
              if (result.isNotEmpty) {
                results.add(result);
              }
            },
            annotationIndex: application.annotationIndex,
            onError: (error) {
              target.element.macroApplicationErrors.add(error);
            },
          );
        }
      }
    }
    return _buildAugmentationLibrary(results);
  }

  Future<String?> executeTypesPhase() async {
    final results = <macro.MacroExecutionResult>[];
    for (final target in _targets) {
      for (final application in target.applications) {
        if (application.shouldExecute(macro.Phase.types)) {
          await _runWithCatchingExceptions(
            () async {
              final result = await application.executeTypesPhase();
              if (result.isNotEmpty) {
                results.add(result);
              }
            },
            annotationIndex: application.annotationIndex,
            onError: (error) {
              target.element.macroApplicationErrors.add(error);
            },
          );
        }
      }
    }
    return _buildAugmentationLibrary(results);
  }

  /// If there are any macro applications in [annotations], add a new
  /// element into [_targets].
  Future<void> _buildApplications(
    MacroTargetElement targetElement,
    List<Annotation> annotations,
    macro.DeclarationKind declarationKind,
    macro.DeclarationImpl Function() getDeclaration, {
    required OperationPerformanceImpl performance,
  }) async {
    final applications = <_MacroApplication>[];

    for (var i = 0; i < annotations.length; i++) {
      Future<macro.MacroInstanceIdentifier?> instantiateSingle({
        required ClassElementImpl macroClass,
        required String constructorName,
        required ArgumentList argumentsNode,
      }) async {
        final importedLibrary = macroClass.library;
        final macroExecutor = importedLibrary.bundleMacroExecutor;
        if (macroExecutor != null) {
          return await _runWithCatchingExceptions(
            () async {
              final arguments = _buildArguments(
                annotationIndex: i,
                node: argumentsNode,
              );
              return await performance.runAsync('instantiate', (_) {
                return macroExecutor.instantiate(
                  libraryUri: macroClass.librarySource.uri,
                  className: macroClass.name,
                  constructorName: constructorName,
                  arguments: arguments,
                );
              });
            },
            annotationIndex: i,
            onError: (error) {
              targetElement.macroApplicationErrors.add(error);
            },
          );
        }
        return null;
      }

      final annotation = annotations[i];
      final macroInstance = await _importedMacroDeclaration(
        annotation,
        whenClass: ({
          required macroClass,
          required constructorName,
        }) async {
          final argumentsNode = annotation.arguments;
          if (argumentsNode != null) {
            return await instantiateSingle(
              macroClass: macroClass,
              constructorName: constructorName ?? '',
              argumentsNode: argumentsNode,
            );
          }
        },
        whenGetter: ({
          required macroClass,
          required instanceCreation,
        }) async {
          return await instantiateSingle(
            macroClass: macroClass,
            constructorName: instanceCreation.constructorName.name?.name ?? '',
            argumentsNode: instanceCreation.argumentList,
          );
        },
      );

      if (macroInstance != null) {
        applications.add(
          _MacroApplication(
            annotationIndex: i,
            instanceIdentifier: macroInstance,
          ),
        );
      }
    }

    if (applications.isNotEmpty) {
      _targets.add(
        _MacroTarget(
          applier: this,
          element: targetElement,
          declarationKind: declarationKind,
          declaration: getDeclaration(),
          applications: applications,
        ),
      );
    }
  }

  /// If there are any [results], builds the augmentation library with them.
  String? _buildAugmentationLibrary(
    List<macro.MacroExecutionResult> results,
  ) {
    if (results.isEmpty) {
      return null;
    }

    final code = macroExecutor.buildAugmentationLibrary(
      results,
      _resolveIdentifier,
      _inferOmittedType,
    );
    return code.trim();
  }

  /// If [annotation] references a macro, invokes the right callback.
  Future<R?> _importedMacroDeclaration<R>(
    Annotation annotation, {
    required Future<R?> Function({
      required ClassElementImpl macroClass,
      required String? constructorName,
    })
        whenClass,
    required Future<R?> Function({
      required ClassElementImpl macroClass,
      required InstanceCreationExpression instanceCreation,
    })
        whenGetter,
  }) async {
    final String? prefix;
    final String name;
    final String? constructorName;
    final nameNode = annotation.name;
    if (nameNode is SimpleIdentifier) {
      prefix = null;
      name = nameNode.name;
      constructorName = annotation.constructorName?.name;
    } else if (nameNode is PrefixedIdentifier) {
      final importPrefixCandidate = nameNode.prefix.name;
      final hasImportPrefix = libraryBuilder.element.imports2.any(
          (import) => import.prefix?.element.name == importPrefixCandidate);
      if (hasImportPrefix) {
        prefix = importPrefixCandidate;
        name = nameNode.identifier.name;
        constructorName = annotation.constructorName?.name;
      } else {
        prefix = null;
        name = nameNode.prefix.name;
        constructorName = nameNode.identifier.name;
      }
    } else {
      throw StateError('${nameNode.runtimeType} $nameNode');
    }

    for (final import in libraryBuilder.element.imports2) {
      if (import.prefix?.element.name != prefix) {
        continue;
      }

      final importedLibrary = import.importedLibrary;
      if (importedLibrary == null) {
        continue;
      }

      // Skip if a library that is being linked.
      final importedUri = importedLibrary.source.uri;
      if (_linker.builders.containsKey(importedUri)) {
        continue;
      }

      final lookupResult = importedLibrary.scope.lookup(name);
      final element = lookupResult.getter;
      if (element is ClassElementImpl) {
        if (element.isMacro) {
          return await whenClass(
            macroClass: element,
            constructorName: constructorName,
          );
        }
      } else if (element is PropertyAccessorElementImpl &&
          element.isGetter &&
          element.isSynthetic) {
        final variable = element.variable;
        final variableType = variable.type;
        if (variable is ConstTopLevelVariableElementImpl &&
            variableType is InterfaceType) {
          final macroClass = variableType.element;
          final initializer = variable.constantInitializer;
          if (macroClass is ClassElementImpl &&
              macroClass.isMacro &&
              initializer is InstanceCreationExpression) {
            return await whenGetter(
              macroClass: macroClass,
              instanceCreation: initializer,
            );
          }
        }
      }
    }
    return null;
  }

  macro.TypeAnnotation _inferOmittedType(
    macro.OmittedTypeAnnotation omittedType,
  ) {
    throw UnimplementedError();
  }

  macro.ResolvedIdentifier _resolveIdentifier(macro.Identifier identifier) {
    throw UnimplementedError();
  }

  static macro.Arguments _buildArguments({
    required int annotationIndex,
    required ArgumentList node,
  }) {
    final positional = <Object?>[];
    final named = <String, Object?>{};
    for (var i = 0; i < node.arguments.length; ++i) {
      final argument = node.arguments[i];
      final evaluation = _ArgumentEvaluation(
        annotationIndex: annotationIndex,
        argumentIndex: i,
      );
      if (argument is NamedExpression) {
        final value = evaluation.evaluate(argument.expression);
        named[argument.name.label.name] = value;
      } else {
        final value = evaluation.evaluate(argument);
        positional.add(value);
      }
    }
    return macro.Arguments(positional, named);
  }

  /// Run the [body], report exceptions as [MacroApplicationError]s to [onError].
  static Future<T?> _runWithCatchingExceptions<T>(
    Future<T> Function() body, {
    required int annotationIndex,
    required void Function(MacroApplicationError) onError,
  }) async {
    try {
      return await body();
    } on MacroApplicationError catch (e) {
      onError(e);
    } on macro.RemoteException catch (e) {
      onError(
        UnknownMacroApplicationError(
          annotationIndex: annotationIndex,
          message: e.error,
          stackTrace: e.stackTrace ?? '<null>',
        ),
      );
    } catch (e, stackTrace) {
      onError(
        UnknownMacroApplicationError(
          annotationIndex: annotationIndex,
          message: e.toString(),
          stackTrace: stackTrace.toString(),
        ),
      );
    }
    return null;
  }
}

/// Helper class for evaluating arguments for a single constructor based
/// macro application.
class _ArgumentEvaluation {
  final int annotationIndex;
  final int argumentIndex;

  _ArgumentEvaluation({
    required this.annotationIndex,
    required this.argumentIndex,
  });

  Object? evaluate(Expression node) {
    if (node is AdjacentStrings) {
      return node.strings.map(evaluate).join('');
    } else if (node is BooleanLiteral) {
      return node.value;
    } else if (node is DoubleLiteral) {
      return node.value;
    } else if (node is IntegerLiteral) {
      return node.value;
    } else if (node is ListLiteral) {
      return node.elements.cast<Expression>().map(evaluate).toList();
    } else if (node is NullLiteral) {
      return null;
    } else if (node is PrefixExpression &&
        node.operator.type == TokenType.MINUS) {
      final operandValue = evaluate(node.operand);
      if (operandValue is double) {
        return -operandValue;
      } else if (operandValue is int) {
        return -operandValue;
      }
    } else if (node is SetOrMapLiteral) {
      return _setOrMapLiteral(node);
    } else if (node is SimpleStringLiteral) {
      return node.value;
    }
    _throwError(node, 'Not supported: ${node.runtimeType}');
  }

  Object _setOrMapLiteral(SetOrMapLiteral node) {
    if (node.elements.every((e) => e is Expression)) {
      final result = <Object?>{};
      for (final element in node.elements) {
        if (element is! Expression) {
          _throwError(element, 'Expression expected');
        }
        final value = evaluate(element);
        result.add(value);
      }
      return result;
    }

    final result = <Object?, Object?>{};
    for (final element in node.elements) {
      if (element is! MapLiteralEntry) {
        _throwError(element, 'MapLiteralEntry expected');
      }
      final key = evaluate(element.key);
      final value = evaluate(element.value);
      result[key] = value;
    }
    return result;
  }

  Never _throwError(AstNode node, String message) {
    throw ArgumentMacroApplicationError(
      annotationIndex: annotationIndex,
      argumentIndex: argumentIndex,
      message: message,
    );
  }
}

class _IdentifierResolver extends macro.IdentifierResolver {
  final LinkedElementFactory elementFactory;
  final DeclarationBuilder declarationBuilder;

  _IdentifierResolver(
    this.elementFactory,
    this.declarationBuilder,
  );

  @override
  Future<macro.Identifier> resolveIdentifier(Uri library, String name) async {
    final libraryElement = elementFactory.libraryOfUri2(library);
    final element = libraryElement.scope.lookup(name).getter!;
    return declarationBuilder.fromElement.identifier(element);
  }
}

class _MacroApplication {
  late final _MacroTarget target;
  final int annotationIndex;
  final macro.MacroInstanceIdentifier instanceIdentifier;

  _MacroApplication({
    required this.annotationIndex,
    required this.instanceIdentifier,
  });

  Future<macro.MacroExecutionResult> executeDeclarationsPhase() async {
    final applier = target.applier;
    final executor = applier.macroExecutor;
    return await executor.executeDeclarationsPhase(
      instanceIdentifier,
      target.declaration,
      applier._identifierResolver,
      applier._typeDeclarationResolver,
      applier._typeResolver,
      applier._typeIntrospector,
    );
  }

  Future<macro.MacroExecutionResult> executeTypesPhase() async {
    final applier = target.applier;
    final executor = applier.macroExecutor;
    return await executor.executeTypesPhase(
      instanceIdentifier,
      target.declaration,
      applier._identifierResolver,
    );
  }

  bool shouldExecute(macro.Phase phase) {
    return instanceIdentifier.shouldExecute(target.declarationKind, phase);
  }
}

class _MacroTarget {
  final LibraryMacroApplier applier;
  final MacroTargetElement element;
  final macro.DeclarationKind declarationKind;
  final macro.DeclarationImpl declaration;
  final List<_MacroApplication> applications;

  _MacroTarget({
    required this.applier,
    required this.element,
    required this.declarationKind,
    required this.declaration,
    required this.applications,
  }) {
    for (final application in applications) {
      application.target = this;
    }
  }
}

class _MacroTargetElementCollector extends GeneralizingElementVisitor<void> {
  final List<MacroTargetElement> targets = [];

  @override
  void visitElement(covariant ElementImpl element) {
    if (element is MacroTargetElement) {
      targets.add(element as MacroTargetElement);
    }
    if (element is MacroTargetElementContainer) {
      element.visitChildren(this);
    }
  }
}

class _StaticTypeImpl extends macro.StaticType {
  final TypeSystemImpl typeSystem;
  final DartType type;

  _StaticTypeImpl(this.typeSystem, this.type);

  @override
  Future<bool> isExactly(_StaticTypeImpl other) {
    // TODO: implement isExactly
    throw UnimplementedError();
  }

  @override
  Future<bool> isSubtypeOf(_StaticTypeImpl other) {
    // TODO(scheglov) write tests
    return Future.value(
      typeSystem.isSubtypeOf(type, other.type),
    );
  }
}

class _TypeDeclarationResolver implements macro.TypeDeclarationResolver {
  final DeclarationBuilder declarationBuilder;

  _TypeDeclarationResolver(this.declarationBuilder);

  @override
  Future<macro.TypeDeclaration> declarationOf(
    covariant IdentifierImpl identifier,
  ) async {
    final element = identifier.element;
    if (element is ClassElementImpl) {
      return declarationBuilder.fromElement.classElement(element);
    } else {
      throw ArgumentError('element: $element');
    }
  }
}

class _TypeIntrospector implements macro.TypeIntrospector {
  final DeclarationBuilder declarationBuilder;

  _TypeIntrospector(this.declarationBuilder);

  @override
  Future<List<macro.ConstructorDeclaration>> constructorsOf(
      covariant macro.IntrospectableType type) {
    // TODO: implement constructorsOf
    throw UnimplementedError();
  }

  @override
  Future<List<macro.FieldDeclaration>> fieldsOf(
    covariant macro.IntrospectableType type,
  ) async {
    if (type is! IntrospectableClassDeclarationImpl) {
      throw UnsupportedError('Only introspection on classes is supported');
    }
    return type.element.fields
        .where((e) => !e.isSynthetic)
        .map(declarationBuilder.fromElement.fieldElement)
        .toList();
  }

  @override
  Future<List<macro.MethodDeclaration>> methodsOf(
      covariant macro.IntrospectableType clazz) {
    // TODO: implement methodsOf
    throw UnimplementedError();
  }
}

class _TypeResolver implements macro.TypeResolver {
  final TypeSystemImpl typeSystem;

  _TypeResolver({
    required this.typeSystem,
  });

  @override
  Future<macro.StaticType> resolve(macro.TypeAnnotationCode type) async {
    var dartType = _resolve(type);
    return _StaticTypeImpl(typeSystem, dartType);
  }

  DartType _resolve(macro.TypeAnnotationCode type) {
    // TODO(scheglov) write tests
    if (type is macro.NamedTypeAnnotationCode) {
      final identifier = type.name as IdentifierImpl;
      final element = identifier.element;
      if (element is ClassElementImpl) {
        return element.instantiate(
          typeArguments: type.typeArguments.map(_resolve).toList(),
          nullabilitySuffix: type.isNullable
              ? NullabilitySuffix.question
              : NullabilitySuffix.none,
        );
      } else {
        // TODO(scheglov) Implement other elements.
        throw UnimplementedError('(${element.runtimeType}) $element');
      }
    } else {
      // TODO(scheglov) Implement other types.
      throw UnimplementedError('(${type.runtimeType}) $type');
    }
  }
}

extension on macro.MacroExecutionResult {
  bool get isNotEmpty =>
      libraryAugmentations.isNotEmpty || classAugmentations.isNotEmpty;
}
