// Copyright (c) 2018, 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:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/src/dart/analysis/dependency/node.dart';
import 'package:analyzer/src/dart/analysis/dependency/reference_collector.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/summary/api_signature.dart';

/// Build [Library] that describes nodes and dependencies of the library
/// with the given [uri] and [units].
///
/// If the [units] are just parsed, then only token signatures and referenced
/// names of nodes can be computed. If the [units] are fully resolved, then
/// also class member references can be recorded.
Library buildLibrary(Uri uri, List<CompilationUnit> units) {
  return _LibraryBuilder(uri, units).build();
}

/// The `show` or `hide` namespace combinator.
class Combinator {
  final bool isShow;
  final List<String> names;

  Combinator(this.isShow, this.names);

  @override
  String toString() {
    if (isShow) {
      return 'show ' + names.join(', ');
    } else {
      return 'hide ' + names.join(', ');
    }
  }
}

/// The `export` directive.
class Export {
  /// The absolute URI of the exported library.
  final Uri uri;

  /// The list of namespace combinators to apply, not `null`.
  final List<Combinator> combinators;

  Export(this.uri, this.combinators);

  @override
  String toString() {
    return 'Export(uri: $uri, combinators: $combinators)';
  }
}

/// The `import` directive.
class Import {
  /// The absolute URI of the imported library.
  final Uri uri;

  /// The import prefix, or `null` if not specified.
  final String? prefix;

  /// The list of namespace combinators to apply, not `null`.
  final List<Combinator> combinators;

  Import(this.uri, this.prefix, this.combinators);

  @override
  String toString() {
    return 'Import(uri: $uri, prefix: $prefix, combinators: $combinators)';
  }
}

/// The collection of imports, exports, and top-level nodes.
class Library {
  /// The absolute URI of the library.
  final Uri uri;

  /// The list of imports in this library.
  final List<Import> imports;

  /// The list of exports in this library.
  final List<Export> exports;

  /// The list of libraries that correspond to the [imports].
  List<Library>? importedLibraries;

  /// The list of top-level nodes defined in the library.
  ///
  /// This list is sorted.
  final List<Node> declaredNodes;

  /// The map of [declaredNodes], used for fast search.
  /// TODO(scheglov) consider using binary search instead.
  final Map<LibraryQualifiedName, Node> declaredNodeMap = {};

  /// The list of nodes exported from this library, either using `export`
  /// directives, or declared in this library.
  ///
  /// This list is sorted.
  List<Node>? exportedNodes;

  /// The map of nodes that are visible in the library, either imported,
  /// or declared in this library.
  ///
  /// TODO(scheglov) support for imports with prefixes
  Map<String, Node>? libraryScope;

  Library(this.uri, this.imports, this.exports, this.declaredNodes) {
    for (var node in declaredNodes) {
      declaredNodeMap[node.name] = node;
    }
  }

  @override
  String toString() => '$uri';
}

class _LibraryBuilder {
  /// The URI of the library.
  final Uri uri;

  /// The units of the library, parsed or fully resolved.
  final List<CompilationUnit> units;

  /// The instance of the referenced names, class members collector.
  final ReferenceCollector referenceCollector = ReferenceCollector();

  /// The list of imports in the library.
  final List<Import> imports = [];

  /// The list of exports in the library.
  final List<Export> exports = [];

  /// The top-level nodes declared in the library.
  final List<Node> declaredNodes = [];

  /// The precomputed signature of the [uri].
  ///
  /// It is mixed into every API token signature, because for example even
  /// though types of two functions might be the same, their locations
  /// are different.
  late List<int> uriSignature;

  /// The name of the enclosing class name, or `null` if outside a class.
  String? enclosingClassName;

  /// The super class of the enclosing class, or `null` if outside a class.
  TypeName? enclosingSuperClass;

  /// The precomputed signature of the enclosing class name, or `null` if
  /// outside a class.
  ///
  /// It is mixed into every API token signature of every class member, because
  /// for example even though types of two methods might be the same, their
  /// locations are different.
  List<int>? enclosingClassNameSignature;

  /// The node of the enclosing class.
  Node? enclosingClass;

  _LibraryBuilder(this.uri, this.units);

  Library build() {
    uriSignature = (ApiSignature()..addString(uri.toString())).toByteList();

    _addImports();
    _addExports();

    for (var unit in units) {
      _addUnit(unit);
    }
    declaredNodes.sort(Node.compare);

    return Library(uri, imports, exports, declaredNodes);
  }

  void _addClassOrMixin(ClassOrMixinDeclaration node) {
    enclosingClassName = node.name.name;
    if (node is ClassDeclaration) {
      enclosingSuperClass = node.extendsClause?.superclass;
    }

    enclosingClassNameSignature =
        (ApiSignature()..addString(enclosingClassName!)).toByteList();

    var apiTokenSignature = _computeTokenSignature(
      node.beginToken,
      node.leftBracket,
    );

    Dependencies api;
    if (node is ClassDeclaration) {
      api = referenceCollector.collect(
        apiTokenSignature,
        thisNodeName: enclosingClassName,
        typeParameters: node.typeParameters,
        extendsClause: node.extendsClause,
        withClause: node.withClause,
        implementsClause: node.implementsClause,
      );
    } else if (node is MixinDeclaration) {
      api = referenceCollector.collect(
        apiTokenSignature,
        thisNodeName: enclosingClassName,
        typeParameters: node.typeParameters,
        onClause: node.onClause,
        implementsClause: node.implementsClause,
      );
    } else {
      throw UnimplementedError('(${node.runtimeType}) $node');
    }

    enclosingClass = Node(
      LibraryQualifiedName(uri, enclosingClassName!),
      node is MixinDeclaration ? NodeKind.MIXIN : NodeKind.CLASS,
      api,
      Dependencies.none,
    );

    var hasConstConstructor = node.members.any(
      (m) => m is ConstructorDeclaration && m.constKeyword != null,
    );

    // TODO(scheglov) do we need type parameters at all?
    List<Node> classTypeParameters;
    if (node.typeParameters != null) {
      classTypeParameters = <Node>[];
      for (var typeParameter in node.typeParameters!.typeParameters) {
        var api = referenceCollector.collect(
          _computeNodeTokenSignature(typeParameter),
          enclosingClassName: enclosingClassName,
          thisNodeName: typeParameter.name.name,
          type: typeParameter.bound,
        );
        classTypeParameters.add(Node(
          LibraryQualifiedName(uri, typeParameter.name.name),
          NodeKind.TYPE_PARAMETER,
          api,
          Dependencies.none,
          enclosingClass: enclosingClass!,
        ));
      }
      classTypeParameters.sort(Node.compare);
      enclosingClass!.setTypeParameters(classTypeParameters);
    }

    var classMembers = <Node>[];
    var hasConstructor = false;
    for (var member in node.members) {
      if (member is ConstructorDeclaration) {
        hasConstructor = true;
        _addConstructor(classMembers, member);
      } else if (member is FieldDeclaration) {
        _addVariables(
          classMembers,
          member.metadata,
          member.fields,
          hasConstConstructor,
        );
      } else if (member is MethodDeclaration) {
        _addMethod(classMembers, member);
      } else {
        throw UnimplementedError('(${member.runtimeType}) $member');
      }
    }

    if (node is ClassDeclaration && !hasConstructor) {
      classMembers.add(Node(
        LibraryQualifiedName(uri, ''),
        NodeKind.CONSTRUCTOR,
        Dependencies.none,
        Dependencies.none,
        enclosingClass: enclosingClass!,
      ));
    }

    classMembers.sort(Node.compare);
    enclosingClass!.setClassMembers(classMembers);

    declaredNodes.add(enclosingClass!);
    enclosingClassName = null;
    enclosingClassNameSignature = null;
    enclosingSuperClass = null;
    enclosingClass = null;
  }

  void _addClassTypeAlias(ClassTypeAlias node) {
    var apiTokenSignature = _computeNodeTokenSignature(node);
    var api = referenceCollector.collect(
      apiTokenSignature,
      typeParameters: node.typeParameters,
      superClass: node.superclass,
      withClause: node.withClause,
      implementsClause: node.implementsClause,
    );

    declaredNodes.add(Node(
      LibraryQualifiedName(uri, node.name.name),
      NodeKind.CLASS_TYPE_ALIAS,
      api,
      Dependencies.none,
    ));
  }

  void _addConstructor(List<Node> classMembers, ConstructorDeclaration node) {
    var builder = _newApiSignatureBuilder();
    _appendMetadataTokens(builder, node.metadata);
    _appendFormalParametersTokens(builder, node.parameters);
    var apiTokenSignature = builder.toByteList();

    var api = referenceCollector.collect(
      apiTokenSignature,
      enclosingClassName: enclosingClassName,
      formalParameters: node.parameters,
    );

    var implTokenSignature = _computeNodeTokenSignature(node.body);
    var impl = referenceCollector.collect(
      implTokenSignature,
      enclosingClassName: enclosingClassName,
      enclosingSuperClass: enclosingSuperClass,
      formalParametersForImpl: node.parameters,
      constructorInitializers: node.initializers,
      redirectedConstructor: node.redirectedConstructor,
      functionBody: node.body,
    );

    classMembers.add(Node(
      LibraryQualifiedName(uri, node.name?.name ?? ''),
      NodeKind.CONSTRUCTOR,
      api,
      impl,
      enclosingClass: enclosingClass!,
    ));
  }

  void _addEnum(EnumDeclaration node) {
    var enumTokenSignature = _newApiSignatureBuilder().toByteList();

    var enumNode = Node(
      LibraryQualifiedName(uri, node.name.name),
      NodeKind.ENUM,
      Dependencies(enumTokenSignature, [], [], [], [], []),
      Dependencies.none,
    );

    Dependencies fieldDependencies;
    {
      var builder = _newApiSignatureBuilder();
      builder.addString(node.name.name);
      _appendTokens(builder, node.leftBracket, node.rightBracket);
      var tokenSignature = builder.toByteList();
      fieldDependencies = Dependencies(tokenSignature, [], [], [], [], []);
    }

    var members = <Node>[];
    for (var constant in node.constants) {
      members.add(Node(
        LibraryQualifiedName(uri, constant.name.name),
        NodeKind.GETTER,
        fieldDependencies,
        Dependencies.none,
        enclosingClass: enumNode,
      ));
    }

    members.add(Node(
      LibraryQualifiedName(uri, 'index'),
      NodeKind.GETTER,
      fieldDependencies,
      Dependencies.none,
      enclosingClass: enumNode,
    ));

    members.add(Node(
      LibraryQualifiedName(uri, 'values'),
      NodeKind.GETTER,
      fieldDependencies,
      Dependencies.none,
      enclosingClass: enumNode,
    ));

    members.sort(Node.compare);
    enumNode.setClassMembers(members);

    declaredNodes.add(enumNode);
  }

  /// Fill [exports] with information about exports.
  void _addExports() {
    for (var directive in units.first.directives) {
      if (directive is ExportDirective) {
        var refUri = directive.uri.stringValue;
        var importUri = uri.resolve(refUri!);
        var combinators = _getCombinators(directive);
        exports.add(Export(importUri, combinators));
      }
    }
  }

  void _addFunction(FunctionDeclaration node) {
    var functionExpression = node.functionExpression;

    var builder = _newApiSignatureBuilder();
    _appendMetadataTokens(builder, node.metadata);
    _appendNodeTokens(builder, node.returnType);
    _appendNodeTokens(builder, functionExpression.typeParameters);
    _appendFormalParametersTokens(builder, functionExpression.parameters);
    var apiTokenSignature = builder.toByteList();

    var rawName = node.name.name;
    var name = LibraryQualifiedName(uri, node.isSetter ? '$rawName=' : rawName);

    NodeKind kind;
    if (node.isGetter) {
      kind = NodeKind.GETTER;
    } else if (node.isSetter) {
      kind = NodeKind.SETTER;
    } else {
      kind = NodeKind.FUNCTION;
    }

    var api = referenceCollector.collect(
      apiTokenSignature,
      thisNodeName: node.name.name,
      typeParameters: functionExpression.typeParameters,
      formalParameters: functionExpression.parameters,
      returnType: node.returnType,
    );

    var body = functionExpression.body;
    var implTokenSignature = _computeNodeTokenSignature(body);
    var impl = referenceCollector.collect(
      implTokenSignature,
      thisNodeName: node.name.name,
      formalParametersForImpl: functionExpression.parameters,
      functionBody: body,
    );

    declaredNodes.add(Node(name, kind, api, impl));
  }

  void _addFunctionTypeAlias(FunctionTypeAlias node) {
    var builder = _newApiSignatureBuilder();
    _appendMetadataTokens(builder, node.metadata);
    _appendNodeTokens(builder, node.typeParameters);
    _appendNodeTokens(builder, node.returnType);
    _appendFormalParametersTokens(builder, node.parameters);
    var apiTokenSignature = builder.toByteList();

    var api = referenceCollector.collect(
      apiTokenSignature,
      thisNodeName: node.name.name,
      typeParameters: node.typeParameters,
      formalParameters: node.parameters,
      returnType: node.returnType,
    );

    declaredNodes.add(Node(
      LibraryQualifiedName(uri, node.name.name),
      NodeKind.FUNCTION_TYPE_ALIAS,
      api,
      Dependencies.none,
    ));
  }

  void _addGenericTypeAlias(GenericTypeAlias node) {
    // TODO(scheglov) Support all types.
    var functionType = node.functionType;

    var builder = _newApiSignatureBuilder();
    _appendMetadataTokens(builder, node.metadata);
    _appendNodeTokens(builder, node.typeParameters);
    _appendNodeTokens(builder, functionType?.returnType);
    _appendNodeTokens(builder, functionType?.typeParameters);
    _appendFormalParametersTokens(builder, functionType?.parameters);
    var apiTokenSignature = builder.toByteList();

    var api = referenceCollector.collect(
      apiTokenSignature,
      typeParameters: node.typeParameters,
      typeParameters2: functionType?.typeParameters,
      formalParameters: functionType?.parameters,
      returnType: functionType?.returnType,
    );

    declaredNodes.add(Node(
      LibraryQualifiedName(uri, node.name.name),
      NodeKind.GENERIC_TYPE_ALIAS,
      api,
      Dependencies.none,
    ));
  }

  /// Fill [imports] with information about imports.
  void _addImports() {
    var hasDartCoreImport = false;
    for (var directive in units.first.directives) {
      if (directive is ImportDirective) {
        var refUri = directive.uri.stringValue;
        var importUri = uri.resolve(refUri!);

        if (importUri.toString() == 'dart:core') {
          hasDartCoreImport = true;
        }

        var combinators = _getCombinators(directive);

        var prefix = directive.prefix;
        imports.add(Import(importUri, prefix?.name, combinators));

        if (prefix != null) {
          referenceCollector.addImportPrefix(prefix.name);
        }
      }
    }

    if (!hasDartCoreImport) {
      imports.add(Import(Uri.parse('dart:core'), null, []));
    }
  }

  void _addMethod(List<Node> classMembers, MethodDeclaration node) {
    var builder = _newApiSignatureBuilder();
    _appendMetadataTokens(builder, node.metadata);
    _appendNodeTokens(builder, node.returnType);
    _appendNodeTokens(builder, node.typeParameters);
    _appendFormalParametersTokens(builder, node.parameters);
    var apiTokenSignature = builder.toByteList();

    NodeKind kind;
    if (node.isGetter) {
      kind = NodeKind.GETTER;
    } else if (node.isSetter) {
      kind = NodeKind.SETTER;
    } else {
      kind = NodeKind.METHOD;
    }

    // TODO(scheglov) metadata, here and everywhere
    var api = referenceCollector.collect(
      apiTokenSignature,
      enclosingClassName: enclosingClassName,
      thisNodeName: node.name.name,
      typeParameters: node.typeParameters,
      formalParameters: node.parameters,
      returnType: node.returnType,
    );

    var implTokenSignature = _computeNodeTokenSignature(node.body);
    var impl = referenceCollector.collect(
      implTokenSignature,
      enclosingClassName: enclosingClassName,
      thisNodeName: node.name.name,
      formalParametersForImpl: node.parameters,
      functionBody: node.body,
    );

    var name = LibraryQualifiedName(uri, node.name.name);
    classMembers.add(
      Node(name, kind, api, impl, enclosingClass: enclosingClass!),
    );
  }

  void _addUnit(CompilationUnit unit) {
    for (var declaration in unit.declarations) {
      if (declaration is ClassOrMixinDeclaration) {
        _addClassOrMixin(declaration);
      } else if (declaration is ClassTypeAlias) {
        _addClassTypeAlias(declaration);
      } else if (declaration is EnumDeclaration) {
        _addEnum(declaration);
      } else if (declaration is FunctionDeclaration) {
        _addFunction(declaration);
      } else if (declaration is FunctionTypeAlias) {
        _addFunctionTypeAlias(declaration);
      } else if (declaration is GenericTypeAlias) {
        _addGenericTypeAlias(declaration);
      } else if (declaration is TopLevelVariableDeclaration) {
        _addVariables(
          declaredNodes,
          declaration.metadata,
          declaration.variables,
          false,
        );
      } else {
        throw UnimplementedError('(${declaration.runtimeType}) $declaration');
      }
    }
  }

  void _addVariables(List<Node> variableNodes, List<Annotation> metadata,
      VariableDeclarationList variables, bool appendInitializerToApi) {
    if (variables.isConst || variables.type == null) {
      appendInitializerToApi = true;
    }

    for (var variable in variables.variables) {
      var initializer = variable.initializer;

      var builder = _newApiSignatureBuilder();
      builder.addInt(variables.isConst ? 1 : 0); // const flag
      _appendMetadataTokens(builder, metadata);
      _appendNodeTokens(builder, variables.type);
      if (appendInitializerToApi) {
        _appendNodeTokens(builder, initializer);
      }

      var apiTokenSignature = builder.toByteList();
      var api = referenceCollector.collect(
        apiTokenSignature,
        enclosingClassName: enclosingClassName,
        thisNodeName: variable.name.name,
        type: variables.type,
        expression: appendInitializerToApi ? initializer : null,
      );

      var implTokenSignature = _computeNodeTokenSignature(initializer);
      var impl = referenceCollector.collect(
        implTokenSignature,
        enclosingClassName: enclosingClassName,
        thisNodeName: variable.name.name,
        expression: initializer,
      );

      var rawName = variable.name.name;
      variableNodes.add(Node(
        LibraryQualifiedName(uri, rawName),
        NodeKind.GETTER,
        api,
        impl,
        enclosingClass: enclosingClass,
      ));

      if (!variables.isConst && !variables.isFinal) {
        // Note that one set of dependencies is enough for body.
        // So, the setter has empty "impl" dependencies.
        variableNodes.add(
          Node(
            LibraryQualifiedName(uri, '$rawName='),
            NodeKind.SETTER,
            api,
            Dependencies.none,
            enclosingClass: enclosingClass,
          ),
        );
      }
    }
  }

  /// Return the signature for all tokens of the [node].
  List<int> _computeNodeTokenSignature(AstNode? node) {
    if (node == null) {
      return const <int>[];
    }
    return _computeTokenSignature(node.beginToken, node.endToken);
  }

  /// Return the signature for tokens from [begin] to [end] (both including).
  List<int> _computeTokenSignature(Token begin, Token end) {
    var signature = _newApiSignatureBuilder();
    _appendTokens(signature, begin, end);
    return signature.toByteList();
  }

  /// Return a new signature builder, primed with the current context salts.
  ApiSignature _newApiSignatureBuilder() {
    var builder = ApiSignature();
    builder.addBytes(uriSignature);
    if (enclosingClassNameSignature != null) {
      builder.addBytes(enclosingClassNameSignature!);
    }
    return builder;
  }

  /// Append tokens of the given [parameters] to the [signature].
  static void _appendFormalParametersTokens(
      ApiSignature signature, FormalParameterList? parameters) {
    if (parameters == null) return;

    for (var parameter in parameters.parameters) {
      if (parameter.isRequiredPositional) {
        signature.addInt(1);
      } else if (parameter.isRequiredNamed) {
        signature.addInt(4);
      } else if (parameter.isOptionalPositional) {
        signature.addInt(2);
      } else if (parameter.isOptionalNamed) {
        signature.addInt(3);
      }

      // If a simple not named parameter, we don't need its name.
      // We should be careful to include also annotations.
      if (parameter is SimpleFormalParameter && parameter.type != null) {
        _appendTokens(
          signature,
          parameter.beginToken,
          parameter.type!.endToken,
        );
        continue;
      }

      // We don't know anything better than adding the whole parameter.
      _appendNodeTokens(signature, parameter);
    }
  }

  static void _appendMetadataTokens(
      ApiSignature signature, List<Annotation> metadata) {
    for (var annotation in metadata) {
      _appendNodeTokens(signature, annotation);
    }
  }

  /// Append tokens of the given [node] to the [signature].
  static void _appendNodeTokens(ApiSignature signature, AstNode? node) {
    if (node != null) {
      _appendTokens(signature, node.beginToken, node.endToken);
    }
  }

  /// Append tokens from [begin] to [end] (both including) to the [signature].
  static void _appendTokens(ApiSignature signature, Token begin, Token end) {
    if (begin is CommentToken) {
      begin = begin.parent!;
    }

    Token? token = begin;
    while (token != null) {
      signature.addString(token.lexeme);

      if (token == end) {
        break;
      }

      var nextToken = token.next;
      if (nextToken == token) {
        break;
      }

      token = nextToken;
    }
  }

  /// Return [Combinator]s for the given import or export [directive].
  static List<Combinator> _getCombinators(NamespaceDirective directive) {
    var combinators = <Combinator>[];
    for (var combinator in directive.combinators) {
      if (combinator is ShowCombinator) {
        combinators.add(
          Combinator(
            true,
            combinator.shownNames.map((id) => id.name).toList(),
          ),
        );
      }
      if (combinator is HideCombinator) {
        combinators.add(
          Combinator(
            false,
            combinator.hiddenNames.map((id) => id.name).toList(),
          ),
        );
      }
    }
    return combinators;
  }
}
