//! Wire encoding. The output of these functions is the conformance target.

use alloc::vec::Vec;

use plexus_core::{Error, HeaderType, PacketHeader};

/// Encode a packet header onto the end of `out`.
///
/// Layout (Reticulum manual, "Wire Format"): a flags byte, a hops byte, the
/// address field(s) — 16 bytes for H1, or a 16-byte transport id followed by the
/// 16-byte destination for H2 — and a 1-byte context. IFAC-authenticated framing
/// is not emitted in v0.
///
/// Flags byte (MSB→LSB): `ifac(1) | header_type(1) | context_flag(1) |
/// transport_type(1) | destination_type(2) | packet_type(2)`.
///
/// # Errors
/// [`Error::InvalidValue`] if the header is H2 but carries no transport id.
pub fn encode_header(header: &PacketHeader, out: &mut Vec<u8>) -> Result<(), Error> {
    let mut flags = 0u8;
    if header.ifac {
        flags |= 0b1000_0000;
    }
    flags |= (header.header_type as u8) << 6;
    if header.context_flag {
        flags |= 0b0010_0000;
    }
    flags |= (header.transport_type as u8) << 4;
    flags |= (header.destination_type as u8) << 2;
    flags |= header.packet_type as u8;

    out.push(flags);
    out.push(header.hops);

    if header.header_type == HeaderType::H2 {
        let id = header.transport_id.ok_or(Error::InvalidValue)?;
        out.extend_from_slice(id.as_bytes());
    }
    out.extend_from_slice(header.destination.as_bytes());
    out.push(header.context.0);
    Ok(())
}
