// Copyright (c) 2015, 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:source_span/source_span.dart';
import 'package:yaml/src/event.dart';
import 'package:yaml/yaml.dart';

/// If all of the elements of [list] are strings, return a list of strings
/// containing the same elements. Otherwise, return `null`.
List<String>? toStringList(List? list) {
  if (list == null) {
    return null;
  }
  List<String> stringList = <String>[];
  for (var element in list) {
    if (element is String) {
      stringList.add(element);
    } else {
      return null;
    }
  }
  return stringList;
}

bool _contains(YamlList l1, YamlNode n2) {
  for (YamlNode n1 in l1.nodes) {
    if (n1.value == n2.value) {
      return true;
    }
  }
  return false;
}

/// Merges two maps (of yaml) with simple override semantics, suitable for
/// merging two maps where one map defines default values that are added to
/// (and possibly overridden) by an overriding map.
class Merger {
  /// Merges a default [o1] with an overriding object [o2].
  ///
  ///   * lists are merged (without duplicates).
  ///   * lists of scalar values can be promoted to simple maps when merged with
  ///     maps of strings to booleans (e.g., ['opt1', 'opt2'] becomes
  ///     {'opt1': true, 'opt2': true}.
  ///   * maps are merged recursively.
  ///   * if map values cannot be merged, the overriding value is taken.
  ///
  YamlNode merge(YamlNode o1, YamlNode? o2) {
    // Handle promotion first.
    YamlMap listToMap(YamlList list) {
      Map<YamlNode, YamlNode> map =
          HashMap<YamlNode, YamlNode>(); // equals: _equals, hashCode: _hashCode
      ScalarEvent event =
          ScalarEvent(o1.span as FileSpan, 'true', ScalarStyle.PLAIN);
      for (var element in list.nodes) {
        map[element] = YamlScalar.internal(true, event);
      }
      return YamlMap.internal(map, o1.span, CollectionStyle.BLOCK);
    }

    if (_isListOfString(o1) && _isMapToBools(o2)) {
      o1 = listToMap(o1 as YamlList);
    } else if (_isMapToBools(o1) && _isListOfString(o2)) {
      o2 = listToMap(o2 as YamlList);
    }

    if (o1 is YamlMap && o2 is YamlMap) {
      return mergeMap(o1, o2);
    }
    if (o1 is YamlList && o2 is YamlList) {
      return mergeList(o1, o2);
    }
    // Default to override, unless the overriding value is `null`.
    return o2 ?? o1;
  }

  /// Merge lists, avoiding duplicates.
  YamlList mergeList(YamlList l1, YamlList l2) {
    List<YamlNode> list = <YamlNode>[];
    list.addAll(l1.nodes);
    for (YamlNode n2 in l2.nodes) {
      if (!_contains(l1, n2)) {
        list.add(n2);
      }
    }
    return YamlList.internal(list, l1.span, CollectionStyle.BLOCK);
  }

  /// Merge maps (recursively).
  YamlMap mergeMap(YamlMap m1, YamlMap m2) {
    Map<YamlNode, YamlNode> merged =
        HashMap<YamlNode, YamlNode>(); // equals: _equals, hashCode: _hashCode
    m1.nodes.forEach((k, v) {
      merged[k] = v;
    });
    m2.nodeMap.forEach((k, v) {
      var value = k.value;
      var mergedKey =
          merged.keys.firstWhere((key) => key.value == value, orElse: () => k)
              as YamlScalar;
      var o1 = merged[mergedKey];
      if (o1 != null) {
        merged[mergedKey] = merge(o1, v);
      } else {
        merged[mergedKey] = v;
      }
    });
    return YamlMap.internal(merged, m1.span, CollectionStyle.BLOCK);
  }

  static bool _isListOfString(Object? o) =>
      o is YamlList &&
      o.nodes.every((e) => e is YamlScalar && e.value is String);

  static bool _isMapToBools(Object? o) =>
      o is YamlMap &&
      o.nodes.values.every((v) => v is YamlScalar && v.value is bool);
}

extension YamlMapExtensions on YamlMap {
  /// Return the value associated with the key whose value matches the given
  /// [key], or `null` if there is no matching key.
  YamlNode? valueAt(String key) {
    for (var keyNode in nodes.keys) {
      if (keyNode is YamlScalar && keyNode.value == key) {
        return nodes[keyNode];
      }
    }
    return null;
  }

  /// Return the [YamlNode] representing the key that corresponds to the value
  /// represented by the [value] node.
  YamlNode? keyAtValue(YamlNode value) {
    for (var entry in nodes.entries) {
      if (entry.value == value) {
        return entry.key;
      }
    }
    return null;
  }

  /// Return the [YamlNode] associated with the given [key], or `null` if there
  /// is no matching key.
  YamlNode? getKey(String key) {
    for (YamlNode k in nodes.keys) {
      if (k is YamlScalar && k.value == key) {
        return k;
      }
    }
    return null;
  }

  /// Return [nodes] as a Map with [YamlNode] keys.
  Map<YamlNode, YamlNode> get nodeMap => nodes.cast<YamlNode, YamlNode>();
}
