use super::*;
use crate::error::Result;
use bytes::{Bytes, BytesMut};

#[test]
fn test_basic() -> Result<()> {
    let mut empty_bytes = &vec![0u8; 0][..];
    let result = Packet::unmarshal(&mut empty_bytes);
    assert!(
        result.is_err(),
        "Unmarshal did not error on zero length packet"
    );

    let raw_pkt = Bytes::from_static(&[
        0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0x00, 0x01, 0x00,
        0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x88, 0x9e,
    ]);
    let parsed_packet = Packet {
        header: Header {
            version: 2,
            padding: false,
            extension: true,
            marker: true,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            csrc: vec![],
            extension_profile: 1,
            extensions: vec![Extension {
                id: 0,
                payload: Bytes::from_static(&[0xFF, 0xFF, 0xFF, 0xFF]),
            }],
            ..Default::default()
        },
        payload: Bytes::from_static(&[0x98, 0x36, 0xbe, 0x88, 0x9e]),
    };
    let buf = &mut raw_pkt.clone();
    let packet = Packet::unmarshal(buf)?;
    assert_eq!(
        packet, parsed_packet,
        "TestBasic unmarshal: got {}, want {}",
        packet, parsed_packet
    );
    assert_eq!(
        packet.header.marshal_size(),
        20,
        "wrong computed header marshal size"
    );
    assert_eq!(
        packet.marshal_size(),
        raw_pkt.len(),
        "wrong computed marshal size"
    );

    let raw = packet.marshal()?;
    let n = raw.len();
    assert_eq!(n, raw_pkt.len(), "wrong marshal size");

    assert_eq!(
        raw.len(),
        raw_pkt.len(),
        "wrong raw marshal size {} vs {}",
        raw.len(),
        raw_pkt.len()
    );
    assert_eq!(
        raw, raw_pkt,
        "TestBasic marshal: got {:?}, want {:?}",
        raw, raw_pkt
    );

    Ok(())
}

#[test]
fn test_extension() -> Result<()> {
    let missing_extension_pkt = Bytes::from_static(&[
        0x90, 0x60, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82,
    ]);
    let buf = &mut missing_extension_pkt.clone();
    let result = Packet::unmarshal(buf);
    assert!(
        result.is_err(),
        "Unmarshal did not error on packet with missing extension data"
    );

    let invalid_extension_length_pkt = Bytes::from_static(&[
        0x90, 0x60, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0x99, 0x99, 0x99,
        0x99,
    ]);
    let buf = &mut invalid_extension_length_pkt.clone();
    let result = Packet::unmarshal(buf);
    assert!(
        result.is_err(),
        "Unmarshal did not error on packet with invalid extension length"
    );

    let packet = Packet {
        header: Header {
            extension: true,
            extension_profile: 3,
            extensions: vec![Extension {
                id: 0,
                payload: Bytes::from_static(&[0]),
            }],
            ..Default::default()
        },
        payload: Bytes::from_static(&[]),
    };

    let mut raw = BytesMut::new();
    let result = packet.marshal_to(&mut raw);
    assert!(
        result.is_err(),
        "Marshal did not error on packet with invalid extension length"
    );
    if let Err(err) = result {
        assert_eq!(Error::ErrBufferTooSmall, err);
    }

    Ok(())
}

#[test]
fn test_padding() -> Result<()> {
    let raw_pkt = Bytes::from_static(&[
        0xa0, 0x60, 0x19, 0x58, 0x63, 0xff, 0x7d, 0x7c, 0x4b, 0x98, 0xd4, 0x0a, 0x67, 0x4d, 0x00,
        0x29, 0x9a, 0x64, 0x03, 0xc0, 0x11, 0x3f, 0x2c, 0xd4, 0x04, 0x04, 0x05, 0x00, 0x00, 0x03,
        0x03, 0xe8, 0x00, 0x00, 0xea, 0x60, 0x04, 0x00, 0x00, 0x03,
    ]);
    let buf = &mut raw_pkt.clone();
    let packet = Packet::unmarshal(buf)?;
    assert_eq!(&packet.payload[..], &raw_pkt[12..12 + 25]);

    let raw = packet.marshal()?;
    assert_eq!(raw, raw_pkt);

    Ok(())
}

#[test]
fn test_packet_marshal_unmarshal() -> Result<()> {
    let pkt = Packet {
        header: Header {
            extension: true,
            csrc: vec![1, 2],
            extension_profile: EXTENSION_PROFILE_TWO_BYTE,
            extensions: vec![
                Extension {
                    id: 1,
                    payload: Bytes::from_static(&[3, 4]),
                },
                Extension {
                    id: 2,
                    payload: Bytes::from_static(&[5, 6]),
                },
            ],
            ..Default::default()
        },
        payload: Bytes::from_static(&[0xFFu8; 15]),
        ..Default::default()
    };
    let mut raw = pkt.marshal()?;
    let p = Packet::unmarshal(&mut raw)?;

    assert_eq!(pkt, p);

    Ok(())
}

#[test]
fn test_rfc_8285_one_byte_extension() -> Result<()> {
    let raw_pkt = Bytes::from_static(&[
        0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00,
        0x01, 0x50, 0xAA, 0x00, 0x00, 0x98, 0x36, 0xbe, 0x88, 0x9e,
    ]);
    let buf = &mut raw_pkt.clone();
    Packet::unmarshal(buf)?;

    let p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![Extension {
                id: 5,
                payload: Bytes::from_static(&[0xAA]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            csrc: vec![],
            ..Default::default()
        },
        payload: raw_pkt.slice(20..),
    };

    let dst = p.marshal()?;
    assert_eq!(dst, raw_pkt);

    Ok(())
}

#[test]
fn test_rfc_8285_one_byte_two_extension_of_two_bytes() -> Result<()> {
    //  0                   1                   2                   3
    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |       0xBE    |    0xDE       |           length=1            |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |  ID   | L=0   |     data      |  ID   |  L=0  |   data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    let raw_pkt = Bytes::from_static(&[
        0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00,
        0x01, 0x10, 0xAA, 0x20, 0xBB, // Payload
        0x98, 0x36, 0xbe, 0x88, 0x9e,
    ]);
    let buf = &mut raw_pkt.clone();
    let p = Packet::unmarshal(buf)?;

    let ext1 = p.header.get_extension(1);
    let ext1_expect = Bytes::from_static(&[0xAA]);
    if let Some(ext1) = ext1 {
        assert_eq!(ext1, ext1_expect);
    } else {
        assert!(false, "ext1 is none");
    }

    let ext2 = p.header.get_extension(2);
    let ext2_expect = Bytes::from_static(&[0xBB]);
    if let Some(ext2) = ext2 {
        assert_eq!(ext2, ext2_expect);
    } else {
        assert!(false, "ext2 is none");
    }

    // Test Marshal
    let p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![
                Extension {
                    id: 1,
                    payload: Bytes::from_static(&[0xAA]),
                },
                Extension {
                    id: 2,
                    payload: Bytes::from_static(&[0xBB]),
                },
            ],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            csrc: vec![],
            ..Default::default()
        },
        payload: raw_pkt.slice(20..),
    };

    let dst = p.marshal()?;
    assert_eq!(dst, raw_pkt);

    Ok(())
}

#[test]
fn test_rfc_8285_one_byte_multiple_extensions_with_padding() -> Result<()> {
    //  0                   1                   2                   3
    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |       0xBE    |    0xDE       |           length=3            |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |  ID   | L=0   |     data      |  ID   |  L=1  |   data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       ...data   |    0 (pad)    |    0 (pad)    |  ID   | L=3   |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |                          data                                 |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    let raw_pkt = Bytes::from_static(&[
        0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00,
        0x03, 0x10, 0xAA, 0x21, 0xBB, 0xBB, 0x00, 0x00, 0x33, 0xCC, 0xCC, 0xCC, 0xCC,
        // Payload
        0x98, 0x36, 0xbe, 0x88, 0x9e,
    ]);
    let buf = &mut raw_pkt.clone();
    let packet = Packet::unmarshal(buf)?;
    let ext1 = packet
        .header
        .get_extension(1)
        .expect("Error getting header extension.");

    let ext1_expect = Bytes::from_static(&[0xAA]);
    assert_eq!(ext1, ext1_expect);

    let ext2 = packet
        .header
        .get_extension(2)
        .expect("Error getting header extension.");

    let ext2_expect = Bytes::from_static(&[0xBB, 0xBB]);
    assert_eq!(ext2, ext2_expect);

    let ext3 = packet
        .header
        .get_extension(3)
        .expect("Error getting header extension.");

    let ext3_expect = Bytes::from_static(&[0xCC, 0xCC, 0xCC, 0xCC]);
    assert_eq!(ext3, ext3_expect);

    let mut dst_buf: Vec<Vec<u8>> = vec![vec![0u8; 1000], vec![0xFF; 1000], vec![0xAA; 2]];

    let raw_pkg_marshal: [u8; 33] = [
        // padding is moved to the end by re-marshaling
        0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00,
        0x03, 0x10, 0xAA, 0x21, 0xBB, 0xBB, 0x33, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00,
        // Payload
        0x98, 0x36, 0xbe, 0x88, 0x9e,
    ];

    let checker = |name: &str, buf: &mut [u8], p: &Packet| -> Result<()> {
        let size = p.marshal_to(buf)?;

        assert_eq!(
            &buf[..size],
            &raw_pkg_marshal[..],
            "Marshalled fields are not equal for {}.",
            name
        );

        Ok(())
    };

    checker("CleanBuffer", &mut dst_buf[0], &packet)?;
    checker("DirtyBuffer", &mut dst_buf[1], &packet)?;

    let result = packet.marshal_to(&mut dst_buf[2]);
    assert!(result.is_err());
    if let Err(err) = result {
        assert_eq!(Error::ErrBufferTooSmall, err);
    }

    Ok(())
}

fn test_rfc_8285_one_byte_multiple_extension() -> Result<()> {
    //  0                   1                   2                   3
    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |       0xBE    |    0xDE       |           length=3            |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |  ID=1 | L=0   |     data      |  ID=2 |  L=1  |   data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //       ...data   |  ID=3 | L=3   |           data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //             ...data             |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    let raw_pkt = &[
        0x90u8, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00,
        0x03, 0x10, 0xAA, 0x21, 0xBB, 0xBB, 0x33, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00,
        // Payload
        0x98, 0x36, 0xbe, 0x88, 0x9e,
    ];

    let p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![
                Extension {
                    id: 1,
                    payload: Bytes::from_static(&[0xAA]),
                },
                Extension {
                    id: 2,
                    payload: Bytes::from_static(&[0xBB, 0xBB]),
                },
                Extension {
                    id: 3,
                    payload: Bytes::from_static(&[0xCC, 0xCC]),
                },
            ],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload: raw_pkt[28..].into(),
    };

    let dst_data = p.marshal()?;
    assert_eq!(
        &dst_data[..],
        raw_pkt,
        "Marshal failed raw \nMarshaled:\n{:?}\nrawPkt:\n{:?}",
        dst_data,
        raw_pkt,
    );

    Ok(())
}

fn test_rfc_8285_two_byte_extension() -> Result<()> {
    let raw_pkt = Bytes::from_static(&[
        0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0x10, 0x00, 0x00,
        0x07, 0x05, 0x18, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
        0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x98,
        0x36, 0xbe, 0x88, 0x9e,
    ]);

    let _ = Packet::unmarshal(&mut raw_pkt.clone())?;

    let p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0x1000,
            extensions: vec![Extension {
                id: 5,
                payload: Bytes::from_static(&[
                    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
                    0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
                ]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload: raw_pkt.slice(44..),
    };

    let dst_data = p.marshal()?;
    assert_eq!(
        dst_data, raw_pkt,
        "Marshal failed raw \nMarshaled:\n{:?}\nrawPkt:\n{:?}",
        dst_data, raw_pkt
    );
    Ok(())
}

fn test_rfc8285_two_byte_multiple_extension_with_padding() -> Result<()> {
    // 0                   1                   2                   3
    // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |       0x10    |    0x00       |           length=3            |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |      ID=1     |     L=0       |     ID=2      |     L=1       |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |       data    |    0 (pad)    |       ID=3    |      L=4      |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |                          data                                 |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    let raw_pkt = Bytes::from_static(&[
        0x90u8, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0x10, 0x00, 0x00,
        0x03, 0x01, 0x00, 0x02, 0x01, 0xBB, 0x00, 0x03, 0x04, 0xCC, 0xCC, 0xCC, 0xCC, 0x98, 0x36,
        0xbe, 0x88, 0x9e,
    ]);

    let p = Packet::unmarshal(&mut raw_pkt.clone())?;

    let ext = p.header.get_extension(1);
    let ext_expect = Some(Bytes::from_static(&[]));
    assert_eq!(
        ext, ext_expect,
        "Extension has incorrect data. Got: {:?}, Expected: {:?}",
        ext, ext_expect
    );

    let ext = p.header.get_extension(2);
    let ext_expect = Some(Bytes::from_static(&[0xBB]));
    assert_eq!(
        ext, ext_expect,
        "Extension has incorrect data. Got: {:?}, Expected: {:?}",
        ext, ext_expect
    );

    let ext = p.header.get_extension(3);
    let ext_expect = Some(Bytes::from_static(&[0xCC, 0xCC, 0xCC, 0xCC]));
    assert_eq!(
        ext, ext_expect,
        "Extension has incorrect data. Got: {:?}, Expected: {:?}",
        ext, ext_expect
    );

    Ok(())
}

fn test_rfc8285_two_byte_multiple_extension_with_large_extension() -> Result<()> {
    // 0                   1                   2                   3
    // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |       0x10    |    0x00       |           length=3            |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |      ID=1     |     L=0       |     ID=2      |     L=1       |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    // |       data    |       ID=3    |      L=17      |    data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //                            ...data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //                            ...data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //                            ...data...
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    //                            ...data...                           |
    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    let raw_pkt = Bytes::from_static(&[
        0x90u8, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0x10, 0x00, 0x00,
        0x06, 0x01, 0x00, 0x02, 0x01, 0xBB, 0x03, 0x11, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
        0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, // Payload
        0x98, 0x36, 0xbe, 0x88, 0x9e,
    ]);

    let p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0x1000,
            extensions: vec![
                Extension {
                    id: 1,
                    payload: Bytes::from_static(&[]),
                },
                Extension {
                    id: 2,
                    payload: Bytes::from_static(&[0xBB]),
                },
                Extension {
                    id: 3,
                    payload: Bytes::from_static(&[
                        0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
                        0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
                    ]),
                },
            ],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload: raw_pkt.slice(40..),
    };

    let dst_data = p.marshal()?;
    assert_eq!(
        dst_data,
        raw_pkt[..],
        "Marshal failed raw \nMarshaled: {:?}, \nraw_pkt:{:?}",
        dst_data,
        raw_pkt
    );

    Ok(())
}

fn test_rfc8285_get_extension_returns_nil_when_extension_disabled() -> Result<()> {
    let payload = Bytes::from_static(&[
        // Payload
        0x98u8, 0x36, 0xbe, 0x88, 0x9e,
    ]);

    let p = Packet {
        header: Header {
            marker: true,
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let res = p.header.get_extension(1);
    assert!(
        res.is_none(),
        "Should return none on get_extension when header extension is false"
    );

    Ok(())
}

fn test_rfc8285_del_extension() -> Result<()> {
    let payload = Bytes::from_static(&[
        // Payload
        0x98u8, 0x36, 0xbe, 0x88, 0x9e,
    ]);
    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![Extension {
                id: 1,
                payload: Bytes::from_static(&[0xAA]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let ext = p.header.get_extension(1);
    assert!(ext.is_some(), "Extension should exist");

    p.header.del_extension(1)?;

    let ext = p.header.get_extension(1);
    assert!(ext.is_none(), "Extension should not exist");

    let err = p.header.del_extension(1);
    assert!(
        err.is_err(),
        "Should return error when deleting extension that doesnt exist"
    );

    Ok(())
}

fn test_rfc8285_get_extension_ids() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![
                Extension {
                    id: 1,
                    payload: Bytes::from_static(&[0xAA]),
                },
                Extension {
                    id: 2,
                    payload: Bytes::from_static(&[0xBB]),
                },
            ],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let ids = p.header.get_extension_ids();
    assert!(!ids.is_empty(), "Extenstions should exist");

    assert_eq!(
        ids.len(),
        p.header.extensions.len(),
        "The number of IDs should be equal to the number of extensions, want={}, hanve{}",
        ids.len(),
        p.header.extensions.len()
    );

    for id in ids {
        let ext = p.header.get_extension(id);
        assert!(ext.is_some(), "Extension should exist for id: {}", id)
    }
}

fn test_rfc8285_get_extension_ids_return_empty_when_extension_disabled() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let p = Packet {
        header: Header {
            marker: true,
            extension: false,
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let ids = p.header.get_extension_ids();
    assert!(ids.is_empty(), "Extenstions should not exist");
}

fn test_rfc8285_del_extension_returns_error_when_extenstions_disabled() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: false,
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let ids = p.header.del_extension(1);
    assert!(
        ids.is_err(),
        "Should return error on del_extension when header extension field is false"
    );
}

fn test_rfc8285_one_byte_set_extension_should_enable_extension_when_adding() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: false,
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let extension = Bytes::from_static(&[0xAAu8, 0xAA]);
    let result = p.header.set_extension(1, extension.clone());
    assert!(result.is_ok(), "Error setting extension");

    assert_eq!(p.header.extension, true, "Extension should be set to true");
    assert_eq!(
        p.header.extension_profile, 0xBEDE,
        "Extension profile should be set to 0xBEDE"
    );
    assert_eq!(
        p.header.extensions.len(),
        1,
        "Extensions len should be set to 1"
    );
    assert_eq!(
        p.header.get_extension(1),
        Some(extension),
        "Extension value is not set"
    )
}

fn test_rfc8285_set_extension_should_set_correct_extension_profile_for_16_byte_extension() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: false,
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let extension = Bytes::from_static(&[
        0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
        0xAA,
    ]);

    let res = p.header.set_extension(1, extension);
    assert!(res.is_ok(), "Error setting extension");

    assert_eq!(
        p.header.extension_profile, 0xBEDE,
        "Extension profile should be 0xBEDE"
    );
}

fn test_rfc8285_set_extension_should_update_existing_extension() -> Result<()> {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![Extension {
                id: 1,
                payload: Bytes::from_static(&[0xAA]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    assert_eq!(
        p.header.get_extension(1),
        Some([0xAA][..].into()),
        "Extension value not initialized properly"
    );

    let extension = Bytes::from_static(&[0xBBu8]);
    p.header.set_extension(1, extension.clone())?;

    assert_eq!(
        p.header.get_extension(1),
        Some(extension),
        "Extension value was not set"
    );

    Ok(())
}

fn test_rfc8285_one_byte_set_extension_should_error_when_invalid_id_provided() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![Extension {
                id: 1,
                payload: Bytes::from_static(&[0xAA]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    assert!(
        p.header
            .set_extension(0, Bytes::from_static(&[0xBBu8]))
            .is_err(),
        "set_extension did not error on invalid id"
    );
    assert!(
        p.header
            .set_extension(15, Bytes::from_static(&[0xBBu8]))
            .is_err(),
        "set_extension did not error on invalid id"
    );
}

fn test_rfc8285_one_byte_extension_terminate_processing_when_reserved_id_encountered() -> Result<()>
{
    let reserved_id_pkt = Bytes::from_static(&[
        0x90u8, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00,
        0x01, 0xF0, 0xAA, 0x98, 0x36, 0xbe, 0x88, 0x9e,
    ]);

    let p = Packet::unmarshal(&mut reserved_id_pkt.clone())?;

    assert_eq!(
        p.header.extensions.len(),
        0,
        "Extension should be empty for invalid ID"
    );

    let payload = reserved_id_pkt.slice(17..);
    assert_eq!(p.payload, payload, "p.payload must be same as payload");

    Ok(())
}

fn test_rfc8285_one_byte_set_extension_should_error_when_payload_too_large() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![Extension {
                id: 1,
                payload: Bytes::from_static(&[0xAAu8]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let res = p.header.set_extension(
        1,
        Bytes::from_static(&[
            0xBBu8, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB,
        ]),
    );

    assert!(
        res.is_err(),
        "set_extension did not error on too large payload"
    );
}

fn test_rfc8285_two_bytes_set_extension_should_enable_extension_when_adding() -> Result<()> {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let extension = Bytes::from_static(&[
        0xAAu8, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
        0xAA, 0xAA,
    ]);

    p.header.set_extension(1, extension.clone())?;

    assert_eq!(p.header.extension, true, "Extension should be set to true");
    assert_eq!(
        p.header.extension_profile, 0x1000,
        "Extension profile should be set to 0xBEDE"
    );
    assert_eq!(
        p.header.extensions.len(),
        1,
        "Extensions should be set to 1"
    );
    assert_eq!(
        p.header.get_extension(1),
        Some(extension),
        "Extension value is not set"
    );

    Ok(())
}

fn test_rfc8285_two_byte_set_extension_should_update_existing_extension() -> Result<()> {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0x1000,
            extensions: vec![Extension {
                id: 1,
                payload: Bytes::from_static(&[0xAA]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    assert_eq!(
        p.header.get_extension(1),
        Some(Bytes::from_static(&[0xAA])),
        "Extension value not initialized properly"
    );

    let extension = Bytes::from_static(&[
        0xBBu8, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
        0xBB, 0xBB,
    ]);

    p.header.set_extension(1, extension.clone())?;

    assert_eq!(p.header.get_extension(1), Some(extension));

    Ok(())
}

fn test_rfc8285_two_byte_set_extension_should_error_when_payload_too_large() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0xBEDE,
            extensions: vec![Extension {
                id: 1,
                payload: Bytes::from_static(&[0xAA]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let res = p.header.set_extension(
        1,
        Bytes::from_static(&[
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
            0xBB, 0xBB, 0xBB, 0xBB,
        ]),
    );

    assert!(
        res.is_err(),
        "Set extension did not error on too large payload"
    );
}

fn test_rfc3550_set_extension_should_error_when_non_zero() -> Result<()> {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0x1111,
            extensions: vec![Extension {
                id: 1,
                payload: Bytes::from_static(&[0xAA]),
            }],
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    p.header.set_extension(0, Bytes::from_static(&[0xBB]))?;
    let res = p.header.get_extension(0);
    assert_eq!(
        res,
        Some(Bytes::from_static(&[0xBB])),
        "p.get_extenstion returned incorrect value"
    );

    Ok(())
}

fn test_rfc3550_set_extension_should_error_when_setting_non_zero_id() {
    let payload = Bytes::from_static(&[0x98u8, 0x36, 0xbe, 0x88, 0x9e]);

    let mut p = Packet {
        header: Header {
            marker: true,
            extension: true,
            extension_profile: 0x1111,
            version: 2,
            payload_type: 96,
            sequence_number: 27023,
            timestamp: 3653407706,
            ssrc: 476325762,
            ..Default::default()
        },
        payload,
        ..Default::default()
    };

    let res = p.header.set_extension(1, Bytes::from_static(&[0xBB]));
    assert!(res.is_err(), "set_extension did not error on invalid id");
}

use std::collections::HashMap;

struct Cases {
    input: Bytes,
    err: Error,
}

fn test_unmarshal_error_handling() {
    let mut cases = HashMap::new();

    cases.insert(
        "ShortHeader",
        Cases {
            input: Bytes::from_static(&[
                0x80, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, // timestamp
                0x1c, 0x64, 0x27, // SSRC (one byte missing)
            ]),
            err: Error::ErrHeaderSizeInsufficient,
        },
    );

    cases.insert(
        "MissingCSRC",
        Cases {
            input: Bytes::from_static(&[
                0x81, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, // timestamp
                0x1c, 0x64, 0x27, 0x82, // SSRC
            ]),
            err: Error::ErrHeaderSizeInsufficient,
        },
    );

    cases.insert(
        "MissingExtension",
        Cases {
            input: Bytes::from_static(&[
                0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, // timestamp
                0x1c, 0x64, 0x27, 0x82, // SSRC
            ]),
            err: Error::ErrHeaderSizeInsufficientForExtension,
        },
    );

    cases.insert(
        "MissingExtensionData",
        Cases {
            input: Bytes::from_static(&[
                0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, // timestamp
                0x1c, 0x64, 0x27, 0x82, // SSRC
                0xBE, 0xDE, 0x00, 0x03, // specified to have 3 extensions, but actually not
            ]),
            err: Error::ErrHeaderSizeInsufficientForExtension,
        },
    );

    cases.insert(
        "MissingExtensionDataPayload",
        Cases {
            input: Bytes::from_static(&[
                0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, // timestamp
                0x1c, 0x64, 0x27, 0x82, // SSRC
                0xBE, 0xDE, 0x00, 0x01, // have 1 extension
                0x12,
                0x00, // length of the payload is expected to be 3, but actually have only 1
            ]),
            err: Error::ErrHeaderSizeInsufficientForExtension,
        },
    );

    for (name, mut test_case) in cases.drain() {
        let result = Header::unmarshal(&mut test_case.input);
        let err = result.err().unwrap();
        assert_eq!(
            test_case.err, err,
            "Expected :{:?}, found: {:?} for testcase {}",
            test_case.err, err, name
        )
    }
}

fn test_round_trip() -> Result<()> {
    let raw_pkt = Bytes::from_static(&[
        0x00u8, 0x10, 0x23, 0x45, 0x12, 0x34, 0x45, 0x67, 0xCC, 0xDD, 0xEE, 0xFF, 0x00, 0x11, 0x22,
        0x33, 0x44, 0x55, 0x66, 0x77,
    ]);

    let payload = raw_pkt.slice(12..);

    let p = Packet::unmarshal(&mut raw_pkt.clone())?;

    assert_eq!(
        payload, p.payload,
        "p.payload must be same as payload.\n p.payload: {:?},\nraw_pkt: {:?}",
        p.payload, payload
    );

    let buf = p.marshal()?;

    assert_eq!(
        raw_pkt, buf,
        "buf must be the same as raw_pkt. \n buf: {:?},\nraw_pkt: {:?}",
        buf, raw_pkt,
    );
    assert_eq!(
        payload, p.payload,
        "p.payload must be the same as payload. \n payload: {:?},\np.payload: {:?}",
        payload, p.payload,
    );

    Ok(())
}
