use rpki::ccr::{
    CcrContentInfo, CcrDigestAlgorithm, TrustAnchorState, compute_state_hash,
    encode::{encode_content_info, encode_trust_anchor_state_payload_der},
};
use std::process::Command;

fn sample_ccr_file() -> (tempfile::TempDir, std::path::PathBuf) {
    let dir = tempfile::tempdir().expect("tempdir");
    let skis = vec![vec![0x11; 20]];
    let skis_der = encode_trust_anchor_state_payload_der(&skis).expect("encode skis");
    let ccr = CcrContentInfo::new(rpki::ccr::RpkiCanonicalCacheRepresentation {
        version: 0,
        hash_alg: CcrDigestAlgorithm::Sha256,
        produced_at: time::OffsetDateTime::parse(
            "2026-03-24T00:00:00Z",
            &time::format_description::well_known::Rfc3339,
        )
        .expect("time"),
        mfts: None,
        vrps: None,
        vaps: None,
        tas: Some(TrustAnchorState {
            skis,
            hash: compute_state_hash(&skis_der),
        }),
        rks: None,
    });
    let path = dir.path().join("sample.ccr");
    std::fs::write(&path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr");
    (dir, path)
}

#[test]
fn ccr_dump_binary_prints_json_summary() {
    let (_dir, ccr_path) = sample_ccr_file();
    let bin = env!("CARGO_BIN_EXE_ccr_dump");
    let out = Command::new(bin)
        .args(["--ccr", ccr_path.to_string_lossy().as_ref()])
        .output()
        .expect("run ccr_dump");
    assert!(
        out.status.success(),
        "stderr={}",
        String::from_utf8_lossy(&out.stderr)
    );
    let json: serde_json::Value = serde_json::from_slice(&out.stdout).expect("parse json");
    assert_eq!(json["version"], 0);
    assert_eq!(json["state_aspects"]["tas"]["ski_count"], 1);
}

#[test]
fn ccr_verify_binary_prints_summary() {
    let (_dir, ccr_path) = sample_ccr_file();
    let bin = env!("CARGO_BIN_EXE_ccr_verify");
    let out = Command::new(bin)
        .args(["--ccr", ccr_path.to_string_lossy().as_ref()])
        .output()
        .expect("run ccr_verify");
    assert!(
        out.status.success(),
        "stderr={}",
        String::from_utf8_lossy(&out.stderr)
    );
    let json: serde_json::Value = serde_json::from_slice(&out.stdout).expect("parse json");
    assert_eq!(json["version"], 0);
    assert_eq!(json["trust_anchor_ski_count"], 1);
    assert_eq!(json["state_hashes_ok"], true);
}

#[test]
fn ccr_to_routinator_csv_binary_writes_vrp_csv() {
    use rpki::ccr::{
        CcrContentInfo, CcrDigestAlgorithm, RpkiCanonicalCacheRepresentation,
        build_roa_payload_state, encode::encode_content_info,
    };
    use rpki::data_model::roa::{IpPrefix, RoaAfi};
    use rpki::validation::objects::Vrp;
    let dir = tempfile::tempdir().expect("tempdir");
    let ccr_path = dir.path().join("vrp.ccr");
    let csv_path = dir.path().join("out.csv");
    let vrps = vec![Vrp {
        asn: 64496,
        prefix: IpPrefix {
            afi: RoaAfi::Ipv4,
            prefix_len: 24,
            addr: [203, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        },
        max_length: 24,
    }];
    let roa_state = build_roa_payload_state(&vrps).expect("build roa state");
    let ccr = CcrContentInfo::new(RpkiCanonicalCacheRepresentation {
        version: 0,
        hash_alg: CcrDigestAlgorithm::Sha256,
        produced_at: time::OffsetDateTime::parse(
            "2026-03-25T00:00:00Z",
            &time::format_description::well_known::Rfc3339,
        )
        .expect("time"),
        mfts: None,
        vrps: Some(roa_state),
        vaps: None,
        tas: None,
        rks: None,
    });
    std::fs::write(&ccr_path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr");

    let bin = env!("CARGO_BIN_EXE_ccr_to_routinator_csv");
    let out = Command::new(bin)
        .args([
            "--ccr",
            ccr_path.to_string_lossy().as_ref(),
            "--out",
            csv_path.to_string_lossy().as_ref(),
            "--trust-anchor",
            "apnic",
        ])
        .output()
        .expect("run ccr_to_routinator_csv");
    assert!(
        out.status.success(),
        "stderr={}",
        String::from_utf8_lossy(&out.stderr)
    );
    let csv = std::fs::read_to_string(csv_path).expect("read csv");
    assert!(csv.contains("ASN,IP Prefix,Max Length,Trust Anchor"));
    assert!(csv.contains("AS64496,203.0.113.0/24,24,unknown"));
}

#[test]
fn ccr_to_compare_views_binary_writes_vrp_and_vap_csvs() {
    use rpki::ccr::{
        CcrContentInfo, CcrDigestAlgorithm, RpkiCanonicalCacheRepresentation,
        build_aspa_payload_state, build_roa_payload_state, encode::encode_content_info,
    };
    use rpki::data_model::roa::{IpPrefix, RoaAfi};
    use rpki::validation::objects::{AspaAttestation, Vrp};

    let dir = tempfile::tempdir().expect("tempdir");
    let ccr_path = dir.path().join("views.ccr");
    let vrps_path = dir.path().join("vrps.csv");
    let vaps_path = dir.path().join("vaps.csv");
    let roa_state = build_roa_payload_state(&[Vrp {
        asn: 64496,
        prefix: IpPrefix {
            afi: RoaAfi::Ipv4,
            prefix_len: 24,
            addr: [198, 51, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        },
        max_length: 24,
    }])
    .expect("build roa state");
    let aspa_state = build_aspa_payload_state(&[AspaAttestation {
        customer_as_id: 64496,
        provider_as_ids: vec![64498, 64497, 64498],
    }])
    .expect("build aspa state");
    let ccr = CcrContentInfo::new(RpkiCanonicalCacheRepresentation {
        version: 0,
        hash_alg: CcrDigestAlgorithm::Sha256,
        produced_at: time::OffsetDateTime::parse(
            "2026-03-30T00:00:00Z",
            &time::format_description::well_known::Rfc3339,
        )
        .expect("time"),
        mfts: None,
        vrps: Some(roa_state),
        vaps: Some(aspa_state),
        tas: None,
        rks: None,
    });
    std::fs::write(&ccr_path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr");

    let bin = env!("CARGO_BIN_EXE_ccr_to_compare_views");
    let out = Command::new(bin)
        .args([
            "--ccr",
            ccr_path.to_string_lossy().as_ref(),
            "--vrps-out",
            vrps_path.to_string_lossy().as_ref(),
            "--vaps-out",
            vaps_path.to_string_lossy().as_ref(),
            "--trust-anchor",
            "apnic",
        ])
        .output()
        .expect("run ccr_to_compare_views");
    assert!(
        out.status.success(),
        "stderr={}",
        String::from_utf8_lossy(&out.stderr)
    );

    let vrps_csv = std::fs::read_to_string(vrps_path).expect("read vrps csv");
    let vaps_csv = std::fs::read_to_string(vaps_path).expect("read vaps csv");
    assert!(vrps_csv.contains("ASN,IP Prefix,Max Length,Trust Anchor"));
    assert!(vrps_csv.contains("AS64496,198.51.100.0/24,24,unknown"));
    assert!(vaps_csv.contains("Customer ASN,Providers,Trust Anchor"));
    assert!(vaps_csv.contains("AS64496,AS64497;AS64498,unknown"));
}

#[test]
fn ccr_to_compare_views_binary_writes_header_only_vap_csv_when_absent() {
    use rpki::ccr::{
        CcrContentInfo, CcrDigestAlgorithm, RpkiCanonicalCacheRepresentation,
        build_roa_payload_state, encode::encode_content_info,
    };
    use rpki::data_model::roa::{IpPrefix, RoaAfi};
    use rpki::validation::objects::Vrp;

    let dir = tempfile::tempdir().expect("tempdir");
    let ccr_path = dir.path().join("views-no-vaps.ccr");
    let vrps_path = dir.path().join("vrps.csv");
    let vaps_path = dir.path().join("vaps.csv");
    let roa_state = build_roa_payload_state(&[Vrp {
        asn: 64496,
        prefix: IpPrefix {
            afi: RoaAfi::Ipv4,
            prefix_len: 24,
            addr: [203, 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        },
        max_length: 24,
    }])
    .expect("build roa state");
    let ccr = CcrContentInfo::new(RpkiCanonicalCacheRepresentation {
        version: 0,
        hash_alg: CcrDigestAlgorithm::Sha256,
        produced_at: time::OffsetDateTime::parse(
            "2026-03-30T00:00:00Z",
            &time::format_description::well_known::Rfc3339,
        )
        .expect("time"),
        mfts: None,
        vrps: Some(roa_state),
        vaps: None,
        tas: None,
        rks: None,
    });
    std::fs::write(&ccr_path, encode_content_info(&ccr).expect("encode ccr")).expect("write ccr");

    let bin = env!("CARGO_BIN_EXE_ccr_to_compare_views");
    let out = Command::new(bin)
        .args([
            "--ccr",
            ccr_path.to_string_lossy().as_ref(),
            "--vrps-out",
            vrps_path.to_string_lossy().as_ref(),
            "--vaps-out",
            vaps_path.to_string_lossy().as_ref(),
            "--trust-anchor",
            "apnic",
        ])
        .output()
        .expect("run ccr_to_compare_views");
    assert!(
        out.status.success(),
        "stderr={}",
        String::from_utf8_lossy(&out.stderr)
    );

    let vaps_csv = std::fs::read_to_string(vaps_path).expect("read vaps csv");
    assert_eq!(vaps_csv, "Customer ASN,Providers,Trust Anchor\n");
}
