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

import 'package:analysis_server/lsp_protocol/protocol.dart' as lsp;
import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart'
    hide MessageType;
import 'package:analysis_server/src/analysis_server.dart' show MessageType;
import 'package:analysis_server/src/services/user_prompts/dart_fix_prompt_manager.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import 'analysis_server_base.dart';
import 'constants.dart';
import 'mocks.dart';

void main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(ServerDomainTest);
    defineReflectiveTests(ServerDartFixPromptTest);
  });
}

/// Checks server interacts with [DartFixPromptManager] correctly.
///
/// Tests for [DartFixPromptManager]'s behaviour are in
/// test/services/user_prompts/dart_fix_prompt_manager_test.dart.
@reflectiveTest
class ServerDartFixPromptTest extends PubPackageAnalysisServerTest {
  late TestDartFixPromptManager promptManager;

  @override
  DartFixPromptManager? get dartFixPromptManager => promptManager;

  @override
  void setUp() {
    promptManager = TestDartFixPromptManager();
    super.setUp();
  }

  Future<void> test_trigger_afterInitialAnalysis() async {
    await setRoots(included: [workspaceRootPath], excluded: []);
    await pumpEventQueue(times: 5000);
    expect(promptManager.checksTriggered, 1);
  }

  Future<void> test_trigger_afterPackageConfigChange() async {
    // Ensure there's a file to analyze otherwise writing the package_config
    // won't trigger any additional analysis.
    newFile('$testPackageLibPath/test.dart', 'void f() {}');

    // Set up and let initial analysis complete.
    await setRoots(included: [workspaceRootPath], excluded: []);
    await pumpEventQueue(times: 5000);
    expect(promptManager.checksTriggered, 1);

    // Expect that writing package config attempts to trigger another check.
    writeTestPackageConfig();
    await pumpEventQueue(times: 5000);
    expect(promptManager.checksTriggered, 2);
  }
}

@reflectiveTest
class ServerDomainTest extends PubPackageAnalysisServerTest {
  Future<void> test_getVersion() async {
    var request = ServerGetVersionParams().toRequest(
      '0',
      clientUriConverter: server.uriConverter,
    );
    var response = await handleSuccessfulRequest(request);
    expect(
      response.toJson(),
      equals({
        Response.ID: '0',
        Response.RESULT: {VERSION: PROTOCOL_VERSION},
      }),
    );
  }

  Future<void> test_openUrl() async {
    server.clientCapabilities.requests = ['openUrlRequest'];

    // Send the request.
    var uri = toUri('https://dart.dev');
    var responseFuture = server.openUriNotificationSender!.call(uri);
    expect(serverChannel.serverRequestsSent, hasLength(1));

    // Simulate the response.
    var request = serverChannel.serverRequestsSent[0];
    serverChannel.simulateResponseFromClient(
      ServerOpenUrlRequestResult().toResponse(
        request.id,
        clientUriConverter: server.uriConverter,
      ),
    );
    await responseFuture;
  }

  Future<void> test_setClientCapabilities_lspCapabilities() async {
    // Test an arbitrary set of capabilities.
    var capabilities = lsp.ClientCapabilities(
      textDocument: lsp.TextDocumentClientCapabilities(
        hover: lsp.HoverClientCapabilities(
          contentFormat: [lsp.MarkupKind.PlainText],
        ),
      ),
      workspace: lsp.WorkspaceClientCapabilities(
        applyEdit: true,
        workspaceEdit: lsp.WorkspaceEditClientCapabilities(
          documentChanges: true,
          resourceOperations: [lsp.ResourceOperationKind.Create],
        ),
      ),
    );

    var request = ServerSetClientCapabilitiesParams(
      [],
      lspCapabilities: capabilities.toJson(),
    ).toRequest('1', clientUriConverter: server.uriConverter);

    await handleSuccessfulRequest(request);
    var effectiveCapabilities = server.editorClientCapabilities;
    expect(
      effectiveCapabilities.hoverContentFormats,
      equals([lsp.MarkupKind.PlainText]),
    );
    expect(effectiveCapabilities.applyEdit, isTrue);
    expect(effectiveCapabilities.documentChanges, isTrue);
    expect(effectiveCapabilities.createResourceOperations, isTrue);
  }

  Future<void> test_setClientCapabilities_lspCapabilities_invalid() async {
    var request = ServerSetClientCapabilitiesParams(
      [],
      lspCapabilities: {
        'textDocument': 1, // Not valid
      },
    ).toRequest('1', clientUriConverter: server.uriConverter);

    var response = await handleRequest(request);
    expect(
      response,
      isResponseFailure('1', RequestErrorCode.INVALID_PARAMETER),
    );
    expect(
      response.error!.message,
      "The 'lspCapabilities' parameter was invalid:"
      ' textDocument must be of type TextDocumentClientCapabilities',
    );
  }

  Future<void> test_setClientCapabilities_requests() async {
    var requestId = -1;

    Future<void> setCapabilities({
      required bool openUrlRequest,
      required bool showMessageRequest,
    }) async {
      var requests = [
        if (openUrlRequest) 'openUrlRequest',
        if (showMessageRequest) 'showMessageRequest',
      ];
      if (requestId >= 0) {
        // This is a bit of a kludge, but the first time this function is called
        // we won't set the request, we'll just test the default state.
        var request = ServerSetClientCapabilitiesParams(requests).toRequest(
          requestId.toString(),
          clientUriConverter: server.uriConverter,
        );
        await handleSuccessfulRequest(request);
      }
      requestId++;

      expect(server.clientCapabilities.requests, requests);
      expect(
        server.openUriNotificationSender,
        openUrlRequest ? isNotNull : isNull,
      );
      expect(server.userPromptSender, showMessageRequest ? isNotNull : isNull);
    }

    await setCapabilities(openUrlRequest: false, showMessageRequest: false);
    await setCapabilities(openUrlRequest: true, showMessageRequest: false);
    await setCapabilities(openUrlRequest: true, showMessageRequest: true);
    await setCapabilities(openUrlRequest: false, showMessageRequest: true);
    await setCapabilities(openUrlRequest: false, showMessageRequest: false);
  }

  /// Verify that the server handles URIs once we've enabled the supportsUris
  /// client capability.
  Future<void>
  test_setClientCapabilities_supportsUris_clientToServer_request() async {
    // Tell the server we support URIs.
    await handleSuccessfulRequest(
      ServerSetClientCapabilitiesParams(
        [],
        supportsUris: true,
      ).toRequest('-1', clientUriConverter: server.uriConverter),
    );

    // Set the roots using a URI. Since the helper methods will to through
    // toJson() (which will convert paths to URIs) we need to pass the JSON
    // manually here.
    await handleSuccessfulRequest(
      Request('1', 'analysis.setAnalysisRoots', {
        'included': [toUri(workspaceRootPath).toString()],
        'excluded': [],
      }),
    );
    await pumpEventQueue(times: 5000);

    // Ensure the roots were recorded correctly.
    expect(server.contextManager.includedPaths, [
      convertPath(workspaceRootPath),
    ]);
  }

  Future<void> test_setClientCapabilities_supportsUris_defaults() async {
    // Before request.
    expect(server.clientCapabilities.supportsUris, isNull);
    expect(server.uriConverter.supportedNonFileSchemes, isEmpty);

    // If not supplied.
    await handleSuccessfulRequest(
      ServerSetClientCapabilitiesParams(
        [],
      ).toRequest('-1', clientUriConverter: server.uriConverter),
    );
    expect(server.clientCapabilities.supportsUris, isNull);
    expect(server.uriConverter.supportedNonFileSchemes, isEmpty);

    // If set explicitly to false.
    await handleSuccessfulRequest(
      ServerSetClientCapabilitiesParams(
        [],
        supportsUris: false,
      ).toRequest('-1', clientUriConverter: server.uriConverter),
    );
    expect(server.clientCapabilities.supportsUris, isFalse);
    expect(server.uriConverter.supportedNonFileSchemes, isEmpty);
  }

  Future<void>
  test_setClientCapabilities_supportsUris_false_rejectsUris() async {
    // Explicitly tell the server we do not support URIs.
    await handleSuccessfulRequest(
      ServerSetClientCapabilitiesParams(
        [],
        supportsUris: false,
      ).toRequest('-1', clientUriConverter: server.uriConverter),
    );

    // Try to send a URI anyway.
    var request = Request('1', 'analysis.setAnalysisRoots', {
      'included': [toUri(workspaceRootPath).toString()],
      'excluded': [],
    });
    var response = await handleRequest(request);
    expect(
      response,
      isResponseFailure(request.id, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
    );
  }

  /// Verify that the server uses URIs in notifications once we've enabled the
  /// supportsUris client capability.
  Future<void>
  test_setClientCapabilities_supportsUris_serverToClient_notification() async {
    // Add a file with an error for testing.
    var testFilePath = convertPath('$testPackageLibPath/test.dart');
    var testFileUriString = toUri(testFilePath).toString();
    newFile(testFilePath, 'broken');

    // Tell the server we support URIs before analysis starts since we will
    // verify the analysis.errors notification.
    await handleSuccessfulRequest(
      ServerSetClientCapabilitiesParams(
        [],
        supportsUris: true,
      ).toRequest('10', clientUriConverter: server.uriConverter),
    );
    await pumpEventQueue(times: 5000);

    // Trigger analysis.
    await setRoots(
      // We can use paths here because toJson() will handle the conversion.
      included: [workspaceRootPath],
      excluded: [],
    );
    await pumpEventQueue(times: 5000);

    // Verify the last error for this file was using a URI.
    var lastErrorFile = serverChannel.notificationsReceived
        .where((notification) => notification.event == 'analysis.errors')
        .map((notification) => notification.params!['file'] as String)
        .lastWhere((filePath) => filePath.endsWith('test.dart'));
    expect(lastErrorFile, testFileUriString);
  }

  /// Verify that the server returns URIs once we've enabled the supportsUris
  /// client capability.
  Future<void>
  test_setClientCapabilities_supportsUris_serverToClient_response() async {
    // Add a file with an error for testing.
    var testFilePath = convertPath('$testPackageLibPath/test.dart');
    var testFileUriString = toUri(testFilePath).toString();
    newFile(testFilePath, 'broken');

    await setRoots(included: [workspaceRootPath], excluded: []);
    await pumpEventQueue(times: 5000);

    // Tell the server we support URIs.
    await handleSuccessfulRequest(
      ServerSetClientCapabilitiesParams(
        [],
        supportsUris: true,
      ).toRequest('10', clientUriConverter: server.uriConverter),
    );
    await pumpEventQueue(times: 5000);

    // Send a GetErrors request. The response has nested FilePaths inside the
    // AnalysisErrors so will confirm the server mapped correctly.
    var response = await handleSuccessfulRequest(
      Request('1', 'analysis.getErrors', {'file': testFileUriString}),
    );
    // Verify the error location was the expected URI.
    expect(
      (response.result as dynamic)['errors'][0]!['location']['file'],
      testFileUriString,
    );
  }

  Future<void>
  test_setClientCapabilities_supportsUris_unspecified_rejectsUris() async {
    // Do not tell the server we support URIs.

    // Try to send a URI anyway.
    var request = Request('1', 'analysis.setAnalysisRoots', {
      'included': [toUri(workspaceRootPath).toString()],
      'excluded': [],
    });
    var response = await handleRequest(request);
    expect(
      response,
      isResponseFailure(request.id, RequestErrorCode.INVALID_FILE_PATH_FORMAT),
    );
  }

  Future<void> test_setSubscriptions_invalidServiceName() async {
    var request = Request('0', SERVER_REQUEST_SET_SUBSCRIPTIONS, {
      SUBSCRIPTIONS: ['noSuchService'],
    });
    var response = await handleRequest(request);
    expect(response, isResponseFailure('0'));
  }

  Future<void> test_setSubscriptions_success() async {
    expect(server.serverServices, isEmpty);
    // send request
    var request = ServerSetSubscriptionsParams([
      ServerService.STATUS,
    ]).toRequest('0', clientUriConverter: server.uriConverter);
    await handleSuccessfulRequest(request);
    // set of services has been changed
    expect(server.serverServices, contains(ServerService.STATUS));
  }

  Future<void> test_showMessage() async {
    server.clientCapabilities.requests = ['showMessageRequest'];

    // Send the request.
    var responseFuture = server.userPromptSender!(
      MessageType.warning,
      'message',
      ['a', 'b'],
    );
    expect(serverChannel.serverRequestsSent, hasLength(1));

    // Simulate the response.
    var request = serverChannel.serverRequestsSent[0];
    serverChannel.simulateResponseFromClient(
      ServerShowMessageRequestResult(
        action: 'a',
      ).toResponse(request.id, clientUriConverter: server.uriConverter),
    );
    var response = await responseFuture;
    expect(response, 'a');
  }

  Future<void> test_showMessage_nullResponse() async {
    server.clientCapabilities.requests = ['showMessageRequest'];

    // Send the request.
    var responseFuture = server.userPromptSender!(
      MessageType.warning,
      'message',
      ['a', 'b'],
    );
    expect(serverChannel.serverRequestsSent, hasLength(1));

    // Simulate the response.
    var request = serverChannel.serverRequestsSent[0];
    serverChannel.simulateResponseFromClient(
      ServerShowMessageRequestResult().toResponse(
        request.id,
        clientUriConverter: server.uriConverter,
      ),
    );
    var response = await responseFuture;
    expect(response, isNull);
  }

  Future<void> test_shutdown() async {
    var request = ServerShutdownParams().toRequest(
      '0',
      clientUriConverter: server.uriConverter,
    );
    await handleSuccessfulRequest(request);
  }
}

class TestDartFixPromptManager implements DartFixPromptManager {
  var checksTriggered = 0;

  @override
  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);

  @override
  void triggerCheck() {
    checksTriggered++;
  }
}
