use std::io::{BufRead, Read, Write};

use crate::slide_buffer::SlideBuffer;

/// Reader for accessing decrypted plaintext from REALITY connections
///
/// This reader provides a view over a SlideBuffer and consumes data from it
/// as it is read. The SlideBuffer handles efficient memory management.
pub struct RealityReader<'a> {
    buffer: &'a mut SlideBuffer,
}

impl<'a> RealityReader<'a> {
    pub fn new(buffer: &'a mut SlideBuffer) -> Self {
        RealityReader { buffer }
    }
}

impl<'a> Read for RealityReader<'a> {
    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
        let available = self.buffer.len();
        let to_read = buf.len().min(available);
        if to_read > 0 {
            buf[..to_read].copy_from_slice(&self.buffer[..to_read]);
            self.buffer.consume(to_read);
        }
        Ok(to_read)
    }
}

impl<'a> BufRead for RealityReader<'a> {
    fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
        Ok(self.buffer.as_slice())
    }

    fn consume(&mut self, amt: usize) {
        let actual = amt.min(self.buffer.len());
        self.buffer.consume(actual);
    }
}

/// Writer for buffering plaintext to be encrypted in REALITY connections
pub struct RealityWriter<'a> {
    buffer: &'a mut Vec<u8>,
}

impl<'a> RealityWriter<'a> {
    pub fn new(buffer: &'a mut Vec<u8>) -> Self {
        RealityWriter { buffer }
    }
}

impl<'a> Write for RealityWriter<'a> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.buffer.extend_from_slice(buf);
        Ok(buf.len())
    }

    fn flush(&mut self) -> std::io::Result<()> {
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_reality_crypto_reader() {
        let mut buffer = SlideBuffer::new(1024);
        buffer.extend_from_slice(b"hello world");

        {
            let mut reader = RealityReader::new(&mut buffer);
            let mut buf = [0u8; 5];
            assert_eq!(reader.read(&mut buf).unwrap(), 5);
            assert_eq!(&buf, b"hello");
        }

        // Buffer should have consumed 5 bytes
        assert_eq!(buffer.len(), 6); // " world" remaining

        {
            let mut reader = RealityReader::new(&mut buffer);
            let mut buf = [0u8; 5];
            assert_eq!(reader.read(&mut buf).unwrap(), 5);
            assert_eq!(&buf[..5], b" worl");
        }

        assert_eq!(buffer.len(), 1); // "d" remaining
    }

    #[test]
    fn test_reality_crypto_reader_bufread() {
        let mut buffer = SlideBuffer::new(1024);
        buffer.extend_from_slice(b"test data");

        let mut reader = RealityReader::new(&mut buffer);

        let buf = reader.fill_buf().unwrap();
        assert_eq!(buf, b"test data");

        reader.consume(5);
        let buf = reader.fill_buf().unwrap();
        assert_eq!(buf, b"data");
    }

    #[test]
    fn test_reality_crypto_writer() {
        let mut buffer = Vec::new();
        let mut writer = RealityWriter::new(&mut buffer);

        assert_eq!(writer.write(b"hello").unwrap(), 5);
        assert_eq!(writer.write(b" world").unwrap(), 6);
        assert_eq!(buffer.as_slice(), b"hello world");
    }
}
