// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Two maps are equal when they hold the same entries **in the same order**.
///
/// Order is part of the content here, so maps built from the same pairs in
/// different orders are not equal — which is what a consumer rendering the
/// entries needs, since a reordering is a visible change. The comparison reads
/// the live entries only: tombstone layout is representation, and two equal
/// maps reached by different histories may well have different spines.
///
/// `O(1)` when the two are physically identical or differ in length, `O(n)`
/// otherwise — and it stops at the first entry that differs.
pub impl[K : Eq, V : Eq] Eq for VectorMap[K, V] with fn equal(self, other) {
  if physical_equal(self, other) {
    return true
  }
  // Comparing lengths first is not just a shortcut: the walk below stops after
  // `self.size` entries, so without it a map would compare equal to any longer
  // map it is a prefix of — and `Eq` would not even be symmetric.
  guard self.size == other.size else { return false }
  let left = self.iter()
  let right = other.iter()
  for _ in 0.. (Repr(k), Repr(v)) ]),
  )
}

///|
/// Serialise as an array of `[key, value]` pairs.
///
/// An array rather than an object, because the point of this type is the order
/// of its entries and JSON object member order is not something a reader is
/// obliged to preserve. It also keeps non-string keys intact. `O(n)`.
pub impl[K : ToJson, V : ToJson] ToJson for VectorMap[K, V] with fn to_json(
  self,
) {
  [
    for k, v in self => ([k, v] : Json)
  ]
}

///|
/// Decode an array of `[key, value]` pairs, applying the same duplicate-key rule
/// as the array constructor, at the same `O(m log n)` for `m` pairs.
pub impl[K : @json.FromJson + Eq + Hash, V : @json.FromJson] @json.FromJson for VectorMap[
  K,
  V,
] with fn from_json(json, path) {
  guard json is Array(pairs) else {
    raise JsonDecodeError((path, "@immut/vector_map.from_json: expected array"))
  }
  let entries : Array[(K, V)] = Array(capacity=pairs.length())
  for i, pair in pairs {
    let entry_path = path.add_index(i)
    guard pair is Array([key, value]) else {
      raise JsonDecodeError(
        (entry_path, "@immut/vector_map.from_json: expected [key, value] pair"),
      )
    }
    entries.push(
      (
        @json.FromJson::from_json(key, entry_path.add_index(0)),
        @json.FromJson::from_json(value, entry_path.add_index(1)),
      ),
    )
  }
  from_pairs(entries.iter())
}