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

#[derive(Debug)]
pub struct Error;

pub struct WireSerializer<'b> {
    buffer: &'b mut [u8],
    position: usize,
}

pub struct WireDeserializer<'b> {
    buffer: &'b [u8],
    position: usize,
}

impl WireSerializer<'_> {
    fn write_naked_bytes(&mut self, bytes: &[u8]) -> Result<(), Error> {
        if self.position + bytes.len() > self.buffer.len() {
            return Err(Error);
        }

        self.buffer[self.position..self.position + bytes.len()].copy_from_slice(bytes);
        self.position += bytes.len();
        Ok(())
    }
}

impl<'de> WireDeserializer<'de> {
    fn read_naked_bytes(&mut self, len: usize) -> Result<&'de [u8], Error> {
        if self.position + len > self.buffer.len() {
            return Err(Error);
        }

        let slice = &self.buffer[self.position..self.position + len];
        self.position += len;
        Ok(slice)
    }
}

impl Serializer for WireSerializer<'_> {
    type Error = Error;

    fn write_i8(&mut self, value: i8) -> Result<(), Self::Error> {
        self.write_naked_bytes(&[value as u8])
    }

    fn write_u8(&mut self, value: u8) -> Result<(), Self::Error> {
        self.write_naked_bytes(&[value])
    }

    fn write_i16(&mut self, value: i16) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_u16(&mut self, value: u16) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_i32(&mut self, value: i32) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_u32(&mut self, value: u32) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_i64(&mut self, value: i64) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_u64(&mut self, value: u64) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_isize(&mut self, value: isize) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_usize(&mut self, value: usize) -> Result<(), Self::Error> {
        self.write_naked_bytes(&value.to_ne_bytes())
    }

    fn write_str(&mut self, data: &str) -> Result<(), Self::Error> {
        self.write_bytes(data.as_bytes())
    }

    fn write_bool(&mut self, value: bool) -> Result<(), Self::Error> {
        self.write_naked_bytes(&[value as u8])
    }

    fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
        if bytes.len() >= u16::MAX as usize {
            return Err(Error);
        }

        self.write_u16(bytes.len() as u16)?;
        self.write_naked_bytes(bytes)
    }

    fn write_enum_variant(&mut self, index: u32) -> Result<(), Self::Error> {
        self.write_u32(index)
    }
}

impl<'de> Deserializer<'de> for WireDeserializer<'de> {
    type Error = Error;

    fn read_i8(&mut self) -> Result<i8, Self::Error> {
        Ok(self.read_naked_bytes(1)?[0] as i8)
    }

    fn read_u8(&mut self) -> Result<u8, Self::Error> {
        Ok(self.read_naked_bytes(1)?[0])
    }

    fn read_i16(&mut self) -> Result<i16, Self::Error> {
        self.read_naked_bytes(size_of::<i16>())?
            .try_into()
            .map(i16::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_u16(&mut self) -> Result<u16, Self::Error> {
        self.read_naked_bytes(size_of::<u16>())?
            .try_into()
            .map(u16::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_i32(&mut self) -> Result<i32, Self::Error> {
        self.read_naked_bytes(size_of::<i32>())?
            .try_into()
            .map(i32::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_u32(&mut self) -> Result<u32, Self::Error> {
        self.read_naked_bytes(size_of::<u32>())?
            .try_into()
            .map(u32::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        self.read_naked_bytes(size_of::<i64>())?
            .try_into()
            .map(i64::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        self.read_naked_bytes(size_of::<u64>())?
            .try_into()
            .map(u64::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_isize(&mut self) -> Result<isize, Self::Error> {
        self.read_naked_bytes(size_of::<isize>())?
            .try_into()
            .map(isize::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_usize(&mut self) -> Result<usize, Self::Error> {
        self.read_naked_bytes(size_of::<usize>())?
            .try_into()
            .map(usize::from_ne_bytes)
            .map_err(|_| Error)
    }

    fn read_str(&mut self) -> Result<&'de str, Self::Error> {
        let bytes = self.read_bytes()?;
        core::str::from_utf8(bytes).map_err(|_| Error)
    }

    fn read_bytes(&mut self) -> Result<&'de [u8], Self::Error> {
        let len = self.read_u16()? as usize;
        self.read_naked_bytes(len)
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        Ok(self.read_u8()? != 0)
    }

    fn read_enum_variant(&mut self) -> Result<u32, Self::Error> {
        self.read_u32()
    }
}

impl DeserializeError for Error {
    const INVALID_ARRAY_LEN: Self = Self;
    const INVALID_ENUM_VARIANT: Self = Self;
}

pub fn to_slice<T: Serialize>(value: &T, buffer: &mut [u8]) -> Result<usize, Error> {
    let mut ser = WireSerializer {
        buffer,
        position: 0,
    };
    value.serialize(&mut ser)?;
    Ok(ser.position)
}

pub fn from_slice<'de, T: Deserialize<'de>>(buffer: &'de [u8]) -> Result<T, Error> {
    let mut des = WireDeserializer {
        buffer,
        position: 0,
    };
    T::deserialize(&mut des)
}
