//! MAVLink v2 codec for the §7.7 command surface (per `architecture.md`).
//!
//! Strictly hand-rolled — no third-party MAVLink SDK. Adding any message
//! outside the §7.7 surface enumerated in [`MavlinkMessage`] requires an
//! explicit design-review note in the PR description.

pub mod crc;
pub mod decoder;
pub mod encoder;
pub mod messages;
pub mod parse_errors;

pub use decoder::{Decoder, DecoderEvent};
pub use encoder::Encoder;
pub use messages::{
    Attitude, CommandAck, CommandLong, ExtendedSysState, GlobalPositionInt, Heartbeat,
    MavlinkMessage, MissionAck, MissionClearAll, MissionCount, MissionCurrent, MissionItemInt,
    MissionItemReached, MissionRequestInt, MissionSetCurrent, SetMode, StatusText, SysStatus,
};
pub use parse_errors::{ParseErrorKind, ParseErrors};

/// MAVLink v2 frame start byte.
pub const MAVLINK_V2_STX: u8 = 0xFD;
/// Frame header size in bytes (STX..msgid inclusive).
pub const HEADER_LEN: usize = 10;
/// CRC trailer length in bytes.
#[allow(dead_code)] // Used in the AZ-642 integration tests below and by AZ-643 signing math.
pub const CRC_LEN: usize = 2;
/// Signature trailer length when `incompat_flags` bit 0 is set.
pub const SIGNATURE_LEN: usize = 13;
/// Maximum possible payload length (255 per the spec).
pub const MAX_PAYLOAD: usize = 255;
/// Incompat-flag bit indicating a signed frame.
pub const INCOMPAT_FLAG_SIGNED: u8 = 0x01;

#[derive(Debug, thiserror::Error)]
pub enum MavlinkParseError {
    #[error("truncated payload (have {have} bytes, need {need})")]
    TruncatedPayload { have: usize, need: usize },
    #[error("wrong CRC (computed {computed:#06x}, frame {frame:#06x})")]
    CrcMismatch { computed: u16, frame: u16 },
    #[error("unknown message id {0}")]
    UnknownMessageId(u32),
    #[error("invalid payload for message id {msg_id}: {reason}")]
    InvalidPayload { msg_id: u32, reason: &'static str },
}
