use crate::{ByteVec, error::PERes, index::string_wrapper::StringWrapper};
use std::io::{Read, Write};
use std::sync::Arc;
use unsigned_varint::{encode, io};
use zigzag::ZigZag;

pub trait InfallibleRead {
    fn read_exact(&mut self, buf: &mut [u8]);
    fn read_slice(&mut self, len: usize) -> ArcSliceRead;
}

pub trait InfallibleWrite {
    fn write_all(&mut self, buf: &[u8]);
}

struct InfallibleReadWrapper<'a, T: InfallibleRead + ?Sized> {
    reader: &'a mut T,
}

#[allow(dead_code)]
impl<'a, T: InfallibleRead + ?Sized> InfallibleReadWrapper<'a, T> {
    fn new(reader: &'a mut T) -> Self {
        InfallibleReadWrapper { reader }
    }
}
impl<T: InfallibleRead + ?Sized> Read for InfallibleReadWrapper<'_, T> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        InfallibleRead::read_exact(self.reader, buf);
        Ok(buf.len())
    }
}

// End of snippet taken from integer-encoding specialized for InfallibleRead

pub(crate) trait InfallibleReadVarInt: InfallibleRead {
    #[inline]
    fn read_varint_u8(&mut self) -> u8 {
        io::read_u8(InfallibleReadWrapper::new(self)).expect("infallible")
    }

    #[inline]
    fn read_varint_u16(&mut self) -> u16 {
        io::read_u16(InfallibleReadWrapper::new(self)).expect("infallible")
    }

    #[inline]
    fn read_varint_u32(&mut self) -> u32 {
        io::read_u32(InfallibleReadWrapper::new(self)).expect("infallible")
    }

    #[inline]
    fn read_varint_u64(&mut self) -> u64 {
        io::read_u64(InfallibleReadWrapper::new(self)).expect("infallible")
    }

    #[inline]
    fn read_varint_u128(&mut self) -> u128 {
        io::read_u128(InfallibleReadWrapper::new(self)).expect("infallible")
    }

    #[inline]
    fn read_varint_i8(&mut self) -> i8 {
        ZigZag::decode(self.read_varint_u8())
    }

    #[inline]
    fn read_varint_i16(&mut self) -> i16 {
        ZigZag::decode(self.read_varint_u16())
    }

    #[inline]
    fn read_varint_i32(&mut self) -> i32 {
        ZigZag::decode(self.read_varint_u32())
    }

    #[inline]
    fn read_varint_i64(&mut self) -> i64 {
        ZigZag::decode(self.read_varint_u64())
    }

    #[inline]
    fn read_varint_i128(&mut self) -> i128 {
        ZigZag::decode(self.read_varint_u128())
    }
}
impl<R: InfallibleRead + ?Sized> InfallibleReadVarInt for R {}

pub(crate) trait InfallibleWriteVarInt: InfallibleWrite {
    #[inline]
    fn write_varint_u8(&mut self, value: u8) {
        self.write_all(encode::u8(value, &mut encode::u8_buffer()));
    }

    #[inline]
    fn write_varint_u16(&mut self, value: u16) {
        self.write_all(encode::u16(value, &mut encode::u16_buffer()));
    }

    #[inline]
    fn write_varint_u32(&mut self, value: u32) {
        self.write_all(encode::u32(value, &mut encode::u32_buffer()));
    }

    #[inline]
    fn write_varint_u64(&mut self, value: u64) {
        self.write_all(encode::u64(value, &mut encode::u64_buffer()));
    }

    #[inline]
    fn write_varint_u128(&mut self, value: u128) {
        self.write_all(encode::u128(value, &mut encode::u128_buffer()));
    }

    #[inline]
    fn write_varint_i8(&mut self, value: i8) {
        self.write_varint_u8(ZigZag::encode(value))
    }

    #[inline]
    fn write_varint_i16(&mut self, value: i16) {
        self.write_varint_u16(ZigZag::encode(value))
    }

    #[inline]
    fn write_varint_i32(&mut self, value: i32) {
        self.write_varint_u32(ZigZag::encode(value))
    }

    #[inline]
    fn write_varint_i64(&mut self, value: i64) {
        self.write_varint_u64(ZigZag::encode(value))
    }

    #[inline]
    fn write_varint_i128(&mut self, value: i128) {
        self.write_varint_u128(ZigZag::encode(value))
    }
}

impl<W: InfallibleWrite + ?Sized> InfallibleWriteVarInt for W {}

#[allow(unused)]
pub(crate) trait InfallibleWriteFormat: InfallibleWrite {
    #[inline]
    fn write_u8(&mut self, value: u8) {
        self.write_all(&[value])
    }

    #[inline]
    fn write_u16(&mut self, value: u16) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_u32(&mut self, value: u32) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_u64(&mut self, value: u64) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_u128(&mut self, value: u128) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_i8(&mut self, value: i8) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_i16(&mut self, value: i16) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_i32(&mut self, value: i32) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_i64(&mut self, value: i64) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_i128(&mut self, value: i128) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_f32(&mut self, value: f32) {
        self.write_all(&value.to_be_bytes())
    }

    #[inline]
    fn write_f64(&mut self, value: f64) {
        self.write_all(&value.to_be_bytes())
    }
}

impl<W: InfallibleWrite + ?Sized> InfallibleWriteFormat for W {}

impl InfallibleWrite for Vec<u8> {
    fn write_all(&mut self, buf: &[u8]) {
        self.extend_from_slice(buf);
    }
}

#[allow(unused)]
pub(crate) trait InfallibleReadFormat: InfallibleRead {
    #[inline]
    fn read_u8(&mut self) -> u8 {
        let mut value = [0; 1];
        self.read_exact(&mut value);
        value[0]
    }

    #[inline]
    fn read_u16(&mut self) -> u16 {
        let mut value = [0; 2];
        self.read_exact(&mut value);
        u16::from_be_bytes(value)
    }

    #[inline]
    fn read_u32(&mut self) -> u32 {
        let mut value = [0; 4];
        self.read_exact(&mut value);
        u32::from_be_bytes(value)
    }

    #[inline]
    fn read_u64(&mut self) -> u64 {
        let mut value = [0; 8];
        self.read_exact(&mut value);
        u64::from_be_bytes(value)
    }

    #[inline]
    fn read_u128(&mut self) -> u128 {
        let mut value = [0; 16];
        self.read_exact(&mut value);
        u128::from_be_bytes(value)
    }

    #[inline]
    fn read_i8(&mut self) -> i8 {
        let mut value = [0; 1];
        self.read_exact(&mut value);
        i8::from_be_bytes(value)
    }

    #[inline]
    fn read_i16(&mut self) -> i16 {
        let mut value = [0; 2];
        self.read_exact(&mut value);
        i16::from_be_bytes(value)
    }

    #[inline]
    fn read_i32(&mut self) -> i32 {
        let mut value = [0; 4];
        self.read_exact(&mut value);
        i32::from_be_bytes(value)
    }

    #[inline]
    fn read_i64(&mut self) -> i64 {
        let mut value = [0; 8];
        self.read_exact(&mut value);
        i64::from_be_bytes(value)
    }

    #[inline]
    fn read_i128(&mut self) -> i128 {
        let mut value = [0; 16];
        self.read_exact(&mut value);
        i128::from_be_bytes(value)
    }

    #[inline]
    fn read_f32(&mut self) -> f32 {
        let mut value = [0; 4];
        self.read_exact(&mut value);
        f32::from_be_bytes(value)
    }

    #[inline]
    fn read_f64(&mut self) -> f64 {
        let mut value = [0; 8];
        self.read_exact(&mut value);
        f64::from_be_bytes(value)
    }
}

impl<R: InfallibleRead + ?Sized> InfallibleReadFormat for R {}

pub struct ArcSliceRead {
    buff: Arc<Vec<u8>>,
    cursor: usize,
    limit: usize,
}

impl ArcSliceRead {
    pub(crate) fn new(buff: Arc<Vec<u8>>, cursor: usize, limit: usize) -> Self {
        Self { buff, cursor, limit }
    }

    pub(crate) fn new_vec(buff: Vec<u8>) -> Self {
        let limit = buff.len();
        Self {
            buff: Arc::new(buff),
            cursor: 0,
            limit,
        }
    }

    pub(crate) fn to_vec(self) -> Vec<u8> {
        let mut buf = vec![0; self.limit - self.cursor];
        Read::read(&mut &self.buff[self.cursor..self.limit], &mut buf).unwrap();
        buf
    }

    #[allow(unused)]
    pub(crate) fn cursor(&self) -> usize {
        self.cursor
    }

    pub(crate) fn to_byte_vec(self) -> ByteVec {
        ByteVec::new_slice(self.buff, self.cursor, self.limit)
    }

    pub(crate) fn to_string_wrapper(self) -> StringWrapper {
        StringWrapper::new_slice(self.buff, self.cursor, self.limit)
    }
}

impl Read for ArcSliceRead {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let len = self.limit;
        let amt = std::cmp::min(self.cursor, len);
        let read = Read::read(&mut &self.buff[amt..len], buf)?;
        self.cursor += read;
        Ok(read)
    }
}

impl InfallibleRead for ArcSliceRead {
    fn read_exact(&mut self, buf: &mut [u8]) {
        assert!(self.limit >= self.cursor + buf.len());
        buf.copy_from_slice(&self.buff[self.cursor..(self.cursor + buf.len())]);
        self.cursor += buf.len();
    }

    fn read_slice(&mut self, size: usize) -> ArcSliceRead {
        assert!(self.limit >= self.cursor + size);
        let read = ArcSliceRead::new(self.buff.clone(), self.cursor, size);
        self.cursor += size;
        read
    }
}

pub(crate) fn read_u16(buf: &[u8]) -> u16 {
    let mut value = [0; 2];
    value[0] = buf[0];
    value[1] = buf[1];
    u16::from_be_bytes(value)
}
pub(crate) fn write_u16(buf: &mut [u8], val: u16) {
    let bv = val.to_be_bytes();
    buf[0] = bv[0];
    buf[1] = bv[1];
}
pub(crate) fn read_u64(buf: &[u8]) -> u64 {
    let mut value = [0; 8];
    value[..8].clone_from_slice(&buf[..8]);
    u64::from_be_bytes(value)
}
pub(crate) fn write_u64(buf: &mut [u8], val: u64) {
    let value = val.to_be_bytes();
    buf[..8].clone_from_slice(&value[..8]);
}

#[allow(unused)]
pub(crate) trait WriteFormat: Write {
    #[inline]
    fn write_u8(&mut self, value: u8) -> PERes<()> {
        Ok(self.write_all(&[value])?)
    }

    #[inline]
    fn write_u16(&mut self, value: u16) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_u32(&mut self, value: u32) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_u64(&mut self, value: u64) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_u128(&mut self, value: u128) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_i8(&mut self, value: i8) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_i16(&mut self, value: i16) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_i32(&mut self, value: i32) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_i64(&mut self, value: i64) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_i128(&mut self, value: i128) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_f32(&mut self, value: f32) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }

    #[inline]
    fn write_f64(&mut self, value: f64) -> PERes<()> {
        Ok(self.write_all(&value.to_be_bytes())?)
    }
}

impl<W: Write + ?Sized> WriteFormat for W {}

#[allow(unused)]
pub(crate) trait ReadFormat: Read {
    #[inline]
    fn read_u8(&mut self) -> PERes<u8> {
        let mut buf = [0; 1];
        self.read_exact(&mut buf)?;
        Ok(buf[0])
    }

    #[inline]
    fn read_u16(&mut self) -> PERes<u16> {
        let mut buf = [0; 2];
        self.read_exact(&mut buf)?;
        Ok(u16::from_be_bytes(buf))
    }

    #[inline]
    fn read_u32(&mut self) -> PERes<u32> {
        let mut buf = [0; 4];
        self.read_exact(&mut buf)?;
        Ok(u32::from_be_bytes(buf))
    }

    #[inline]
    fn read_u64(&mut self) -> PERes<u64> {
        let mut buf = [0; 8];
        self.read_exact(&mut buf)?;
        Ok(u64::from_be_bytes(buf))
    }

    #[inline]
    fn read_u128(&mut self) -> PERes<u128> {
        let mut buf = [0; 16];
        self.read_exact(&mut buf)?;
        Ok(u128::from_be_bytes(buf))
    }

    #[inline]
    fn read_i8(&mut self) -> PERes<i8> {
        let mut buf = [0; 1];
        self.read_exact(&mut buf)?;
        Ok(buf[0] as i8)
    }

    #[inline]
    fn read_i16(&mut self) -> PERes<i16> {
        let mut buf = [0; 2];
        self.read_exact(&mut buf)?;
        Ok(i16::from_be_bytes(buf))
    }

    #[inline]
    fn read_i32(&mut self) -> PERes<i32> {
        let mut buf = [0; 4];
        self.read_exact(&mut buf)?;
        Ok(i32::from_be_bytes(buf))
    }

    #[inline]
    fn read_i64(&mut self) -> PERes<i64> {
        let mut buf = [0; 8];
        self.read_exact(&mut buf)?;
        Ok(i64::from_be_bytes(buf))
    }

    #[inline]
    fn read_i128(&mut self) -> PERes<i128> {
        let mut buf = [0; 16];
        self.read_exact(&mut buf)?;
        Ok(i128::from_be_bytes(buf))
    }

    #[inline]
    fn read_f32(&mut self) -> PERes<f32> {
        let mut buf = [0; 4];
        self.read_exact(&mut buf)?;
        Ok(f32::from_be_bytes(buf))
    }

    #[inline]
    fn read_f64(&mut self) -> PERes<f64> {
        let mut buf = [0; 8];
        self.read_exact(&mut buf)?;
        Ok(f64::from_be_bytes(buf))
    }
}

impl<R: Read + ?Sized> ReadFormat for R {}

#[allow(unused)]
pub(crate) trait ReadVarInt: Read {
    #[inline]
    fn read_varint_u8(&mut self) -> PERes<u8> {
        Ok(io::read_u8(self)?)
    }

    #[inline]
    fn read_varint_u16(&mut self) -> PERes<u16> {
        Ok(io::read_u16(self)?)
    }

    #[inline]
    fn read_varint_u32(&mut self) -> PERes<u32> {
        Ok(io::read_u32(self)?)
    }

    #[inline]
    fn read_varint_u64(&mut self) -> PERes<u64> {
        Ok(io::read_u64(self)?)
    }

    #[inline]
    fn read_varint_u128(&mut self) -> PERes<u128> {
        Ok(io::read_u128(self)?)
    }

    #[inline]
    fn read_varint_i8(&mut self) -> PERes<i8> {
        Ok(ZigZag::decode(self.read_varint_u8()?))
    }

    #[inline]
    fn read_varint_i16(&mut self) -> PERes<i16> {
        Ok(ZigZag::decode(self.read_varint_u16()?))
    }

    #[inline]
    fn read_varint_i32(&mut self) -> PERes<i32> {
        Ok(ZigZag::decode(self.read_varint_u32()?))
    }

    #[inline]
    fn read_varint_i64(&mut self) -> PERes<i64> {
        Ok(ZigZag::decode(self.read_varint_u64()?))
    }

    #[inline]
    fn read_varint_i128(&mut self) -> PERes<i128> {
        Ok(ZigZag::decode(self.read_varint_u128()?))
    }
}
impl<R: Read + ?Sized> ReadVarInt for R {}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    #[test]
    pub fn test_format() {
        use super::{ReadFormat, WriteFormat};
        let mut buffer = Vec::new();
        buffer.write_i8(10).unwrap();
        buffer.write_i16(11).unwrap();
        buffer.write_i32(12).unwrap();
        buffer.write_i64(13).unwrap();
        buffer.write_i128(14).unwrap();
        buffer.write_u8(15).unwrap();
        buffer.write_u16(16).unwrap();
        buffer.write_u32(17).unwrap();
        buffer.write_u64(18).unwrap();
        buffer.write_u128(19).unwrap();
        buffer.write_f32(10.0).unwrap();
        buffer.write_f64(11.0).unwrap();
        let mut read = Cursor::new(buffer);
        assert_eq!(read.read_i8().unwrap(), 10);
        assert_eq!(read.read_i16().unwrap(), 11);
        assert_eq!(read.read_i32().unwrap(), 12);
        assert_eq!(read.read_i64().unwrap(), 13);
        assert_eq!(read.read_i128().unwrap(), 14);
        assert_eq!(read.read_u8().unwrap(), 15);
        assert_eq!(read.read_u16().unwrap(), 16);
        assert_eq!(read.read_u32().unwrap(), 17);
        assert_eq!(read.read_u64().unwrap(), 18);
        assert_eq!(read.read_u128().unwrap(), 19);
        assert_eq!(read.read_f32().unwrap(), 10.0);
        assert_eq!(read.read_f64().unwrap(), 11.0);
    }

    mod infallible {

        use super::super::{ArcSliceRead, InfallibleRead, InfallibleReadFormat, InfallibleWriteFormat, Read};
        use std::io::Cursor;

        impl InfallibleRead for Cursor<Vec<u8>> {
            fn read_exact(&mut self, buf: &mut [u8]) {
                Read::read_exact(self, buf).expect("in memory buff never fail");
            }

            fn read_slice(&mut self, size: usize) -> ArcSliceRead {
                let mut slice: Vec<u8> = vec![0; size];
                InfallibleRead::read_exact(self, &mut slice);
                ArcSliceRead::new_vec(slice)
            }
        }
        #[test]
        pub fn test_infallible_format() {
            let mut buffer = Vec::new();
            buffer.write_i8(10);
            buffer.write_i16(11);
            buffer.write_i32(12);
            buffer.write_i64(13);
            buffer.write_i128(14);
            buffer.write_u8(15);
            buffer.write_u16(16);
            buffer.write_u32(17);
            buffer.write_u64(18);
            buffer.write_u128(19);
            buffer.write_f32(10.0);
            buffer.write_f64(11.0);
            let mut read = Cursor::new(buffer);
            assert_eq!(read.read_i8(), 10);
            assert_eq!(read.read_i16(), 11);
            assert_eq!(read.read_i32(), 12);
            assert_eq!(read.read_i64(), 13);
            assert_eq!(read.read_i128(), 14);
            assert_eq!(read.read_u8(), 15);
            assert_eq!(read.read_u16(), 16);
            assert_eq!(read.read_u32(), 17);
            assert_eq!(read.read_u64(), 18);
            assert_eq!(read.read_u128(), 19);
            assert_eq!(read.read_f32(), 10.0);
            assert_eq!(read.read_f64(), 11.0);
        }
    }
}
