// Performance contract for client->server->RCT stage timing.
//
// Scope: model the T0-T5 timing budget emitted by the black-box transport
// summary and upstream sampler.
// Targets: scripts/manual/client_rct_transport_summary.py and
// scripts/manual/client_rct_transport_layers.py.
// Why: the full upstream route should stay below one second end-to-end while
// preserving sync and keeping server sink lateness small enough to avoid drift.

const TRANSPORT_SUMMARY: &str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/scripts/manual/client_rct_transport_summary.py"
));
const TRANSPORT_LAYERS: &str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/scripts/manual/client_rct_transport_layers.py"
));

#[derive(Clone, Copy)]
struct RouteStageSample {
    client_queue_ms: f64,
    transport_receive_ms: f64,
    decode_spool_ms: f64,
    final_rct_ms: f64,
    sink_late_ms: f64,
}

impl RouteStageSample {
    fn end_to_end_ms(self) -> f64 {
        self.client_queue_ms + self.transport_receive_ms + self.decode_spool_ms + self.final_rct_ms
    }
}

fn percentile_95(values: &mut [f64]) -> f64 {
    values.sort_by(|a, b| a.total_cmp(b));
    let index = ((values.len() as f64) * 0.95).ceil() as usize - 1;
    values[index.min(values.len() - 1)]
}

fn representative_hevc_route_samples() -> Vec<RouteStageSample> {
    (0..32)
        .map(|idx| RouteStageSample {
            client_queue_ms: 18.0 + f64::from(idx % 5),
            transport_receive_ms: 145.0 + f64::from(idx % 7) * 6.0,
            decode_spool_ms: 95.0 + f64::from(idx % 4) * 5.0,
            final_rct_ms: 250.0 + f64::from(idx % 6) * 10.0,
            sink_late_ms: 2.0 + f64::from(idx % 4),
        })
        .collect()
}

#[test]
fn t0_to_t5_route_budget_stays_under_one_second_and_sink_late_under_20ms() {
    for marker in [
        "video_age_p95_ms",
        "audio_age_p95_ms",
        "server_receive_age_p95_ms",
        "sink_late_p95_ms",
        "post_client_send_worst_p95_ms",
        "freshness_bottleneck",
    ] {
        assert!(
            TRANSPORT_SUMMARY.contains(marker) || TRANSPORT_LAYERS.contains(marker),
            "transport summary should preserve T0-T5 marker {marker}"
        );
    }

    let samples = representative_hevc_route_samples();
    let mut end_to_end: Vec<f64> = samples
        .iter()
        .map(|sample| sample.end_to_end_ms())
        .collect();
    let mut sink_late: Vec<f64> = samples.iter().map(|sample| sample.sink_late_ms).collect();

    assert!(percentile_95(&mut end_to_end) < 1_000.0);
    assert!(percentile_95(&mut sink_late) < 20.0);
}

#[test]
fn queue_growth_is_bounded_in_the_route_budget_model() {
    let samples = representative_hevc_route_samples();
    let first = samples.first().expect("first sample").client_queue_ms;
    let last = samples.last().expect("last sample").client_queue_ms;
    let max = samples
        .iter()
        .map(|sample| sample.client_queue_ms)
        .fold(0.0, f64::max);

    assert!(
        last - first < 10.0,
        "client queue should not monotonically grow"
    );
    assert!(
        max < 150.0,
        "client queue p95 budget should remain fresh-first"
    );
}
