// Copyright (c) 2017, 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.

/// @docImport 'package:analysis_server/src/analysis_server.dart';
library;

import 'dart:async';
import 'dart:convert';

import 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/src/channel/channel.dart';
import 'package:analysis_server/src/plugin/plugin_isolate.dart';
import 'package:analysis_server/src/plugin/plugin_manager.dart';
import 'package:analysis_server/src/session_logger/session_logger.dart';
import 'package:analyzer/dart/analysis/context_root.dart' as analyzer;
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer_plugin/protocol/protocol.dart' as plugin;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as plugin;
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart' as plugin;
import 'package:watcher/watcher.dart';

/// A mock [ServerCommunicationChannel] for testing [AnalysisServer].
class MockServerChannel implements ServerCommunicationChannel {
  /// A controller for the stream of requests, responses and notifications from
  /// the client to the server.
  ///
  /// Messages added to this stream should be converted to/from JSON to ensure
  /// they are fully serialized/deserialized as they would be in a real server
  /// otherwise tests may receive real instances where in reality they would be
  /// maps.
  StreamController<ClientMessage> requestController =
      StreamController<ClientMessage>();

  /// A controller for the stream of requests and responses from the server to
  /// the client.
  ///
  /// Messages added to this stream should be converted to/from JSON to ensure
  /// they are fully serialized/deserialized as they would be in a real server
  /// otherwise tests may receive real instances where in reality they would be
  /// maps.
  StreamController<RequestOrResponse> responseController =
      StreamController<RequestOrResponse>.broadcast();

  /// A controller for the stream of notifications from the server to the
  /// client.
  ///
  /// Unlike [requestController] and [responseController], notifications added
  /// here are not round-tripped through JSON but instead have real class
  /// instances as their `params`. This is because they are only used by tests
  /// which will cast and/or switch on the types for convenience.
  StreamController<Notification> notificationController =
      StreamController<Notification>.broadcast(sync: true);

  Completer<Response>? errorCompleter;

  List<Response> responsesReceived = [];
  List<Notification> notificationsReceived = [];
  List<Request> serverRequestsSent = [];

  bool _closed = false;

  String? name;

  /// True if we are printing out messages exchanged with the server.
  final bool printMessages;

  new({bool? printMessages}) : printMessages = printMessages ?? false;

  /// Return the broadcast stream of notifications.
  Stream<Notification> get notifications {
    return notificationController.stream;
  }

  @override
  Stream<ClientMessage> get requests => requestController.stream;

  /// Return the broadcast stream of server-to-client requests.
  Stream<Request> get serverToClientRequests {
    return responseController.stream.where((r) => r is Request).cast<Request>();
  }

  @override
  void close() {
    _closed = true;
  }

  @override
  void sendNotification(Notification notification) {
    // Don't deliver notifications after the connection is closed.
    if (_closed) {
      return;
    }

    notificationsReceived.add(notification);
    notificationController.add(notification);

    var errorCompleter = this.errorCompleter;
    if (errorCompleter != null && notification.event == 'server.error') {
      var params = notification.params!;
      print('[server.error] test: $name message: ${params['message']}');
      errorCompleter.completeError(
        ServerError(params['message'] as String),
        StackTrace.fromString(params['stackTrace'] as String),
      );
    }
  }

  @override
  void sendRequest(Request request) {
    var jsonString = jsonEncode(request.toJson());
    if (printMessages) {
      print('<== $jsonString');
    }

    // Round-trip via JSON to ensure all types are fully serialized as they
    // would be in a real setup.
    request = Request.fromJson(jsonDecode(jsonString) as Map<String, Object?>)!;

    serverRequestsSent.add(request);
    responseController.add(request);
  }

  @override
  void sendResponse(Response response) {
    // Don't deliver responses after the connection is closed.
    if (_closed) {
      return;
    }

    var jsonString = jsonEncode(response.toJson());
    if (printMessages) {
      print('<== $jsonString');
    }

    // Round-trip via JSON to ensure all types are fully serialized as they
    // would be in a real setup.
    response = Response.fromJson(
      jsonDecode(jsonString) as Map<String, Object?>,
    )!;

    responsesReceived.add(response);
    responseController.add(response);
  }

  /// Send the given [notification] to the server as if it had been sent from
  /// the client.
  ///
  /// A notification has no response, so there is nothing to wait for.
  void simulateNotificationFromClient(Notification notification) {
    if (_closed) {
      throw Exception('simulateNotificationFromClient after connection closed');
    }

    var jsonString = jsonEncode(notification.toJson());
    if (printMessages) {
      print('==> $jsonString');
    }

    // Round-trip via JSON to ensure all types are fully serialized as they
    // would be in a real setup.
    notification = Notification.fromJson(
      jsonDecode(jsonString) as Map<String, Object?>,
    );

    requestController.add(notification);
  }

  /// Send the given [request] to the server as if it had been sent from the
  /// client, and return a future that will complete when a response associated
  /// with the [request] has been received.
  ///
  /// The value of the future will be the received response.
  Future<Response> simulateRequestFromClient(Request request) async {
    if (_closed) {
      throw Exception('simulateRequestFromClient after connection closed');
    }

    var jsonString = jsonEncode(request.toJson());
    if (printMessages) {
      print('==> $jsonString');
    }

    // Round-trip via JSON to ensure all types are fully serialized as they
    // would be in a real setup.
    request = Request.fromJson(jsonDecode(jsonString) as Map<String, Object?>)!;

    requestController.add(request);
    var response = await waitForResponse(request);

    // Round-trip via JSON to ensure all types are fully serialized as they
    // would be in a real setup.
    response = Response.fromJson(
      jsonDecode(jsonEncode(response)) as Map<String, Object?>,
    )!;

    return response;
  }

  /// Send the given [response] to the server as if it had been sent from the
  /// client.
  void simulateResponseFromClient(Response response) {
    // No further requests should be sent after the connection is closed.
    if (_closed) {
      throw Exception('simulateRequestFromClient after connection closed');
    }

    var jsonString = jsonEncode(response.toJson());
    if (printMessages) {
      print('==> $jsonString');
    }

    // Round-trip via JSON to ensure all types are fully serialized as they
    // would be in a real setup.
    response = Response.fromJson(
      jsonDecode(jsonString) as Map<String, Object?>,
    )!;

    requestController.add(response);
  }

  /// Return a future that will complete when a response associated with the
  /// given [request] has been received. The value of the future will be the
  /// received response.
  ///
  /// Unlike [simulateRequestFromClient], this method assumes that the [request]
  /// has already been sent to the server.
  Future<Response> waitForResponse(Request request) {
    var id = request.id;
    return responseController.stream
        .where((r) => r is Response)
        .cast<Response>()
        .firstWhere((response) => response.id == id);
  }
}

class ServerError implements Exception {
  final String message;

  new(this.message);

  @override
  String toString() {
    return 'Server Error: $message';
  }
}

class TestPluginIsolate implements PluginIsolate {
  @override
  final String pluginId;

  final List<plugin.RequestParams> requests = [];

  new(this.pluginId);

  @override
  bool get isLegacy => false;

  @override
  dynamic noSuchMethod(Invocation invocation) =>
      throw UnimplementedError('${invocation.memberName} is unimplemented');

  @override
  Future<plugin.PluginDetailsResult?> requestDetails() async => null;

  @override
  void sendRequest(plugin.RequestParams params) {
    requests.add(params);
  }

  @override
  Future<void> stop() async {}
}

/// A plugin manager that simulates broadcasting requests to plugins by
/// hard-coding the responses.
class TestPluginManager(final ResourceProvider resourceProvider)
    implements PluginManager {
  plugin.AnalysisSetAnalysisRootsParams? analysisSetAnalysisRootsParams;
  plugin.AnalysisSetPriorityFilesParams? analysisSetPriorityFilesParams;
  plugin.AnalysisSetSubscriptionsParams? analysisSetSubscriptionsParams;
  plugin.AnalysisUpdateContentParams? analysisUpdateContentParams;
  plugin.RequestParams? broadcastedRequest;
  Map<PluginIsolate, Future<plugin.Response>>? broadcastResults;
  Map<PluginIsolate, Future<plugin.Response>>? Function(plugin.RequestParams)?
  handleRequest;
  Map<analyzer.ContextRoot, List<String>> contextRootPlugins = {};

  @override
  List<PluginIsolate> pluginIsolates = [];

  @override
  final Completer<void> initializedCompleter = Completer();

  StreamController<void> pluginsChangedController =
      StreamController.broadcast();

  @override
  final contextRootsWithNoPlugins = <String>{};

  @override
  final SessionLogger sessionLogger = SessionLogger();

  @override
  InstrumentationService get instrumentationService =>
      InstrumentationService.NULL_SERVICE;

  @override
  List<PluginIsolate> get legacyPluginIsolates =>
      pluginIsolates.where((e) => e.isLegacy).toList();

  @override
  List<PluginIsolate> get newPluginIsolates =>
      pluginIsolates.where((e) => !e.isLegacy).toList();

  @override
  Stream<void> get pluginsChanged => pluginsChangedController.stream;

  @override
  Future<void> addPluginToContextRoot(
    analyzer.ContextRoot contextRoot,
    String path, {
    required bool isLegacyPlugin,
  }) async {
    contextRootPlugins.putIfAbsent(contextRoot, () => []).add(path);
    if (!isLegacyPlugin) {
      pluginIsolates.add(TestPluginIsolate(path));
    }
  }

  @override
  Map<PluginIsolate, Future<plugin.Response>> broadcastRequest(
    plugin.RequestParams params, {
    analyzer.ContextRoot? contextRoot,
  }) {
    broadcastedRequest = params;
    return handleRequest?.call(params) ?? broadcastResults ?? {};
  }

  @override
  List<Future<plugin.Response>> broadcastWatchEvent(WatchEvent watchEvent) {
    return [];
  }

  @override
  dynamic noSuchMethod(Invocation invocation) =>
      throw Exception('Unexpected invocation of ${invocation.memberName}');

  @override
  Folder pluginStateFolder(String contextRootPath) {
    return resourceProvider.getFolder(
      resourceProvider.pathContext.join(contextRootPath, '.plugin_state'),
    );
  }

  @override
  String pluginStateFolderPath(String pluginPath) => '/some/path';

  @override
  void removedContextRoot(analyzer.ContextRoot contextRoot) {
    contextRootPlugins.remove(contextRoot);
  }

  @override
  Future<void> restartPlugins() async {
    // Nothing to restart.
  }

  @override
  void setAnalysisSetAnalysisRootsParams(
    plugin.AnalysisSetAnalysisRootsParams params,
  ) {
    analysisSetAnalysisRootsParams = params;
  }

  @override
  void setAnalysisSetPriorityFilesParams(
    plugin.AnalysisSetPriorityFilesParams params,
  ) {
    analysisSetPriorityFilesParams = params;
  }

  @override
  void setAnalysisSetSubscriptionsParams(
    plugin.AnalysisSetSubscriptionsParams params,
  ) {
    analysisSetSubscriptionsParams = params;
  }

  @override
  void setAnalysisUpdateContentParams(
    plugin.AnalysisUpdateContentParams params, {
    String? precomputedNewContentForChange,
  }) {
    analysisUpdateContentParams = params;
  }
}
