use serde::Deserialize;
use serde::de::{Visitor, SeqAccess, MapAccess, EnumAccess, VariantAccess, DeserializeSeed};

use std::borrow::Cow;
use std::io;
use std::marker::PhantomData;

use super::value::boundary as B;
use super::value::{IOValue, IOValueDomainCodec, PackedReader, TextReader, ViaCodec};
use super::value::reader::{Reader, IOBinarySource, BytesBinarySource};

pub use super::error::Error;

pub type Result<T> = std::result::Result<T, Error>;

pub struct Deserializer<'de, 'r, R: Reader<'de, IOValue>> {
    pub read: &'r mut R,
    phantom: PhantomData<&'de ()>,
}

pub fn from_bytes<'de, T>(bytes: &'de [u8]) ->
    Result<T>
where
    T: Deserialize<'de>
{
    from_reader(&mut PackedReader::new(&mut BytesBinarySource::new(bytes), IOValueDomainCodec))
}

pub fn from_text<'de, T>(text: &'de str) -> Result<T> where T: Deserialize<'de> {
    from_reader(&mut TextReader::new(&mut BytesBinarySource::new(text.as_bytes()),
                                     ViaCodec::new(IOValueDomainCodec)))
}

pub fn from_read<'de, 'r, IOR: io::Read + io::Seek, T>(read: &'r mut IOR) ->
    Result<T>
where
    T: Deserialize<'de>
{
    from_reader(&mut PackedReader::new(&mut IOBinarySource::new(read), IOValueDomainCodec))
}

pub fn from_reader<'r, 'de, R: Reader<'de, IOValue>, T>(read: &'r mut R) ->
    Result<T>
where
    T: Deserialize<'de>
{
    let mut de = Deserializer::from_reader(read);
    let t = T::deserialize(&mut de)?;
    Ok(t)
}

impl<'r, 'de, R: Reader<'de, IOValue>> Deserializer<'de, 'r, R> {
    pub fn from_reader(read: &'r mut R) -> Self {
        Deserializer { read, phantom: PhantomData }
    }
}

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

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        // Won't support this here -- use value::de::Deserializer for this
        Err(Error::CannotDeserializeAny)
    }

    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_bool(self.read.next_boolean()?)
    }

    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_i8(self.read.next_i8()?)
    }

    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_i16(self.read.next_i16()?)
    }

    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_i32(self.read.next_i32()?)
    }

    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_i64(self.read.next_i64()?)
    }

    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_u8(self.read.next_u8()?)
    }

    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_u16(self.read.next_u16()?)
    }

    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_u32(self.read.next_u32()?)
    }

    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_u64(self.read.next_u64()?)
    }

    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_f32(self.read.next_f32()?)
    }

    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_f64(self.read.next_f64()?)
    }

    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_char(self.read.next_char()?)
    }

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        match self.read.next_str()? {
            Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
            Cow::Owned(s) => visitor.visit_str(&s),
        }
    }

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

    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        match self.read.next_bytestring()? {
            Cow::Borrowed(bs) => visitor.visit_borrowed_bytes(bs),
            Cow::Owned(bs) => visitor.visit_bytes(&bs),
        }
    }

    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_byte_buf(self.read.next_bytestring()?.into_owned())
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        if let Some(mut b) = self.read.open_option()? {
            self.read.ensure_more_expected(&mut b, &B::Item::RecordField)?;
            let result = visitor.visit_some(&mut *self)?;
            self.read.ensure_complete(b, &B::Item::RecordField)?;
            Ok(result)
        } else {
            Ok(visitor.visit_none::<Error>()?)
        }
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        let b = self.read.open_simple_record("tuple", Some(0))?;
        let result = visitor.visit_unit::<Error>()?;
        self.read.ensure_complete(b, &B::Item::RecordField)?;
        Ok(result)
    }

    fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V)
                                  -> Result<V::Value> where V: Visitor<'de>
    {
        let b = self.read.open_simple_record(name, Some(0))?;
        let result = visitor.visit_unit::<Error>()?;
        self.read.ensure_complete(b, &B::Item::RecordField)?;
        Ok(result)
    }

    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V)
                                     -> Result<V::Value> where V: Visitor<'de>
    {
        match super::value::magic::transmit_input_value(
            name, || Ok(self.read.demand_next(true)?))?
        {
            Some(v) => visitor.visit_u64(v),
            None => {
                let mut b = self.read.open_simple_record(name, Some(1))?;
                self.read.ensure_more_expected(&mut b, &B::Item::RecordField)?;
                let result = visitor.visit_newtype_struct(&mut *self)?;
                self.read.ensure_complete(b, &B::Item::RecordField)?;
                Ok(result)
            }
        }
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> {
        // Hack around serde's model: Deserialize *sets* as sequences,
        // too, and reconstruct them as Rust Sets on the visitor side.
        let i = self.read.open_sequence_or_set()?;
        visitor.visit_seq(Seq::new(self, B::Type::default(), i))
    }

    fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        let b = self.read.open_simple_record("tuple", Some(len))?;
        let mut seq = Seq::new(self, b, B::Item::RecordField);
        let result = visitor.visit_seq(&mut seq)?;
        seq.skip_remainder()?;
        Ok(result)
    }

    fn deserialize_tuple_struct<V>(self, name: &'static str, len: usize, visitor: V)
                                   -> Result<V::Value> where V: Visitor<'de>
    {
        let b = self.read.open_simple_record(name, Some(len))?;
        let mut seq = Seq::new(self, b, B::Item::RecordField);
        let result = visitor.visit_seq(&mut seq)?;
        seq.skip_remainder()?;
        Ok(result)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> {
        self.read.open_dictionary()?;
        let mut seq = Seq::new(self, B::Type::default(), B::Item::DictionaryKey);
        let result = visitor.visit_map(&mut seq)?;
        Ok(result)
    }

    fn deserialize_struct<V>(self,
                             name: &'static str,
                             fields: &'static [&'static str],
                             visitor: V)
                             -> Result<V::Value> where V: Visitor<'de>
    {
        let b = self.read.open_simple_record(name, Some(fields.len()))?;
        let mut seq = Seq::new(self, b, B::Item::RecordField);
        let result = visitor.visit_seq(&mut seq)?;
        seq.skip_remainder()?;
        Ok(result)
    }

    fn deserialize_enum<V>(self,
                           _name: &'static str,
                           _variants: &'static [&'static str],
                           visitor: V)
                           -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_enum(self)
    }

    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        match self.read.next_symbol()? {
            Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
            Cow::Owned(s) => visitor.visit_str(&s),
        }
    }

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

pub struct Seq<'de, 'r, 'a, R: Reader<'de, IOValue>> {
    b: B::Type,
    i: B::Item,
    de: &'a mut Deserializer<'de, 'r, R>,
}

impl<'de, 'r, 'a, R: Reader<'de, IOValue>> Seq<'de, 'r, 'a, R> {
    fn new(de: &'a mut Deserializer<'de, 'r, R>, b: B::Type, i: B::Item) -> Self {
        Seq { b, i, de }
    }

    fn skip_remainder(&mut self) -> Result<()> {
        while !self.de.read.close_compound(&mut self.b, &self.i)? {
            self.de.read.skip_value()?;
        }
        Ok(())
    }

    fn next_item<T>(&mut self, seed: T) ->
        Result<Option<T::Value>> where T: DeserializeSeed<'de>
    {
        match self.de.read.close_compound(&mut self.b, &self.i)? {
            true => Ok(None),
            false => Ok(Some(seed.deserialize(&mut *self.de)?)),
        }
    }
}

impl<'de, 'r, 'a, R: Reader<'de, IOValue>> SeqAccess<'de> for Seq<'de, 'r, 'a, R> {
    type Error = Error;

    fn next_element_seed<T>(&mut self, seed: T) ->
        Result<Option<T::Value>> where T: DeserializeSeed<'de>
    {
        Ok(self.next_item(seed)?)
    }
}

impl<'de, 'r, 'a, R: Reader<'de, IOValue>> MapAccess<'de> for Seq<'de, 'r, 'a, R> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) ->
        Result<Option<K::Value>> where K: DeserializeSeed<'de>
    {
        self.i = B::Item::DictionaryKey;
        self.next_item(seed)
    }

    fn next_value_seed<V>(&mut self, seed: V) ->
        Result<V::Value> where V: DeserializeSeed<'de>
    {
        self.i = B::Item::DictionaryValue;
        match self.next_item(seed)? {
            Some(item) => Ok(item),
            None => Err(Error::MissingItem),
        }
    }
}

impl<'de, 'r, 'a, R: Reader<'de, IOValue>> EnumAccess<'de> for &'a mut Deserializer<'de, 'r, R> {
    type Error = Error;
    type Variant = Seq<'de, 'r, 'a, R>;

    fn variant_seed<V>(self, seed: V)
                       -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>
    {
        let b = self.read.open_record(None)?;
        let variant = seed.deserialize(&mut *self)?;
        Ok((variant, Seq::new(self, b, B::Item::RecordField)))
    }
}

impl<'de, 'r, 'a, R: Reader<'de, IOValue>> VariantAccess<'de> for Seq<'de, 'r, 'a, R> {
    type Error = Error;

    fn unit_variant(mut self) -> Result<()> {
        self.skip_remainder()
    }

    fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value> where T: DeserializeSeed<'de> {
        match self.next_item(seed)? {
            None => Err(Error::MissingItem),
            Some(v) => {
                self.skip_remainder()?;
                Ok(v)
            }
        }
    }

    fn tuple_variant<V>(mut self, _len: usize, visitor: V) ->
        Result<V::Value>
    where
        V: Visitor<'de>
    {
        let result = visitor.visit_seq(&mut self)?;
        self.skip_remainder()?;
        Ok(result)
    }

    fn struct_variant<V>(mut self, _fields: &'static [&'static str], visitor: V) ->
        Result<V::Value>
    where
        V: Visitor<'de>
    {
        let result = visitor.visit_seq(&mut self)?;
        self.skip_remainder()?;
        Ok(result)
    }
}
