use crate::error::{Error, Result};
use std::io::{Read, Write};

pub fn write_frame<W: Write>(
    mut stream: W,
    magic: [u8; 4],
    version: u8,
    frame_type: u8,
    payload: &[u8],
) -> Result<()> {
    let mut header = [0u8; 12];
    header[0..4].copy_from_slice(&magic);
    header[4] = version;
    header[5] = frame_type;
    header[6..8].copy_from_slice(&0u16.to_le_bytes());
    header[8..12].copy_from_slice(&(payload.len() as u32).to_le_bytes());

    stream.write_all(&header)?;
    stream.write_all(payload)?;
    Ok(())
}

pub fn read_frame<R: Read>(mut stream: R, magic: [u8; 4], version: u8) -> Result<(u8, Vec<u8>)> {
    let mut header = [0u8; 12];
    stream.read_exact(&mut header)?;

    if header[0..4] != magic {
        return Err(Error::Protocol("invalid frame magic".to_string()));
    }
    if header[4] != version {
        return Err(Error::Protocol("unsupported protocol version".to_string()));
    }

    let frame_type = header[5];
    let len = u32::from_le_bytes([header[8], header[9], header[10], header[11]]) as usize;

    let mut payload = vec![0u8; len];
    stream.read_exact(&mut payload)?;

    Ok((frame_type, payload))
}
