// Integration coverage for client-triggered server audio epoch recovery.
//
// Scope: exercise the public server upstream media runtime the RecoverUac RPC
// calls, and inspect the RPC helper binding.
// Targets: `server/src/upstream_media_runtime.rs` and
// `server/src/main/rpc_helpers.rs`.
// Why: manual and automatic Heal Audio must retire only the stale microphone
// epoch while preserving video playout and calibration offsets.

use lesavka_server::upstream_media_runtime::UpstreamMediaRuntime;

const RPC_HELPERS_SRC: &str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/server/src/main/rpc_helpers.rs"
));

#[test]
fn recover_uac_rpc_is_bound_to_microphone_epoch_recovery_only() {
    let uac_start = RPC_HELPERS_SRC
        .find("async fn recover_uac_reply")
        .expect("recover_uac_reply should exist");
    let uvc_start = RPC_HELPERS_SRC
        .find("async fn recover_uvc_reply")
        .expect("recover_uvc_reply should follow recover_uac_reply");
    let uac_block = &RPC_HELPERS_SRC[uac_start..uvc_start];

    assert!(uac_block.contains("self.upstream_media_rt.soft_recover_microphone();"));
    assert!(!uac_block.contains("recover_enumeration"));
    assert!(!uac_block.contains("restart_uvc_helper"));
    assert!(!uac_block.contains("self.camera_rt.soft_recover"));
}

#[test]
fn stale_microphone_epoch_recovery_preserves_camera_session_and_offsets() {
    let runtime = UpstreamMediaRuntime::new();
    runtime.set_playout_offsets(127_952, 0);

    let camera = runtime.activate_camera();
    let stale_microphone = runtime.activate_microphone();
    let session_id = runtime.snapshot().session_id;

    runtime.soft_recover_microphone();

    let snapshot = runtime.snapshot();
    assert_eq!(snapshot.session_id, session_id);
    assert_eq!(runtime.playout_offsets(), (127_952, 0));
    assert!(
        runtime.is_camera_active(camera.generation),
        "audio heal should not disturb active video generation"
    );
    assert!(
        !runtime.is_microphone_active(stale_microphone.generation),
        "audio heal should retire the stale microphone generation"
    );

    let fresh_microphone = runtime.activate_microphone();
    assert_eq!(fresh_microphone.session_id, camera.session_id);
    assert!(fresh_microphone.generation > stale_microphone.generation);
    assert!(runtime.is_microphone_active(fresh_microphone.generation));
}
