// 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 'dart:collection';

import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:test/test.dart';

import 'domain_completion_util.dart';

/// A base class for classes containing completion tests.
abstract class CompletionTestCase extends AbstractCompletionDomainTest {
  static const String CURSOR_MARKER = '!';

  List<String> get suggestedCompletions => suggestions
      .map((CompletionSuggestion suggestion) => suggestion.completion)
      .toList();

  void assertHasCompletion(
    String completion, {
    ElementKind? elementKind,
    bool? isDeprecated,
    Matcher? libraryUri,
  }) {
    var expectedOffset = completion.indexOf(CURSOR_MARKER);
    if (expectedOffset >= 0) {
      if (completion.contains(CURSOR_MARKER, expectedOffset + 1)) {
        fail(
          "Invalid completion, contains multiple cursor positions: '$completion'",
        );
      }
      completion = completion.replaceFirst(CURSOR_MARKER, '');
    } else {
      expectedOffset = completion.length;
    }
    CompletionSuggestion? matchingSuggestion;
    for (var suggestion in suggestions) {
      if (suggestion.completion == completion) {
        if (matchingSuggestion == null) {
          matchingSuggestion = suggestion;
        } else {
          // It is OK to have a class and its default constructor suggestions.
          if (matchingSuggestion.element?.kind == ElementKind.CLASS &&
                  suggestion.element?.kind == ElementKind.CONSTRUCTOR ||
              matchingSuggestion.element?.kind == ElementKind.CONSTRUCTOR &&
                  suggestion.element?.kind == ElementKind.CLASS) {
            return;
          }
          fail(
            "Expected exactly one '$completion' but found multiple:\n  $suggestedCompletions",
          );
        }
      }
    }
    if (matchingSuggestion == null) {
      fail("Expected '$completion' but found none:\n  $suggestedCompletions");
    }
    expect(matchingSuggestion.selectionOffset, equals(expectedOffset));
    expect(matchingSuggestion.selectionLength, equals(0));
    if (elementKind != null) {
      expect(matchingSuggestion.element!.kind, elementKind);
    }
    if (isDeprecated != null) {
      expect(matchingSuggestion.isDeprecated, isDeprecated);
    }
    if (libraryUri != null) {
      expect(matchingSuggestion.libraryUri, libraryUri);
    }
  }

  void assertHasNoCompletion(String completion) {
    if (suggestions.any(
      (CompletionSuggestion suggestion) => suggestion.completion == completion,
    )) {
      fail(
        "Did not expect completion '$completion' but found:\n  $suggestedCompletions",
      );
    }
  }

  /// Discard any results that do not start with the characters the user has
  /// "already typed".
  void filterResults(String content) {
    var charsAlreadyTyped = content
        .substring(replacementOffset!, completionOffset)
        .toLowerCase();
    suggestions = suggestions
        .where(
          (CompletionSuggestion suggestion) =>
              suggestion.completion.toLowerCase().startsWith(charsAlreadyTyped),
        )
        .toList();
  }

  Future<void> runTest(
    LocationSpec spec, [
    Map<String, String>? extraFiles,
  ]) async {
    await super.setUp();

    try {
      extraFiles?.forEach((String fileName, String content) {
        newFile(fileName, content);
      });

      newFile(testFile.path, spec.source);
      completionOffset = spec.testLocation;
      await getSuggestions(
        path: testFile.path,
        completionOffset: completionOffset,
        maxResults: 1 << 10,
      );

      filterResults(spec.source);
      for (var result in spec.positiveResults) {
        assertHasCompletion(result);
      }
      for (var result in spec.negativeResults) {
        assertHasNoCompletion(result);
      }
    } finally {
      await super.tearDown();
    }
  }
}

/// A specification of the completion results expected at a given location.
class LocationSpec {
  String id;
  int testLocation = -1;
  List<String> positiveResults = <String>[];
  List<String> negativeResults = <String>[];
  late String source;

  LocationSpec(this.id);

  /// Parse a set of tests from the given `originalSource`. Return a list of the
  /// specifications that were parsed.
  ///
  /// The source string has test locations embedded in it, which are identified
  /// by '!X' where X is a single character. Each X is matched to positive or
  /// negative results in the array of [validationStrings]. Validation strings
  /// contain the name of a prediction with a two character prefix. The first
  /// character of the prefix corresponds to an X in the [originalSource]. The
  /// second character is either a '+' or a '-' indicating whether the string is
  /// a positive or negative result. If logical not is needed in the source it
  /// can be represented by '!!'.
  ///
  /// The [originalSource] is the source for a test that contains test
  /// locations. The [validationStrings] are the positive and negative
  /// predictions.
  static List<LocationSpec> from(
    String originalSource,
    List<String> validationStrings,
  ) {
    Map<String, LocationSpec> tests = HashMap<String, LocationSpec>();
    var modifiedSource = originalSource;
    var modifiedPosition = 0;
    while (true) {
      var index = modifiedSource.indexOf('!', modifiedPosition);
      if (index < 0) {
        break;
      }
      var n = 1; // only delete one char for double-bangs
      var id = modifiedSource.substring(index + 1, index + 2);
      if (id != '!') {
        n = 2;
        var test = LocationSpec(id);
        tests[id] = test;
        test.testLocation = index;
      } else {
        modifiedPosition = index + 1;
      }
      modifiedSource =
          modifiedSource.substring(0, index) +
          modifiedSource.substring(index + n);
    }
    if (modifiedSource == originalSource) {
      throw StateError('No tests in source: $originalSource');
    }
    for (var result in validationStrings) {
      if (result.length < 3) {
        throw StateError('Invalid location result: $result');
      }
      var id = result.substring(0, 1);
      var sign = result.substring(1, 2);
      var value = result.substring(2);
      var test = tests[id];
      if (test == null) {
        throw StateError('Invalid location result id: $id for: $result');
      }
      test.source = modifiedSource;
      if (sign == '+') {
        test.positiveResults.add(value);
      } else if (sign == '-') {
        test.negativeResults.add(value);
      } else {
        var err = 'Invalid location result sign: $sign for: $result';
        throw StateError(err);
      }
    }
    var badPoints = <String>[];
    var badResults = <String>[];
    for (var test in tests.values) {
      if (test.testLocation == -1) {
        badPoints.add(test.id);
      }
      if (test.positiveResults.isEmpty && test.negativeResults.isEmpty) {
        badResults.add(test.id);
      }
    }
    if (!(badPoints.isEmpty && badResults.isEmpty)) {
      var err = StringBuffer();
      if (badPoints.isNotEmpty) {
        err.write('No test location for tests:');
        for (var ch in badPoints) {
          err
            ..write(' ')
            ..write(ch);
        }
        err.write(' ');
      }
      if (badResults.isNotEmpty) {
        err.write('No results for tests:');
        for (var ch in badResults) {
          err
            ..write(' ')
            ..write(ch);
        }
      }
      throw StateError(err.toString());
    }
    return tests.values.toList();
  }
}
