// Golden-file coverage for client-to-RCT transport summaries.
//
// Scope: parse representative route summary fixtures and compare the compact
// operator rendering against golden text.
// Targets: scripts/manual/client_rct_transport_summary.py and emitted
// client-rct-transport-summary.{json,txt} artifacts.
// Why: lab runs are expensive; deterministic fixtures keep pass, weak-evidence,
// and freshness-failure reports stable enough to diagnose without replaying
// Theia/Tethys hardware every time.

use serde_json::Value;

struct SummaryCase {
    name: &'static str,
    json: &'static str,
    golden: &'static str,
}

const CASES: &[SummaryCase] = &[
    SummaryCase {
        name: "pass",
        json: include_str!("../../fixtures/client_rct/transport_summary_pass.json"),
        golden: include_str!("../../golden/client_rct/transport_summary_pass.txt"),
    },
    SummaryCase {
        name: "weak evidence",
        json: include_str!("../../fixtures/client_rct/transport_summary_weak_evidence.json"),
        golden: include_str!("../../golden/client_rct/transport_summary_weak_evidence.txt"),
    },
    SummaryCase {
        name: "freshness fail",
        json: include_str!("../../fixtures/client_rct/transport_summary_freshness_fail.json"),
        golden: include_str!("../../golden/client_rct/transport_summary_freshness_fail.txt"),
    },
];

fn render_summary(value: &Value) -> String {
    let sync = &value["sync"];
    let freshness = &value["freshness"];
    let smoothness = &value["smoothness"];
    let evidence = if sync["evidence_complete"].as_bool().unwrap_or(false) {
        "complete"
    } else {
        "weak"
    };

    format!(
        "Client-to-RCT transport summary\n\
         - verdict: {}\n\
         - sync: {} p95={:.1}ms paired={}/{} evidence={}\n\
         - freshness: {} budget={:.1}ms limit={:.1}ms bottleneck={}\n\
         - smoothness: {} video_hiccups={} audio_hiccups={} video_freezes={}\n",
        value["verdict"].as_str().expect("verdict"),
        sync["verdict"].as_str().expect("sync verdict"),
        sync["p95_abs_skew_ms"].as_f64().expect("sync p95"),
        sync["paired_events"].as_u64().expect("paired events"),
        sync["min_paired_events"].as_u64().expect("min paired"),
        evidence,
        freshness["verdict"].as_str().expect("freshness verdict"),
        freshness["budget_ms"].as_f64().expect("freshness budget"),
        freshness["limit_ms"].as_f64().expect("freshness limit"),
        freshness["freshness_bottleneck"]
            .as_str()
            .expect("freshness bottleneck"),
        smoothness["verdict"].as_str().expect("smoothness verdict"),
        smoothness["video_hiccups"].as_u64().expect("video hiccups"),
        smoothness["audio_hiccups"].as_u64().expect("audio hiccups"),
        smoothness["video_freezes"].as_u64().expect("video freezes"),
    )
}

#[test]
fn client_rct_summary_fixtures_match_operator_goldens() {
    for case in CASES {
        let parsed: Value = serde_json::from_str(case.json).expect(case.name);
        assert_eq!(render_summary(&parsed), case.golden);
    }
}

#[test]
fn client_rct_summary_fixtures_cover_required_diagnostic_outcomes() {
    let mut saw_pass = false;
    let mut saw_weak_evidence = false;
    let mut saw_freshness_fail = false;

    for case in CASES {
        let parsed: Value = serde_json::from_str(case.json).expect(case.name);
        assert_eq!(
            parsed["schema"].as_str(),
            Some("lesavka.client-rct-transport-summary.v1")
        );
        assert!(parsed["freshness"]["stages"]["client_queue_p95_ms"].is_number());
        assert!(parsed["freshness"]["stages"]["server_receive_age_p95_ms"].is_number());
        assert!(parsed["freshness"]["stages"]["decode_spool_p95_ms"].is_number());
        assert!(parsed["freshness"]["stages"]["final_rct_age_p95_ms"].is_number());
        assert!(parsed["freshness"]["stages"]["sink_late_p95_ms"].is_number());

        saw_pass |= parsed["verdict"] == "pass";
        saw_weak_evidence |= parsed["sync"]["evidence_complete"] == false;
        saw_freshness_fail |= parsed["freshness"]["verdict"] == "fail";
    }

    assert!(saw_pass, "fixtures should include a clean pass baseline");
    assert!(
        saw_weak_evidence,
        "fixtures should include weak event-pair evidence"
    );
    assert!(
        saw_freshness_fail,
        "fixtures should include a freshness failure with stage attribution"
    );
}
