use thiserror::Error;
use super::row::SerializedValues;
pub struct RowWriter<'buf> {
        buf: &'buf mut Vec<u8>,
        value_count: usize,
}
impl<'buf> RowWriter<'buf> {
                #[inline]
    pub fn new(buf: &'buf mut Vec<u8>) -> Self {
        Self {
            buf,
            value_count: 0,
        }
    }
                    #[inline]
    pub fn value_count(&self) -> usize {
        self.value_count
    }
            #[inline]
    pub fn make_cell_writer(&mut self) -> CellWriter<'_> {
        self.value_count += 1;
        CellWriter::new(self.buf)
    }
            #[inline]
    pub fn append_serialize_row(&mut self, sv: &SerializedValues) {
        self.value_count += sv.element_count() as usize;
        self.buf.extend_from_slice(sv.get_contents())
    }
}
pub struct CellWriter<'buf> {
    buf: &'buf mut Vec<u8>,
    write_size: bool,
}
impl<'buf> CellWriter<'buf> {
                #[inline]
    pub fn new(buf: &'buf mut Vec<u8>) -> Self {
        Self {
            buf,
            write_size: true,
        }
    }
                #[inline]
    pub fn new_without_size(buf: &'buf mut Vec<u8>) -> Self {
        Self {
            buf,
            write_size: false,
        }
    }
        #[inline]
    pub fn set_null(self) -> WrittenCellProof<'buf> {
        self.buf.extend_from_slice(&(-1i32).to_be_bytes());
        WrittenCellProof::new()
    }
        #[inline]
    pub fn set_unset(self) -> WrittenCellProof<'buf> {
        self.buf.extend_from_slice(&(-2i32).to_be_bytes());
        WrittenCellProof::new()
    }
                                    #[inline]
    pub fn set_value(self, contents: &[u8]) -> Result<WrittenCellProof<'buf>, CellOverflowError> {
        let value_len: i32 = contents.len().try_into().map_err(|_| CellOverflowError)?;
        if self.write_size {
            self.buf.extend_from_slice(&value_len.to_be_bytes());
        }
        self.buf.extend_from_slice(contents);
        Ok(WrittenCellProof::new())
    }
                            #[inline]
    pub fn into_value_builder(self) -> CellValueBuilder<'buf> {
        CellValueBuilder::new(self.buf, self.write_size)
    }
}
pub struct CellValueBuilder<'buf> {
        buf: &'buf mut Vec<u8>,
        starting_pos: usize,
        write_size: bool,
}
impl<'buf> CellValueBuilder<'buf> {
    #[inline]
    fn new(buf: &'buf mut Vec<u8>, write_size: bool) -> Self {
                                                        let starting_pos = buf.len();
        if write_size {
            buf.extend_from_slice(&(-3i32).to_be_bytes());
        }
        Self {
            buf,
            starting_pos,
            write_size,
        }
    }
        #[inline]
    pub fn append_bytes(&mut self, bytes: &[u8]) {
        self.buf.extend_from_slice(bytes);
    }
            #[inline]
    pub fn make_sub_writer(&mut self) -> CellWriter<'_> {
        CellWriter::new(self.buf)
    }
            #[inline]
    pub fn make_sub_writer_without_size(&mut self) -> CellWriter<'_> {
        CellWriter::new_without_size(self.buf)
    }
                    #[inline]
    pub fn finish(self) -> Result<WrittenCellProof<'buf>, CellOverflowError> {
        if self.write_size {
            let value_len: i32 = (self.buf.len() - self.starting_pos - 4)
                .try_into()
                .map_err(|_| CellOverflowError)?;
            self.buf[self.starting_pos..self.starting_pos + 4]
                .copy_from_slice(&value_len.to_be_bytes());
        }
        Ok(WrittenCellProof::new())
    }
}
#[derive(Debug)]
pub struct WrittenCellProof<'buf> {
                _phantom: std::marker::PhantomData<*mut &'buf ()>,
}
impl WrittenCellProof<'_> {
                    #[inline]
    fn new() -> Self {
        WrittenCellProof {
            _phantom: std::marker::PhantomData,
        }
    }
}
#[derive(Debug, Clone, Copy, Error)]
#[error("CQL cell overflowed the maximum allowed size of 2^31 - 1")]
pub struct CellOverflowError;
#[cfg(test)]
mod tests {
    use super::{CellWriter, RowWriter};
    #[test]
    fn test_cell_writer() {
        let mut data = Vec::new();
        let writer = CellWriter::new(&mut data);
        let mut sub_writer = writer.into_value_builder();
        sub_writer.make_sub_writer().set_null();
        sub_writer
            .make_sub_writer()
            .set_value(&[1, 2, 3, 4])
            .unwrap();
        sub_writer.make_sub_writer().set_unset();
        sub_writer.finish().unwrap();
        assert_eq!(
            data,
            [
                0, 0, 0, 16,                 255, 255, 255, 255,                 0, 0, 0, 4, 1, 2, 3, 4,                 255, 255, 255, 254,             ]
        );
    }
    #[test]
    fn test_poisoned_appender() {
        let mut data = Vec::new();
        let writer = CellWriter::new(&mut data);
        let _ = writer.into_value_builder();
        assert_eq!(
            data,
            [
                255, 255, 255, 253,             ]
        );
    }
    #[test]
    fn test_row_writer() {
        let mut data = Vec::new();
        let mut writer = RowWriter::new(&mut data);
        writer.make_cell_writer().set_null();
        writer.make_cell_writer().set_value(&[1, 2, 3, 4]).unwrap();
        writer.make_cell_writer().set_unset();
        assert_eq!(
            data,
            [
                255, 255, 255, 255,                 0, 0, 0, 4, 1, 2, 3, 4,                 255, 255, 255, 254,             ]
        )
    }
}