use std::{borrow::Cow, sync::Arc};
use hashbrown::HashMap;
use indexmap::IndexMap;
use parking_lot::RwLock;
use serde::Serialize;
#[derive(Debug, Clone, PartialEq)]
pub enum WildDocValue {
    Null,
    Bool(bool),
    Number(serde_json::Number),
    String(String),
    Array(Vec<WildDocValue>),
    Object(IndexMap<String, WildDocValue>),
    Binary(Vec<u8>),
}
impl Serialize for WildDocValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            Self::Null => serializer.serialize_none(),
            Self::Bool(v) => v.serialize(serializer),
            Self::Number(v) => v.serialize(serializer),
            Self::String(v) => v.serialize(serializer),
            Self::Array(v) => v.serialize(serializer),
            Self::Object(v) => v.serialize(serializer),
            Self::Binary(v) => v.serialize(serializer),
        }
    }
}
impl From<serde_json::Value> for WildDocValue {
    fn from(value: serde_json::Value) -> Self {
        match value {
            serde_json::Value::Null => Self::Null,
            serde_json::Value::Bool(v) => Self::Bool(v),
            serde_json::Value::Number(v) => Self::Number(v),
            serde_json::Value::String(v) => Self::String(v),
            serde_json::Value::Array(v) => {
                Self::Array(v.into_iter().map(|v| Self::from(v)).collect())
            }
            serde_json::Value::Object(v) => {
                Self::Object(v.into_iter().map(|(k, v)| (k, Self::from(v))).collect())
            }
        }
    }
}
impl From<serde_json::Number> for WildDocValue {
    fn from(value: serde_json::Number) -> Self {
        Self::Number(value)
    }
}
impl std::fmt::Display for WildDocValue {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match self {
            Self::Null => {
                write!(f, "null")?;
                Ok(())
            }
            Self::Bool(v) => v.fmt(f),
            Self::Number(v) => v.fmt(f),
            Self::String(v) => v.fmt(f),
            Self::Array(v) => {
                write!(f, "[")?;
                let mut iter = v.iter();
                if let Some(i) = iter.next() {
                    i.fmt(f)?;
                }
                for i in iter {
                    write!(f, " , ")?;
                    i.fmt(f)?;
                }
                write!(f, "]")
            }
            Self::Object(v) => {
                write!(f, "{{")?;
                let mut iter = v.iter();
                if let Some((k, v)) = iter.next() {
                    write!(f, "\"{}\" : ", k)?;
                    v.fmt(f)?;
                }
                for (k, v) in iter {
                    write!(f, " , \"{}\" : ", k)?;
                    v.fmt(f)?;
                }
                write!(f, "}}")
            }
            Self::Binary(v) => {
                write!(f, "{:?}", v)
            }
        }
    }
}
impl WildDocValue {
    #[inline(always)]
    pub fn to_str(&self) -> Cow<str> {
        match self {
            Self::String(s) => Cow::Borrowed(s),
            Self::Binary(value) => Cow::Borrowed(unsafe { std::str::from_utf8_unchecked(value) }),
            _ => Cow::Owned(self.to_string()),
        }
    }
    #[inline(always)]
    pub fn is_object(&self) -> bool {
        match self {
            Self::Object(_) => true,
            _ => false,
        }
    }
    #[inline(always)]
    pub fn is_null(&self) -> bool {
        match self {
            Self::Null => true,
            _ => false,
        }
    }
    #[inline(always)]
    pub fn as_bool(&self) -> Option<&bool> {
        match self {
            Self::Bool(v) => Some(v),
            _ => None,
        }
    }
}
pub type Vars = HashMap<Vec<u8>, Arc<RwLock<WildDocValue>>>;
pub type VarsStack = Vec<Vars>;