// 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:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';

import '../analysis_abstract.dart';
import '../analysis_server_base.dart';

class AbstractSearchDomainTest extends PubPackageAnalysisServerTest {
  final Map<String, _ResultSet> _resultSets = {};
  String? searchId;
  List<SearchResult> results = <SearchResult>[];
  late SearchResult result;

  void assertHasResult(SearchResultKind kind, String search, [int? length]) {
    var offset = findOffset(search);
    length ??= findIdentifierLength(search);
    findResult(kind, testFile.path, offset, length, true);
  }

  void assertNoResult(SearchResultKind kind, String search, [int? length]) {
    var offset = findOffset(search);
    length ??= findIdentifierLength(search);
    findResult(kind, testFile.path, offset, length, false);
  }

  void findResult(
    SearchResultKind kind,
    String file,
    int offset,
    int length,
    bool expected,
  ) {
    for (var result in results) {
      var location = result.location;
      if (result.kind == kind &&
          location.file == file &&
          location.offset == offset &&
          location.length == length) {
        if (!expected) {
          fail('Unexpected result $result in\n${results.join('\n')}');
        }
        this.result = result;
        return;
      }
    }
    if (expected) {
      fail(
        'Not found: "search" kind=$kind offset=$offset length=$length\nin\n${results.join('\n')}',
      );
    }
  }

  String getPathString(List<Element> path) {
    return path
        .map((Element element) {
          var kindName = element.kind.name;
          var name = element.name;
          if (name.isEmpty) {
            return kindName;
          } else {
            return '$kindName $name';
          }
        })
        .join('\n');
  }

  @override
  void processNotification(Notification notification) {
    super.processNotification(notification);
    if (notification.event == searchNotificationResults) {
      var params = SearchResultsParams.fromNotification(
        notification,
        clientUriConverter: server.uriConverter,
      );
      var id = params.id;
      var resultSet = _resultSets[id];
      if (resultSet == null) {
        resultSet = _ResultSet(id);
        _resultSets[id] = resultSet;
      }
      resultSet.results.addAll(params.results);
      resultSet.done = params.isLast;
    }
  }

  @override
  Future<void> setUp() async {
    super.setUp();
    await setRoots(included: [workspaceRootPath], excluded: []);
  }

  Future<void> waitForSearchResults() {
    var resultSet = _resultSets[searchId];
    if (resultSet != null && resultSet.done) {
      results = resultSet.results;
      return Future.value();
    }
    return Future.delayed(Duration.zero, waitForSearchResults);
  }
}

class _ResultSet {
  final String id;
  final List<SearchResult> results = <SearchResult>[];
  bool done = false;

  new(this.id);
}
