use serde::de::{self, IgnoredAny};
use crate::value::{number::Number, JsoncValue};
use super::{map::ValueMapDeserializer, number::FromNumber, r#enum::ValueEnumDeserializer, seq::ValueSeqDeserializer};
pub struct ValueDeserializer<'de, I, F> {
    pub(crate) value: &'de JsoncValue<I, F>,
}
impl<'de, I, F> ValueDeserializer<'de, I, F>
where
    I: num::ToPrimitive,
    F: num::ToPrimitive,
{
    pub fn new(value: &'de JsoncValue<I, F>) -> Self {
        Self { value }
    }
    pub fn deserialize_number_value<V, Fn, N>(self, visitor: V, f: Fn) -> crate::Result<V::Value>
    where
        V: de::Visitor<'de>,
        N: FromNumber<I, F>,
        N::Err: de::Error,
        crate::Error: From<N::Err>,
        Fn: FnOnce(V, N) -> Result<V::Value, N::Err>,
    {
        match self.value.as_number() {
            Some(number) => Ok(f(visitor, FromNumber::from_number(number)?)?),
            _ => Err(self.invalid_type::<crate::Error>(&visitor))?,
        }
    }
    pub fn invalid_type<E: de::Error>(&self, exp: &dyn de::Expected) -> E {
        E::invalid_type(self.unexpected(), exp)
    }
    pub fn unexpected(&self) -> de::Unexpected {
        match &self.value {
            JsoncValue::Object(_) => de::Unexpected::Map,
            JsoncValue::Array(_) => de::Unexpected::Seq,
            JsoncValue::Bool(b) => de::Unexpected::Bool(*b),
            JsoncValue::Null => de::Unexpected::Unit,
            JsoncValue::String(s) => de::Unexpected::Str(s),
            JsoncValue::Number(n) => match n {
                Number::Integer(i) => match i.to_i64() {
                    Some(signed) => de::Unexpected::Signed(signed),
                    None => de::Unexpected::Other("number"),
                },
                Number::Float(f) => match f.to_f64() {
                    Some(float) => de::Unexpected::Float(float),
                    None => de::Unexpected::Other("number"),
                },
            },
        }
    }
}
impl<'de, I, F> de::Deserializer<'de> for ValueDeserializer<'de, I, F>
where
    I: num::ToPrimitive,
    F: num::ToPrimitive,
{
    type Error = crate::Error;
    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value {
            JsoncValue::Object(_) => self.deserialize_map(visitor),
            JsoncValue::Array(_) => self.deserialize_seq(visitor),
            JsoncValue::Bool(_) => self.deserialize_bool(visitor),
            JsoncValue::Null => self.deserialize_unit(visitor),
            JsoncValue::String(_) => self.deserialize_str(visitor),
            JsoncValue::Number(n) => match n {
                Number::Integer(_) => self.deserialize_i64(visitor), Number::Float(_) => self.deserialize_f64(visitor),
            },
        }
    }
    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value.as_bool() {
            Some(&b) => visitor.visit_bool(b),
            None => Err(self.invalid_type::<crate::Error>(&visitor))?,
        }
    }
    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_i8(n))
    }
    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_i16(n))
    }
    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_i32(n))
    }
    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_i64(n))
    }
    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_u8(n))
    }
    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_u16(n))
    }
    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_u32(n))
    }
    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_u64(n))
    }
    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_f32(n))
    }
    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_number_value(visitor, |v, n| v.visit_f64(n))
    }
    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_str(visitor)
    }
    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value.as_str() {
            Some(s) => visitor.visit_borrowed_str(s),
            None => Err(self.invalid_type::<crate::Error>(&visitor))?,
        }
    }
    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_str(visitor)
    }
    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value.as_str() {
            Some(s) => visitor.visit_str(s),
            _ => Err(self.invalid_type(&visitor)),
        }
    }
    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_bytes(visitor)
    }
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value.as_unit() {
            Some(()) => visitor.visit_none(),
            None => visitor.visit_some(self),
        }
    }
    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value.as_unit() {
            Some(()) => visitor.visit_unit(),
            None => Err(self.invalid_type(&visitor)),
        }
    }
    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_unit(visitor)
    }
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_newtype_struct(self)
    }
    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value.as_vec() {
            Some(v) => visitor.visit_seq(ValueSeqDeserializer::new(v)),
            None => Err(self.invalid_type(&visitor)),
        }
    }
    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_seq(visitor)
    }
    fn deserialize_tuple_struct<V>(self, _name: &'static str, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_seq(visitor)
    }
    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value.as_map() {
            Some(m) => visitor.visit_map(ValueMapDeserializer::new(m)),
            None => Err(self.invalid_type(&visitor)),
        }
    }
    fn deserialize_struct<V>(
        self,
        _name: &'static str,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value {
            JsoncValue::Array(_) => self.deserialize_seq(visitor),
            JsoncValue::Object(_) => self.deserialize_map(visitor),
            _ => Err(self.invalid_type(&visitor)),
        }
    }
    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.value {
            JsoncValue::Object(m) => {
                let mut iter = m.iter();
                match (iter.next(), iter.next()) {
                    (Some((key, value)), None) => visitor.visit_enum(ValueEnumDeserializer::new(key, Some(value))),
                    _ => Err(self.invalid_type(&visitor)),
                }
            }
            JsoncValue::String(s) => visitor.visit_enum(ValueEnumDeserializer::<I, F>::new(s, None)),
            _ => Err(self.invalid_type(&visitor)),
        }
    }
    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_str(visitor)
    }
    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let _ = self.deserialize_any(IgnoredAny)?;
        visitor.visit_unit()
    }
}