use std::path::PathBuf;

fn fixture_path(rel: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(rel)
}

fn run_offline_case(phase2_workers: Option<usize>) -> (serde_json::Value, Vec<u8>) {
    let db_dir = tempfile::tempdir().expect("db tempdir");
    let out_dir = tempfile::tempdir().expect("out tempdir");
    let report_path = out_dir.path().join("report.json");
    let ccr_path = out_dir.path().join("result.ccr");

    let mut argv = vec![
        "rpki".to_string(),
        "--db".to_string(),
        db_dir.path().to_string_lossy().to_string(),
        "--tal-path".to_string(),
        fixture_path("tests/fixtures/tal/apnic-rfc7730-https.tal")
            .to_string_lossy()
            .to_string(),
        "--ta-path".to_string(),
        fixture_path("tests/fixtures/ta/apnic-ta.cer")
            .to_string_lossy()
            .to_string(),
        "--disable-rrdp".to_string(),
        "--rsync-local-dir".to_string(),
        fixture_path("tests/fixtures/repository")
            .to_string_lossy()
            .to_string(),
        "--validation-time".to_string(),
        "2026-04-07T00:00:00Z".to_string(),
        "--max-depth".to_string(),
        "4".to_string(),
        "--max-instances".to_string(),
        "64".to_string(),
        "--report-json".to_string(),
        report_path.to_string_lossy().to_string(),
        "--ccr-out".to_string(),
        ccr_path.to_string_lossy().to_string(),
    ];
    if let Some(workers) = phase2_workers {
        argv.push("--parallel-phase2-object-workers".to_string());
        argv.push(workers.to_string());
        argv.push("--parallel-phase2-worker-queue-capacity".to_string());
        argv.push("64".to_string());
    }

    rpki::cli::run(&argv).expect("cli run");

    let report_bytes = std::fs::read(&report_path).expect("read report");
    let report: serde_json::Value = serde_json::from_slice(&report_bytes).expect("parse report");
    let ccr_bytes = std::fs::read(&ccr_path).expect("read ccr");
    (report, ccr_bytes)
}

#[test]
fn offline_default_parallel_and_configured_phase2_match_compare_views() {
    let (default_report, default_ccr_bytes) = run_offline_case(None);
    let (configured_report, configured_ccr_bytes) = run_offline_case(Some(4));

    let default_ccr =
        rpki::ccr::decode_content_info(&default_ccr_bytes).expect("decode default ccr");
    let configured_ccr =
        rpki::ccr::decode_content_info(&configured_ccr_bytes).expect("decode configured ccr");

    let (default_vrps, default_vaps) =
        rpki::ccr::decode_ccr_compare_views(&default_ccr).expect("default compare view");
    let (configured_vrps, configured_vaps) =
        rpki::ccr::decode_ccr_compare_views(&configured_ccr).expect("configured compare view");

    assert_eq!(
        default_vrps, configured_vrps,
        "VRP compare views must match"
    );
    assert_eq!(
        default_vaps, configured_vaps,
        "VAP compare views must match"
    );

    let default_points = default_report["publication_points"]
        .as_array()
        .expect("default publication_points");
    let configured_points = configured_report["publication_points"]
        .as_array()
        .expect("configured publication_points");
    assert_eq!(
        default_points.len(),
        configured_points.len(),
        "publication point counts must match"
    );
}

#[test]
fn offline_default_parallel_emits_online_ccr_accumulator_output() {
    let (report, ccr_bytes) = run_offline_case(None);
    let ccr = rpki::ccr::decode_content_info(&ccr_bytes).expect("decode ccr");
    let (_vrps, _vaps) = rpki::ccr::decode_ccr_compare_views(&ccr).expect("compare view");
    assert!(
        report["publication_points"]
            .as_array()
            .expect("publication_points")
            .len()
            > 0,
        "default parallel replay must process publication points"
    );
}
