// Copyright (c) 2014, 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/collections.dart';
import 'package:analysis_server/src/protocol_server.dart' as proto;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:collection/collection.dart';

/// Return the elements that the given [element] overrides.
OverriddenElements findOverriddenElements(Element element) {
  if (element.enclosingElement2 is InterfaceElement) {
    return _OverriddenElementsFinder(element).find();
  }
  return OverriddenElements(element, <Element>[], <Element>[]);
}

/// A computer for class member overrides in a Dart [CompilationUnit].
class DartUnitOverridesComputer {
  final CompilationUnit _unit;
  final List<proto.Override> _overrides = <proto.Override>[];

  DartUnitOverridesComputer(this._unit);

  /// Returns the computed occurrences, not `null`.
  List<proto.Override> compute() {
    for (var unitMember in _unit.declarations) {
      if (unitMember is ClassDeclaration) {
        _classMembers(unitMember.members);
      } else if (unitMember is EnumDeclaration) {
        _classMembers(unitMember.members);
      } else if (unitMember is ExtensionTypeDeclaration) {
        _classMembers(unitMember.members);
      } else if (unitMember is MixinDeclaration) {
        _classMembers(unitMember.members);
      }
    }
    return _overrides;
  }

  /// Add a new [proto.Override] for the declaration with the given name
  /// [token].
  void _addOverride(Token token, Element? element) {
    if (element != null) {
      var overridesResult = _OverriddenElementsFinder(element).find();
      var superElements = overridesResult.superElements;
      var interfaceElements = overridesResult.interfaceElements;
      if (superElements.isNotEmpty || interfaceElements.isNotEmpty) {
        var superMember =
            superElements.isNotEmpty
                ? proto.newOverriddenMember_fromEngine(
                  superElements.first.nonSynthetic2,
                )
                : null;
        var interfaceMembers =
            interfaceElements
                .map(
                  (member) => proto.newOverriddenMember_fromEngine(
                    member.nonSynthetic2,
                  ),
                )
                .toList();
        _overrides.add(
          proto.Override(
            token.offset,
            token.length,
            superclassMember: superMember,
            interfaceMembers: nullIfEmpty(interfaceMembers),
          ),
        );
      }
    }
  }

  void _classMembers(List<ClassMember> members) {
    for (var classMember in members) {
      if (classMember is MethodDeclaration) {
        if (classMember.isStatic) {
          continue;
        }
        _addOverride(classMember.name, classMember.declaredFragment?.element);
      }
      if (classMember is FieldDeclaration) {
        if (classMember.isStatic) {
          continue;
        }
        List<VariableDeclaration> fields = classMember.fields.variables;
        for (var field in fields) {
          _addOverride(field.name, field.declaredFragment?.element);
        }
      }
    }
  }
}

/// The container with elements that a class member overrides.
class OverriddenElements {
  /// The element that overrides other class members.
  final Element element;

  /// The elements that [element] overrides and which is defined in a class that
  /// is a superclass of the class that defines [element].
  final List<Element> superElements;

  /// The elements that [element] overrides and which is defined in a class that
  /// which is implemented by the class that defines [element].
  final List<Element> interfaceElements;

  OverriddenElements(this.element, this.superElements, this.interfaceElements);
}

class _OverriddenElementsFinder {
  Element _seed;
  LibraryElement _library;
  InterfaceElement _class;
  String _name;
  List<ElementKind> _kinds;

  final List<Element> _superElements = <Element>[];
  final List<Element> _interfaceElements = <Element>[];
  final Set<InterfaceElement> _visited = {};

  factory _OverriddenElementsFinder(Element seed) {
    var class_ = seed.enclosingElement2 as InterfaceElement;
    var library = class_.library2;
    var name = seed.displayName;
    List<ElementKind> kinds;
    if (seed is FieldElement) {
      kinds = [ElementKind.GETTER, if (!seed.isFinal) ElementKind.SETTER];
    } else if (seed is MethodElement) {
      kinds = const [ElementKind.METHOD];
    } else if (seed is GetterElement) {
      kinds = const [ElementKind.GETTER];
    } else if (seed is SetterElement) {
      kinds = const [ElementKind.SETTER];
    } else {
      kinds = const [];
    }
    return _OverriddenElementsFinder._(seed, library, class_, name, kinds);
  }

  _OverriddenElementsFinder._(
    this._seed,
    this._library,
    this._class,
    this._name,
    this._kinds,
  );

  /// Add the [OverriddenElements] for this element.
  OverriddenElements find() {
    _visited.clear();
    _addSuperOverrides(_class, withThisType: false);
    _visited.clear();
    _addInterfaceOverrides(_class, false);
    _superElements.forEach(_interfaceElements.remove);
    return OverriddenElements(_seed, _superElements, _interfaceElements);
  }

  void _addInterfaceOverrides(InterfaceElement? class_, bool checkType) {
    if (class_ == null) {
      return;
    }
    if (!_visited.add(class_)) {
      return;
    }
    // this type
    if (checkType) {
      var element = _lookupMember(class_);
      if (element != null && !_interfaceElements.contains(element)) {
        _interfaceElements.add(element);
      }
    }
    // interfaces
    for (var interfaceType in class_.interfaces) {
      _addInterfaceOverrides(interfaceType.element3, true);
    }
    // super
    _addInterfaceOverrides(class_.supertype?.element3, checkType);
    if (class_ is MixinElement) {
      for (var constraint in class_.superclassConstraints) {
        _addInterfaceOverrides(constraint.element3, true);
      }
    }
  }

  void _addSuperOverrides(
    InterfaceElement? class_, {
    bool withThisType = true,
  }) {
    if (class_ == null) {
      return;
    }
    if (!_visited.add(class_)) {
      return;
    }

    if (withThisType) {
      var element = _lookupMember(class_);
      if (element != null && !_superElements.contains(element)) {
        _superElements.add(element);
      }
    }

    _addSuperOverrides(class_.supertype?.element3);
    for (var mixin_ in class_.mixins) {
      _addSuperOverrides(mixin_.element3);
    }
    if (class_ is MixinElement) {
      for (var constraint in class_.superclassConstraints) {
        _addSuperOverrides(constraint.element3);
      }
    }
  }

  Element? _lookupMember(InterfaceElement classElement) {
    Element? findMatchingElement(Iterable<Element> elements) {
      return elements.firstWhereOrNull((Element element) {
        if (!identical(element.library2, _library) && _name.startsWith('_')) {
          return false;
        }
        return element.name3 == _name;
      });
    }

    // method
    if (_kinds.contains(ElementKind.METHOD)) {
      var member = findMatchingElement(classElement.methods2);
      if (member != null) {
        return member;
      }
    }
    // getter
    if (_kinds.contains(ElementKind.GETTER)) {
      var member = findMatchingElement(classElement.getters2);
      if (member != null) {
        return member;
      }
    }
    // setter
    if (_kinds.contains(ElementKind.SETTER)) {
      var member = findMatchingElement(classElement.setters2);
      if (member != null) {
        return member;
      }
    }
    // not found
    return null;
  }
}
