// 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 'dart:math' as math;

import 'package:analysis_server/lsp_protocol/protocol_custom_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:analysis_server/lsp_protocol/protocol_special.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/domains/completion/available_suggestions.dart';
import 'package:analysis_server/src/lsp/client_capabilities.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/lsp_analysis_server.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
import 'package:analysis_server/src/services/completion/completion_performance.dart';
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/services/completion/filtering/fuzzy_matcher.dart';
import 'package:analysis_server/src/services/completion/yaml/analysis_options_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/fix_data_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/pubspec_generator.dart';
import 'package:analysis_server/src/services/completion/yaml/yaml_completion_generator.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart' as ast;
import 'package:analyzer/source/line_info.dart';
import 'package:analyzer/src/services/available_declarations.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer/src/util/performance/operation_performance.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';

class CompletionHandler
    extends MessageHandler<CompletionParams, List<CompletionItem>>
    with LspPluginRequestHandlerMixin {
  final bool suggestFromUnimportedLibraries;
  CompletionHandler(
      LspAnalysisServer server, this.suggestFromUnimportedLibraries)
      : super(server);

  @override
  Method get handlesMessage => Method.textDocument_completion;

  @override
  LspJsonHandler<CompletionParams> get jsonHandler =>
      CompletionParams.jsonHandler;

  @override
  Future<ErrorOr<List<CompletionItem>>> handle(
      CompletionParams params, CancellationToken token) async {
    final clientCapabilities = server.clientCapabilities;
    if (clientCapabilities == null) {
      // This should not happen unless a client misbehaves.
      return error(ErrorCodes.ServerNotInitialized,
          'Requests not before server is initilized');
    }

    final includeSuggestionSets =
        suggestFromUnimportedLibraries && clientCapabilities.applyEdit;

    final triggerCharacter = params.context?.triggerCharacter;
    final pos = params.position;
    final path = pathOfDoc(params.textDocument);
    final unit = await path.mapResult(requireResolvedUnit);

    final lineInfo = await unit.map(
      // If we don't have a unit, we can still try to obtain the line info for
      // plugin contributors.
      (error) => path.mapResult(getLineInfo),
      (unit) => success(unit.lineInfo),
    );
    final offset =
        await lineInfo.mapResult((lineInfo) => toOffset(lineInfo, pos));

    return offset.mapResult((offset) async {
      Future<ErrorOr<List<CompletionItem>>>? serverResultsFuture;
      final pathContext = server.resourceProvider.pathContext;
      final fileExtension = pathContext.extension(path.result);

      if (fileExtension == '.dart' && !unit.isError) {
        serverResultsFuture = _getServerDartItems(
          clientCapabilities,
          includeSuggestionSets,
          unit.result,
          offset,
          triggerCharacter,
          token,
        );
      } else if (fileExtension == '.yaml') {
        YamlCompletionGenerator? generator;
        if (file_paths.isAnalysisOptionsYaml(pathContext, path.result)) {
          generator = AnalysisOptionsGenerator(server.resourceProvider);
        } else if (file_paths.isFixDataYaml(pathContext, path.result)) {
          generator = FixDataGenerator(server.resourceProvider);
        } else if (file_paths.isPubspecYaml(pathContext, path.result)) {
          generator = PubspecGenerator(
              server.resourceProvider, server.pubPackageService);
        }
        if (generator != null) {
          serverResultsFuture = _getServerYamlItems(
            generator,
            clientCapabilities,
            path.result,
            lineInfo.result,
            offset,
            token,
          );
        }
      }

      serverResultsFuture ??= Future.value(success(const <CompletionItem>[]));

      final pluginResultsFuture = _getPluginResults(
          clientCapabilities, lineInfo.result, path.result, offset);

      // Await both server + plugin results together to allow async/IO to
      // overlap.
      final serverAndPluginResults =
          await Future.wait([serverResultsFuture, pluginResultsFuture]);
      final serverResults = serverAndPluginResults[0];
      final pluginResults = serverAndPluginResults[1];

      if (serverResults.isError) return serverResults;
      if (pluginResults.isError) return pluginResults;

      return success(
        serverResults.result.followedBy(pluginResults.result).toList(),
      );
    });
  }

  /// Build a list of existing imports so we can filter out any suggestions
  /// that resolve to the same underlying declared symbol.
  /// Map with key "elementName/elementDeclaringLibraryUri"
  /// Value is a set of imported URIs that import that element.
  Map<String, Set<String>> _buildLookupOfImportedSymbols(
      ResolvedUnitResult unit) {
    final alreadyImportedSymbols = <String, Set<String>>{};
    final importElementList = unit.libraryElement.imports;
    for (var import in importElementList) {
      final importedLibrary = import.importedLibrary;
      if (importedLibrary == null) continue;

      for (var element in import.namespace.definedNames.values) {
        final librarySource = element.librarySource;
        final elementName = element.name;
        if (librarySource != null && elementName != null) {
          final declaringLibraryUri = librarySource.uri;

          final key =
              _createImportedSymbolKey(elementName, declaringLibraryUri);
          alreadyImportedSymbols
              .putIfAbsent(key, () => <String>{})
              .add('${importedLibrary.librarySource.uri}');
        }
      }
    }
    return alreadyImportedSymbols;
  }

  /// The insert length is the shorter of the replacementLength or the
  /// difference between the replacementOffset and the caret position.
  int _computeInsertLength(
      int offset, int replacementOffset, int replacementLength) {
    final insertLength =
        math.min(offset - replacementOffset, replacementLength);
    assert(insertLength >= 0);
    assert(insertLength <= replacementLength);
    return insertLength;
  }

  String _createImportedSymbolKey(String name, Uri declaringUri) =>
      '$name/$declaringUri';

  Future<ErrorOr<List<CompletionItem>>> _getPluginResults(
    LspClientCapabilities capabilities,
    LineInfo lineInfo,
    String path,
    int offset,
  ) async {
    final requestParams = plugin.CompletionGetSuggestionsParams(path, offset);
    final pluginResponses = await requestFromPlugins(path, requestParams,
        timeout: const Duration(milliseconds: 100));

    final pluginResults = pluginResponses
        .map((e) => plugin.CompletionGetSuggestionsResult.fromResponse(e))
        .toList();

    return success(_pluginResultsToItems(
      capabilities,
      lineInfo,
      offset,
      pluginResults,
    ).toList());
  }

  Future<ErrorOr<List<CompletionItem>>> _getServerDartItems(
    LspClientCapabilities capabilities,
    bool includeSuggestionSets,
    ResolvedUnitResult unit,
    int offset,
    String? triggerCharacter,
    CancellationToken token,
  ) async {
    var performance = OperationPerformanceImpl('<root>');
    return await performance.runAsync(
      'request',
      (performance) async {
        final completionPerformance = CompletionPerformance(
          operation: performance,
          path: unit.path,
          content: unit.content,
          offset: offset,
        );
        server.performanceStats.completion.add(completionPerformance);

        final completionRequest = DartCompletionRequest.forResolvedUnit(
          resolvedUnit: unit,
          offset: offset,
          dartdocDirectiveInfo: server.getDartdocDirectiveInfoFor(unit),
          completionPreference: CompletionPreference.replace,
        );
        final target = completionRequest.target;

        if (triggerCharacter != null) {
          if (!_triggerCharacterValid(offset, triggerCharacter, target)) {
            return success([]);
          }
        }

        Set<ElementKind>? includedElementKinds;
        Set<String>? includedElementNames;
        List<IncludedSuggestionRelevanceTag>? includedSuggestionRelevanceTags;
        if (includeSuggestionSets) {
          includedElementKinds = <ElementKind>{};
          includedElementNames = <String>{};
          includedSuggestionRelevanceTags = <IncludedSuggestionRelevanceTag>[];
        }

        try {
          var contributor = DartCompletionManager(
            budget: CompletionBudget(CompletionBudget.defaultDuration),
            includedElementKinds: includedElementKinds,
            includedElementNames: includedElementNames,
            includedSuggestionRelevanceTags: includedSuggestionRelevanceTags,
          );

          final serverSuggestions = await contributor.computeSuggestions(
            completionRequest,
            performance,
          );

          final insertLength = _computeInsertLength(
            offset,
            completionRequest.replacementOffset,
            completionRequest.replacementLength,
          );

          if (token.isCancellationRequested) {
            return cancelled();
          }

          /// completeFunctionCalls should be suppressed if the target is an
          /// invocation that already has an argument list, otherwise we would
          /// insert dupes.
          final completeFunctionCalls = _hasExistingArgList(target.entity)
              ? false
              : server.clientConfiguration.global.completeFunctionCalls;

          final results = serverSuggestions.map(
            (item) {
              var itemReplacementOffset =
                  item.replacementOffset ?? completionRequest.replacementOffset;
              var itemReplacementLength =
                  item.replacementLength ?? completionRequest.replacementLength;
              var itemInsertLength = insertLength;

              // Recompute the insert length if it may be affected by the above.
              if (item.replacementOffset != null ||
                  item.replacementLength != null) {
                itemInsertLength = _computeInsertLength(
                    offset, itemReplacementOffset, itemInsertLength);
              }

              return toCompletionItem(
                capabilities,
                unit.lineInfo,
                item,
                itemReplacementOffset,
                itemInsertLength,
                itemReplacementLength,
                // TODO(dantup): Including commit characters in every completion
                // increases the payload size. The LSP spec is ambigious
                // about how this should be handled (and VS Code requires it) but
                // this should be removed (or made conditional based on a capability)
                // depending on how the spec is updated.
                // https://github.com/microsoft/vscode-languageserver-node/issues/673
                includeCommitCharacters:
                    server.clientConfiguration.global.previewCommitCharacters,
                completeFunctionCalls: completeFunctionCalls,
              );
            },
          ).toList();

          // Now compute items in suggestion sets.
          var includedSuggestionSets = <IncludedSuggestionSet>[];
          final declarationsTracker = server.declarationsTracker;
          if (declarationsTracker != null &&
              includedElementKinds != null &&
              includedElementNames != null &&
              includedSuggestionRelevanceTags != null) {
            computeIncludedSetList(
              declarationsTracker,
              completionRequest,
              includedSuggestionSets,
              includedElementNames,
            );

            // Build a fast lookup for imported symbols so that we can filter out
            // duplicates.
            final alreadyImportedSymbols = _buildLookupOfImportedSymbols(unit);

            includedSuggestionSets.forEach((includedSet) {
              final library = declarationsTracker.getLibrary(includedSet.id);
              if (library == null) {
                return;
              }

              // Make a fast lookup for tag relevance.
              final tagBoosts = <String, int>{};
              includedSuggestionRelevanceTags!
                  .forEach((t) => tagBoosts[t.tag] = t.relevanceBoost);

              // Only specific types of child declarations should be included.
              // This list matches what's in _protocolAvailableSuggestion in
              // the DAS implementation.
              bool shouldIncludeChild(Declaration child) =>
                  child.kind == DeclarationKind.CONSTRUCTOR ||
                  child.kind == DeclarationKind.ENUM_CONSTANT ||
                  (child.kind == DeclarationKind.GETTER && child.isStatic) ||
                  (child.kind == DeclarationKind.FIELD && child.isStatic);

              // Collect declarations and their children.
              final allDeclarations = library.declarations
                  .followedBy(library.declarations.expand(
                      (decl) => decl.children.where(shouldIncludeChild)))
                  .toList();

              final setResults = allDeclarations
                  // Filter to only the kinds we should return.
                  .where((item) => includedElementKinds!
                      .contains(protocolElementKind(item.kind)))
                  .where((item) {
                // Check existing imports to ensure we don't already import
                // this element (this exact element from its declaring
                // library, not just something with the same name). If we do
                // we'll want to skip it.
                final declaringUri =
                    item.parent?.locationLibraryUri ?? item.locationLibraryUri!;

                // For enums and named constructors, only the parent enum/class is in
                // the list of imported symbols so we use the parents name.
                final nameKey = item.kind == DeclarationKind.ENUM_CONSTANT ||
                        item.kind == DeclarationKind.CONSTRUCTOR
                    ? item.parent!.name
                    : item.name;
                final key = _createImportedSymbolKey(nameKey, declaringUri);
                final importingUris = alreadyImportedSymbols[key];

                // Keep it only if:
                // - no existing imports include it
                //     (in which case all libraries will be offered as
                //     auto-imports)
                // - this is the first imported URI that includes it
                //     (we don't want to repeat it for each imported library that
                //     includes it)
                return importingUris == null ||
                    importingUris.first == '${library.uri}';
              }).map((item) => declarationToCompletionItem(
                        capabilities,
                        unit.path,
                        offset,
                        includedSet,
                        library,
                        tagBoosts,
                        unit.lineInfo,
                        item,
                        completionRequest.replacementOffset,
                        insertLength,
                        completionRequest.replacementLength,
                        // TODO(dantup): Including commit characters in every completion
                        // increases the payload size. The LSP spec is ambigious
                        // about how this should be handled (and VS Code requires it) but
                        // this should be removed (or made conditional based on a capability)
                        // depending on how the spec is updated.
                        // https://github.com/microsoft/vscode-languageserver-node/issues/673
                        includeCommitCharacters: server
                            .clientConfiguration.global.previewCommitCharacters,
                        completeFunctionCalls: completeFunctionCalls,
                      ));
              results.addAll(setResults);
            });
          }

          // Perform fuzzy matching based on the identifier in front of the caret to
          // reduce the size of the payload.
          final fuzzyPattern = completionRequest.targetPrefix;
          final fuzzyMatcher =
              FuzzyMatcher(fuzzyPattern, matchStyle: MatchStyle.TEXT);

          final matchingResults =
              results.where((e) => fuzzyMatcher.score(e.label) > 0).toList();

          completionPerformance.suggestionCount = results.length;

          return success(matchingResults);
        } on AbortCompletion {
          return success([]);
        }
      },
    );
  }

  Future<ErrorOr<List<CompletionItem>>> _getServerYamlItems(
    YamlCompletionGenerator generator,
    LspClientCapabilities capabilities,
    String path,
    LineInfo lineInfo,
    int offset,
    CancellationToken token,
  ) async {
    final suggestions = generator.getSuggestions(path, offset);
    final insertLength = _computeInsertLength(
      offset,
      suggestions.replacementOffset,
      suggestions.replacementLength,
    );
    final completionItems = suggestions.suggestions
        .map(
          (item) => toCompletionItem(
            capabilities,
            lineInfo,
            item,
            suggestions.replacementOffset,
            insertLength,
            suggestions.replacementLength,
            includeCommitCharacters: false,
            completeFunctionCalls: false,
            // Add on any completion-kind-specific resolution data that will be
            // used during resolve() calls to provide additional information.
            resolutionData: item.kind == CompletionSuggestionKind.PACKAGE_NAME
                ? PubPackageCompletionItemResolutionInfo(
                    file: path,
                    offset: offset,
                    // The completion for package names may contain a trailing
                    // ': ' for convenience, so if it's there, trim it off.
                    packageName: item.completion.split(':').first,
                  )
                : null,
          ),
        )
        .toList();
    return success(completionItems);
  }

  /// Returns true if [node] is part of an invocation and already has an argument
  /// list.
  bool _hasExistingArgList(Object? node) {
    // print^('foo');
    if (node is ast.ExpressionStatement) {
      node = node.expression;
    }
    // super.foo^();
    if (node is ast.SimpleIdentifier) {
      node = node.parent;
    }
    // new Aaaa.bar^()
    if (node is ast.ConstructorName) {
      node = node.parent;
    }
    return (node is ast.InvocationExpression &&
            !node.argumentList.beginToken.isSynthetic) ||
        (node is ast.InstanceCreationExpression &&
            !node.argumentList.beginToken.isSynthetic) ||
        // "ClassName.^()" will appear as accessing a property named '('.
        (node is ast.PropertyAccess && node.propertyName.name.startsWith('('));
  }

  Iterable<CompletionItem> _pluginResultsToItems(
    LspClientCapabilities capabilities,
    LineInfo lineInfo,
    int offset,
    List<plugin.CompletionGetSuggestionsResult> pluginResults,
  ) {
    return pluginResults.expand((result) {
      return result.results.map(
        (item) => toCompletionItem(
          capabilities,
          lineInfo,
          item,
          result.replacementOffset,
          _computeInsertLength(
            offset,
            result.replacementOffset,
            result.replacementLength,
          ),
          result.replacementLength,
          // Plugins cannot currently contribute commit characters and we should
          // not assume that the Dart ones would be correct for all of their
          // completions.
          includeCommitCharacters: false,
          completeFunctionCalls: false,
        ),
      );
    });
  }

  /// Checks whether the given [triggerCharacter] is valid for [target].
  ///
  /// Some trigger characters are only valid in certain locations, for example
  /// a single quote ' is valid to trigger completion after typing an import
  /// statement, but not when terminating a string. The client has no context
  /// and sends the requests unconditionally.
  bool _triggerCharacterValid(
      int offset, String triggerCharacter, CompletionTarget target) {
    final node = target.containingNode;

    switch (triggerCharacter) {
      // For quotes, it's only valid if we're right after the opening quote of a
      // directive.
      case '"':
      case "'":
        return node is ast.SimpleStringLiteral &&
            node.parent is ast.Directive &&
            offset == node.contentsOffset;
      // Braces only for starting interpolated expressions.
      case '{':
        return node is ast.InterpolationExpression &&
            node.expression.offset == offset;
      // Slashes only as path separators in directives.
      case '/':
        return node is ast.SimpleStringLiteral &&
            node.parent is ast.Directive &&
            offset >= node.contentsOffset &&
            offset <= node.contentsEnd;
    }

    return true; // Any other trigger character can be handled always.
  }
}
