// 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/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/src/test_utilities/package_config_file_builder.dart';
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
import 'package:analyzer_plugin/protocol/protocol_common.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,
    );
    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', rootPath: fooLibFolder.parent.path);
    writePackageConfig(projectPackageConfigFile, config);
    await pumpEventQueue(times: 1); // Allow server to begin processing.
    config.add(name: 'bar', rootPath: barLibFolder.parent.path);
    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 == SERVER_NOTIFICATION_ERROR,
    );
    expect(
      errors.single.params![SERVER_NOTIFICATION_ERROR_MESSAGE],
      contains('dummy exception'),
    );
  }

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

    var errors = channel.notificationsReceived.where(
      (notification) => notification.event == SERVER_NOTIFICATION_ERROR,
    );
    expect(
      errors.single.params![SERVER_NOTIFICATION_ERROR_MESSAGE],
      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 == SERVER_NOTIFICATION_STATUS) {
          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 == SERVER_NOTIFICATION_STATUS) {
          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 == ANALYSIS_NOTIFICATION_NAVIGATION;
      }),
      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 == ANALYSIS_NOTIFICATION_NAVIGATION;
      }),
      isTrue,
    );
  }

  Future<void> test_shutdown() {
    var request = Request('my28', SERVER_REQUEST_SHUTDOWN);
    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(toUriStr: toUriStr));
  }

  /// 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;
  }
}
