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

import 'package:analysis_server/lsp_protocol/protocol.dart';
import 'package:analysis_server/src/computer/computer_highlights.dart';
import 'package:analysis_server/src/lsp/handlers/handlers.dart';
import 'package:analysis_server/src/lsp/mapping.dart';
import 'package:analysis_server/src/lsp/semantic_tokens/encoder.dart';
import 'package:analyzer/source/source_range.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';

abstract class AbstractSemanticTokensHandler<T>
    extends MessageHandler<T, SemanticTokens?>
    with LspPluginRequestHandlerMixin {
  AbstractSemanticTokensHandler(super.server);

  List<List<HighlightRegion>> getPluginResults(String path) {
    final notificationManager = server.notificationManager;
    return notificationManager.highlights.getResults(path);
  }

  Future<List<SemanticTokenInfo>> getServerResult(
      String path, SourceRange? range) async {
    final result = await server.getResolvedUnit(path);
    final unit = result?.unit;
    if (unit != null) {
      final computer = DartUnitHighlightsComputer(unit, range: range);
      return computer.computeSemanticTokens();
    }
    return [];
  }

  Iterable<SemanticTokenInfo> _filter(
      Iterable<SemanticTokenInfo> tokens, SourceRange? range) {
    if (range == null) {
      return tokens;
    }

    return tokens.where((token) =>
        !(token.offset + token.length < range.offset ||
            token.offset > range.end));
  }

  Future<ErrorOr<SemanticTokens?>> _handleImpl(
      TextDocumentIdentifier textDocument, CancellationToken token,
      {Range? range}) async {
    final path = pathOfDoc(textDocument);

    return path.mapResult((path) async {
      final lineInfo = server.getLineInfo(path);
      // If there is no lineInfo, the request cannot be translated from LSP
      // line/col to server offset/length.
      if (lineInfo == null) {
        return success(null);
      }

      return toSourceRangeNullable(lineInfo, range).mapResult((range) async {
        final serverTokens = await getServerResult(path, range);
        final pluginHighlightRegions =
            getPluginResults(path).expand((results) => results).toList();

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

        final encoder = SemanticTokenEncoder();
        Iterable<SemanticTokenInfo> pluginTokens =
            encoder.convertHighlightToTokens(pluginHighlightRegions);

        // Plugin tokens are not filtered at source, so need to be filtered here.
        pluginTokens = _filter(pluginTokens, range);

        Iterable<SemanticTokenInfo> tokens = [...serverTokens, ...pluginTokens];

        // Capabilities exist for supporting multiline/overlapping tokens. These
        // could be used if any clients take it up (VS Code does not).
        // - clientCapabilities?.multilineTokenSupport
        // - clientCapabilities?.overlappingTokenSupport
        final allowMultilineTokens = false;
        final allowOverlappingTokens = false;

        // Some of the translation operations and the final encoding require
        // the tokens to be sorted. Do it once here to avoid each method needing
        // to do it itself (resulting in multiple sorts).
        tokens = tokens.toList()
          ..sort(SemanticTokenInfo.offsetLengthPrioritySort);

        if (!allowOverlappingTokens) {
          tokens = encoder.splitOverlappingTokens(tokens);
        }

        if (!allowMultilineTokens) {
          tokens = tokens
              .expand((token) => encoder.splitMultilineTokens(token, lineInfo));

          // Tokens may need re-filtering after being split up as there may
          // now be tokens outside of the range.
          tokens = _filter(tokens, range);
        }

        final semanticTokens = encoder.encodeTokens(tokens.toList(), lineInfo);

        return success(semanticTokens);
      });
    });
  }
}

class SemanticTokensFullHandler
    extends AbstractSemanticTokensHandler<SemanticTokensParams> {
  SemanticTokensFullHandler(super.server);

  @override
  Method get handlesMessage => Method.textDocument_semanticTokens_full;

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

  @override
  Future<ErrorOr<SemanticTokens?>> handle(SemanticTokensParams params,
          MessageInfo message, CancellationToken token) =>
      _handleImpl(params.textDocument, token);
}

class SemanticTokensRangeHandler
    extends AbstractSemanticTokensHandler<SemanticTokensRangeParams> {
  SemanticTokensRangeHandler(super.server);

  @override
  Method get handlesMessage => Method.textDocument_semanticTokens_range;

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

  @override
  Future<ErrorOr<SemanticTokens?>> handle(SemanticTokensRangeParams params,
          MessageInfo message, CancellationToken token) =>
      _handleImpl(params.textDocument, token, range: params.range);
}
