//! Arbitrary data deserialization.
//!
//! The [`Deserializer`] type is a [`serde::de::Deserializer`] implementation which can deserialize arbitrary data types from [`ReadBuffer`]s.
//! It is compatible with the [`serde`] ecosystem.
//! The implementation supports both zero-copy and owned deserialization.

use crate::decode::*;
use crate::*;

/// Deserializer implementation for deserializing `petra` into arbitrary data types.
pub struct Deserializer<'de> {
    buf: ReadBufferBorrowed<'de>,
}

impl<'de> Deserializer<'de> {
    pub fn from_buffer(buf: &mut ReadBuffer<'de>) -> Self {
        Self { buf: buf.borrow() }
    }

    fn parse_seq<V>(&mut self, len: Option<usize>, visitor: V) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_seq(SeqAccess { de: self, len })
    }

    fn parse_map<V>(&mut self, len: Option<usize>, visitor: V) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_map(MapAccess { de: self, len })
    }

    fn parse_any<V>(&mut self, visitor: V) -> Result<V::Value, Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let marker = __peek_marker(&self.buf)?;
        match marker {
            Marker::ImmPos { .. } => visitor.visit_u8(__read_unsigned(&self.buf)? as _),
            Marker::ImmNeg { .. } => visitor.visit_i8(__read_signed(&self.buf)? as _),

            Marker::U8 => visitor.visit_u8(__read_u8(&self.buf)?),
            Marker::U16 => visitor.visit_u16(__read_u16(&self.buf)?),
            Marker::U32 => visitor.visit_u32(__read_u32(&self.buf)?),
            Marker::U64 => visitor.visit_u64(__read_u64(&self.buf)?),

            Marker::I8 => visitor.visit_i8(__read_i8(&self.buf)?),
            Marker::I16 => visitor.visit_i16(__read_i16(&self.buf)?),
            Marker::I32 => visitor.visit_i32(__read_i32(&self.buf)?),
            Marker::I64 => visitor.visit_i64(__read_i64(&self.buf)?),

            Marker::F32 => visitor.visit_f32(__read_f32(&self.buf)?),
            Marker::F64 => visitor.visit_f64(__read_f64(&self.buf)?),

            Marker::ImmStr { .. } | Marker::S8 | Marker::S16 | Marker::S32 => {
                visitor.visit_borrowed_str(__read_str(&self.buf)?)
            }

            Marker::ImmArr { .. } | Marker::A8 | Marker::A16 | Marker::A32 | Marker::AFlex => {
                let len = __read_array(&self.buf)?;
                self.parse_seq(len, visitor)
            }

            Marker::ImmMap { .. } | Marker::M8 | Marker::M16 | Marker::M32 | Marker::MFlex => {
                let len = __read_map(&self.buf)?;
                self.parse_map(len, visitor)
            }

            Marker::B8 | Marker::B16 | Marker::B32 => visitor.visit_bytes(__read_bin(&self.buf)?),

            Marker::Bool { .. } => visitor.visit_bool(__read_bool(&self.buf)?),
            Marker::Null => {
                self.buf.discard(1)?;
                visitor.visit_unit()
            }
            Marker::Term | Marker::Reserved => Err(Error::Unexpected),
        }
    }
}

impl<'de, 'a> serde::de::Deserializer<'de> for &'a mut Deserializer<'de> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.parse_any(visitor)
    }

    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_bool(__read_bool(&self.buf)?)
    }

    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_signed(&self.buf)?;
        if i8::MIN as isize <= value && value <= i8::MAX as _ {
            visitor.visit_i8(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_signed(&self.buf)?;
        if i16::MIN as isize <= value && value <= i16::MAX as _ {
            visitor.visit_i16(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_signed(&self.buf)?;
        if i32::MIN as isize <= value && value <= i32::MAX as _ {
            visitor.visit_i32(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_signed(&self.buf)?;
        if i64::MIN as isize <= value && value <= i64::MAX as _ {
            visitor.visit_i64(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_unsigned(&self.buf)?;
        if u8::MIN as usize <= value && value <= u8::MAX as _ {
            visitor.visit_u8(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_unsigned(&self.buf)?;
        if u16::MIN as usize <= value && value <= u16::MAX as _ {
            visitor.visit_u16(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_unsigned(&self.buf)?;
        if u32::MIN as usize <= value && value <= u32::MAX as _ {
            visitor.visit_u32(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let value = __read_unsigned(&self.buf)?;
        if u64::MIN as usize <= value && value <= u64::MAX as _ {
            visitor.visit_u64(value as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_f32(__read_f32(&self.buf)?)
    }

    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_f64(__read_f64(&self.buf)?)
    }

    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let buf = __read_str(&self.buf)?.as_bytes();
        if buf.len() == 1 {
            visitor.visit_char(buf[0] as _)
        } else {
            Err(Error::OutOfRange)
        }
    }

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_borrowed_str(__read_str(&self.buf)?)
    }

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_string(__read_str(&self.buf)?.into())
    }

    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_bytes(__read_bin(&self.buf)?)
    }

    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_byte_buf(__read_bin(&self.buf)?.into())
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        match __peek_marker(&self.buf)? {
            Marker::Null => visitor.visit_none(),
            _ => visitor.visit_some(self),
        }
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        match __read_marker(&self.buf)? {
            Marker::Null => visitor.visit_unit(),
            _ => Err(Error::Unexpected),
        }
    }

    fn deserialize_unit_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        match __read_marker(&self.buf)? {
            Marker::ImmArr { len: 0 } | Marker::Null => visitor.visit_unit(),
            _ => Err(Error::Unexpected),
        }
    }

    fn deserialize_newtype_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let len = __read_array(&self.buf)?;
        self.parse_seq(len, visitor)
    }

    fn deserialize_tuple<V>(self, expected: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let len = __read_array(&self.buf)?.ok_or(Error::Unexpected)?;
        if len != expected {
            return Err(Error::Unexpected);
        };

        self.parse_seq(Some(len), visitor)
    }

    fn deserialize_tuple_struct<V>(
        self,
        _name: &'static str,
        len: usize,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_tuple(len, visitor)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let len = __read_map(&self.buf)?;
        self.parse_map(len, visitor)
    }

    fn deserialize_struct<V>(
        self,
        _name: &'static str,
        fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        let len = __read_map(&self.buf)?.ok_or(Error::Unexpected)?;
        if len != fields.len() {
            return Err(Error::Unexpected);
        }

        self.parse_map(Some(len), visitor)
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        // Can be                               -->   serialized as
        //   - unit variant     E::A            -->   str
        //   - newtype variant  E::A(u8)        -->   map { str: value }
        //   - tuple variant    E::A(u8, &str)  -->   map { str: sequence }
        //   - struct variant   E::A { f: u8 }  -->   map { str: map }

        let marker = __peek_marker(&self.buf)?;
        let encoded_as_str = if marker.is_str() {
            true
        } else if marker.is_map() {
            if __read_map(&self.buf)?.ok_or(Error::Unexpected)? != 1 {
                return Err(Error::Unexpected);
            }

            false
        } else {
            return Err(Error::Unexpected);
        };

        visitor.visit_enum(EnumAccess {
            de: self,
            encoded_as_str,
        })
    }

    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_str(visitor)
    }

    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        self.deserialize_any(visitor)
    }
}

struct SeqAccess<'a, 'de> {
    de: &'a mut Deserializer<'de>,
    len: Option<usize>,
}

impl<'a, 'de> serde::de::SeqAccess<'de> for SeqAccess<'a, 'de> {
    type Error = Error;

    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    where
        T: serde::de::DeserializeSeed<'de>,
    {
        match self.len.as_mut() {
            Some(len) => {
                if *len == 0 {
                    return Ok(None);
                }

                *len -= 1;

                Ok(Some(seed.deserialize(&mut *self.de)?))
            }
            None => match __peek_marker(&self.de.buf)? {
                Marker::Term => {
                    // Skip the terminator
                    self.de.buf.discard(1).unwrap_or_else(|_| unreachable!());

                    Ok(None)
                }
                _ => Ok(Some(seed.deserialize(&mut *self.de)?)),
            },
        }
    }

    fn size_hint(&self) -> Option<usize> {
        self.len
    }
}

struct MapAccess<'a, 'de> {
    de: &'a mut Deserializer<'de>,
    len: Option<usize>,
}

impl<'a, 'de> serde::de::MapAccess<'de> for MapAccess<'a, 'de> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    where
        K: serde::de::DeserializeSeed<'de>,
    {
        match self.len.as_mut() {
            Some(0) => Ok(None),
            Some(len) => {
                *len -= 1;
                Ok(Some(seed.deserialize(&mut *self.de)?))
            }
            None => match __peek_marker(&self.de.buf)? {
                Marker::Term => {
                    // Skip the terminator
                    self.de.buf.discard(1).unwrap_or_else(|_| unreachable!());

                    Ok(None)
                }
                _ => Ok(Some(seed.deserialize(&mut *self.de)?)),
            },
        }
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::DeserializeSeed<'de>,
    {
        seed.deserialize(&mut *self.de)
    }

    #[inline(always)]
    fn size_hint(&self) -> Option<usize> {
        self.len
    }
}

struct EnumAccess<'a, 'de> {
    de: &'a mut Deserializer<'de>,
    encoded_as_str: bool,
}

impl<'a, 'de> serde::de::EnumAccess<'de> for EnumAccess<'a, 'de> {
    type Error = Error;
    type Variant = Self;

    #[inline]
    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
    where
        V: serde::de::DeserializeSeed<'de>,
    {
        Ok((seed.deserialize(&mut *self.de)?, self))
    }
}

impl<'de, 'a> serde::de::VariantAccess<'de> for EnumAccess<'a, 'de> {
    type Error = Error;

    #[inline]
    fn unit_variant(self) -> Result<(), Self::Error> {
        if self.encoded_as_str {
            return Ok(());
        }

        let marker = __read_marker(&self.de.buf)?;
        if !matches!(marker, Marker::Null) {
            return Err(Error::Unexpected);
        }

        Ok(())
    }

    #[inline]
    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
    where
        T: serde::de::DeserializeSeed<'de>,
    {
        if self.encoded_as_str {
            return Err(Error::Unexpected);
        }

        seed.deserialize(self.de)
    }

    #[inline]
    fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        if self.encoded_as_str {
            return Err(Error::Unexpected);
        }

        serde::de::Deserializer::deserialize_tuple(self.de, len, visitor)
    }

    #[inline]
    fn struct_variant<V>(
        self,
        fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: serde::de::Visitor<'de>,
    {
        serde::de::Deserializer::deserialize_struct(self.de, "", fields, visitor)
    }
}

#[cfg(test)]
mod tests;
