#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-media -- Media Framework Core (RTP, codec negotiation, pipeline)
pub mod rtp;
use std::collections::HashMap;

#[derive(Debug)]
pub enum MediaError { UnsupportedCodec(String), PipelineError(String), PayloadTooLarge(String) }
impl std::fmt::Display for MediaError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self { Self::UnsupportedCodec(e) => write!(f, "Unsupported: {e}"), Self::PipelineError(e) => write!(f, "Pipeline: {e}"), Self::PayloadTooLarge(e) => write!(f, "Too large: {e}") }
    }
}
impl std::error::Error for MediaError {}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CodecType { H264, H265, VP8, VP9, AV1, Opus, G711 }
impl CodecType {
    pub fn payload_type(&self) -> u8 {
        match self { Self::H264 => 96, Self::H265 => 97, Self::VP8 => 98, Self::VP9 => 99, Self::AV1 => 100, Self::Opus => 111, Self::G711 => 0 }
    }
    pub fn clock_rate(&self) -> u32 {
        match self { Self::Opus => 48000, Self::G711 => 8000, _ => 90000 }
    }
}

#[derive(Debug, Clone)]
pub struct RtpPacket {
    pub version: u8, pub payload_type: u8, pub sequence: u16,
    pub timestamp: u32, pub ssrc: u32, pub payload: Vec<u8>,
    pub marker: bool,
}

impl RtpPacket {
    pub fn new(pt: u8, seq: u16, ts: u32, ssrc: u32, payload: Vec<u8>, marker: bool) -> Self {
        Self { version: 2, payload_type: pt, sequence: seq, timestamp: ts, ssrc: ssrc, payload, marker }
    }
    /// Serialize to bytes (simplified RTP header)
    pub fn to_bytes(&self) -> Vec<u8> {
        let mut buf = Vec::with_capacity(12 + self.payload.len());
        buf.push((self.version << 6) | if self.marker { 0x80 >> 1 } else { 0 });
        buf.push(self.payload_type | if self.marker { 0x80 } else { 0 });
        buf.extend_from_slice(&self.sequence.to_be_bytes());
        buf.extend_from_slice(&self.timestamp.to_be_bytes());
        buf.extend_from_slice(&self.ssrc.to_be_bytes());
        buf.extend_from_slice(&self.payload);
        buf
    }
    /// Parse from bytes
    pub fn from_bytes(data: &[u8]) -> Result<Self, MediaError> {
        if data.len() < 12 { return Err(MediaError::PayloadTooLarge("Packet too small".into())); }
        let version = (data[0] >> 6) & 0x03;
        let marker = (data[1] & 0x80) != 0;
        let pt = data[1] & 0x7F;
        let seq = u16::from_be_bytes([data[2], data[3]]);
        let ts = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
        let ssrc = u32::from_be_bytes([data[8], data[9], data[10], data[11]]);
        Ok(Self { version, payload_type: pt, sequence: seq, timestamp: ts, ssrc, payload: data[12..].to_vec(), marker })
    }
}

/// Codec negotiation: find common codecs between offer and answer
pub fn negotiate_codecs(offer: &[CodecType], answer: &[CodecType]) -> Vec<CodecType> {
    offer.iter().filter(|c| answer.contains(c)).cloned().collect()
}

/// Jitter buffer: reorder packets by sequence number
pub struct JitterBuffer { buffer: HashMap<u16, RtpPacket>, next_seq: u16, max_size: usize }
impl JitterBuffer {
    pub fn new(max_size: usize) -> Self { Self { buffer: HashMap::new(), next_seq: 0, max_size } }
    pub fn push(&mut self, pkt: RtpPacket) {
        if self.buffer.len() >= self.max_size { self.buffer.remove(&self.next_seq); self.next_seq = self.next_seq.wrapping_add(1); }
        self.buffer.insert(pkt.sequence, pkt);
    }
    pub fn pop_ordered(&mut self) -> Option<RtpPacket> {
        let pkt = self.buffer.remove(&self.next_seq)?;
        self.next_seq = self.next_seq.wrapping_add(1);
        Some(pkt)
    }
    pub fn len(&self) -> usize { self.buffer.len() }
    pub fn is_empty(&self) -> bool { self.buffer.is_empty() }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_rtp_roundtrip() {
        let pkt = RtpPacket::new(96, 42, 1000, 0xDEAD, vec![1, 2, 3], true);
        let bytes = pkt.to_bytes();
        let parsed = RtpPacket::from_bytes(&bytes).unwrap();
        assert_eq!(parsed.sequence, 42);
        assert_eq!(parsed.payload, vec![1, 2, 3]);
    }
    #[test]
    fn test_negotiate() {
        let offer = vec![CodecType::VP9, CodecType::H264, CodecType::Opus];
        let answer = vec![CodecType::H264, CodecType::Opus, CodecType::AV1];
        let common = negotiate_codecs(&offer, &answer);
        assert_eq!(common, vec![CodecType::H264, CodecType::Opus]);
    }
    #[test]
    fn test_jitter_buffer() {
        let mut jb = JitterBuffer::new(10);
        jb.push(RtpPacket::new(96, 2, 2000, 1, vec![], false));
        jb.push(RtpPacket::new(96, 0, 0, 1, vec![], false));
        jb.push(RtpPacket::new(96, 1, 1000, 1, vec![], false));
        let p0 = jb.pop_ordered().unwrap();
        assert_eq!(p0.sequence, 0);
        let p1 = jb.pop_ordered().unwrap();
        assert_eq!(p1.sequence, 1);
    }
}
