// Copyright (c) 2019, 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 'dart:typed_data';

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/invokes_super_self.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/summary/api_signature.dart';
import 'package:collection/collection.dart';

/// Return the bytes of the unlinked API signature of the given [unit].
///
/// If API signatures of two units are different, they may have different APIs.
Uint8List computeUnlinkedApiSignature(CompilationUnit unit) {
  var computer = _UnitApiSignatureComputer();
  computer.compute(unit);
  return computer.signature.toByteList();
}

class _UnitApiSignatureComputer {
  static const int _kindConstructorDeclaration = 1;
  static const int _kindFieldDeclaration = 2;
  static const int _kindMethodDeclaration = 3;
  static const int _nullNode = 0;
  static const int _notNullNode = 1;
  static const int _nullToken = 0;
  static const int _notNullToken = 1;

  final ApiSignature signature = ApiSignature();

  void compute(CompilationUnit unit) {
    signature.addFeatureSet(unit.featureSet);

    signature.addInt(unit.directives.length);
    unit.directives.forEach(_addNode);

    signature.addInt(unit.declarations.length);
    for (var declaration in unit.declarations) {
      if (declaration is ClassOrMixinDeclaration) {
        _addClassOrMixin(declaration);
      } else if (declaration is EnumDeclaration) {
        _addEnum(declaration);
      } else if (declaration is ExtensionDeclaration) {
        _addExtension(declaration);
      } else if (declaration is FunctionDeclaration) {
        var functionExpression = declaration.functionExpression;
        _addTokens(
          declaration.beginToken,
          (functionExpression.parameters ?? declaration.name).endToken,
        );
        _addFunctionBodyModifiers(functionExpression.body);
      } else if (declaration is TopLevelVariableDeclaration) {
        _topLevelVariableDeclaration(declaration);
      } else {
        _addNode(declaration);
      }
    }
  }

  void _addClassMembers(List<ClassMember> members, bool hasConstConstructor) {
    signature.addInt(members.length);
    for (var member in members) {
      if (member is ConstructorDeclaration) {
        _addConstructorDeclaration(member);
      } else if (member is FieldDeclaration) {
        _addFieldDeclaration(member, hasConstConstructor);
      } else if (member is MethodDeclaration) {
        _addMethodDeclaration(member);
      } else {
        throw UnimplementedError('(${member.runtimeType}) $member');
      }
    }
  }

  void _addClassOrMixin(ClassOrMixinDeclaration node) {
    _addTokens(node.beginToken, node.leftBracket);

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

    _addClassMembers(node.members, hasConstConstructor);
  }

  void _addConstructorDeclaration(ConstructorDeclaration node) {
    signature.addInt(_kindConstructorDeclaration);
    _addTokens(node.beginToken, node.parameters.endToken);
    _addNodeList(node.initializers);
    _addNode(node.redirectedConstructor);
  }

  void _addEnum(EnumDeclaration node) {
    var members = node.members;

    // If not enhanced, include the whole node.
    var firstMember = members.firstOrNull;
    if (firstMember == null) {
      _addNode(node);
      return;
    }

    _addTokens(node.beginToken, firstMember.beginToken);
    _addClassMembers(members, true);
  }

  void _addExtension(ExtensionDeclaration node) {
    _addTokens(node.beginToken, node.leftBracket);
    _addClassMembers(node.members, false);
  }

  void _addFieldDeclaration(FieldDeclaration node, bool hasConstConstructor) {
    signature.addInt(_kindFieldDeclaration);

    _addToken(node.abstractKeyword);
    _addToken(node.covariantKeyword);
    _addToken(node.externalKeyword);
    _addToken(node.staticKeyword);
    _addNodeList(node.metadata);

    var variableList = node.fields;
    var includeInitializers = variableList.type == null ||
        variableList.isConst ||
        hasConstConstructor && !node.isStatic && variableList.isFinal;
    _variableList(variableList, includeInitializers);
  }

  void _addFunctionBodyModifiers(FunctionBody? node) {
    if (node != null) {
      signature.addBool(node.isSynchronous);
      signature.addBool(node.isGenerator);
      signature.addBool(node is NativeFunctionBody);
    }
  }

  void _addMethodDeclaration(MethodDeclaration node) {
    signature.addInt(_kindMethodDeclaration);
    _addTokens(
      node.beginToken,
      (node.parameters ?? node.name).endToken,
    );
    signature.addBool(node.body is EmptyFunctionBody);
    _addFunctionBodyModifiers(node.body);
    signature.addBool(node.invokesSuperSelf);
  }

  void _addNode(AstNode? node) {
    if (node != null) {
      signature.addInt(_notNullNode);
      _addTokens(node.beginToken, node.endToken);
    } else {
      signature.addInt(_nullNode);
    }
  }

  void _addNodeList(List<AstNode> nodes) {
    for (var node in nodes) {
      _addNode(node);
    }
  }

  void _addToken(Token? token) {
    if (token != null) {
      signature.addInt(_notNullToken);
      signature.addString(token.lexeme);
    } else {
      signature.addInt(_nullToken);
    }
  }

  /// Appends tokens from [begin] (including), to [end] (also including).
  void _addTokens(Token begin, Token end) {
    if (begin is CommentToken) {
      begin = begin.parent!;
    }

    Token? token = begin;
    while (token != null) {
      _addToken(token);

      if (token == end) {
        break;
      }

      var nextToken = token.next;

      // Stop if EOF.
      if (nextToken == token) {
        break;
      }

      token = nextToken;
    }
  }

  void _topLevelVariableDeclaration(TopLevelVariableDeclaration node) {
    _addToken(node.externalKeyword);
    _addNodeList(node.metadata);

    var variableList = node.variables;
    var includeInitializers = variableList.type == null || variableList.isConst;
    _variableList(variableList, includeInitializers);
  }

  void _variableList(VariableDeclarationList node, bool includeInitializers) {
    _addToken(node.keyword);
    _addToken(node.lateKeyword);
    _addNode(node.type);

    var variables = node.variables;
    signature.addInt(variables.length);

    for (var variable in variables) {
      _addNode(variable.name);
      signature.addBool(variable.initializer != null);
      if (includeInitializers) {
        _addNode(variable.initializer);
      }
    }
  }
}
