// 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 'package:analysis_server/protocol/protocol.dart';
import 'package:analysis_server/protocol/protocol_constants.dart';
import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/analytics/analytics_manager.dart';
import 'package:analysis_server/src/legacy_analysis_server.dart';
import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
import 'package:analysis_server/src/server/error_notifier.dart';
import 'package:analysis_server/src/session_logger/session_logger.dart';
import 'package:analysis_server/src/utilities/mocks.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/test_utilities/mock_sdk.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:analyzer_testing/package_config_file_builder.dart';
import 'package:analyzer_testing/resource_provider_mixin.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unified_analytics/unified_analytics.dart';

import 'constants.dart';

void main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(AnalysisServerTest);
  });
}

@reflectiveTest
class AnalysisServerTest with ResourceProviderMixin {
  @override
  MemoryResourceProvider resourceProvider = MemoryResourceProvider(
    // Force the in-memory file watchers to be slowly initialized to emulate
    // the physical watchers (for test_concurrentContextRebuilds).
    delayWatcherInitialization: Duration(milliseconds: 1),
  );

  late MockServerChannel channel;
  late ErrorNotifier errorNotifier;
  late LegacyAnalysisServer server;

  void setUp() {
    channel = MockServerChannel(printMessages: debugPrintCommunication);

    // Create an SDK in the mock file system.
    var sdkRoot = newFolder('/sdk');
    createMockSdk(resourceProvider: resourceProvider, root: sdkRoot);

    errorNotifier = ErrorNotifier();
    server = LegacyAnalysisServer(
      channel,
      resourceProvider,
      AnalysisServerOptions(),
      DartSdkManager(sdkRoot.path),
      AnalyticsManager(NoOpAnalytics()),
      CrashReportingAttachmentsBuilder.empty,
      errorNotifier,
      SessionLogger(),
    );
    errorNotifier.server = server;
  }

  /// See https://github.com/dart-lang/sdk/issues/50496
  Future<void> test_caching_mixin_superInvokedNames_setter_change() async {
    var lib = convertPath('/lib');
    newFolder(lib);
    var foo = newFile('/lib/foo.dart', '''
class A {
  set foo(int _) {}
}
mixin M on A {
  void bar() {
    super.boo = 0;
  }
}
class X extends A with M {}
''');
    await server.setAnalysisRoots('0', [lib], []);
    await server.onAnalysisComplete;
    expect(server.statusAnalyzing, isFalse);
    channel.notificationsReceived.clear();

    server.updateContent('0', {
      foo.path: AddContentOverlay('''
class A {
  set foo(int _) {}
}
mixin M on A {
  void bar() {
    super.foo = 0;
  }
}
class X extends A with M {}
'''),
    });
    await server.onAnalysisComplete;
    expect(server.statusAnalyzing, isFalse);
    var notifications = channel.notificationsReceived;
    expect(notifications, hasLength(1));
    var notification = notifications.first;
    expect(notification.event, 'analysis.errors');
    var params = notification.params!;
    var errors = params['errors'] as List<Map<String, Object?>>;
    expect(errors, isEmpty);
  }

  /// Test that modifying package_config again while a context rebuild is in
  /// progress does not get lost due to a gap between creating a file watcher
  /// and it raising events.
  /// https://github.com/Dart-Code/Dart-Code/issues/3438
  Future<void> test_concurrentContextRebuilds() async {
    // Subscribe to STATUS so we'll know when analysis is done.
    server.serverServices = {ServerService.STATUS};
    var projectRoot = convertPath('/foo');
    var projectTestFile = convertPath('/foo/lib/test.dart');
    var projectPackageConfigFile = convertPath(
      '/foo/.dart_tool/package_config.json',
    );

    // Create a file that references two packages, which will we write to
    // package_config.json individually.
    newFolder(projectRoot);
    newFile(projectTestFile, r'''
      import "package:foo/foo.dart";'
      import "package:bar/bar.dart";'
      ''');

    // Ensure the packages and package_config exist.
    var fooLibFolder = _addSimplePackage('foo', '');
    var barLibFolder = _addSimplePackage('bar', '');
    var config = PackageConfigFileBuilder();
    writePackageConfig(projectPackageConfigFile, config);

    // Track diagnostics that arrive.
    var errorsByFile = <String, List<AnalysisError>>{};
    channel.notifications
        .where((notification) => notification.event == 'analysis.errors')
        .listen((notification) {
          var params = AnalysisErrorsParams.fromNotification(
            notification,
            clientUriConverter: server.uriConverter,
          );
          errorsByFile[params.file] = params.errors;
        });

    /// Helper that waits for analysis then returns the relevant errors.
    Future<List<AnalysisError>> getUriNotExistErrors() async {
      await server.onAnalysisComplete;
      expect(server.statusAnalyzing, isFalse);
      return errorsByFile[projectTestFile]!
          .where((error) => error.code == 'uri_does_not_exist')
          .toList();
    }

    // Set roots and expect 2 uri_does_not_exist errors.
    await server.setAnalysisRoots('0', [projectRoot], []);
    expect(await getUriNotExistErrors(), hasLength(2));

    // Write both packages, in two events so that the first one will trigger
    // a rebuild.
    config.add(name: 'foo', rootFolder: fooLibFolder.parent);
    writePackageConfig(projectPackageConfigFile, config);
    await pumpEventQueue(times: 1); // Allow server to begin processing.
    config.add(name: 'bar', rootFolder: barLibFolder.parent);
    writePackageConfig(projectPackageConfigFile, config);

    // Eventually the errors are gone.
    while (true) {
      var errors = await getUriNotExistErrors();
      if (errors.isEmpty) {
        break;
      }
      await pumpEventQueue(times: 5000);
    }
  }

  Future<void> test_errorNotification_errorNotifier() async {
    errorNotifier.logException(Exception('dummy exception'));

    var errors = channel.notificationsReceived.where(
      (notification) => notification.event == serverNotificationError,
    );
    expect(
      errors.single.params![serverNotificationErrorMessage],
      contains('dummy exception'),
    );
  }

  Future<void> test_errorNotification_sendNotification() async {
    server.sendServerErrorNotification(
      'message',
      Exception('dummy exception'),
      null,
    );

    var errors = channel.notificationsReceived.where(
      (notification) => notification.event == serverNotificationError,
    );
    expect(
      errors.single.params![serverNotificationErrorMessage],
      contains('dummy exception'),
    );
  }

  Future<void> test_serverStatusNotifications_hasFile() async {
    server.serverServices.add(ServerService.STATUS);

    newFile('/test/lib/a.dart', r'''
class A {}
''');
    await server.setAnalysisRoots('0', [convertPath('/test')], []);

    // Pump the event queue, so that the server has finished any analysis.
    await pumpEventQueue(times: 5000);

    var notifications = channel.notificationsReceived;
    expect(notifications, isNotEmpty);

    // At least one notification indicating analysis is in progress.
    expect(
      notifications.any((Notification notification) {
        if (notification.event == serverNotificationStatus) {
          var params = ServerStatusParams.fromNotification(
            notification,
            clientUriConverter: server.uriConverter,
          );
          var analysis = params.analysis;
          if (analysis != null) {
            return analysis.isAnalyzing;
          }
        }
        return false;
      }),
      isTrue,
    );

    // The last notification should indicate that analysis is complete.
    var notification = notifications[notifications.length - 1];
    var params = ServerStatusParams.fromNotification(
      notification,
      clientUriConverter: server.uriConverter,
    );
    expect(params.analysis!.isAnalyzing, isFalse);
  }

  Future<void> test_serverStatusNotifications_noFiles() async {
    server.serverServices.add(ServerService.STATUS);

    newFolder('/test');
    await server.setAnalysisRoots('0', [convertPath('/test')], []);

    // Pump the event queue, so that the server has finished any analysis.
    await pumpEventQueue(times: 5000);

    var notifications = channel.notificationsReceived;
    expect(notifications, isNotEmpty);

    // At least one notification indicating analysis is in progress.
    expect(
      notifications.any((Notification notification) {
        if (notification.event == serverNotificationStatus) {
          var params = ServerStatusParams.fromNotification(
            notification,
            clientUriConverter: server.uriConverter,
          );
          var analysis = params.analysis;
          if (analysis != null) {
            return analysis.isAnalyzing;
          }
        }
        return false;
      }),
      isTrue,
    );

    // The last notification should indicate that analysis is complete.
    var notification = notifications[notifications.length - 1];
    var params = ServerStatusParams.fromNotification(
      notification,
      clientUriConverter: server.uriConverter,
    );
    expect(params.analysis!.isAnalyzing, isFalse);
  }

  Future<void>
  test_setAnalysisSubscriptions_fileInIgnoredFolder_newOptions() async {
    var path = convertPath('/project/samples/sample.dart');
    newFile(path, '');
    newAnalysisOptionsYamlFile('/project', r'''
analyzer:
  exclude:
    - 'samples/**'
''');
    await server.setAnalysisRoots('0', [convertPath('/project')], []);
    server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
      AnalysisService.NAVIGATION: <String>{path},
    });

    // We respect subscriptions, even for excluded files.
    await pumpEventQueue(times: 5000);
    expect(
      channel.notificationsReceived.any((notification) {
        return notification.event == analysisNotificationNavigation;
      }),
      isTrue,
    );
  }

  Future<void>
  test_setAnalysisSubscriptions_fileInIgnoredFolder_oldOptions() async {
    var path = convertPath('/project/samples/sample.dart');
    newFile(path, '');
    newAnalysisOptionsYamlFile('/project', r'''
analyzer:
  exclude:
    - 'samples/**'
''');
    await server.setAnalysisRoots('0', [convertPath('/project')], []);
    server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
      AnalysisService.NAVIGATION: <String>{path},
    });

    // We respect subscriptions, even for excluded files.
    await pumpEventQueue(times: 5000);
    expect(
      channel.notificationsReceived.any((notification) {
        return notification.event == analysisNotificationNavigation;
      }),
      isTrue,
    );
  }

  Future<void> test_shutdown() {
    var request = Request('my28', serverRequestShutdown);
    return channel.simulateRequestFromClient(request).then((Response response) {
      expect(response.id, equals('my28'));
      expect(response.error, isNull);
    });
  }

  Future<void> test_unknownRequest() {
    var request = Request('my22', 'randomRequest');
    return channel.simulateRequestFromClient(request).then((Response response) {
      expect(response.id, equals('my22'));
      expect(response.error, isNotNull);
    });
  }

  void writePackageConfig(String path, PackageConfigFileBuilder config) {
    newFile(path, config.toContent());
  }

  /// Creates a simple package named [name] with [content] in the file at
  /// `package:$name/$name.dart`.
  ///
  /// Returns a [Folder] that represents the packages `lib` folder.
  Folder _addSimplePackage(String name, String content) {
    var packagePath = '/packages/$name';
    var file = newFile('$packagePath/lib/$name.dart', content);
    return file.parent;
  }
}
