// Copyright (c) 2020, 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/src/protocol_server.dart';
import 'package:analysis_server/src/services/completion/yaml/producer.dart';
import 'package:analysis_server/src/services/pub/pub_package_service.dart';
import 'package:analysis_server/src/utilities/extensions/yaml.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/util/yaml.dart';
import 'package:yaml/yaml.dart';

/// A completion generator that can produce completion suggestions for files
/// containing a YAML structure.
abstract class YamlCompletionGenerator {
  /// The resource provider used to access the content of the file in which
  /// completion was requested.
  final ResourceProvider resourceProvider;

  /// A service used for collecting Pub package information. May be `null` for
  /// generators that do not use Pub packages.
  final PubPackageService? pubPackageService;

  /// Initialize a newly created generator to use the [resourceProvider] to
  /// access the content of the file in which completion was requested.
  YamlCompletionGenerator(this.resourceProvider, this.pubPackageService);

  /// Return the producer used to produce suggestions at the top-level of the
  /// file.
  Producer get topLevelProducer;

  /// Return the completion suggestions appropriate for the given [offset] in
  /// the file at the given [filePath].
  YamlCompletionResults getSuggestions(String filePath, int offset) {
    var file = resourceProvider.getFile(filePath);
    String content;
    try {
      content = file.readAsStringSync();
    } on FileSystemException {
      // If the file doesn't exist or can't be read, then there are no
      // suggestions.
      return const YamlCompletionResults.empty();
    }
    var root = _parseYaml(content);
    if (root == null) {
      // If the contents can't be parsed, then there are no suggestions.
      return const YamlCompletionResults.empty();
    }
    var nodePath = _pathToOffset(root, offset);
    var completionNode = nodePath.last;
    var precedingText = '';
    if (completionNode is YamlScalar) {
      var value = completionNode.value;
      if (value is String && completionNode.style == ScalarStyle.PLAIN) {
        precedingText =
            value.substring(0, offset - completionNode.span.start.offset);
      } else if (value != null) {
        // There are no completions at the given location.
        return const YamlCompletionResults.empty();
      }
    }
    var request = YamlCompletionRequest(
        filePath: filePath,
        precedingText: precedingText,
        resourceProvider: resourceProvider,
        pubPackageService: pubPackageService);
    return getSuggestionsForPath(request, nodePath, offset);
  }

  /// Given the [request] to pass to producers, a [nodePath] to the node in
  /// which completions are being requested and the offset of the cursor, return
  /// the completions appropriate at that location.
  YamlCompletionResults getSuggestionsForPath(
      YamlCompletionRequest request, List<YamlNode> nodePath, int offset) {
    var producer = _producerForPath(nodePath);
    if (producer == null) {
      return const YamlCompletionResults.empty();
    }
    var invalidSuggestions = _siblingsOnPath(nodePath);
    var suggestions = <CompletionSuggestion>[];
    for (var suggestion in producer.suggestions(request)) {
      if (!invalidSuggestions.contains(suggestion.completion)) {
        suggestions.add(suggestion);
      }
    }
    final node = nodePath.isNotEmpty ? nodePath.last : null;
    int replacementOffset;
    int replacementLength;
    if (node is YamlScalar && node.containsOffset(offset)) {
      replacementOffset = node.span.start.offset;
      replacementLength = node.span.length;
    } else {
      replacementOffset = offset;
      replacementLength = 0;
    }
    return YamlCompletionResults(
        suggestions, replacementOffset, replacementLength);
  }

  /// Return the result of parsing the file [content] into a YAML node.
  YamlNode? _parseYaml(String content) {
    try {
      return loadYamlNode(content, recover: true);
    } on YamlException {
      // If the file can't be parsed, then fall through to return `null`.
    }
    return null;
  }

  /// Return a list containing the node containing the [offset] and all of the
  /// nodes between that and the [root] node. The root node is first in the list
  /// and the node containing the offset is the last element in the list.
  List<YamlNode> _pathToOffset(YamlNode root, int offset) {
    var path = <YamlNode>[];
    YamlNode? node = root;
    while (node != null) {
      path.add(node);
      node = node.childContainingOffset(offset);
    }
    return path;
  }

  /// Return the producer that should be used to produce completion suggestions
  /// for the last node in the node [path].
  Producer? _producerForPath(List<YamlNode> path) {
    Producer? producer = topLevelProducer;
    for (var i = 0; i < path.length - 1; i++) {
      var node = path[i];
      if (node is YamlMap && producer is KeyValueProducer) {
        // Value producers are based on keys, so try to locate the key for the
        // value that was next in the path.
        var key = node.keyAtValue(path[i + 1]);
        if (key is YamlScalar) {
          producer = producer.producerForKey(key.value as String);
          // Otherwise, if the item next in the path was a key itself, use the
          // current producer to provide completion for the key.
        } else if (node.nodes.containsKey(path[i + 1])) {
          return producer;
        } else {
          return null;
        }
      } else if (node is YamlList && producer is ListProducer) {
        producer = producer.element;
      } else {
        return producer;
      }
    }
    return producer;
  }

  /// Return a list of the suggestions that should not be suggested because they
  /// are already in the structure.
  List<String> _siblingsOnPath(List<YamlNode> path) {
    List<String> siblingsInList(YamlList list, YamlNode? currentElement) {
      var siblings = <String>[];
      for (var element in list.nodes) {
        if (element != currentElement && element is YamlScalar) {
          var value = element.value;
          if (value is String) {
            siblings.add(value);
          }
        }
      }
      return siblings;
    }

    List<String> siblingsInMap(YamlMap map, YamlNode? currentKey) {
      var siblings = <String>[];
      for (var key in map.nodes.keys) {
        if (key != currentKey && key is YamlScalar && key.value is String) {
          siblings.add('${key.value}: ');
        }
      }
      return siblings;
    }

    var length = path.length;
    if (length < 2) {
      return const <String>[];
    }
    var node = path[length - 1];
    if (node is YamlList) {
      return siblingsInList(node, null);
    } else if (node is YamlMap) {
      return siblingsInMap(node, null);
    }
    var parent = path[length - 2];
    if (parent is YamlList) {
      return siblingsInList(parent, node);
    } else if (parent is YamlMap) {
      return siblingsInMap(parent, node);
    }
    return const <String>[];
  }
}

class YamlCompletionResults {
  final List<CompletionSuggestion> suggestions;
  final int replacementOffset;
  final int replacementLength;

  const YamlCompletionResults(
      this.suggestions, this.replacementOffset, this.replacementLength);

  const YamlCompletionResults.empty()
      : suggestions = const [],
        replacementOffset = 0,
        replacementLength = 0;
}
