use core::mem::MaybeUninit;

use crate::{
    des::{DeserializeError, Deserializer},
    ser::Serializer,
    Deserialize, Serialize,
};

macro impl_primitive_serde($($ty:ty : [$read:ident, $write:ident]),+) {
    $(
        impl<'de> $crate::des::Deserialize<'de> for $ty {
            fn deserialize<D: $crate::des::Deserializer<'de>>(deserializer: &mut D) -> Result<$ty, D::Error> {
                deserializer.$read()
            }
        }

        impl $crate::ser::Serialize for $ty {
            fn serialize<S: $crate::ser::Serializer>(
                &self,
                serializer: &mut S,
            ) -> Result<(), S::Error> {
                serializer.$write(*self)
            }
        }
    )+
}

impl_primitive_serde!(
    bool: [read_bool, write_bool],
    i8: [read_i8, write_i8],
    i16: [read_i16, write_i16],
    i32: [read_i32, write_i32],
    i64: [read_i64, write_i64],
    isize: [read_isize, write_isize],
    u8: [read_u8, write_u8],
    u16: [read_u16, write_u16],
    u32: [read_u32, write_u32],
    u64: [read_u64, write_u64],
    usize: [read_usize, write_usize]
);

impl Serialize for () {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        let _ = serializer;
        Ok(())
    }
}

impl<'de> Deserialize<'de> for () {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        let _ = deserializer;
        Ok(())
    }
}

impl<const N: usize, T: Serialize> Serialize for [T; N] {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        for item in self[0..N].iter() {
            item.serialize(serializer)?;
        }
        Ok(())
    }
}

impl<'de, const N: usize, T: Deserialize<'de>> Deserialize<'de> for [T; N] {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        let mut array = [const { MaybeUninit::uninit() }; N];
        for item in array[0..N].iter_mut() {
            item.write(Deserialize::deserialize(deserializer)?);
        }
        Ok(unsafe { MaybeUninit::array_assume_init(array) })
    }
}

impl Serialize for &[u8] {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        serializer.write_bytes(self)
    }
}

impl<'de> Deserialize<'de> for &'de [u8] {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        deserializer.read_bytes()
    }
}

impl Serialize for &str {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        serializer.write_str(self)
    }
}

impl<'de> Deserialize<'de> for &'de str {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        deserializer.read_str()
    }
}

// impl<const N: usize> Serialize for [u8; N]
// where
//     [u8; N]: Sized,
// {
//     fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
//         serializer.write_bytes(self)
//     }
// }
//
// impl<'de, const N: usize> Deserialize<'de> for [u8; N]
// where
//     [u8; N]: Sized,
// {
//     fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
//         deserializer
//             .read_bytes()?
//             .try_into()
//             .map_err(|_| D::Error::INVALID_ARRAY_LEN)
//     }
// }

impl<T: Serialize> Serialize for Option<T> {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        match self {
            None => serializer.write_u8(0),
            Some(value) => {
                serializer.write_u8(1)?;
                value.serialize(serializer)
            }
        }
    }
}

impl<'de, T: Deserialize<'de>> Deserialize<'de> for Option<T> {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        let variant = deserializer.read_u8()?;
        match variant {
            0 => Ok(None),
            1 => T::deserialize(deserializer).map(Some),
            _ => Err(D::Error::INVALID_ENUM_VARIANT),
        }
    }
}

impl<T: Serialize, E: Serialize> Serialize for Result<T, E> {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        match self {
            Ok(value) => {
                serializer.write_u8(0)?;
                value.serialize(serializer)
            }
            Err(error) => {
                serializer.write_u8(1)?;
                error.serialize(serializer)
            }
        }
    }
}

impl<'de, T: Deserialize<'de>, E: Deserialize<'de>> Deserialize<'de> for Result<T, E> {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        let variant = deserializer.read_u8()?;
        match variant {
            0 => T::deserialize(deserializer).map(Ok),
            1 => E::deserialize(deserializer).map(Err),
            _ => Err(D::Error::INVALID_ENUM_VARIANT),
        }
    }
}

#[cfg(test)]
mod test {
    use crate::test::test_serialize_reversibility;

    #[test]
    fn test_option_sanity() {
        let mut buffer = [0; 256];
        test_serialize_reversibility(&mut buffer, &Some(1234u32));
        test_serialize_reversibility(&mut buffer, &Some("abcdef"));
        test_serialize_reversibility(&mut buffer, &Option::<u32>::None);
        test_serialize_reversibility(&mut buffer, &Option::<u8>::None);
        test_serialize_reversibility(&mut buffer, &Option::<&str>::None);
    }

    #[test]
    fn test_result_sanity() {
        let mut buffer = [0; 256];
        test_serialize_reversibility(&mut buffer, &Result::<_, u32>::Ok(1234u32));
        test_serialize_reversibility(&mut buffer, &Result::<u32, _>::Err("abcdef"));
    }
}
