use crate::{private, Value};
use indexmap::IndexMap;
use serde::{Deserialize, Deserializer, Serialize};
use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::fmt::{self, Display};
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::mem;
#[derive(Clone, Default, Eq, PartialEq)]
pub struct Mapping {
    map: IndexMap<Value, Value>,
}
impl Mapping {
    #[inline]
    pub fn new() -> Self {
        Self::default()
    }
    #[inline]
    pub fn with_capacity(capacity: usize) -> Self {
        Mapping {
            map: IndexMap::with_capacity(capacity),
        }
    }
    #[inline]
    pub fn reserve(&mut self, additional: usize) {
        self.map.reserve(additional);
    }
    #[inline]
    pub fn shrink_to_fit(&mut self) {
        self.map.shrink_to_fit();
    }
    #[inline]
    pub fn insert(&mut self, k: Value, v: Value) -> Option<Value> {
        self.map.insert(k, v)
    }
    #[inline]
    pub fn contains_key<I: Index>(&self, index: I) -> bool {
        index.is_key_into(self)
    }
    #[inline]
    pub fn get<I: Index>(&self, index: I) -> Option<&Value> {
        index.index_into(self)
    }
    #[inline]
    pub fn get_mut<I: Index>(&mut self, index: I) -> Option<&mut Value> {
        index.index_into_mut(self)
    }
    #[inline]
    pub fn entry(&mut self, k: Value) -> Entry {
        match self.map.entry(k) {
            indexmap::map::Entry::Occupied(occupied) => Entry::Occupied(OccupiedEntry { occupied }),
            indexmap::map::Entry::Vacant(vacant) => Entry::Vacant(VacantEntry { vacant }),
        }
    }
    #[inline]
    pub fn remove<I: Index>(&mut self, index: I) -> Option<Value> {
        index.remove_from(self)
    }
    #[inline]
    pub fn remove_entry<I: Index>(&mut self, index: I) -> Option<(Value, Value)> {
        index.remove_entry_from(self)
    }
    #[inline]
    pub fn retain<F>(&mut self, keep: F)
    where
        F: FnMut(&Value, &mut Value) -> bool,
    {
        self.map.retain(keep);
    }
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }
    #[inline]
    pub fn clear(&mut self) {
        self.map.clear();
    }
    #[inline]
    pub fn iter(&self) -> Iter {
        Iter {
            iter: self.map.iter(),
        }
    }
    #[inline]
    pub fn iter_mut(&mut self) -> IterMut {
        IterMut {
            iter: self.map.iter_mut(),
        }
    }
    pub fn keys(&self) -> Keys {
        Keys {
            iter: self.map.keys(),
        }
    }
    pub fn into_keys(self) -> IntoKeys {
        IntoKeys {
            iter: self.map.into_keys(),
        }
    }
    pub fn values(&self) -> Values {
        Values {
            iter: self.map.values(),
        }
    }
    pub fn values_mut(&mut self) -> ValuesMut {
        ValuesMut {
            iter: self.map.values_mut(),
        }
    }
    pub fn into_values(self) -> IntoValues {
        IntoValues {
            iter: self.map.into_values(),
        }
    }
}
pub trait Index: private::Sealed {
    #[doc(hidden)]
    fn is_key_into(&self, v: &Mapping) -> bool;
    #[doc(hidden)]
    fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value>;
    #[doc(hidden)]
    fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value>;
    #[doc(hidden)]
    fn remove_from(&self, v: &mut Mapping) -> Option<Value>;
    #[doc(hidden)]
    fn remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)>;
}
struct HashLikeValue<'a>(&'a str);
impl<'a> indexmap::Equivalent<Value> for HashLikeValue<'a> {
    fn equivalent(&self, key: &Value) -> bool {
        match key {
            Value::String(string) => self.0 == string,
            _ => false,
        }
    }
}
impl<'a> Hash for HashLikeValue<'a> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        const STRING: Value = Value::String(String::new());
        mem::discriminant(&STRING).hash(state);
        self.0.hash(state);
    }
}
impl Index for Value {
    fn is_key_into(&self, v: &Mapping) -> bool {
        v.map.contains_key(self)
    }
    fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> {
        v.map.get(self)
    }
    fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> {
        v.map.get_mut(self)
    }
    fn remove_from(&self, v: &mut Mapping) -> Option<Value> {
        v.map.remove(self)
    }
    fn remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> {
        v.map.remove_entry(self)
    }
}
impl Index for str {
    fn is_key_into(&self, v: &Mapping) -> bool {
        v.map.contains_key(&HashLikeValue(self))
    }
    fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> {
        v.map.get(&HashLikeValue(self))
    }
    fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> {
        v.map.get_mut(&HashLikeValue(self))
    }
    fn remove_from(&self, v: &mut Mapping) -> Option<Value> {
        v.map.remove(&HashLikeValue(self))
    }
    fn remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> {
        v.map.remove_entry(&HashLikeValue(self))
    }
}
impl Index for String {
    fn is_key_into(&self, v: &Mapping) -> bool {
        self.as_str().is_key_into(v)
    }
    fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> {
        self.as_str().index_into(v)
    }
    fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> {
        self.as_str().index_into_mut(v)
    }
    fn remove_from(&self, v: &mut Mapping) -> Option<Value> {
        self.as_str().remove_from(v)
    }
    fn remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> {
        self.as_str().remove_entry_from(v)
    }
}
impl<T> Index for &T
where
    T: ?Sized + Index,
{
    fn is_key_into(&self, v: &Mapping) -> bool {
        (**self).is_key_into(v)
    }
    fn index_into<'a>(&self, v: &'a Mapping) -> Option<&'a Value> {
        (**self).index_into(v)
    }
    fn index_into_mut<'a>(&self, v: &'a mut Mapping) -> Option<&'a mut Value> {
        (**self).index_into_mut(v)
    }
    fn remove_from(&self, v: &mut Mapping) -> Option<Value> {
        (**self).remove_from(v)
    }
    fn remove_entry_from(&self, v: &mut Mapping) -> Option<(Value, Value)> {
        (**self).remove_entry_from(v)
    }
}
#[allow(clippy::derived_hash_with_manual_eq)]
impl Hash for Mapping {
    fn hash<H: Hasher>(&self, state: &mut H) {
        let mut xor = 0;
        for (k, v) in self {
            let mut hasher = DefaultHasher::new();
            k.hash(&mut hasher);
            v.hash(&mut hasher);
            xor ^= hasher.finish();
        }
        xor.hash(state);
    }
}
impl PartialOrd for Mapping {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        let mut self_entries = Vec::from_iter(self);
        let mut other_entries = Vec::from_iter(other);
        fn total_cmp(a: &Value, b: &Value) -> Ordering {
            match (a, b) {
                (Value::Null, Value::Null) => Ordering::Equal,
                (Value::Null, _) => Ordering::Less,
                (_, Value::Null) => Ordering::Greater,
                (Value::Bool(a), Value::Bool(b)) => a.cmp(b),
                (Value::Bool(_), _) => Ordering::Less,
                (_, Value::Bool(_)) => Ordering::Greater,
                (Value::Number(a), Value::Number(b)) => a.total_cmp(b),
                (Value::Number(_), _) => Ordering::Less,
                (_, Value::Number(_)) => Ordering::Greater,
                (Value::String(a), Value::String(b)) => a.cmp(b),
                (Value::String(_), _) => Ordering::Less,
                (_, Value::String(_)) => Ordering::Greater,
                (Value::Sequence(a), Value::Sequence(b)) => iter_cmp_by(a, b, total_cmp),
                (Value::Sequence(_), _) => Ordering::Less,
                (_, Value::Sequence(_)) => Ordering::Greater,
                (Value::Mapping(a), Value::Mapping(b)) => {
                    iter_cmp_by(a, b, |(ak, av), (bk, bv)| {
                        total_cmp(ak, bk).then_with(|| total_cmp(av, bv))
                    })
                }
                (Value::Mapping(_), _) => Ordering::Less,
                (_, Value::Mapping(_)) => Ordering::Greater,
                (Value::Tagged(a), Value::Tagged(b)) => a
                    .tag
                    .cmp(&b.tag)
                    .then_with(|| total_cmp(&a.value, &b.value)),
            }
        }
        fn iter_cmp_by<I, F>(this: I, other: I, mut cmp: F) -> Ordering
        where
            I: IntoIterator,
            F: FnMut(I::Item, I::Item) -> Ordering,
        {
            let mut this = this.into_iter();
            let mut other = other.into_iter();
            loop {
                let x = match this.next() {
                    None => {
                        if other.next().is_none() {
                            return Ordering::Equal;
                        } else {
                            return Ordering::Less;
                        }
                    }
                    Some(val) => val,
                };
                let y = match other.next() {
                    None => return Ordering::Greater,
                    Some(val) => val,
                };
                match cmp(x, y) {
                    Ordering::Equal => {}
                    non_eq => return non_eq,
                }
            }
        }
        let total_cmp = |&(a, _): &_, &(b, _): &_| total_cmp(a, b);
        self_entries.sort_by(total_cmp);
        other_entries.sort_by(total_cmp);
        self_entries.partial_cmp(&other_entries)
    }
}
impl<I> std::ops::Index<I> for Mapping
where
    I: Index,
{
    type Output = Value;
    #[inline]
    #[track_caller]
    fn index(&self, index: I) -> &Value {
        index.index_into(self).unwrap()
    }
}
impl<I> std::ops::IndexMut<I> for Mapping
where
    I: Index,
{
    #[inline]
    #[track_caller]
    fn index_mut(&mut self, index: I) -> &mut Value {
        index.index_into_mut(self).unwrap()
    }
}
impl Extend<(Value, Value)> for Mapping {
    #[inline]
    fn extend<I: IntoIterator<Item = (Value, Value)>>(&mut self, iter: I) {
        self.map.extend(iter);
    }
}
impl FromIterator<(Value, Value)> for Mapping {
    #[inline]
    fn from_iter<I: IntoIterator<Item = (Value, Value)>>(iter: I) -> Self {
        Mapping {
            map: IndexMap::from_iter(iter),
        }
    }
}
macro_rules! delegate_iterator {
    (($name:ident $($generics:tt)*) => $item:ty) => {
        impl $($generics)* Iterator for $name $($generics)* {
            type Item = $item;
            #[inline]
            fn next(&mut self) -> Option<Self::Item> {
                self.iter.next()
            }
            #[inline]
            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter.size_hint()
            }
        }
        impl $($generics)* ExactSizeIterator for $name $($generics)* {
            #[inline]
            fn len(&self) -> usize {
                self.iter.len()
            }
        }
    }
}
pub struct Iter<'a> {
    iter: indexmap::map::Iter<'a, Value, Value>,
}
delegate_iterator!((Iter<'a>) => (&'a Value, &'a Value));
impl<'a> IntoIterator for &'a Mapping {
    type Item = (&'a Value, &'a Value);
    type IntoIter = Iter<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        Iter {
            iter: self.map.iter(),
        }
    }
}
pub struct IterMut<'a> {
    iter: indexmap::map::IterMut<'a, Value, Value>,
}
delegate_iterator!((IterMut<'a>) => (&'a Value, &'a mut Value));
impl<'a> IntoIterator for &'a mut Mapping {
    type Item = (&'a Value, &'a mut Value);
    type IntoIter = IterMut<'a>;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IterMut {
            iter: self.map.iter_mut(),
        }
    }
}
pub struct IntoIter {
    iter: indexmap::map::IntoIter<Value, Value>,
}
delegate_iterator!((IntoIter) => (Value, Value));
impl IntoIterator for Mapping {
    type Item = (Value, Value);
    type IntoIter = IntoIter;
    #[inline]
    fn into_iter(self) -> Self::IntoIter {
        IntoIter {
            iter: self.map.into_iter(),
        }
    }
}
pub struct Keys<'a> {
    iter: indexmap::map::Keys<'a, Value, Value>,
}
delegate_iterator!((Keys<'a>) => &'a Value);
pub struct IntoKeys {
    iter: indexmap::map::IntoKeys<Value, Value>,
}
delegate_iterator!((IntoKeys) => Value);
pub struct Values<'a> {
    iter: indexmap::map::Values<'a, Value, Value>,
}
delegate_iterator!((Values<'a>) => &'a Value);
pub struct ValuesMut<'a> {
    iter: indexmap::map::ValuesMut<'a, Value, Value>,
}
delegate_iterator!((ValuesMut<'a>) => &'a mut Value);
pub struct IntoValues {
    iter: indexmap::map::IntoValues<Value, Value>,
}
delegate_iterator!((IntoValues) => Value);
pub enum Entry<'a> {
    Occupied(OccupiedEntry<'a>),
    Vacant(VacantEntry<'a>),
}
pub struct OccupiedEntry<'a> {
    occupied: indexmap::map::OccupiedEntry<'a, Value, Value>,
}
pub struct VacantEntry<'a> {
    vacant: indexmap::map::VacantEntry<'a, Value, Value>,
}
impl<'a> Entry<'a> {
    pub fn key(&self) -> &Value {
        match self {
            Entry::Vacant(e) => e.key(),
            Entry::Occupied(e) => e.key(),
        }
    }
    pub fn or_insert(self, default: Value) -> &'a mut Value {
        match self {
            Entry::Vacant(entry) => entry.insert(default),
            Entry::Occupied(entry) => entry.into_mut(),
        }
    }
    pub fn or_insert_with<F>(self, default: F) -> &'a mut Value
    where
        F: FnOnce() -> Value,
    {
        match self {
            Entry::Vacant(entry) => entry.insert(default()),
            Entry::Occupied(entry) => entry.into_mut(),
        }
    }
    pub fn and_modify<F>(self, f: F) -> Self
    where
        F: FnOnce(&mut Value),
    {
        match self {
            Entry::Occupied(mut entry) => {
                f(entry.get_mut());
                Entry::Occupied(entry)
            }
            Entry::Vacant(entry) => Entry::Vacant(entry),
        }
    }
}
impl<'a> OccupiedEntry<'a> {
    #[inline]
    pub fn key(&self) -> &Value {
        self.occupied.key()
    }
    #[inline]
    pub fn get(&self) -> &Value {
        self.occupied.get()
    }
    #[inline]
    pub fn get_mut(&mut self) -> &mut Value {
        self.occupied.get_mut()
    }
    #[inline]
    pub fn into_mut(self) -> &'a mut Value {
        self.occupied.into_mut()
    }
    #[inline]
    pub fn insert(&mut self, value: Value) -> Value {
        self.occupied.insert(value)
    }
    #[inline]
    pub fn remove(self) -> Value {
        self.occupied.swap_remove()
    }
    #[inline]
    pub fn remove_entry(self) -> (Value, Value) {
        self.occupied.swap_remove_entry()
    }
}
impl<'a> VacantEntry<'a> {
    #[inline]
    pub fn key(&self) -> &Value {
        self.vacant.key()
    }
    #[inline]
    pub fn into_key(self) -> Value {
        self.vacant.into_key()
    }
    #[inline]
    pub fn insert(self, value: Value) -> &'a mut Value {
        self.vacant.insert(value)
    }
}
impl Serialize for Mapping {
    #[inline]
    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        use serde::ser::SerializeMap;
        let mut map_serializer = serializer.serialize_map(Some(self.len()))?;
        for (k, v) in self {
            map_serializer.serialize_entry(k, v)?;
        }
        map_serializer.end()
    }
}
impl<'de> Deserialize<'de> for Mapping {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct Visitor;
        impl<'de> serde::de::Visitor<'de> for Visitor {
            type Value = Mapping;
            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a YAML mapping")
            }
            #[inline]
            fn visit_unit<E>(self) -> Result<Self::Value, E>
            where
                E: serde::de::Error,
            {
                Ok(Mapping::new())
            }
            #[inline]
            fn visit_map<A>(self, mut data: A) -> Result<Self::Value, A::Error>
            where
                A: serde::de::MapAccess<'de>,
            {
                let mut mapping = Mapping::new();
                while let Some(key) = data.next_key()? {
                    match mapping.entry(key) {
                        Entry::Occupied(entry) => {
                            return Err(serde::de::Error::custom(DuplicateKeyError { entry }));
                        }
                        Entry::Vacant(entry) => {
                            let value = data.next_value()?;
                            entry.insert(value);
                        }
                    }
                }
                Ok(mapping)
            }
        }
        deserializer.deserialize_map(Visitor)
    }
}
struct DuplicateKeyError<'a> {
    entry: OccupiedEntry<'a>,
}
impl<'a> Display for DuplicateKeyError<'a> {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("duplicate entry ")?;
        match self.entry.key() {
            Value::Null => formatter.write_str("with null key"),
            Value::Bool(boolean) => write!(formatter, "with key `{}`", boolean),
            Value::Number(number) => write!(formatter, "with key {}", number),
            Value::String(string) => write!(formatter, "with key {:?}", string),
            Value::Sequence(_) | Value::Mapping(_) | Value::Tagged(_) => {
                formatter.write_str("in YAML map")
            }
        }
    }
}