use crate::value::repr::{Float, Double};
use crate::value::{Value, NestedValue, IOValue, UnwrappedIOValue, Map};
use crate::error::{Error, ExpectedKind, Received};
use serde::Deserialize;
use serde::de::{Visitor, SeqAccess, MapAccess, EnumAccess, VariantAccess, DeserializeSeed};
use std::iter::Iterator;

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

pub struct Deserializer<'de> {
    input: &'de IOValue,
}

pub fn from_value<'a, T>(v: &'a IOValue) -> Result<T> where T: Deserialize<'a>
{
    let mut de = Deserializer::from_value(v);
    let t = T::deserialize(&mut de)?;
    Ok(t)
}

impl<'de> Deserializer<'de> {
    pub fn from_value(v: &'de IOValue) -> Self {
        Deserializer { input: v }
    }

    fn check<'a, T, F>(&'a mut self, f: F, k: ExpectedKind) -> Result<T>
    where F: FnOnce(&'de UnwrappedIOValue) -> Option<T>
    {
        f(self.input.value()).ok_or_else(
            || Error::Expected(k, Received::ReceivedOtherValue(format!("{:?}", self.input))))
    }
}

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> where V: Visitor<'de>
    {
        let v = self.input.value();
        match v {
            Value::Boolean(b) => visitor.visit_bool(*b),
            Value::Float(Float(f)) => visitor.visit_f32(*f),
            Value::Double(Double(d)) => visitor.visit_f64(*d),
            Value::String(ref s) => visitor.visit_str(&s),
            Value::ByteString(_) => self.deserialize_bytes(visitor),
            Value::Record(_) =>
                if v.is_simple_record("tuple", Some(0)) {
                    self.deserialize_unit(visitor)
                } else if v.is_simple_record("UnicodeScalar", Some(1)) {
                    self.deserialize_char(visitor)
                } else if v.is_simple_record("None", Some(0)) || v.is_simple_record("Some", Some(1)) {
                    self.deserialize_option(visitor)
                } else if v.is_simple_record("tuple", None) {
                    visitor.visit_seq(VecSeq::new(self, v.as_simple_record("tuple", None).unwrap().iter()))
                } else {
                    Err(Error::CannotDeserializeAny)
                }
            Value::Sequence(ref v) => visitor.visit_seq(VecSeq::new(self, v.iter())),
            Value::Dictionary(ref d) => visitor.visit_map(DictMap::new(self, d)),
            _ => match v.as_i64() {
                Some(i) => visitor.visit_i64(i),
                None => match v.as_u64() {
                    Some(u) => visitor.visit_u64(u),
                    None => match v.as_signedinteger() {
                        Some(n) => Err(Error::NumberOutOfRange(n.into())),
                        None => Err(Error::CannotDeserializeAny),
                    }
                }
            }
        }
    }

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

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

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

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

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

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

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

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

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

    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        match self.input.value().as_f64() {
            Some(d) => visitor.visit_f32(d as f32),
            None => visitor.visit_f32(self.input.value().to_f32()?),
        }
    }

    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        match self.input.value().as_f32() {
            Some(f) => visitor.visit_f64(f as f64),
            None => visitor.visit_f64(self.input.value().to_f64()?),
        }
    }

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

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        let s: &'de str = &self.input.value().to_string()?;
        visitor.visit_borrowed_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>
    {
        let bs: &'de [u8] = &self.input.value().to_bytestring()?;
        visitor.visit_borrowed_bytes(bs)
    }

    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_byte_buf(self.input.value().to_bytestring()?.clone())
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        match self.input.value().to_option()? {
            None => visitor.visit_none(),
            Some(v) => {
                self.input = v;
                visitor.visit_some(self)
            }
        }
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        let _fs = self.input.value().to_simple_record("tuple", Some(0))?;
        visitor.visit_unit()
    }

    fn deserialize_unit_struct<V>(self, name: &'static str, visitor: V)
                                  -> Result<V::Value> where V: Visitor<'de>
    {
        let _fs = self.input.value().to_simple_record(name, Some(0))?;
        visitor.visit_unit()
    }

    fn deserialize_newtype_struct<V>(self, name: &'static str, visitor: V)
                                     -> Result<V::Value> where V: Visitor<'de>
    {
        match super::magic::transmit_input_value(name, || Ok(self.input.clone()))? {
            Some(v) => visitor.visit_u64(v),
            None => {
                let fs = self.input.value().to_simple_record(name, Some(1))?;
                self.input = &fs[0];
                visitor.visit_newtype_struct(self)
            }
        }
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> {
        match self.input.value().as_sequence() {
            Some(vs) => visitor.visit_seq(VecSeq::new(self, vs.iter())),
            None => {
                // Hack around serde's model: Deserialize *sets* as
                // sequences, too, and reconstruct them as Rust Sets
                // on the visitor side.
                visitor.visit_seq(VecSeq::new(self, self.input.value().to_set()?.iter()))
            }
        }
    }

    fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value> where V: Visitor<'de>
    {
        let fs = self.input.value().to_simple_record("tuple", Some(len))?;
        visitor.visit_seq(VecSeq::new(self, fs.iter()))
    }

    fn deserialize_tuple_struct<V>(self, name: &'static str, len: usize, visitor: V)
                                   -> Result<V::Value> where V: Visitor<'de>
    {
        let fs = self.input.value().to_simple_record(name, Some(len))?;
        visitor.visit_seq(VecSeq::new(self, fs.iter()))
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value> where V: Visitor<'de> {
        let d = self.input.value().to_dictionary()?;
        visitor.visit_map(DictMap::new(self, d))
    }

    fn deserialize_struct<V>(self,
                             name: &'static str,
                             fields: &'static [&'static str],
                             visitor: V)
                             -> Result<V::Value> where V: Visitor<'de>
    {
        let fs = self.input.value().to_simple_record(name, Some(fields.len()))?;
        visitor.visit_seq(VecSeq::new(self, fs.iter()))
    }

    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>
    {
        visitor.visit_str(&self.input.value().to_symbol()?)
    }

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

pub struct VecSeq<'a, 'de: 'a, I: Iterator<Item = &'de IOValue>> {
    iter: I,
    de: &'a mut Deserializer<'de>,
}

impl<'de, 'a, I: Iterator<Item = &'de IOValue>> VecSeq<'a, 'de, I> {
    fn new(de: &'a mut Deserializer<'de>, iter: I) -> Self {
        VecSeq { iter, de }
    }
}

impl<'de, 'a, I: Iterator<Item = &'de IOValue>> SeqAccess<'de> for VecSeq<'a, 'de, I> {
    type Error = Error;

    fn next_element_seed<T>(&mut self, seed: T) ->
        Result<Option<T::Value>>
    where
        T: DeserializeSeed<'de>
    {
        match self.iter.next() {
            None => Ok(None),
            Some(v) => {
                self.de.input = v;
                Ok(Some(seed.deserialize(&mut *self.de)?))
            }
        }
    }
}

pub struct DictMap<'a, 'de: 'a> {
    pending: Option<&'de IOValue>,
    iter: Box<dyn Iterator<Item = (&'de IOValue, &'de IOValue)> + 'a>,
    de: &'a mut Deserializer<'de>,
}

impl<'de, 'a> DictMap<'a, 'de> {
    fn new(de: &'a mut Deserializer<'de>, d: &'de Map<IOValue, IOValue>) -> Self {
        DictMap{ pending: None, iter: Box::new(d.iter()), de }
    }
}

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

    fn next_key_seed<K>(&mut self, seed: K)
                        -> Result<Option<K::Value>> where K: DeserializeSeed<'de>
    {
        match self.iter.next() {
            None => Ok(None),
            Some((k, v)) => {
                self.pending = Some(v);
                self.de.input = k;
                Ok(Some(seed.deserialize(&mut *self.de)?))
            }
        }
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value> where V: DeserializeSeed<'de> {
        let v = self.pending.unwrap();
        self.pending = None;
        self.de.input = v;
        Ok(seed.deserialize(&mut *self.de)?)
    }
}

impl<'a, 'de> EnumAccess<'de> for &'a mut Deserializer<'de> {
    type Error = Error;
    type Variant = Self;

    fn variant_seed<V>(self, seed: V)
                       -> Result<(V::Value, Self::Variant)> where V: DeserializeSeed<'de>
    {
        let r = self.check(|v| v.as_record(None), ExpectedKind::Record(None))?;
        let v = self.input;
        self.input = r.label();
        let variant = seed.deserialize(&mut *self)?;
        self.input = v;
        Ok((variant, self))
    }
}

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

    fn unit_variant(self) -> Result<()> {
        Ok(())
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value> where T: DeserializeSeed<'de> {
        let r = self.check(|v| v.as_record(Some(1)), ExpectedKind::Record(Some(1)))?;
        self.input = &r.fields()[0];
        seed.deserialize(&mut *self)
    }

    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value> where V: Visitor<'de> {
        visitor.visit_seq(VecSeq::new(self, self.input.value().as_record(None).unwrap().fields().iter()))
    }

    fn struct_variant<V>(self, fields: &'static [&'static str], visitor: V)
                         -> Result<V::Value> where V: Visitor<'de>
    {
        visitor.visit_seq(VecSeq::new(self, self.input.value().as_record(Some(fields.len())).unwrap().fields().iter()))
    }
}
