use crate::{
    impl_default, impl_message_from_buf, impl_response_ops, impl_var_message_ops, len, std::fmt,
    ChannelValue, ChannelValueList, Error, MessageOps, MessageType, ResponseOps, Result, Vec,
};
pub mod index {
    pub const NUM_CHANNELS: usize = 4;
    pub const CHANNEL_VALUES: usize = NUM_CHANNELS + 1;
}
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ChannelValueDataResponse {
    buf: [u8; len::CHANNEL_VALUE_DATA_RESPONSE],
}
impl ChannelValueDataResponse {
    pub fn new() -> Self {
        let mut msg = Self {
            buf: [0u8; len::CHANNEL_VALUE_DATA_RESPONSE],
        };
        msg.init();
        msg
    }
    pub fn num_channels(&self) -> usize {
        self.buf[index::NUM_CHANNELS].into()
    }
    pub fn channel_values(&self) -> Result<ChannelValueList> {
        self.is_valid()?;
        let channel_values_end = self.channel_values_end();
        Ok(self.buf[index::CHANNEL_VALUES..channel_values_end]
            .iter()
            .map(|&v| ChannelValue::from([v]))
            .collect::<Vec<ChannelValue>>()
            .into())
    }
    fn channel_values_end(&self) -> usize {
        index::CHANNEL_VALUES + self.num_channels()
    }
    pub fn is_valid(&self) -> Result<()> {
        use crate::message::index as msg_index;
        let end_range = len::HEADER + self.data_len();
        let values_end = self.channel_values_end();
        if (msg_index::DATA..=end_range).contains(&values_end) {
            Ok(())
        } else {
            Err(Error::InvalidDataLength((values_end, end_range)))
        }
    }
}
impl_default!(ChannelValueDataResponse);
impl_message_from_buf!(ChannelValueDataResponse);
impl_var_message_ops!(ChannelValueDataResponse, MessageType::ChannelValueData);
impl_response_ops!(ChannelValueDataResponse);
impl fmt::Display for ChannelValueDataResponse {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self.is_valid() {
            Ok(_) => {
                let stx = self.stx();
                let seqid = self.sequence_id();
                let len = self.data_len();
                let status = self.response_status();
                let num_channels = self.num_channels();
                let channel_values = self.channel_values().unwrap();
                let crc = self.checksum();
                write!(f, "STX: 0x{stx:02x} | SEQID: {seqid} | LEN: 0x{len:02x} | Response status: {status} | Number of channels: {num_channels} | Channel values: {channel_values} | CRC-16: 0x{crc:04x}")
            }
            Err(err) => {
                write!(f, "Invalid ChannelValueDataResponse message: {err}")
            }
        }
    }
}
#[cfg(test)]
mod tests {
    use crate::Result;
    use super::*;
    #[test]
    #[rustfmt::skip]
    fn test_unit_data_response() -> Result<()> {
        use crate::{STX, ResponseStatus};
        let channel_value_data_response_bytes = [
            STX,
            0x80,
            0x06, 
            0xf0,
            0x04,
            0x05, 0x0a, 0x14, 0x32,
            0xb8, 0xba,
        ];
        let exp_response = ResponseStatus::Ok;
        let exp_num_channels = 4;
        let exp_channel_values = [
            ChannelValue::from(5),
            ChannelValue::from(10),
            ChannelValue::from(20),
            ChannelValue::from(50),
        ];
        let response = ChannelValueDataResponse::try_from(channel_value_data_response_bytes)?;
        assert_eq!(response.len(), channel_value_data_response_bytes.len());
        assert_eq!(response.data_len(), channel_value_data_response_bytes.len() - len::METADATA);
        assert_eq!(response.response_status(), exp_response);
        assert_eq!(response.num_channels(), exp_num_channels);
        assert_eq!(response.channel_values()?.as_ref(), exp_channel_values.as_ref());
        Ok(())
    }
}