// Copyright (c) 2019, 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';
import 'package:analysis_server/src/protocol/protocol_internal.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Position;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import 'server_abstract.dart';

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

@reflectiveTest
class DocumentChangesTest extends AbstractLspAnalysisServerTest {
  String get content => '''
class Foo {
  String get bar => 'baz';
}
''';

  String get contentAfterUpdate => '''
class Bar {
  String get bar => 'updated';
}
''';

  Future<void> test_documentChange_notifiesPlugins() async {
    await _initializeAndOpen();
    await changeFile(2, mainFileUri, [
      Either2<TextDocumentContentChangeEvent1,
          TextDocumentContentChangeEvent2>.t1(TextDocumentContentChangeEvent1(
        range: Range(
            start: Position(line: 0, character: 6),
            end: Position(line: 0, character: 9)),
        text: 'Bar',
      )),
      Either2<TextDocumentContentChangeEvent1,
          TextDocumentContentChangeEvent2>.t1(TextDocumentContentChangeEvent1(
        range: Range(
            start: Position(line: 1, character: 21),
            end: Position(line: 1, character: 24)),
        text: 'updated',
      )),
    ]);

    final notifiedChanges = pluginManager.analysisUpdateContentParams!
        .files[mainFilePath] as ChangeContentOverlay;

    expect(
      applySequenceOfEdits(content, notifiedChanges.edits),
      contentAfterUpdate,
    );
  }

  Future<void> test_documentChange_updatesOverlay() async {
    await _initializeAndOpen();
    await changeFile(2, mainFileUri, [
      Either2<TextDocumentContentChangeEvent1,
          TextDocumentContentChangeEvent2>.t1(TextDocumentContentChangeEvent1(
        range: Range(
            start: Position(line: 0, character: 6),
            end: Position(line: 0, character: 9)),
        text: 'Bar',
      )),
      Either2<TextDocumentContentChangeEvent1,
          TextDocumentContentChangeEvent2>.t1(TextDocumentContentChangeEvent1(
        range: Range(
            start: Position(line: 1, character: 21),
            end: Position(line: 1, character: 24)),
        text: 'updated',
      )),
    ]);

    expect(server.resourceProvider.hasOverlay(mainFilePath), isTrue);
    expect(server.resourceProvider.getFile(mainFilePath).readAsStringSync(),
        equals(contentAfterUpdate));
  }

  Future<void> test_documentClose_deletesOverlay() async {
    await _initializeAndOpen();
    await closeFile(mainFileUri);

    expect(server.resourceProvider.hasOverlay(mainFilePath), isFalse);
  }

  Future<void> test_documentClose_notifiesPlugins() async {
    await _initializeAndOpen();
    await closeFile(mainFileUri);

    expect(pluginManager.analysisUpdateContentParams!.files,
        equals({mainFilePath: RemoveContentOverlay()}));
  }

  Future<void>
      test_documentOpen_addsOverlayOnlyToDriver_onlyIfInsideRoots() async {
    // Ensures that opening a file doesn't add it to the driver if it's outside
    // of the drivers root.
    final fileInsideRootPath = mainFilePath;
    final fileOutsideRootPath = convertPath('/home/unrelated/main.dart');
    await initialize();
    await openFile(Uri.file(fileInsideRootPath), content);
    await openFile(Uri.file(fileOutsideRootPath), content);

    // Expect both files return the same driver
    final driverForInside = server.getAnalysisDriver(fileInsideRootPath)!;
    final driverForOutside = server.getAnalysisDriver(fileOutsideRootPath)!;
    expect(driverForInside, equals(driverForOutside));
    // But that only the file inside the root was added.
    expect(driverForInside.addedFiles, contains(fileInsideRootPath));
    expect(driverForInside.addedFiles, isNot(contains(fileOutsideRootPath)));
  }

  Future<void> test_documentOpen_createsOverlay() async {
    await _initializeAndOpen();

    expect(server.resourceProvider.hasOverlay(mainFilePath), isTrue);
    expect(server.resourceProvider.getFile(mainFilePath).readAsStringSync(),
        equals(content));
  }

  Future<void> test_documentOpen_notifiesPlugins() async {
    await _initializeAndOpen();

    expect(pluginManager.analysisUpdateContentParams!.files,
        equals({mainFilePath: AddContentOverlay(content)}));
  }

  Future<void> test_documentOpen_setsPriorityFileIfEarly() async {
    // When initializing with config support, the server will call back to the client
    // which can delay analysis roots being configured. This can result in files
    // being opened before analysis roots are set which has previously caused the
    // files not to be marked as priority on the created drivers.
    // https://github.com/Dart-Code/Dart-Code/issues/2438
    // https://github.com/dart-lang/sdk/issues/42994

    // Initialize the server, but delay providing the configuration until after
    // we've opened the file.
    final completer = Completer<void>();

    // Send the initialize request but do not await it.
    final initResponse = initialize(
        workspaceCapabilities: withDidChangeConfigurationDynamicRegistration(
            withConfigurationSupport(emptyWorkspaceClientCapabilities)));

    // When asked for config, delay the response until we have sent the openFile notification.
    final config = provideConfig(
      () => initResponse,
      completer.future.then((_) => {'dart.foo': false}),
    );

    // Wait for initialization to finish, open the file, then allow config to complete.
    await initResponse;
    await openFile(mainFileUri, content);
    completer.complete();
    await config;
    await pumpEventQueue(times: 5000);

    // Ensure the opened file is in the priority list.
    expect(server.getAnalysisDriver(mainFilePath)!.priorityFiles,
        equals([mainFilePath]));
  }

  Future<void> _initializeAndOpen() async {
    await initialize();
    await openFile(mainFileUri, content);
  }
}
