// Copyright (c) 2024, 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_plugin/edit/assist/assist.dart';
import 'package:analysis_server_plugin/edit/assist/dart_assist_context.dart';
import 'package:analysis_server_plugin/edit/fix/dart_fix_context.dart';
import 'package:analysis_server_plugin/edit/fix/fix.dart';
import 'package:analysis_server_plugin/plugin.dart';
import 'package:analysis_server_plugin/src/correction/assist_processor.dart';
import 'package:analysis_server_plugin/src/correction/dart_change_workspace.dart';
import 'package:analysis_server_plugin/src/correction/fix_processor.dart';
import 'package:analysis_server_plugin/src/registry.dart';
import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/diagnostic/diagnostic.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/overlay_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/dart/analysis/analysis_context_collection.dart';
import 'package:analyzer/src/dart/analysis/analysis_options.dart';
import 'package:analyzer/src/dart/analysis/byte_store.dart';
import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/ignore_comments/ignore_info.dart';
import 'package:analyzer/src/lint/linter.dart';
import 'package:analyzer/src/lint/linter_visitor.dart';
import 'package:analyzer/src/lint/registry.dart';
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
import 'package:analyzer_plugin/channel/channel.dart';
import 'package:analyzer_plugin/protocol/protocol.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol;
import 'package:analyzer_plugin/protocol/protocol_constants.dart' as protocol;
import 'package:analyzer_plugin/protocol/protocol_generated.dart' as protocol;
import 'package:analyzer_plugin/src/protocol/protocol_internal.dart';

typedef _ErrorAndProtocolError = ({
  Diagnostic diagnostic,
  protocol.AnalysisError protocolError,
});

typedef _PluginState = ({
  AnalysisContext analysisContext,
  List<_ErrorAndProtocolError> errors,
});

/// The server that communicates with the analysis server, passing requests and
/// responses between the analysis server and individual plugins.
class PluginServer {
  /// The communication channel being used to communicate with the analysis
  /// server.
  late PluginCommunicationChannel _channel;

  final OverlayResourceProvider _resourceProvider;

  late final ByteStore _byteStore =
      MemoryCachingByteStore(NullByteStore(), 1024 * 1024 * 256);

  AnalysisContextCollectionImpl? _contextCollection;

  String? _sdkPath;

  /// Paths of priority files.
  Set<String> _priorityPaths = {};

  final List<Plugin> _plugins;

  final _registry = PluginRegistryImpl();

  /// The recent state of analysis reults, to be cleared on file changes.
  final _recentState = <String, _PluginState>{};

  /// The next modification stamp for a changed file in the [resourceProvider].
  int _overlayModificationStamp = 0;

  PluginServer({
    required ResourceProvider resourceProvider,
    required List<Plugin> plugins,
  })  : _resourceProvider = OverlayResourceProvider(resourceProvider),
        _plugins = plugins {
    for (var plugin in plugins) {
      plugin.register(_registry);
    }
    _registry.registerIgnoreProducerGenerators();
  }

  /// Handles an 'analysis.setPriorityFiles' request.
  ///
  /// Throws a [RequestFailure] if the request could not be handled.
  Future<protocol.AnalysisSetPriorityFilesResult>
      handleAnalysisSetPriorityFiles(
          protocol.AnalysisSetPriorityFilesParams parameters) async {
    _priorityPaths = parameters.files.toSet();
    return protocol.AnalysisSetPriorityFilesResult();
  }

  /// Handles an 'edit.getAssists' request.
  ///
  /// Throws a [RequestFailure] if the request could not be handled.
  Future<protocol.EditGetAssistsResult> handleEditGetAssists(
      protocol.EditGetAssistsParams parameters) async {
    var path = parameters.file;

    var recentState = _recentState[path];
    if (recentState == null) {
      return protocol.EditGetAssistsResult(const []);
    }

    var (:analysisContext, :errors) = recentState;
    var libraryResult =
        await analysisContext.currentSession.getResolvedLibrary(path);
    if (libraryResult is! ResolvedLibraryResult) {
      return protocol.EditGetAssistsResult(const []);
    }
    var unitResult = libraryResult.unitWithPath(path);
    if (unitResult is! ResolvedUnitResult) {
      return protocol.EditGetAssistsResult(const []);
    }

    var context = DartAssistContext(
      // TODO(srawlins): Use a real instrumentation service. Other
      // implementations get InstrumentationService from AnalysisServer.
      InstrumentationService.NULL_SERVICE,
      DartChangeWorkspace([analysisContext.currentSession]),
      libraryResult,
      unitResult,
      parameters.offset,
      parameters.length,
    );

    List<Assist> assists;
    try {
      assists = await computeAssists(context);
    } on InconsistentAnalysisException {
      // TODO(srawlins): Is it important to at least log this? Or does it
      // happen on the regular?
      assists = [];
    }

    if (assists.isEmpty) {
      return protocol.EditGetAssistsResult(const []);
    }

    var corrections = [
      for (var assist in assists..sort(Assist.compareAssists))
        protocol.PrioritizedSourceChange(assist.kind.priority, assist.change)
    ];
    return protocol.EditGetAssistsResult(corrections);
  }

  /// Handles an 'edit.getFixes' request.
  ///
  /// Throws a [RequestFailure] if the request could not be handled.
  Future<protocol.EditGetFixesResult> handleEditGetFixes(
      protocol.EditGetFixesParams parameters) async {
    var path = parameters.file;
    var offset = parameters.offset;

    var recentState = _recentState[path];
    if (recentState == null) {
      return protocol.EditGetFixesResult(const []);
    }

    var (:analysisContext, :errors) = recentState;

    var libraryResult =
        await analysisContext.currentSession.getResolvedLibrary(path);
    if (libraryResult is! ResolvedLibraryResult) {
      return protocol.EditGetFixesResult(const []);
    }
    var unitResult = libraryResult.unitWithPath(path);
    if (unitResult is! ResolvedUnitResult) {
      return protocol.EditGetFixesResult(const []);
    }

    var lintAtOffset =
        errors.where((error) => error.diagnostic.offset == offset);
    if (lintAtOffset.isEmpty) return protocol.EditGetFixesResult(const []);

    var errorFixesList = <protocol.AnalysisErrorFixes>[];

    var workspace = DartChangeWorkspace([analysisContext.currentSession]);
    for (var (:diagnostic, :protocolError) in lintAtOffset) {
      var context = DartFixContext(
        // TODO(srawlins): Use a real instrumentation service. Other
        // implementations get InstrumentationService from AnalysisServer.
        instrumentationService: InstrumentationService.NULL_SERVICE,
        workspace: workspace,
        libraryResult: libraryResult,
        unitResult: unitResult,
        error: diagnostic,
      );

      List<Fix> fixes;
      try {
        fixes = await computeFixes(context);
      } on InconsistentAnalysisException {
        // TODO(srawlins): Is it important to at least log this? Or does it
        // happen on the regular?
        fixes = [];
      }

      if (fixes.isNotEmpty) {
        fixes.sort(Fix.compareFixes);
        var errorFixes = protocol.AnalysisErrorFixes(protocolError);
        errorFixesList.add(errorFixes);
        for (var fix in fixes) {
          errorFixes.fixes.add(protocol.PrioritizedSourceChange(1, fix.change));
        }
      }
    }

    return protocol.EditGetFixesResult(errorFixesList);
  }

  /// Handles a 'plugin.versionCheck' request.
  Future<protocol.PluginVersionCheckResult> handlePluginVersionCheck(
      protocol.PluginVersionCheckParams parameters) async {
    // TODO(srawlins): It seems improper for _this_ method to be the point where
    // the SDK path is configured...
    _sdkPath = parameters.sdkPath;
    return protocol.PluginVersionCheckResult(
        true, 'Plugin Server', '0.0.1', ['*.dart']);
  }

  /// Initializes each of the registered plugins.
  Future<void> initialize() async {
    await Future.wait(
        _plugins.map((p) => p.start()).whereType<Future<Object?>>());
  }

  /// Starts this plugin by listening to the given communication [channel].
  void start(PluginCommunicationChannel channel) {
    _channel = channel;
    _channel.listen(_handleRequestZoned,
        // TODO(srawlins): Implement.
        onDone: () {});
  }

  /// This method is invoked when a new instance of [AnalysisContextCollection]
  /// is created, so the plugin can perform initial analysis of analyzed files.
  Future<void> _analyzeAllFilesInContextCollection({
    required AnalysisContextCollection contextCollection,
  }) async {
    _channel.sendNotification(
        protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(true))
            .toNotification());
    await _forAnalysisContexts(contextCollection, (analysisContext) async {
      var paths = analysisContext.contextRoot
          .analyzedFiles()
          // TODO(srawlins): Enable analysis on other files, even if only
          // YAML files for analysis options and pubspec analysis and quick
          // fixes.
          .where((p) => file_paths.isDart(_resourceProvider.pathContext, p))
          .toSet();

      await _analyzeFiles(
        analysisContext: analysisContext,
        paths: paths,
      );
    });
    _channel.sendNotification(
        protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(false))
            .toNotification());
  }

  Future<void> _analyzeFile({
    required AnalysisContext analysisContext,
    required String path,
  }) async {
    var file = _resourceProvider.getFile(path);
    var analysisOptions = analysisContext.getAnalysisOptionsForFile(file);
    var diagnostics = await _computeDiagnostics(
      analysisContext,
      path,
      analysisOptions: analysisOptions as AnalysisOptionsImpl,
    );
    _channel.sendNotification(
        protocol.AnalysisErrorsParams(path, diagnostics).toNotification());
  }

  /// Analyzes the files at the given [paths].
  Future<void> _analyzeFiles({
    required AnalysisContext analysisContext,
    required Set<String> paths,
  }) async {
    // First analyze priority files.
    for (var path in _priorityPaths) {
      if (paths.remove(path)) {
        await _analyzeFile(analysisContext: analysisContext, path: path);
      }
    }

    // Then analyze the remaining files.
    for (var path in paths) {
      await _analyzeFile(analysisContext: analysisContext, path: path);
    }
  }

  Future<List<protocol.AnalysisError>> _computeDiagnostics(
    AnalysisContext analysisContext,
    String path, {
    required AnalysisOptionsImpl analysisOptions,
  }) async {
    var libraryResult =
        await analysisContext.currentSession.getResolvedLibrary(path);
    if (libraryResult is! ResolvedLibraryResult) {
      return const [];
    }
    var unitResult = await analysisContext.currentSession.getResolvedUnit(path);
    if (unitResult is! ResolvedUnitResult) {
      return const [];
    }
    var listener = RecordingErrorListener();
    var errorReporter = ErrorReporter(
        listener, unitResult.libraryElement2.firstFragment.source);

    var currentUnit = LintRuleUnitContext(
      file: unitResult.file,
      content: unitResult.content,
      errorReporter: errorReporter,
      unit: unitResult.unit,
    );
    var allUnits = [
      for (var unitResult in libraryResult.units)
        LintRuleUnitContext(
          file: unitResult.file,
          content: unitResult.content,
          errorReporter: errorReporter,
          unit: unitResult.unit,
        ),
    ];

    // TODO(srawlins): Enable timing similar to what the linter package's
    // `benchhmark.dart` script does.
    var nodeRegistry = RuleVisitorRegistry(enableTiming: false);

    var context = LinterContextWithResolvedResults(
      allUnits,
      currentUnit,
      libraryResult.element2.typeProvider,
      libraryResult.element2.typeSystem as TypeSystemImpl,
      // TODO(srawlins): Support 'package' parameter.
      null,
    );

    // A mapping from each lint and warning code to its corresponding plugin.
    var pluginCodeMapping = <String, String>{};

    for (var configuration in analysisOptions.pluginConfigurations) {
      if (!configuration.isEnabled) continue;
      // TODO(srawlins): Namespace rules by their plugin, to avoid collisions.
      var rules =
          Registry.ruleRegistry.enabled(configuration.diagnosticConfigs);
      for (var rule in rules) {
        rule.reporter = errorReporter;
        // TODO(srawlins): Enable timing similar to what the linter package's
        // `benchhmark.dart` script does.
        rule.registerNodeProcessors(nodeRegistry, context);
      }
      for (var code in rules.expand((r) => r.diagnosticCodes)) {
        var existingPlugin = pluginCodeMapping[code.name];
        if (existingPlugin == null) {
          pluginCodeMapping[code.name] = configuration.name;
        }
      }
    }

    context.currentUnit = currentUnit;
    currentUnit.unit.accept(
        AnalysisRuleVisitor(nodeRegistry, shouldPropagateExceptions: true));

    var ignoreInfo = IgnoreInfo.forDart(unitResult.unit, unitResult.content);
    var diagnostics = listener.errors.where((e) {
      var pluginName = pluginCodeMapping[e.errorCode.name];
      if (pluginName == null) {
        // If [e] is somehow not mapped, something is wrong; but don't mark it
        // as ignored.
        return true;
      }
      return !ignoreInfo.ignored(e, pluginName: pluginName);
    });

    // The list of the `AnalysisError`s and their associated
    // `protocol.AnalysisError`s.
    var diagnosticsAndProtocolErrors = [
      for (var diagnostic in diagnostics)
        (
          diagnostic: diagnostic,
          protocolError: protocol.AnalysisError(
            _severityOf(diagnostic),
            protocol.AnalysisErrorType.STATIC_WARNING,
            _locationFor(currentUnit.unit, path, diagnostic),
            diagnostic.message,
            diagnostic.errorCode.name,
            correction: diagnostic.correctionMessage,
            // TODO(srawlins): Use a valid value here.
            hasFix: true,
          )
        ),
    ];
    _recentState[path] = (
      analysisContext: analysisContext,
      errors: [...diagnosticsAndProtocolErrors],
    );
    return diagnosticsAndProtocolErrors.map((e) => e.protocolError).toList();
  }

  /// Converts the severity of [diagnostic] into a
  /// [protocol.AnalysisErrorSeverity].
  protocol.AnalysisErrorSeverity _severityOf(Diagnostic diagnostic) {
    try {
      return protocol.AnalysisErrorSeverity.values
          .byName(diagnostic.severity.name.toUpperCase());
    } catch (_) {
      assert(false, 'Invalid severity: ${diagnostic.severity}');
      // Return the default severity of `LintCode`.
      return protocol.AnalysisErrorSeverity.INFO;
    }
  }

  /// Invokes [fn] first for priority analysis contexts, then for the rest.
  Future<void> _forAnalysisContexts(
    AnalysisContextCollection contextCollection,
    Future<void> Function(AnalysisContext analysisContext) fn,
  ) async {
    var nonPriorityAnalysisContexts = <AnalysisContext>[];
    for (var analysisContext in contextCollection.contexts) {
      if (_isPriorityAnalysisContext(analysisContext)) {
        await fn(analysisContext);
      } else {
        nonPriorityAnalysisContexts.add(analysisContext);
      }
    }

    for (var analysisContext in nonPriorityAnalysisContexts) {
      await fn(analysisContext);
    }
  }

  /// Computes the response for the given [request].
  Future<Response?> _getResponse(Request request, int requestTime) async {
    ResponseResult? result;
    switch (request.method) {
      case protocol.ANALYSIS_REQUEST_GET_NAVIGATION:
      case protocol.ANALYSIS_REQUEST_HANDLE_WATCH_EVENTS:
        result = null;

      case protocol.ANALYSIS_REQUEST_SET_CONTEXT_ROOTS:
        var params =
            protocol.AnalysisSetContextRootsParams.fromRequest(request);
        result = await _handleAnalysisSetContextRoots(params);

      case protocol.ANALYSIS_REQUEST_SET_PRIORITY_FILES:
      case protocol.ANALYSIS_REQUEST_SET_SUBSCRIPTIONS:
      case protocol.ANALYSIS_REQUEST_UPDATE_CONTENT:
        var params = protocol.AnalysisUpdateContentParams.fromRequest(request);
        result = await _handleAnalysisUpdateContent(params);

      case protocol.COMPLETION_REQUEST_GET_SUGGESTIONS:
        result = null;

      case protocol.EDIT_REQUEST_GET_ASSISTS:
        var params = protocol.EditGetAssistsParams.fromRequest(request);
        result = await handleEditGetAssists(params);

      case protocol.EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS:
        result = null;

      case protocol.EDIT_REQUEST_GET_FIXES:
        var params = protocol.EditGetFixesParams.fromRequest(request);
        result = await handleEditGetFixes(params);

      case protocol.EDIT_REQUEST_GET_REFACTORING:
        result = null;

      case protocol.PLUGIN_REQUEST_SHUTDOWN:
        _channel.sendResponse(protocol.PluginShutdownResult()
            .toResponse(request.id, requestTime));
        _channel.close();
        return null;

      case protocol.PLUGIN_REQUEST_VERSION_CHECK:
        var params = protocol.PluginVersionCheckParams.fromRequest(request);
        result = await handlePluginVersionCheck(params);
    }
    if (result == null) {
      return Response(request.id, requestTime,
          error: RequestErrorFactory.unknownRequest(request.method));
    }
    return result.toResponse(request.id, requestTime);
  }

  /// Handles files that might have been affected by a content change of
  /// one or more files. The implementation may check if these files should
  /// be analyzed, do such analysis, and send diagnostics.
  ///
  /// By default invokes [_analyzeFiles] only for files that are analyzed in
  /// this [analysisContext].
  Future<void> _handleAffectedFiles({
    required AnalysisContext analysisContext,
    required List<String> paths,
  }) async {
    var analyzedPaths =
        paths.where(analysisContext.contextRoot.isAnalyzed).toSet();

    await _analyzeFiles(
      analysisContext: analysisContext,
      paths: analyzedPaths,
    );
  }

  /// Handles an 'analysis.setContextRoots' request.
  Future<protocol.AnalysisSetContextRootsResult> _handleAnalysisSetContextRoots(
      protocol.AnalysisSetContextRootsParams parameters) async {
    var currentContextCollection = _contextCollection;
    if (currentContextCollection != null) {
      _contextCollection = null;
      await currentContextCollection.dispose();
    }

    var includedPaths = parameters.roots.map((e) => e.root).toList();
    var contextCollection = AnalysisContextCollectionImpl(
      resourceProvider: _resourceProvider,
      includedPaths: includedPaths,
      byteStore: _byteStore,
      sdkPath: _sdkPath,
      fileContentCache: FileContentCache(_resourceProvider),
    );
    _contextCollection = contextCollection;
    await _analyzeAllFilesInContextCollection(
        contextCollection: contextCollection);
    return protocol.AnalysisSetContextRootsResult();
  }

  /// Handles an 'analysis.updateContent' request.
  ///
  /// Throws a [RequestFailure] if the request could not be handled.
  Future<protocol.AnalysisUpdateContentResult> _handleAnalysisUpdateContent(
      protocol.AnalysisUpdateContentParams parameters) async {
    var changedPaths = <String>{};
    var paths = parameters.files;
    paths.forEach((String path, Object overlay) {
      // Prepare the old overlay contents.
      String? oldContent;
      try {
        if (_resourceProvider.hasOverlay(path)) {
          oldContent = _resourceProvider.getFile(path).readAsStringSync();
        }
      } catch (_) {
        // Leave `oldContent` empty.
      }

      // Prepare the new contents.
      String? newContent;
      if (overlay is protocol.AddContentOverlay) {
        newContent = overlay.content;
      } else if (overlay is protocol.ChangeContentOverlay) {
        if (oldContent == null) {
          // The server should only send a ChangeContentOverlay if there is
          // already an existing overlay for the source.
          throw RequestFailure(
              RequestErrorFactory.invalidOverlayChangeNoContent());
        }
        try {
          newContent =
              protocol.SourceEdit.applySequence(oldContent, overlay.edits);
        } on RangeError {
          throw RequestFailure(
              RequestErrorFactory.invalidOverlayChangeInvalidEdit());
        }
      } else if (overlay is protocol.RemoveContentOverlay) {
        newContent = null;
      }

      if (newContent != null) {
        _resourceProvider.setOverlay(
          path,
          content: newContent,
          modificationStamp: _overlayModificationStamp++,
        );
      } else {
        _resourceProvider.removeOverlay(path);
      }

      changedPaths.add(path);
    });
    await _handleContentChanged(changedPaths.toList());
    return protocol.AnalysisUpdateContentResult();
  }

  /// Handles the fact that files with [paths] were changed.
  Future<void> _handleContentChanged(List<String> paths) async {
    if (_contextCollection case var contextCollection?) {
      _channel.sendNotification(
          protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(true))
              .toNotification());
      await _forAnalysisContexts(contextCollection, (analysisContext) async {
        for (var path in paths) {
          analysisContext.changeFile(path);
        }
        var affected = await analysisContext.applyPendingFileChanges();
        await _handleAffectedFiles(
            analysisContext: analysisContext, paths: affected);
      });
      _channel.sendNotification(
          protocol.PluginStatusParams(analysis: protocol.AnalysisStatus(false))
              .toNotification());
    }
  }

  Future<void> _handleRequest(Request request) async {
    var requestTime = DateTime.now().millisecondsSinceEpoch;
    var id = request.id;
    Response? response;
    try {
      response = await _getResponse(request, requestTime);
    } on RequestFailure catch (exception) {
      response = Response(id, requestTime, error: exception.error);
    } catch (exception, stackTrace) {
      response = Response(id, requestTime,
          error: protocol.RequestError(
              protocol.RequestErrorCode.PLUGIN_ERROR, exception.toString(),
              stackTrace: stackTrace.toString()));
    }
    if (response != null) {
      _channel.sendResponse(response);
    }
  }

  Future<void> _handleRequestZoned(Request request) async {
    await runZonedGuarded(
      () => _handleRequest(request),
      (error, stackTrace) {
        _channel.sendNotification(protocol.PluginErrorParams(
                false /* isFatal */, error.toString(), stackTrace.toString())
            .toNotification());
      },
    );
  }

  bool _isPriorityAnalysisContext(AnalysisContext analysisContext) =>
      _priorityPaths.any(analysisContext.contextRoot.isAnalyzed);

  static protocol.Location _locationFor(
      CompilationUnit unit, String path, Diagnostic diagnostic) {
    var lineInfo = unit.lineInfo;
    var startLocation = lineInfo.getLocation(diagnostic.offset);
    var endLocation =
        lineInfo.getLocation(diagnostic.offset + diagnostic.length);
    return protocol.Location(
      path,
      diagnostic.offset,
      diagnostic.length,
      startLocation.lineNumber,
      startLocation.columnNumber,
      endLine: endLocation.lineNumber,
      endColumn: endLocation.columnNumber,
    );
  }
}
