// Downstream video latency budget contracts.
//
// Scope: verify that both server capture and client display paths are biased
// toward bounded freshness rather than unbounded smoothness debt.
// Targets: `server/src/video/eye_capture.rs` and
// `client/src/app/downlink_media.rs` plus the client monitor renderers.
// Why: downstream desktop usability depends on seeing input effects quickly;
// stale-but-perfect frames are worse than bounded drops.

const SERVER_EYE_CAPTURE: &str = include_str!("../../../../server/src/video/eye_capture.rs");
const CLIENT_DOWNLINK_MEDIA: &str = include_str!("../../../../client/src/app/downlink_media.rs");
const CLIENT_MONITOR: &str = include_str!("../../../../client/src/output/video/monitor_window.rs");
const CLIENT_UNIFIED_MONITOR: &str =
    include_str!("../../../../client/src/output/video/unified_monitor.rs");

fn percentile_95(mut values: Vec<u64>) -> u64 {
    values.sort_unstable();
    values[((values.len() - 1) as f64 * 0.95).ceil() as usize]
}

fn simulate_bounded_display_queue(
    source_interval_ms: u64,
    display_interval_ms: u64,
    frames: u64,
    queue_capacity: usize,
) -> (u64, u64) {
    let mut queue = std::collections::VecDeque::new();
    let mut displayed_ages = Vec::new();
    let mut dropped = 0_u64;
    let mut next_display_ms = 0_u64;

    for frame in 0..frames {
        let now_ms = frame * source_interval_ms;
        while queue.len() >= queue_capacity {
            queue.pop_front();
            dropped += 1;
        }
        queue.push_back(now_ms);

        if now_ms >= next_display_ms {
            if let Some(captured_ms) = queue.pop_back() {
                queue.clear();
                displayed_ages.push(now_ms.saturating_sub(captured_ms));
            }
            next_display_ms = now_ms + display_interval_ms;
        }
    }

    (percentile_95(displayed_ages), dropped)
}

#[test]
fn downstream_display_queue_model_keeps_p95_age_under_interactive_budget() {
    let (p95_age_ms, dropped) = simulate_bounded_display_queue(16, 33, 600, 2);

    assert!(
        p95_age_ms < 150,
        "downstream frame age p95 should stay below 150ms, got {p95_age_ms}ms"
    );
    assert!(
        dropped > 0,
        "the model should prove stale frames are dropped instead of queued forever"
    );
}

#[test]
fn server_capture_path_uses_bounded_leaky_queues_and_try_send() {
    for marker in [
        "queue max-size-buffers={queue_buffers} max-size-time=0 max-size-bytes=0 leaky=downstream",
        "appsink name=sink emit-signals=true max-buffers={appsink_buffers} drop=true",
        "LESAVKA_EYE_CHAN_CAPACITY",
        "let chan_capacity = env_usize(\"LESAVKA_EYE_CHAN_CAPACITY\", 32).max(8);",
        "tx.try_send(Ok(pkt))",
        "TrySendError::Full",
        "queue_peak_depth_for_cb.fetch_max",
    ] {
        assert!(
            SERVER_EYE_CAPTURE.contains(marker),
            "server downstream path should preserve latency marker {marker}"
        );
    }
}

#[test]
fn client_display_path_is_bounded_and_uses_idr_recovery_after_drops() {
    for marker in [
        "TrySendError::Full",
        "wait_for_idr = true",
        "if wait_for_idr && !is_idr",
        "crate::video_support::contains_idr(&pkt.data)",
    ] {
        assert!(
            CLIENT_DOWNLINK_MEDIA.contains(marker),
            "client downlink should preserve latency/recovery marker {marker}"
        );
    }
    for source in [CLIENT_MONITOR, CLIENT_UNIFIED_MONITOR] {
        for marker in [
            "appsrc name=src",
            "is-live=true",
            "do-timestamp=true",
            "block=true max-buffers=8 max-time=0 max-bytes=0",
            "queue max-size-buffers=8 max-size-time=0 max-size-bytes=0",
            "sync=false",
        ] {
            assert!(
                source.contains(marker),
                "client downstream display should preserve marker {marker}"
            );
        }
        assert!(
            !source.contains("leaky=downstream"),
            "client H.264 decoder input should not leak arbitrary access units"
        );
    }
}
