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

import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/correction/levenshtein.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/services/search/hierarchy.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
import 'package:analyzer_plugin/utilities/range_factory.dart';

/// A predicate is a one-argument function that returns a boolean value.
typedef _ElementPredicate = bool Function(Element argument);

class ChangeTo extends CorrectionProducer {
  /// The kind of elements that should be proposed.
  final _ReplacementKind _kind;

  /// The name to which the undefined name will be changed.
  String _proposedName = '';

  /// Initialize a newly created instance that will propose elements of the
  /// given [_kind].
  ChangeTo(this._kind);

  @override
  List<Object> get fixArguments => [_proposedName];

  @override
  FixKind get fixKind => DartFixKind.CHANGE_TO;

  @override
  Future<void> compute(ChangeBuilder builder) async {
    // TODO(brianwilkerson) Unify these separate methods as much as is
    //  reasonably possible.
    // TODO(brianwilkerson) Consider proposing all of the names within a
    //  reasonable distance, rather than just the first near match we find.
    if (_kind == _ReplacementKind.annotation) {
      await _proposeAnnotation(builder);
    } else if (_kind == _ReplacementKind.classOrMixin) {
      await _proposeClassOrMixin(builder, node);
    } else if (_kind == _ReplacementKind.function) {
      await _proposeFunction(builder);
    } else if (_kind == _ReplacementKind.getterOrSetter) {
      await _proposeGetterOrSetter(builder);
    } else if (_kind == _ReplacementKind.method) {
      await _proposeMethod(builder);
    }
  }

  Future<void> _proposeAnnotation(ChangeBuilder builder) async {
    final node = this.node;
    if (node is Annotation) {
      var name = node.name;
      if (name.staticElement == null) {
        if (node.arguments != null) {
          await _proposeClassOrMixin(builder, name);
        }
      }
    }
  }

  Future<void> _proposeClassOrMixin(ChangeBuilder builder, AstNode node) async {
    // Prepare the optional import prefix name.
    String? prefixName;
    if (node is PrefixedIdentifier &&
        node.parent is NamedType &&
        node.prefix.staticElement is PrefixElement) {
      prefixName = node.prefix.name;
      node = node.identifier;
    }
    // Process if looks like a type.
    if (mightBeTypeIdentifier(node)) {
      // Prepare for selecting the closest element.
      var name = (node as SimpleIdentifier).name;
      var finder = _ClosestElementFinder(
          name, (Element element) => element is ClassElement);
      // Check elements of this library.
      if (prefixName == null) {
        for (var unit in resolvedResult.libraryElement.units) {
          finder._updateList(unit.classes);
        }
      }
      // Check elements from imports.
      for (var importElement in resolvedResult.libraryElement.imports) {
        if (importElement.prefix?.name == prefixName) {
          var namespace = getImportNamespace(importElement);
          finder._updateList(namespace.values);
        }
      }
      // If we have a close enough element, suggest to use it.
      var foundElementName = finder._element?.name;
      if (foundElementName != null) {
        _proposedName = foundElementName;
        await builder.addDartFileEdit(file, (builder) {
          builder.addSimpleReplacement(range.node(node), _proposedName);
        });
      }
    }
  }

  Future<void> _proposeClassOrMixinMember(ChangeBuilder builder,
      Expression? target, _ElementPredicate predicate) async {
    final node = this.node;
    var targetIdentifierElement =
        target is Identifier ? target.staticElement : null;
    if (node is SimpleIdentifier) {
      var finder = _ClosestElementFinder(node.name, predicate);
      // unqualified invocation
      if (target == null) {
        var clazz = node.thisOrAncestorOfType<ClassDeclaration>();
        if (clazz != null) {
          var classElement = clazz.declaredElement!;
          _updateFinderWithClassMembers(finder, classElement);
        }
      } else if (target is ExtensionOverride) {
        _updateFinderWithExtensionMembers(finder, target.staticElement);
      } else if (targetIdentifierElement is ExtensionElement) {
        _updateFinderWithExtensionMembers(finder, targetIdentifierElement);
      } else {
        var classElement = getTargetClassElement(target);
        if (classElement != null) {
          _updateFinderWithClassMembers(finder, classElement);
        }
      }
      // if we have close enough element, suggest to use it
      var foundElementName = finder._element?.displayName;
      if (foundElementName != null) {
        _proposedName = foundElementName;
        await builder.addDartFileEdit(file, (builder) {
          builder.addSimpleReplacement(range.node(node), _proposedName);
        });
      }
    }
  }

  Future<void> _proposeFunction(ChangeBuilder builder) async {
    final node = this.node;
    if (node is SimpleIdentifier) {
      // Prepare the optional import prefix name.
      String? prefixName;
      {
        var invocation = node.parent;
        if (invocation is MethodInvocation && invocation.methodName == node) {
          var target = invocation.target;
          if (target is SimpleIdentifier &&
              target.staticElement is PrefixElement) {
            prefixName = target.name;
          }
        }
      }
      // Prepare for selecting the closest element.
      var finder = _ClosestElementFinder(
          node.name, (Element element) => element is FunctionElement);
      // Check to this library units.
      if (prefixName == null) {
        for (var unit in resolvedResult.libraryElement.units) {
          finder._updateList(unit.functions);
        }
      }
      // Check unprefixed imports.
      for (var importElement in resolvedResult.libraryElement.imports) {
        if (importElement.prefix?.name == prefixName) {
          var namespace = getImportNamespace(importElement);
          finder._updateList(namespace.values);
        }
      }
      // If we have a close enough element, suggest to use it.
      var foundElementName = finder._element?.name;
      if (foundElementName != null) {
        _proposedName = foundElementName;
        await builder.addDartFileEdit(file, (builder) {
          builder.addSimpleReplacement(range.node(node), _proposedName);
        });
      }
    }
  }

  Future<void> _proposeGetterOrSetter(ChangeBuilder builder) async {
    final node = this.node;
    if (node is SimpleIdentifier) {
      // prepare target
      Expression? target;
      var parent = node.parent;
      if (parent is PrefixedIdentifier) {
        target = parent.prefix;
      } else if (parent is PropertyAccess) {
        target = parent.target;
      }
      // find getter or setter
      var wantGetter = node.inGetterContext();
      var wantSetter = node.inSetterContext();
      await _proposeClassOrMixinMember(builder, target, (Element element) {
        if (element is PropertyAccessorElement) {
          return wantGetter && element.isGetter ||
              wantSetter && element.isSetter;
        } else if (element is FieldElement) {
          return wantGetter && element.getter != null ||
              wantSetter && element.setter != null;
        }
        return false;
      });
    }
  }

  Future<void> _proposeMethod(ChangeBuilder builder) async {
    if (node.parent is MethodInvocation) {
      var invocation = node.parent as MethodInvocation;
      await _proposeClassOrMixinMember(builder, invocation.realTarget,
          (Element element) => element is MethodElement && !element.isOperator);
    }
  }

  void _updateFinderWithClassMembers(
      _ClosestElementFinder finder, ClassElement clazz) {
    var members = getMembers(clazz);
    finder._updateList(members);
  }

  void _updateFinderWithExtensionMembers(
      _ClosestElementFinder finder, ExtensionElement? element) {
    if (element != null) {
      finder._updateList(getExtensionMembers(element));
    }
  }

  /// Return an instance of this class that will propose classes and mixins.
  /// Used as a tear-off in `FixProcessor`.
  static ChangeTo annotation() => ChangeTo(_ReplacementKind.annotation);

  /// Return an instance of this class that will propose classes and mixins.
  /// Used as a tear-off in `FixProcessor`.
  static ChangeTo classOrMixin() => ChangeTo(_ReplacementKind.classOrMixin);

  /// Return an instance of this class that will propose functions. Used as a
  /// tear-off in `FixProcessor`.
  static ChangeTo function() => ChangeTo(_ReplacementKind.function);

  /// Return an instance of this class that will propose getters and setters.
  /// Used as a tear-off in `FixProcessor`.
  static ChangeTo getterOrSetter() => ChangeTo(_ReplacementKind.getterOrSetter);

  /// Return an instance of this class that will propose methods. Used as a
  /// tear-off in `FixProcessor`.
  static ChangeTo method() => ChangeTo(_ReplacementKind.method);
}

/// Helper for finding [Element] with name closest to the given.
class _ClosestElementFinder {
  /// The maximum Levenshtein distance between the existing name and a possible
  /// replacement before the replacement is deemed to not be worth offering.
  static const _maxDistance = 3;

  /// The name to be replaced.
  final String _targetName;

  /// A function used to filter the possible elements to those of the right
  /// kind.
  final _ElementPredicate _predicate;

  int _distance = _maxDistance;

  Element? _element;

  _ClosestElementFinder(this._targetName, this._predicate);

  void _update(Element element) {
    if (_predicate(element)) {
      var name = element.name;
      if (name != null) {
        var memberDistance = levenshtein(name, _targetName, _distance);
        if (memberDistance < _distance) {
          _element = element;
          _distance = memberDistance;
        }
      }
    }
  }

  void _updateList(Iterable<Element> elements) {
    for (var element in elements) {
      _update(element);
    }
  }
}

/// A representation of the kind of element that should be suggested.
enum _ReplacementKind {
  annotation,
  classOrMixin,
  function,
  getterOrSetter,
  method
}
