//! Universal Bitstream Protocol
//!
//! Binary wire format for streaming any I/O between source and receiver.
//! Designed to be the same protocol a neural renderer would emit.
//!
//! ## Header Format (16 bytes)
//!
//! ```text
//! ┌──────┬───────┬──────┬───────────┬───────┬────────┬────────┐
//! │ type │ flags │ seq  │ timestamp │ width │ height │ length │
//! │  u8  │  u8   │ u16  │    u32    │  u16  │  u16   │  u32   │
//! └──────┴───────┴──────┴───────────┴───────┴────────┴────────┘
//! ```

/// Frame header size in bytes.
pub const HEADER_SIZE: usize = 16;

/// Protocol version.
pub const PROTOCOL_VERSION: u16 = 12;

/// Check if a remote version is compatible (same major).
pub fn check_version(v: u16) -> bool { v == PROTOCOL_VERSION }

/// Magic bytes for protocol identification.
pub const MAGIC: [u8; 2] = [0xD5, 0x7A]; // "DS" + "z" for stream

// ─── Frame Types ───

/// Output frame types — what the source generates.
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrameType {
    /// Raw RGBA pixel data (width × height × 4 bytes)
    Pixels = 0x01,
    /// PNG/WebP compressed frame
    CompressedPixels = 0x02,
    /// Delta frame — XOR diff from previous keyframe
    DeltaPixels = 0x03,
    /// Audio PCM samples (f32, interleaved channels)
    AudioPcm = 0x10,
    /// Opus-compressed audio chunk
    AudioCompressed = 0x11,
    /// Haptic pulse command
    Haptic = 0x20,
    /// Actuator/motor command
    Actuator = 0x21,
    /// LED/display matrix data
    LedMatrix = 0x22,
    /// Signal graph state sync (DreamStack-native)
    SignalSync = 0x30,
    /// Signal diff — only changed signals
    SignalDiff = 0x31,
    /// Schema announcement — source declares its output signals
    SchemaAnnounce = 0x32,
    /// Subscribe filter — receiver declares which signals it wants
    SubscribeFilter = 0x33,

    // ── Forward-thinking: Neural rendering ──

    /// Neural-generated frame (model output tensor as pixels)
    NeuralFrame = 0x40,
    /// Neural audio synthesis output
    NeuralAudio = 0x41,
    /// Neural actuator command (learned motor control)
    NeuralActuator = 0x42,
    /// Neural scene description (latent space representation)
    NeuralLatent = 0x43,

    // ── v0.12: State Sync ──

    /// State snapshot for reconnect sync
    StateSync = 0x50,

    /// Replay buffer frame
    Replay = 0x51,

    /// RLE-compressed frame
    Compressed = 0x52,

    // ── Control ──

    /// Keyframe — receiver should reset state
    Keyframe = 0xF0,
    /// Authentication handshake
    Auth = 0x0F,
    /// Acknowledgement — receiver → source with seq + RTT
    Ack = 0xFD,
    /// Heartbeat / keep-alive
    Ping = 0xFE,
    /// Stream end
    End = 0xFF,
}

impl FrameType {
    pub fn from_u8(v: u8) -> Option<Self> {
        match v {
            0x01 => Some(Self::Pixels),
            0x02 => Some(Self::CompressedPixels),
            0x03 => Some(Self::DeltaPixels),
            0x10 => Some(Self::AudioPcm),
            0x11 => Some(Self::AudioCompressed),
            0x20 => Some(Self::Haptic),
            0x21 => Some(Self::Actuator),
            0x22 => Some(Self::LedMatrix),
            0x30 => Some(Self::SignalSync),
            0x31 => Some(Self::SignalDiff),
            0x32 => Some(Self::SchemaAnnounce),
            0x33 => Some(Self::SubscribeFilter),
            0x40 => Some(Self::NeuralFrame),
            0x41 => Some(Self::NeuralAudio),
            0x42 => Some(Self::NeuralActuator),
            0x43 => Some(Self::NeuralLatent),
            0x50 => Some(Self::StateSync),
            0x51 => Some(Self::Replay),
            0x52 => Some(Self::Compressed),
            0xF0 => Some(Self::Keyframe),
            0x0F => Some(Self::Auth),
            0xFD => Some(Self::Ack),
            0xFE => Some(Self::Ping),
            0xFF => Some(Self::End),
            _ => None,
        }
    }

    /// Human-readable name for this frame type.
    pub fn name(&self) -> &'static str {
        match self {
            Self::Pixels => "Pixels",
            Self::CompressedPixels => "CompressedPixels",
            Self::DeltaPixels => "DeltaPixels",
            Self::AudioPcm => "AudioPcm",
            Self::AudioCompressed => "AudioCompressed",
            Self::Haptic => "Haptic",
            Self::Actuator => "Actuator",
            Self::LedMatrix => "LedMatrix",
            Self::SignalSync => "SignalSync",
            Self::SignalDiff => "SignalDiff",
            Self::SchemaAnnounce => "SchemaAnnounce",
            Self::SubscribeFilter => "SubscribeFilter",
            Self::NeuralFrame => "NeuralFrame",
            Self::NeuralAudio => "NeuralAudio",
            Self::NeuralActuator => "NeuralActuator",
            Self::NeuralLatent => "NeuralLatent",
            Self::StateSync => "StateSync",
            Self::Replay => "Replay",
            Self::Compressed => "Compressed",
            Self::Keyframe => "Keyframe",
            Self::Auth => "Auth",
            Self::Ack => "Ack",
            Self::Ping => "Ping",
            Self::End => "End",
        }
    }
}

// ─── Input Types ───

/// Input event types — what the receiver sends back.
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InputType {
    /// Pointer/mouse: x(u16), y(u16), buttons(u8)
    Pointer = 0x01,
    /// Pointer down
    PointerDown = 0x02,
    /// Pointer up
    PointerUp = 0x03,
    /// Key down: keycode(u16), modifiers(u8)
    KeyDown = 0x10,
    /// Key up
    KeyUp = 0x11,
    /// Touch start/move: id(u8), x(u16), y(u16)
    Touch = 0x20,
    /// Touch end
    TouchEnd = 0x21,
    /// Gamepad axis: axis(u8), value(f32)
    GamepadAxis = 0x30,
    /// Gamepad button: button(u8), pressed(bool)
    GamepadButton = 0x31,
    /// MIDI message: status(u8), data1(u8), data2(u8)
    Midi = 0x40,
    /// Scroll/wheel: dx(i16), dy(i16)
    Scroll = 0x50,
    /// Resize: width(u16), height(u16)
    Resize = 0x60,

    // ── Forward-thinking ──

    /// Voice/audio input chunk
    VoiceInput = 0x70,
    /// Camera frame from receiver
    CameraInput = 0x71,
    /// Sensor telemetry (accelerometer, gyro, etc.)
    SensorInput = 0x80,
    /// BCI/neural signal input
    BciInput = 0x90,
}

impl InputType {
    pub fn from_u8(v: u8) -> Option<Self> {
        match v {
            0x01 => Some(Self::Pointer),
            0x02 => Some(Self::PointerDown),
            0x03 => Some(Self::PointerUp),
            0x10 => Some(Self::KeyDown),
            0x11 => Some(Self::KeyUp),
            0x20 => Some(Self::Touch),
            0x21 => Some(Self::TouchEnd),
            0x30 => Some(Self::GamepadAxis),
            0x31 => Some(Self::GamepadButton),
            0x40 => Some(Self::Midi),
            0x50 => Some(Self::Scroll),
            0x60 => Some(Self::Resize),
            0x70 => Some(Self::VoiceInput),
            0x71 => Some(Self::CameraInput),
            0x80 => Some(Self::SensorInput),
            0x90 => Some(Self::BciInput),
            _ => None,
        }
    }
}

// ─── Frame Header ───

/// 16-byte frame header for all bitstream messages.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FrameHeader {
    /// Frame type (FrameType or InputType discriminant)
    pub frame_type: u8,
    /// Flags: bit 0 = is_input (1) vs is_output (0), bits 1-7 reserved
    pub flags: u8,
    /// Sequence number (wraps at u16::MAX)
    pub seq: u16,
    /// Timestamp in milliseconds (relative to stream start)
    pub timestamp: u32,
    /// Width (for pixel frames) or channel count (for audio)
    pub width: u16,
    /// Height (for pixel frames) or sample rate / 100 (for audio)
    pub height: u16,
    /// Payload length in bytes
    pub length: u32,
}

/// Flag: this message carries input (receiver → source)
pub const FLAG_INPUT: u8 = 0x01;
/// Flag: this is a keyframe (full state, no delta)
pub const FLAG_KEYFRAME: u8 = 0x02;
/// Flag: payload is compressed
pub const FLAG_COMPRESSED: u8 = 0x04;

impl FrameHeader {
    /// Encode header to 16 bytes (little-endian).
    pub fn encode(&self) -> [u8; HEADER_SIZE] {
        let mut buf = [0u8; HEADER_SIZE];
        buf[0] = self.frame_type;
        buf[1] = self.flags;
        buf[2..4].copy_from_slice(&self.seq.to_le_bytes());
        buf[4..8].copy_from_slice(&self.timestamp.to_le_bytes());
        buf[8..10].copy_from_slice(&self.width.to_le_bytes());
        buf[10..12].copy_from_slice(&self.height.to_le_bytes());
        buf[12..16].copy_from_slice(&self.length.to_le_bytes());
        buf
    }

    /// Decode header from 16 bytes (little-endian).
    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < HEADER_SIZE {
            return None;
        }
        Some(Self {
            frame_type: buf[0],
            flags: buf[1],
            seq: u16::from_le_bytes([buf[2], buf[3]]),
            timestamp: u32::from_le_bytes([buf[4], buf[5], buf[6], buf[7]]),
            width: u16::from_le_bytes([buf[8], buf[9]]),
            height: u16::from_le_bytes([buf[10], buf[11]]),
            length: u32::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
        })
    }

    /// Check if this is an input event (receiver → source).
    pub fn is_input(&self) -> bool {
        self.flags & FLAG_INPUT != 0
    }

    /// Check if this is a keyframe.
    pub fn is_keyframe(&self) -> bool {
        self.flags & FLAG_KEYFRAME != 0
    }
}

// ─── Input Events ───

/// Compact binary input event (pointer).
#[derive(Debug, Clone, Copy)]
pub struct PointerEvent {
    pub x: u16,
    pub y: u16,
    pub buttons: u8,
}

impl PointerEvent {
    pub const SIZE: usize = 5;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0..2].copy_from_slice(&self.x.to_le_bytes());
        buf[2..4].copy_from_slice(&self.y.to_le_bytes());
        buf[4] = self.buttons;
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            x: u16::from_le_bytes([buf[0], buf[1]]),
            y: u16::from_le_bytes([buf[2], buf[3]]),
            buttons: buf[4],
        })
    }
}

/// Compact binary input event (key).
#[derive(Debug, Clone, Copy)]
pub struct KeyEvent {
    pub keycode: u16,
    pub modifiers: u8,
}

impl KeyEvent {
    pub const SIZE: usize = 3;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0..2].copy_from_slice(&self.keycode.to_le_bytes());
        buf[2] = self.modifiers;
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            keycode: u16::from_le_bytes([buf[0], buf[1]]),
            modifiers: buf[2],
        })
    }
}

/// Compact binary scroll event.
#[derive(Debug, Clone, Copy)]
pub struct ScrollEvent {
    pub dx: i16,
    pub dy: i16,
}

impl ScrollEvent {
    pub const SIZE: usize = 4;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0..2].copy_from_slice(&self.dx.to_le_bytes());
        buf[2..4].copy_from_slice(&self.dy.to_le_bytes());
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            dx: i16::from_le_bytes([buf[0], buf[1]]),
            dy: i16::from_le_bytes([buf[2], buf[3]]),
        })
    }
}

/// Touch input event.
#[derive(Debug, Clone, Copy)]
pub struct TouchEvent {
    /// Touch identifier (for multi-touch)
    pub id: u8,
    pub x: u16,
    pub y: u16,
    /// 0 = start/move, 1 = end, 2 = cancel
    pub phase: u8,
}

impl TouchEvent {
    pub const SIZE: usize = 6;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0] = self.id;
        buf[1..3].copy_from_slice(&self.x.to_le_bytes());
        buf[3..5].copy_from_slice(&self.y.to_le_bytes());
        buf[5] = self.phase;
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            id: buf[0],
            x: u16::from_le_bytes([buf[1], buf[2]]),
            y: u16::from_le_bytes([buf[3], buf[4]]),
            phase: buf[5],
        })
    }
}

/// Gamepad axis event.
#[derive(Debug, Clone, Copy)]
pub struct GamepadAxisEvent {
    /// Axis index (0=left-x, 1=left-y, 2=right-x, 3=right-y, 4=left-trigger, 5=right-trigger)
    pub axis: u8,
    /// Axis value: -32768 to 32767 mapped from -1.0 to 1.0
    pub value: i16,
}

impl GamepadAxisEvent {
    pub const SIZE: usize = 3;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0] = self.axis;
        buf[1..3].copy_from_slice(&self.value.to_le_bytes());
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            axis: buf[0],
            value: i16::from_le_bytes([buf[1], buf[2]]),
        })
    }
}

/// Gamepad button event.
#[derive(Debug, Clone, Copy)]
pub struct GamepadButtonEvent {
    /// Button index
    pub button: u8,
    /// 0 = released, 1 = pressed
    pub pressed: u8,
    /// Analog value 0-255 (for triggers)
    pub analog: u8,
}

impl GamepadButtonEvent {
    pub const SIZE: usize = 3;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        [self.button, self.pressed, self.analog]
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            button: buf[0],
            pressed: buf[1],
            analog: buf[2],
        })
    }
}

/// Resize event.
#[derive(Debug, Clone, Copy)]
pub struct ResizeEvent {
    pub width: u16,
    pub height: u16,
}

impl ResizeEvent {
    pub const SIZE: usize = 4;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0..2].copy_from_slice(&self.width.to_le_bytes());
        buf[2..4].copy_from_slice(&self.height.to_le_bytes());
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            width: u16::from_le_bytes([buf[0], buf[1]]),
            height: u16::from_le_bytes([buf[2], buf[3]]),
        })
    }
}

/// MIDI input event: status byte + two data bytes.
#[derive(Debug, Clone, Copy)]
pub struct MidiEvent {
    /// MIDI status byte (e.g., 0x90 = note on, 0x80 = note off)
    pub status: u8,
    /// First data byte (e.g., note number 0-127)
    pub data1: u8,
    /// Second data byte (e.g., velocity 0-127)
    pub data2: u8,
}

impl MidiEvent {
    pub const SIZE: usize = 3;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        [self.status, self.data1, self.data2]
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            status: buf[0],
            data1: buf[1],
            data2: buf[2],
        })
    }
}

/// Voice/audio input header. Payload follows as raw PCM samples.
#[derive(Debug, Clone, Copy)]
pub struct VoiceInputEvent {
    /// Sample rate in Hz (e.g., 16000, 44100, 48000)
    pub sample_rate: u16,
    /// Number of channels (1 = mono, 2 = stereo)
    pub channels: u8,
    /// Format: 0 = f32, 1 = i16, 2 = opus
    pub format: u8,
}

impl VoiceInputEvent {
    pub const SIZE: usize = 4;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0..2].copy_from_slice(&self.sample_rate.to_le_bytes());
        buf[2] = self.channels;
        buf[3] = self.format;
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            sample_rate: u16::from_le_bytes([buf[0], buf[1]]),
            channels: buf[2],
            format: buf[3],
        })
    }
}

/// Camera frame input header. Payload follows as compressed image data.
#[derive(Debug, Clone, Copy)]
pub struct CameraInputEvent {
    /// Frame width in pixels
    pub width: u16,
    /// Frame height in pixels
    pub height: u16,
    /// Format: 0 = RGBA, 1 = JPEG, 2 = WebP, 3 = H264 NAL
    pub format: u8,
}

impl CameraInputEvent {
    pub const SIZE: usize = 5;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0..2].copy_from_slice(&self.width.to_le_bytes());
        buf[2..4].copy_from_slice(&self.height.to_le_bytes());
        buf[4] = self.format;
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            width: u16::from_le_bytes([buf[0], buf[1]]),
            height: u16::from_le_bytes([buf[2], buf[3]]),
            format: buf[4],
        })
    }
}

/// Sensor telemetry input (accelerometer, gyroscope, magnetometer, etc.).
#[derive(Debug, Clone, Copy)]
pub struct SensorInputEvent {
    /// Sensor type: 0 = accelerometer, 1 = gyroscope, 2 = magnetometer, 3 = orientation
    pub sensor_type: u8,
    /// X-axis value (scaled: real_value * 1000)
    pub x: i16,
    /// Y-axis value (scaled: real_value * 1000)
    pub y: i16,
    /// Z-axis value (scaled: real_value * 1000)
    pub z: i16,
}

impl SensorInputEvent {
    pub const SIZE: usize = 7;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0] = self.sensor_type;
        buf[1..3].copy_from_slice(&self.x.to_le_bytes());
        buf[3..5].copy_from_slice(&self.y.to_le_bytes());
        buf[5..7].copy_from_slice(&self.z.to_le_bytes());
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            sensor_type: buf[0],
            x: i16::from_le_bytes([buf[1], buf[2]]),
            y: i16::from_le_bytes([buf[3], buf[4]]),
            z: i16::from_le_bytes([buf[5], buf[6]]),
        })
    }
}

/// BCI (Brain-Computer Interface) input header. Payload follows as f32 samples.
#[derive(Debug, Clone, Copy)]
pub struct BciInputEvent {
    /// Number of EEG/neural channels
    pub channel_count: u8,
    /// Sample rate in Hz
    pub sample_rate: u16,
}

impl BciInputEvent {
    pub const SIZE: usize = 3;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0] = self.channel_count;
        buf[1..3].copy_from_slice(&self.sample_rate.to_le_bytes());
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            channel_count: buf[0],
            sample_rate: u16::from_le_bytes([buf[1], buf[2]]),
        })
    }
}


/// Acknowledgement event — receiver → source for RTT measurement.
#[derive(Debug, Clone, Copy)]
pub struct AckEvent {
    /// Sequence number being acknowledged
    pub ack_seq: u16,
    /// Round-trip time in milliseconds (measured by receiver)
    pub rtt_ms: u16,
}

impl AckEvent {
    pub const SIZE: usize = 4;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0..2].copy_from_slice(&self.ack_seq.to_le_bytes());
        buf[2..4].copy_from_slice(&self.rtt_ms.to_le_bytes());
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE {
            return None;
        }
        Some(Self {
            ack_seq: u16::from_le_bytes([buf[0], buf[1]]),
            rtt_ms: u16::from_le_bytes([buf[2], buf[3]]),
        })
    }
}

/// Get a human-readable name for any frame type byte.
pub fn frame_type_name(type_byte: u8) -> &'static str {
    if let Some(ft) = FrameType::from_u8(type_byte) {
        ft.name()
    } else if InputType::from_u8(type_byte).is_some() {
        match type_byte {
            0x01 => "Pointer",
            0x02 => "PointerDown",
            0x03 => "PointerUp",
            0x10 => "KeyDown",
            0x11 => "KeyUp",
            0x20 => "Touch",
            0x21 => "TouchEnd",
            0x30 => "GamepadAxis",
            0x31 => "GamepadButton",
            0x40 => "Midi",
            0x50 => "Scroll",
            0x60 => "Resize",
            0x70 => "VoiceInput",
            0x71 => "CameraInput",
            0x80 => "SensorInput",
            0x90 => "BciInput",
            _ => "Unknown",
        }
    } else {
        "Unknown"
    }
}

/// Check if a frame type byte represents an input event.
pub fn is_input_type(type_byte: u8) -> bool {
    InputType::from_u8(type_byte).is_some()
}

// ─── Compressed Pixel Format ───

/// Image encoding format for CompressedPixels (0x02) frames.
/// The format byte is the first byte of the CompressedPixels payload.
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompressedPixelFormat {
    Png = 0,
    WebP = 1,
    Jpeg = 2,
}

impl CompressedPixelFormat {
    pub fn from_u8(val: u8) -> Option<Self> {
        match val {
            0 => Some(Self::Png),
            1 => Some(Self::WebP),
            2 => Some(Self::Jpeg),
            _ => None,
        }
    }

    pub fn name(&self) -> &'static str {
        match self {
            Self::Png => "PNG",
            Self::WebP => "WebP",
            Self::Jpeg => "JPEG",
        }
    }

    pub fn mime_type(&self) -> &'static str {
        match self {
            Self::Png => "image/png",
            Self::WebP => "image/webp",
            Self::Jpeg => "image/jpeg",
        }
    }
}

// ─── v0.4: Audio Format ───

/// Audio encoding format for AudioCompressed (0x08) frames.
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AudioFormat {
    Pcm = 0,
    Opus = 1,
    Aac = 2,
}

impl AudioFormat {
    pub fn from_u8(val: u8) -> Option<Self> {
        match val {
            0 => Some(Self::Pcm),
            1 => Some(Self::Opus),
            2 => Some(Self::Aac),
            _ => None,
        }
    }

    pub fn name(&self) -> &'static str {
        match self {
            Self::Pcm => "PCM",
            Self::Opus => "Opus",
            Self::Aac => "AAC",
        }
    }
}

/// Structured audio header (first 8 bytes of AudioCompressed payload).
/// ```text
/// [format: u8] [channels: u8] [sample_rate: u32 LE] [frame_size: u16 LE]
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AudioHeader {
    pub format: AudioFormat,
    pub channels: u8,
    pub sample_rate: u32,
    pub frame_size: u16,
}

impl AudioHeader {
    pub const SIZE: usize = 8;

    pub fn encode(&self) -> [u8; Self::SIZE] {
        let mut buf = [0u8; Self::SIZE];
        buf[0] = self.format as u8;
        buf[1] = self.channels;
        let sr = self.sample_rate.to_le_bytes();
        buf[2] = sr[0]; buf[3] = sr[1]; buf[4] = sr[2]; buf[5] = sr[3];
        let fs = self.frame_size.to_le_bytes();
        buf[6] = fs[0]; buf[7] = fs[1];
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::SIZE { return None; }
        Some(Self {
            format: AudioFormat::from_u8(buf[0])?,
            channels: buf[1],
            sample_rate: u32::from_le_bytes([buf[2], buf[3], buf[4], buf[5]]),
            frame_size: u16::from_le_bytes([buf[6], buf[7]]),
        })
    }
}

// ─── v0.5: Auth Payload ───

/// Authentication handshake payload.
/// Phase 0 = challenge (server → client, carries nonce).
/// Phase 1 = response (client → server, carries token + nonce).
#[derive(Debug, Clone, PartialEq)]
pub struct AuthPayload {
    pub phase: u8,
    pub nonce: [u8; 8],
    pub token: Vec<u8>,
}

impl AuthPayload {
    /// Minimum encoded size (phase + nonce).
    pub const MIN_SIZE: usize = 9;

    pub fn encode(&self) -> Vec<u8> {
        let mut buf = Vec::with_capacity(Self::MIN_SIZE + self.token.len());
        buf.push(self.phase);
        buf.extend_from_slice(&self.nonce);
        buf.extend_from_slice(&self.token);
        buf
    }

    pub fn decode(buf: &[u8]) -> Option<Self> {
        if buf.len() < Self::MIN_SIZE { return None; }
        let mut nonce = [0u8; 8];
        nonce.copy_from_slice(&buf[1..9]);
        Some(Self {
            phase: buf[0],
            nonce,
            token: buf[9..].to_vec(),
        })
    }
}

// ─── v0.5: XOR Scrambling ───

/// XOR-scramble a payload with a repeating key. Not encryption — just obfuscation.
pub fn scramble_payload(payload: &[u8], key: &[u8]) -> Vec<u8> {
    if key.is_empty() { return payload.to_vec(); }
    payload.iter().enumerate().map(|(i, &b)| b ^ key[i % key.len()]).collect()
}

/// Descramble = same operation (XOR is its own inverse).
pub fn descramble_payload(payload: &[u8], key: &[u8]) -> Vec<u8> {
    scramble_payload(payload, key)
}

// ─── v0.10: Stream Multiplexing ───

/// Stream ID occupies the upper 4 bits of the flags byte (supports 0-15).
pub type StreamId = u8;

/// Mask for extracting stream ID from flags.
pub const STREAM_ID_MASK: u8 = 0xF0;
/// Mask for extracting non-stream flags from flags.
pub const FLAGS_MASK: u8 = 0x0F;

/// Extract stream ID from flags byte.
pub fn extract_stream_id(flags: u8) -> StreamId {
    (flags & STREAM_ID_MASK) >> 4
}

/// Embed stream ID into flags byte (preserves lower 4 flag bits).
pub fn embed_stream_id(flags: u8, stream_id: StreamId) -> u8 {
    (flags & FLAGS_MASK) | ((stream_id & 0x0F) << 4)
}

// ─── v0.11: Stream Health ───

/// Compute composite stream health score (0.0 = dead, 1.0 = perfect).
/// Inputs: frame_count (recent window), avg_rtt_ms, throughput_bps, drop_rate (0.0-1.0).
pub fn compute_health(frame_count: u64, avg_rtt_ms: f64, throughput_bps: f64, drop_rate: f64) -> f32 {
    // Score components (each 0.0-1.0):
    let frame_score = (frame_count as f64 / 30.0).min(1.0); // 30+ fps = perfect
    let latency_score = (1.0 - (avg_rtt_ms / 500.0).min(1.0)).max(0.0); // <500ms = good
    let throughput_score = (throughput_bps / 1_000_000.0).min(1.0); // 1Mbps = perfect
    let drop_score = (1.0 - drop_rate * 5.0).max(0.0); // >20% drops = 0

    // Weighted average: latency and drops matter most
    let health = frame_score * 0.2 + latency_score * 0.3 + throughput_score * 0.2 + drop_score * 0.3;
    health as f32
}

// ─── Tests ───

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn header_roundtrip() {
        let header = FrameHeader {
            frame_type: FrameType::Pixels as u8,
            flags: FLAG_KEYFRAME,
            seq: 42,
            timestamp: 1234567,
            width: 1920,
            height: 1080,
            length: 1920 * 1080 * 4,
        };
        let encoded = header.encode();
        let decoded = FrameHeader::decode(&encoded).unwrap();
        assert_eq!(header, decoded);
    }

    #[test]
    fn header_too_short() {
        assert!(FrameHeader::decode(&[0u8; 15]).is_none());
    }

    #[test]
    fn pointer_event_roundtrip() {
        let evt = PointerEvent { x: 500, y: 300, buttons: 1 };
        let encoded = evt.encode();
        let decoded = PointerEvent::decode(&encoded).unwrap();
        assert_eq!(evt.x, decoded.x);
        assert_eq!(evt.y, decoded.y);
        assert_eq!(evt.buttons, decoded.buttons);
    }

    #[test]
    fn key_event_roundtrip() {
        let evt = KeyEvent { keycode: 0x0041, modifiers: 0x03 };
        let encoded = evt.encode();
        let decoded = KeyEvent::decode(&encoded).unwrap();
        assert_eq!(evt.keycode, decoded.keycode);
        assert_eq!(evt.modifiers, decoded.modifiers);
    }

    #[test]
    fn scroll_event_roundtrip() {
        let evt = ScrollEvent { dx: -120, dy: 360 };
        let encoded = evt.encode();
        let decoded = ScrollEvent::decode(&encoded).unwrap();
        assert_eq!(evt.dx, decoded.dx);
        assert_eq!(evt.dy, decoded.dy);
    }

    #[test]
    fn frame_type_roundtrip() {
        for val in [0x01, 0x02, 0x03, 0x10, 0x11, 0x20, 0x30, 0x31, 0x40, 0x41, 0xF0, 0xFD, 0xFE, 0xFF] {
            let ft = FrameType::from_u8(val);
            assert!(ft.is_some(), "FrameType::from_u8({:#x}) should be Some", val);
            assert_eq!(ft.unwrap() as u8, val);
        }
        assert!(FrameType::from_u8(0x99).is_none());
    }

    #[test]
    fn ack_event_roundtrip() {
        let evt = AckEvent { ack_seq: 42, rtt_ms: 15 };
        let encoded = evt.encode();
        let decoded = AckEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.ack_seq, 42);
        assert_eq!(decoded.rtt_ms, 15);
    }

    #[test]
    fn ack_event_too_short() {
        assert!(AckEvent::decode(&[0u8; 3]).is_none());
    }

    #[test]
    fn frame_type_name_lookup() {
        assert_eq!(frame_type_name(0x01), "Pixels");
        assert_eq!(frame_type_name(0xFD), "Ack");
        assert_eq!(frame_type_name(0xFE), "Ping");
        assert_eq!(frame_type_name(0xFF), "End");
        assert_eq!(frame_type_name(0x99), "Unknown");
    }

    #[test]
    fn is_input_type_check() {
        assert!(is_input_type(0x01));  // Pointer (also Pixels — shared value)
        assert!(is_input_type(0x50));  // Scroll
        assert!(is_input_type(0x90));  // BciInput
        assert!(!is_input_type(0xFE)); // Ping — not an input type
        assert!(!is_input_type(0xF0)); // Keyframe — not an input type
    }

    #[test]
    fn input_type_roundtrip() {
        for val in [0x01, 0x02, 0x03, 0x10, 0x11, 0x20, 0x21, 0x30, 0x31, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90] {
            let it = InputType::from_u8(val);
            assert!(it.is_some(), "InputType::from_u8({:#x}) should be Some", val);
            assert_eq!(it.unwrap() as u8, val);
        }
        assert!(InputType::from_u8(0xAA).is_none());
    }

    #[test]
    fn header_flags() {
        let h = FrameHeader {
            frame_type: FrameType::Pixels as u8,
            flags: FLAG_INPUT | FLAG_KEYFRAME,
            seq: 0,
            timestamp: 0,
            width: 0,
            height: 0,
            length: 0,
        };
        assert!(h.is_input());
        assert!(h.is_keyframe());

        let h2 = FrameHeader { flags: 0, ..h };
        assert!(!h2.is_input());
        assert!(!h2.is_keyframe());
    }

    #[test]
    fn touch_event_roundtrip() {
        let evt = TouchEvent { id: 2, x: 400, y: 600, phase: 0 };
        let encoded = evt.encode();
        let decoded = TouchEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.id, 2);
        assert_eq!(decoded.x, 400);
        assert_eq!(decoded.y, 600);
        assert_eq!(decoded.phase, 0);
    }

    #[test]
    fn gamepad_axis_roundtrip() {
        let evt = GamepadAxisEvent { axis: 1, value: -16384 };
        let encoded = evt.encode();
        let decoded = GamepadAxisEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.axis, 1);
        assert_eq!(decoded.value, -16384);
    }

    #[test]
    fn gamepad_button_roundtrip() {
        let evt = GamepadButtonEvent { button: 5, pressed: 1, analog: 200 };
        let encoded = evt.encode();
        let decoded = GamepadButtonEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.button, 5);
        assert_eq!(decoded.pressed, 1);
        assert_eq!(decoded.analog, 200);
    }

    #[test]
    fn resize_event_roundtrip() {
        let evt = ResizeEvent { width: 1920, height: 1080 };
        let encoded = evt.encode();
        let decoded = ResizeEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.width, 1920);
        assert_eq!(decoded.height, 1080);
    }

    #[test]
    fn touch_event_too_short() {
        assert!(TouchEvent::decode(&[0u8; 5]).is_none());
    }

    #[test]
    fn gamepad_axis_too_short() {
        assert!(GamepadAxisEvent::decode(&[0u8; 2]).is_none());
    }

    #[test]
    fn midi_event_roundtrip() {
        let evt = MidiEvent { status: 0x90, data1: 60, data2: 100 };
        let encoded = evt.encode();
        let decoded = MidiEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.status, 0x90);
        assert_eq!(decoded.data1, 60);
        assert_eq!(decoded.data2, 100);
    }

    #[test]
    fn midi_event_too_short() {
        assert!(MidiEvent::decode(&[0u8; 2]).is_none());
    }

    #[test]
    fn voice_input_event_roundtrip() {
        let evt = VoiceInputEvent { sample_rate: 48000, channels: 2, format: 0 };
        let encoded = evt.encode();
        let decoded = VoiceInputEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.sample_rate, 48000);
        assert_eq!(decoded.channels, 2);
        assert_eq!(decoded.format, 0);
    }

    #[test]
    fn voice_input_event_too_short() {
        assert!(VoiceInputEvent::decode(&[0u8; 3]).is_none());
    }

    #[test]
    fn camera_input_event_roundtrip() {
        let evt = CameraInputEvent { width: 1280, height: 720, format: 2 };
        let encoded = evt.encode();
        let decoded = CameraInputEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.width, 1280);
        assert_eq!(decoded.height, 720);
        assert_eq!(decoded.format, 2);
    }

    #[test]
    fn camera_input_event_too_short() {
        assert!(CameraInputEvent::decode(&[0u8; 4]).is_none());
    }

    #[test]
    fn sensor_input_event_roundtrip() {
        let evt = SensorInputEvent { sensor_type: 1, x: -1000, y: 500, z: 9800 };
        let encoded = evt.encode();
        let decoded = SensorInputEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.sensor_type, 1);
        assert_eq!(decoded.x, -1000);
        assert_eq!(decoded.y, 500);
        assert_eq!(decoded.z, 9800);
    }

    #[test]
    fn sensor_input_event_too_short() {
        assert!(SensorInputEvent::decode(&[0u8; 6]).is_none());
    }

    #[test]
    fn bci_input_event_roundtrip() {
        let evt = BciInputEvent { channel_count: 32, sample_rate: 256 };
        let encoded = evt.encode();
        let decoded = BciInputEvent::decode(&encoded).unwrap();
        assert_eq!(decoded.channel_count, 32);
        assert_eq!(decoded.sample_rate, 256);
    }

    #[test]
    fn bci_input_event_too_short() {
        assert!(BciInputEvent::decode(&[0u8; 2]).is_none());
    }
}
