use super::{Message, Signals};
use crate::compat::Name;

impl Message {
    pub(crate) fn new(id: u32, name: Name, dlc: u8, sender: Name, signals: Signals) -> Self {
        // Validation should have been done prior (by builder or parse)
        Self {
            id,
            name,
            dlc,
            sender,
            signals,
        }
    }

    /// Returns the CAN message ID.
    ///
    /// This returns the raw CAN ID as it would appear on the bus (11-bit or 29-bit).
    /// For extended (29-bit) IDs, the internal flag bit is stripped.
    /// Use [`is_extended()`](Self::is_extended) to check if this is an extended ID.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::Dbc;
    ///
    /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
    /// let message = dbc.messages().at(0).unwrap();
    /// assert_eq!(message.id(), 256);
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[inline]
    #[must_use = "return value should be used"]
    pub fn id(&self) -> u32 {
        self.id & Self::MAX_EXTENDED_ID
    }

    /// Returns the raw internal ID including any extended ID flag.
    ///
    /// This is primarily for internal use. Most users should use [`id()`](Self::id) instead.
    #[inline]
    #[must_use = "return value should be used"]
    pub(crate) fn id_with_flag(&self) -> u32 {
        self.id
    }

    /// Returns `true` if this message uses an extended (29-bit) CAN ID.
    ///
    /// Standard CAN uses 11-bit identifiers (0-2047), while extended CAN uses 29-bit
    /// identifiers (0-536870911).
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::Dbc;
    ///
    /// // Standard 11-bit ID
    /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
    /// let message = dbc.messages().at(0).unwrap();
    /// assert!(!message.is_extended());
    ///
    /// // Extended 29-bit ID (with flag bit set: 0x80000000 | 0x18DAF115)
    /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 2564485397 OBD2 : 8 ECM"#)?;
    /// let message = dbc.messages().at(0).unwrap();
    /// assert!(message.is_extended());
    /// assert_eq!(message.id(), 0x18DAF115);
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[inline]
    #[must_use = "return value should be used"]
    pub fn is_extended(&self) -> bool {
        (self.id & Self::EXTENDED_ID_FLAG) != 0
    }

    /// Returns the message name.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::Dbc;
    ///
    /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
    /// let message = dbc.messages().at(0).unwrap();
    /// assert_eq!(message.name(), "EngineData");
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[inline]
    #[must_use = "return value should be used"]
    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// Returns the Data Length Code (DLC) in bytes.
    ///
    /// DLC specifies the size of the message payload. For classic CAN, this is 1-8 bytes.
    /// For CAN FD, this can be up to 64 bytes.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::Dbc;
    ///
    /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
    /// let message = dbc.messages().at(0).unwrap();
    /// assert_eq!(message.dlc(), 8);
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[inline]
    #[must_use = "return value should be used"]
    pub fn dlc(&self) -> u8 {
        self.dlc
    }

    /// Get the sender node name for this message.
    ///
    /// The sender is the node that transmits this message on the CAN bus.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::Dbc;
    ///
    /// let dbc = Dbc::parse(r#"VERSION "1.0"
    ///
    /// BU_: ECM TCM
    ///
    /// BO_ 256 Engine : 8 ECM
    ///  SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
    /// "#)?;
    ///
    /// let message = dbc.messages().iter().next().unwrap();
    /// assert_eq!(message.sender(), "ECM");
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[inline]
    #[must_use = "return value should be used"]
    pub fn sender(&self) -> &str {
        self.sender.as_str()
    }

    /// Returns a reference to the signals collection for this message.
    ///
    /// The [`Signals`] collection provides methods to iterate, search, and access signals by index.
    ///
    /// # Examples
    ///
    /// ```rust,no_run
    /// use dbc_rs::Dbc;
    ///
    /// let dbc = Dbc::parse(r#"VERSION "1.0"
    ///
    /// BU_: ECM
    ///
    /// BO_ 256 Engine : 8 ECM
    ///  SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" ECM
    ///  SG_ Torque : 16|16@1+ (0.1,0) [0|500] "Nm" ECM
    /// "#)?;
    ///
    /// let message = dbc.messages().find("Engine").unwrap();
    /// let signals = message.signals();
    /// assert_eq!(signals.len(), 2);
    /// assert!(signals.find("RPM").is_some());
    /// # Ok::<(), dbc_rs::Error>(())
    /// ```
    #[inline]
    #[must_use = "return value should be used"]
    pub fn signals(&self) -> &Signals {
        &self.signals
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{Parser, Signal};

    #[test]
    fn test_message_getters_edge_cases() {
        // Test with minimum values
        let data = b"BO_ 0 A : 1 B";
        let mut parser = Parser::new(data).unwrap();
        let signals: &[Signal] = &[];
        let message = Message::parse(&mut parser, signals).unwrap();

        assert_eq!(message.id(), 0);
        assert_eq!(message.name(), "A");
        assert_eq!(message.dlc(), 1);
        assert_eq!(message.sender(), "B");
    }
}
