// Unit coverage for HEVC recovery state in the client upstream path.
//
// Scope: include the client HEVC keyframe helpers with a tiny camera-config
// shim so the logic can be tested without GTK/GStreamer capture hardware.
// Targets: `client/src/app/uplink_media/video_keyframes.rs`.
// Why: freshness-first dropping is only safe for predictive codecs when the
// next emitted video frame is a clean recovery point.

mod input {
    pub mod camera {
        #[derive(Clone, Copy)]
        pub enum CameraCodec {
            Mjpeg,
            Hevc,
        }

        #[derive(Clone, Copy)]
        pub struct CameraConfig {
            pub codec: CameraCodec,
        }
    }
}

use lesavka_common::lesavka::{UpstreamMediaBundle, VideoPacket};
use temp_env::with_vars;

include!("../../../../client/src/app/uplink_media/video_keyframes.rs");

fn video_bundle(data: Vec<u8>) -> UpstreamMediaBundle {
    UpstreamMediaBundle {
        video: Some(VideoPacket {
            data,
            ..Default::default()
        }),
        ..Default::default()
    }
}

#[test]
fn annex_b_irap_detection_handles_three_and_four_byte_start_codes() {
    assert!(contains_hevc_irap(&[0, 0, 0, 1, 0x26, 0x01, 0xaa]));
    assert!(contains_hevc_irap(&[0, 0, 1, 0x28, 0x01, 0xbb]));
    assert!(contains_hevc_irap(&[
        0, 0, 1, 0x02, 0x01, 0xcc, 0, 0, 0, 1, 0x2e, 0x01, 0xdd
    ]));
    assert!(!contains_hevc_irap(&[0, 0, 0, 1, 0x02, 0x01, 0xee]));
    assert!(!contains_hevc_irap(&[0x26, 0x01, 0xaa]));
}

#[test]
fn recovery_wait_holds_delta_bundles_and_releases_on_irap() {
    let delta = video_bundle(vec![0, 0, 0, 1, 0x02, 0x01, 0xaa]);
    let irap = video_bundle(vec![0, 0, 0, 1, 0x26, 0x01, 0xbb]);

    assert!(!should_hold_hevc_bundle_for_keyframe_recovery(
        false, &delta
    ));
    assert!(should_hold_hevc_bundle_for_keyframe_recovery(true, &delta));
    assert!(!should_hold_hevc_bundle_for_keyframe_recovery(true, &irap));
    assert!(bundle_has_hevc_recovery_keyframe(&irap));
    assert!(!bundle_has_hevc_recovery_keyframe(&delta));
}

#[test]
fn capture_gap_only_enters_wait_state_when_hevc_recovery_applies() {
    let mut waiting = false;
    note_hevc_capture_gap(false, &mut waiting);
    assert!(!waiting);

    note_hevc_capture_gap(true, &mut waiting);
    assert!(waiting);
}

#[test]
fn codec_selection_enables_recovery_for_hevc_only() {
    use input::camera::{CameraCodec, CameraConfig};

    assert!(upstream_camera_uses_hevc(Some(CameraConfig {
        codec: CameraCodec::Hevc,
    })));
    assert!(!upstream_camera_uses_hevc(Some(CameraConfig {
        codec: CameraCodec::Mjpeg,
    })));

    with_vars([("LESAVKA_CAM_CODEC", Some("h.265"))], || {
        assert!(upstream_camera_uses_hevc(None));
    });
    with_vars([("LESAVKA_CAM_CODEC", Some("mjpeg"))], || {
        assert!(!upstream_camera_uses_hevc(None));
    });
}
