use core::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};

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

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

impl<'de> Deserialize<'de> for SocketAddrV4 {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        let ip = Ipv4Addr::deserialize(deserializer)?;
        let port = u16::deserialize(deserializer)?;
        Ok(Self::new(ip, port))
    }
}

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

impl Serialize for SocketAddrV4 {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        self.ip().serialize(serializer)?;
        self.port().serialize(serializer)?;
        Ok(())
    }
}

impl<'de> Deserialize<'de> for Ipv6Addr {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        deserializer
            .read_bytes()?
            .try_into()
            .map(Self::from_octets)
            .map_err(|_| D::Error::INVALID_ARRAY_LEN)
    }
}

impl<'de> Deserialize<'de> for SocketAddrV6 {
    fn deserialize<D: Deserializer<'de>>(deserializer: &mut D) -> Result<Self, D::Error> {
        let ip = Ipv6Addr::deserialize(deserializer)?;
        let port = u16::deserialize(deserializer)?;
        let flowinfo = u32::deserialize(deserializer)?;
        let scope_id = u32::deserialize(deserializer)?;
        Ok(Self::new(ip, port, flowinfo, scope_id))
    }
}

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

impl Serialize for SocketAddrV6 {
    fn serialize<S: Serializer>(&self, serializer: &mut S) -> Result<(), S::Error> {
        self.ip().serialize(serializer)?;
        self.port().serialize(serializer)?;
        self.flowinfo().serialize(serializer)?;
        self.scope_id().serialize(serializer)?;
        Ok(())
    }
}

crate::impl_enum1_serde!(IpAddr: [
    V4 => 4,
    V6 => 6
]);
crate::impl_enum1_serde!(SocketAddr: [
    V4 => 4,
    V6 => 6
]);
