#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ImuOutputPayload {
    pub status: i32,
    pub timestamp: u32,
    pub uncomp_mag_x: f32,
    pub uncomp_mag_y: f32,
    pub uncomp_mag_z: f32,
    pub uncomp_acc_x: f32,
    pub uncomp_acc_y: f32,
    pub uncomp_acc_z: f32,
    pub uncomp_gyro_x: f32,
    pub uncomp_gyro_y: f32,
    pub uncomp_gyro_z: f32,
    pub pressure: f32,
    pub temperature: f32,
    pub mag_x: f32,
    pub mag_y: f32,
    pub mag_z: f32,
    pub acc_x: f32,
    pub acc_y: f32,
    pub acc_z: f32,
    pub gyro_x: f32,
    pub gyro_y: f32,
    pub gyro_z: f32,
}

impl ImuOutputPayload {
    pub const SYSTEM_ID: u8 = 1;
    pub const MODULE_ID: u8 = 15;
    pub const LEN: usize = 88;

    pub fn validate_payload(payload: &[u8]) -> Result<(), crate::gen::payload_io::PayloadError> {
        if payload.len() != Self::LEN {
            return Err(crate::gen::payload_io::PayloadError::LengthMismatch { expected: Self::LEN, actual: payload.len() });
        }
        Ok(())
    }

    pub fn parse(payload: &[u8]) -> Result<ImuOutputPayload, crate::gen::payload_io::PayloadError> {
        Self::validate_payload(payload)?;
        let mut cursor = crate::gen::payload_io::PayloadCursor::new(payload);
        Ok(Self {
            status: cursor.read_i32(),
            timestamp: cursor.read_u32(),
            uncomp_mag_x: cursor.read_f32(),
            uncomp_mag_y: cursor.read_f32(),
            uncomp_mag_z: cursor.read_f32(),
            uncomp_acc_x: cursor.read_f32(),
            uncomp_acc_y: cursor.read_f32(),
            uncomp_acc_z: cursor.read_f32(),
            uncomp_gyro_x: cursor.read_f32(),
            uncomp_gyro_y: cursor.read_f32(),
            uncomp_gyro_z: cursor.read_f32(),
            pressure: cursor.read_f32(),
            temperature: cursor.read_f32(),
            mag_x: cursor.read_f32(),
            mag_y: cursor.read_f32(),
            mag_z: cursor.read_f32(),
            acc_x: cursor.read_f32(),
            acc_y: cursor.read_f32(),
            acc_z: cursor.read_f32(),
            gyro_x: cursor.read_f32(),
            gyro_y: cursor.read_f32(),
            gyro_z: cursor.read_f32(),
        })
    }

    pub fn from_bytes_exact(payload: &[u8; Self::LEN]) -> ImuOutputPayload {
        // Length already guaranteed by the array type
        Self::parse(payload).expect("slice length matches payload size")
    }

    pub fn to_bytes(&self) -> [u8; Self::LEN] {
        let mut buf = [0u8; Self::LEN];
        let mut writer = crate::gen::payload_io::PayloadWriter::new(&mut buf);
        writer.write_i32(self.status);
        writer.write_u32(self.timestamp);
        writer.write_f32(self.uncomp_mag_x);
        writer.write_f32(self.uncomp_mag_y);
        writer.write_f32(self.uncomp_mag_z);
        writer.write_f32(self.uncomp_acc_x);
        writer.write_f32(self.uncomp_acc_y);
        writer.write_f32(self.uncomp_acc_z);
        writer.write_f32(self.uncomp_gyro_x);
        writer.write_f32(self.uncomp_gyro_y);
        writer.write_f32(self.uncomp_gyro_z);
        writer.write_f32(self.pressure);
        writer.write_f32(self.temperature);
        writer.write_f32(self.mag_x);
        writer.write_f32(self.mag_y);
        writer.write_f32(self.mag_z);
        writer.write_f32(self.acc_x);
        writer.write_f32(self.acc_y);
        writer.write_f32(self.acc_z);
        writer.write_f32(self.gyro_x);
        writer.write_f32(self.gyro_y);
        writer.write_f32(self.gyro_z);
        buf
    }
}
