//! RFC 3550 RTP compliance tests.
//!
//! These tests verify compliance with RFC 3550 (RTP: A Transport Protocol for Real-Time Applications),
//! focusing on packet structure, sequence number handling, timestamp management, SSRC collision detection,
//! and RTCP requirements.

use crate::rtp::*;
use bytes::Bytes;

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

    /// RFC 3550 Section 5.1: RTP version must be 2
    #[test]
    fn test_rtp_version_2() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet = session.create_packet(vec![1, 2, 3, 4], 160, false);
        assert_eq!(packet.version, 2);
    }

    /// RFC 3550 Section 5.1: Minimal RTP header is 12 bytes
    #[test]
    fn test_minimal_header_size() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet = session.create_packet(vec![0; 10], 160, false);
        let bytes = packet.build();
        // Minimal header (12 bytes) + payload (10 bytes)
        assert!(bytes.len() >= RTP_HEADER_SIZE);
    }

    /// RFC 3550 Section 5.1: Parse minimal valid RTP packet
    #[test]
    fn test_parse_minimal_packet() {
        let data = [
            0x80, // V=2, P=0, X=0, CC=0
            0x00, // M=0, PT=0
            0x00, 0x01, // Sequence 1
            0x00, 0x00, 0x00, 0xa0, // Timestamp 160
            0x00, 0x00, 0x30, 0x39, // SSRC 12345
            0xaa, 0xbb, // Payload
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert_eq!(packet.version, 2);
        assert!(!packet.padding);
        assert!(!packet.extension);
        assert_eq!(packet.payload_type, 0);
        assert_eq!(packet.sequence_number, 1);
        assert_eq!(packet.timestamp, 160);
        assert_eq!(packet.ssrc, 12345);
        assert_eq!(packet.payload.len(), 2);
    }

    /// RFC 3550 Section 5.1: Reject packets with invalid version
    #[test]
    fn test_reject_invalid_version() {
        let data = [
            0x40, // V=1 (invalid), P=0, X=0, CC=0
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa, 0xbb,
        ];

        let result = RtpPacket::parse(&data);
        assert!(result.is_err());
        assert!(matches!(result, Err(RtpParseError::InvalidVersion(1))));
    }

    /// RFC 3550 Section 5.1: Reject truncated packets
    #[test]
    fn test_reject_truncated_packet() {
        let data = [0x80, 0x00, 0x00, 0x01]; // Only 4 bytes
        let result = RtpPacket::parse(&data);
        assert!(result.is_err());
        assert!(matches!(result, Err(RtpParseError::TooShort(_))));
    }

    /// RFC 3550 Section 5.1: Marker bit handling
    #[test]
    fn test_marker_bit() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet_no_marker = session.create_packet(vec![1, 2, 3], 160, false);
        assert!(!packet_no_marker.marker);

        let packet_with_marker = session.create_packet(vec![1, 2, 3], 320, true);
        assert!(packet_with_marker.marker);
    }

    /// RFC 3550 Section 5.1: Payload type field (7 bits)
    #[test]
    fn test_payload_type() {
        let mut session = RtpSession::new(12345, 96, 8000);
        let packet = session.create_packet(vec![0; 10], 160, false);
        assert_eq!(packet.payload_type, 96);
    }

    /// RFC 3550 Section 5.1: Payload type maximum value (127)
    #[test]
    fn test_payload_type_max() {
        let data = [
            0x80, 0xFF, // V=2, M=1, PT=127 (max)
            0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa,
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert_eq!(packet.payload_type, 127);
        assert!(packet.marker);
    }
}

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

    /// RFC 3550 Section 5.1: Sequence numbers increment by 1
    #[test]
    fn test_sequence_increment() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet1 = session.create_packet(vec![1], 160, false);
        let packet2 = session.create_packet(vec![2], 320, false);
        assert_eq!(
            packet2.sequence_number,
            packet1.sequence_number.wrapping_add(1)
        );
    }

    /// RFC 3550 Appendix A.1: Sequence number wraparound (65535 -> 0)
    #[test]
    fn test_sequence_wraparound() {
        let mut session = RtpSession::new(12345, 0, 8000);

        // Create 65536 packets to force wraparound (impractical, so test logic instead)
        let packet1 = session.create_packet(vec![1], 160, false);
        let seq1 = packet1.sequence_number;

        // Test that wrapping_add works correctly
        assert_eq!(65535_u16.wrapping_add(1), 0);
        assert_eq!(seq1.wrapping_add(1), seq1 + 1);
    }

    /// RFC 3550 Appendix A.1: Sequence comparison with wraparound
    #[test]
    fn test_sequence_newer() {
        // Normal case: 100 is newer than 99
        assert!(sequence_newer(100, 99));

        // Wraparound case: 10 is newer than 65530
        assert!(sequence_newer(10, 65530));

        // Not newer
        assert!(!sequence_newer(99, 100));
    }

    /// RFC 3550 Appendix A.1: Sequence difference calculation
    #[test]
    fn test_sequence_diff() {
        // Normal case
        assert_eq!(sequence_diff(100, 99), 1);

        // Wraparound case
        assert_eq!(sequence_diff(10, 65535), 11);

        // Negative diff
        assert_eq!(sequence_diff(99, 100), -1);
    }

    /// RFC 3550 Appendix A.1: Handle large sequence jumps
    #[test]
    fn test_large_sequence_jump() {
        // Jump of 32768 (half of u16 range) is ambiguous
        // sequence_diff treats it based on signed 16-bit arithmetic
        let diff = sequence_diff(40000, 7232);
        // This is actually a backward jump: 40000 - 7232 = 32768
        // In signed i16, this wraps to -32768, so diff will be negative
        assert_ne!(diff, 0);
    }
}

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

    /// RFC 3550 Section 5.1: Timestamps increment by sample count
    #[test]
    fn test_timestamp_increment() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet1 = session.create_packet(vec![0; 160], 160, false);
        let ts1 = packet1.timestamp;

        let packet2 = session.create_packet(vec![0; 160], 160, false);
        let ts2 = packet2.timestamp;

        assert_eq!(ts2, ts1 + 160);
    }

    /// RFC 3550 Section 5.1: Timestamp wraparound (32-bit)
    #[test]
    fn test_timestamp_wraparound() {
        // Test that wraparound works correctly arithmetically
        let ts_near_max = u32::MAX - 100;
        let new_ts = ts_near_max.wrapping_add(160);

        // Should wrap around
        assert!(new_ts < ts_near_max);
        assert_eq!(new_ts, 59); // (4294967295 - 100 + 160) % 2^32 = 59
    }

    /// RFC 3550 Section 5.1: Timestamp for different clock rates
    #[test]
    fn test_timestamp_clock_rate() {
        // 8kHz clock (like G.711)
        let mut session_8k = RtpSession::new(12345, 0, 8000);
        let packet1_8k = session_8k.create_packet(vec![0; 160], 160, false);
        let packet2_8k = session_8k.create_packet(vec![0; 160], 160, false);

        // 16kHz clock (like G.722)
        let mut session_16k = RtpSession::new(12346, 9, 16000);
        let packet1_16k = session_16k.create_packet(vec![0; 320], 320, false);
        let packet2_16k = session_16k.create_packet(vec![0; 320], 320, false);

        // Timestamps should increment by the sample count provided
        assert_eq!(packet2_8k.timestamp, packet1_8k.timestamp + 160);
        assert_eq!(packet2_16k.timestamp, packet1_16k.timestamp + 320);
    }
}

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

    /// RFC 3550 Section 5.1: SSRC is constant for a session
    #[test]
    fn test_ssrc_constant() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet1 = session.create_packet(vec![1], 160, false);
        let packet2 = session.create_packet(vec![2], 320, false);
        assert_eq!(packet1.ssrc, packet2.ssrc);
        assert_eq!(packet1.ssrc, 12345);
    }

    /// RFC 3550 Section 8.2: SSRC collision detection
    #[test]
    fn test_ssrc_collision_detection() {
        let _session = RtpSession::new(12345, 0, 8000);

        // Receive packet from same SSRC
        let data = [
            0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30,
            0x39, // SSRC 12345 (collision!)
            0xaa, 0xbb,
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert_eq!(packet.ssrc, 12345);

        // Session should detect this collision in practice
        // (implementation detail - just verify we can parse it)
    }

    /// RFC 3550 Section 5.1: Different SSRCs from different sources
    #[test]
    fn test_different_ssrcs() {
        let session1 = RtpSession::new(11111, 0, 8000);
        let session2 = RtpSession::new(22222, 0, 8000);

        assert_ne!(session1.ssrc(), session2.ssrc());
    }
}

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

    /// RFC 3550 Section 5.1: CSRC count field (4 bits, max 15)
    #[test]
    fn test_max_csrc_count() {
        assert_eq!(MAX_CSRC, 15);
    }

    /// RFC 3550 Section 5.1: Parse packet with CSRC list
    #[test]
    fn test_parse_with_csrc() {
        let data = [
            0x82, // V=2, P=0, X=0, CC=2
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, // SSRC
            0x00, 0x00, 0x00, 0x01, // CSRC[0]
            0x00, 0x00, 0x00, 0x02, // CSRC[1]
            0xaa, 0xbb, // Payload
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert_eq!(packet.csrc.len(), 2);
        assert_eq!(packet.csrc[0], 1);
        assert_eq!(packet.csrc[1], 2);
    }

    /// RFC 3550 Section 5.1: Empty CSRC list
    #[test]
    fn test_empty_csrc() {
        let data = [
            0x80, // V=2, CC=0
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa,
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert_eq!(packet.csrc.len(), 0);
    }

    /// RFC 3550 Section 5.1: Truncated CSRC list should error
    #[test]
    fn test_truncated_csrc() {
        let data = [
            0x82, // V=2, CC=2 (claims 2 CSRCs)
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, // SSRC
            0x00, 0x00, 0x00, 0x01, // Only 1 CSRC (missing second one)
        ];

        let result = RtpPacket::parse(&data);
        assert!(result.is_err());
    }
}

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

    /// RFC 3550 Section 5.1: Padding bit and padding count
    #[test]
    fn test_padding_bit() {
        let data = [
            0xA0, // V=2, P=1 (padding), X=0, CC=0
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, // SSRC
            0xaa, 0xbb, 0xcc, // Payload
            0x00, 0x04, // Padding (last byte = 4 bytes of padding)
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert!(packet.padding);
        // Payload should be shorter due to padding removal
        assert_eq!(packet.payload.len(), 1); // Original 5 bytes - 4 padding = 1
    }

    /// RFC 3550 Section 5.1: No padding
    #[test]
    fn test_no_padding() {
        let data = [
            0x80, // P=0 (no padding)
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa, 0xbb,
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert!(!packet.padding);
        assert_eq!(packet.payload.len(), 2);
    }
}

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

    /// RFC 3550 Section 5.3.1: Extension header format
    #[test]
    fn test_extension_header() {
        let data = [
            0x90, // V=2, P=0, X=1 (extension), CC=0
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, // SSRC
            0xAB, 0xCD, // Extension profile
            0x00, 0x01, // Length = 1 word (4 bytes)
            0x11, 0x22, 0x33, 0x44, // Extension data
            0xaa, 0xbb, // Payload
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert!(packet.extension);
        assert!(packet.extension_header.is_some());

        let ext = packet.extension_header.unwrap();
        assert_eq!(ext.profile, 0xABCD);
        assert_eq!(ext.data.len(), 4);
        assert_eq!(&ext.data[..], &[0x11, 0x22, 0x33, 0x44]);
    }

    /// RFC 3550 Section 5.3.1: No extension header
    #[test]
    fn test_no_extension() {
        let data = [
            0x80, // X=0 (no extension)
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, 0xaa,
        ];

        let packet = RtpPacket::parse(&data).unwrap();
        assert!(!packet.extension);
        assert!(packet.extension_header.is_none());
    }

    /// RFC 3550 Section 5.3.1: Truncated extension header
    #[test]
    fn test_truncated_extension() {
        let data = [
            0x90, // X=1
            0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x30, 0x39, // SSRC
            0xAB, 0xCD, // Profile
                  // Missing length field
        ];

        let result = RtpPacket::parse(&data);
        assert!(result.is_err());
    }
}

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

    /// RFC 3550 Section 5.1: Build and re-parse packet
    #[test]
    fn test_build_and_parse_roundtrip() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let original_payload = vec![0xAA, 0xBB, 0xCC, 0xDD];
        let packet = session.create_packet(original_payload.clone(), 160, true);

        let bytes = packet.build();
        let parsed = RtpPacket::parse(&bytes).unwrap();

        assert_eq!(parsed.version, 2);
        assert_eq!(parsed.payload_type, 0);
        assert_eq!(parsed.ssrc, 12345);
        assert!(parsed.marker);
        assert_eq!(&parsed.payload[..], &original_payload[..]);
    }

    /// RFC 3550 Section 5.1: Build packet with all features
    #[test]
    fn test_build_complex_packet() {
        let packet = RtpPacket {
            version: 2,
            padding: false,
            extension: false,
            marker: true,
            payload_type: 96,
            sequence_number: 12345,
            timestamp: 987654,
            ssrc: 0xDEADBEEF,
            csrc: vec![0x1111, 0x2222],
            extension_header: None,
            payload: Bytes::from_static(&[0xAA, 0xBB, 0xCC]),
        };

        let bytes = packet.build();
        let parsed = RtpPacket::parse(&bytes).unwrap();

        assert_eq!(parsed.version, 2);
        assert_eq!(parsed.payload_type, 96);
        assert_eq!(parsed.sequence_number, 12345);
        assert_eq!(parsed.timestamp, 987654);
        assert_eq!(parsed.ssrc, 0xDEADBEEF);
        assert_eq!(parsed.csrc.len(), 2);
        assert_eq!(parsed.csrc[0], 0x1111);
        assert_eq!(parsed.csrc[1], 0x2222);
    }
}

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

    /// RFC 3550 Section 6: Session creation with initial values
    #[test]
    fn test_session_creation() {
        let session = RtpSession::new(12345, 0, 8000);
        assert_eq!(session.ssrc(), 12345);
    }

    /// RFC 3550 Section 6: Session tracks sequence and timestamp
    #[test]
    fn test_session_tracking() {
        let mut session = RtpSession::new(12345, 0, 8000);

        let packet1 = session.create_packet(vec![0; 160], 160, false);
        let seq1 = packet1.sequence_number;
        let ts1 = packet1.timestamp;

        let packet2 = session.create_packet(vec![0; 160], 160, false);
        assert_eq!(packet2.sequence_number, seq1 + 1);
        assert_eq!(packet2.timestamp, ts1 + 160);
    }

    /// RFC 3550: Payload type is set at session creation
    #[test]
    fn test_session_payload_type() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet1 = session.create_packet(vec![0; 10], 160, false);
        assert_eq!(packet1.payload_type, 0);

        // Create a new session with different payload type
        let mut session2 = RtpSession::new(12345, 96, 8000);
        let packet2 = session2.create_packet(vec![0; 10], 160, false);
        assert_eq!(packet2.payload_type, 96);
    }
}

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

    /// Empty payload is valid
    #[test]
    fn test_empty_payload() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let packet = session.create_packet(vec![], 160, false);
        assert_eq!(packet.payload.len(), 0);

        let bytes = packet.build();
        let parsed = RtpPacket::parse(&bytes).unwrap();
        assert_eq!(parsed.payload.len(), 0);
    }

    /// Maximum payload size
    #[test]
    fn test_large_payload() {
        let mut session = RtpSession::new(12345, 0, 8000);
        let large_payload = vec![0xAA; 1400]; // Typical MTU size
        let packet = session.create_packet(large_payload.clone(), 160, false);

        let bytes = packet.build();
        let parsed = RtpPacket::parse(&bytes).unwrap();
        assert_eq!(parsed.payload.len(), 1400);
    }

    /// All payload types (0-127)
    #[test]
    fn test_all_payload_types() {
        for pt in 0..=127 {
            let mut session = RtpSession::new(12345, pt, 8000);
            let packet = session.create_packet(vec![0; 10], 160, false);
            assert_eq!(packet.payload_type, pt);
        }
    }

    /// Sequence number at boundaries
    #[test]
    fn test_sequence_boundaries() {
        // Test wraparound arithmetic
        assert_eq!(0_u16.wrapping_sub(1), 65535);
        assert_eq!(65535_u16.wrapping_add(1), 0);

        // Test that sequence numbers work correctly
        let mut session = RtpSession::new(12345, 0, 8000);
        let p1 = session.create_packet(vec![1], 160, false);
        let p2 = session.create_packet(vec![2], 320, false);
        assert_eq!(p2.sequence_number, p1.sequence_number.wrapping_add(1));
    }

    /// Timestamp at boundaries
    #[test]
    fn test_timestamp_boundaries() {
        // Test wraparound arithmetic
        let ts_max = u32::MAX;
        let ts_wrapped = ts_max.wrapping_add(100);
        assert_eq!(ts_wrapped, 99);

        // Test timestamp increments
        let mut session = RtpSession::new(12345, 0, 8000);
        let p1 = session.create_packet(vec![1], 160, false);
        let p2 = session.create_packet(vec![2], 160, false);
        assert_eq!(p2.timestamp, p1.timestamp.wrapping_add(160));
    }
}
