use rpki::data_model::manifest::ManifestObject;
use rpki::data_model::ta::TrustAnchor;
use rpki::data_model::tal::Tal;
use rpki::validation::ca_instance::{CaInstanceUrisError, ca_instance_uris_from_ca_certificate};
use url::Url;

fn load_tal_and_ta_fixture(tal_name: &str, ta_name: &str) -> TrustAnchor {
    let tal_bytes =
        std::fs::read(format!("tests/fixtures/tal/{tal_name}")).expect("read TAL fixture");
    let tal = Tal::decode_bytes(&tal_bytes).expect("decode TAL");

    let ta_der = std::fs::read(format!("tests/fixtures/ta/{ta_name}")).expect("read TA fixture");
    let resolved = tal.ta_uris[0].clone();

    TrustAnchor::bind_der(tal, &ta_der, Some(&resolved)).expect("bind TAL and TA")
}

#[test]
fn ca_instance_uris_are_discoverable_from_trust_anchor_certificates() {
    let cases = [
        ("afrinic.tal", "afrinic-ta.cer"),
        ("apnic-rfc7730-https.tal", "apnic-ta.cer"),
        ("arin.tal", "arin-ta.cer"),
        ("lacnic.tal", "lacnic-ta.cer"),
        ("ripe-ncc.tal", "ripe-ncc-ta.cer"),
    ];

    for (tal, ta) in cases {
        let trust_anchor = load_tal_and_ta_fixture(tal, ta);
        let uris = ca_instance_uris_from_ca_certificate(&trust_anchor.ta_certificate.rc_ca)
            .expect("extract CA instance URIs");

        assert!(uris.rsync_base_uri.starts_with("rsync://"));
        assert!(uris.rsync_base_uri.ends_with('/'));
        assert!(uris.publication_point_rsync_uri.starts_with("rsync://"));
        assert!(uris.publication_point_rsync_uri.ends_with('/'));
        assert!(uris.manifest_rsync_uri.starts_with("rsync://"));
        assert!(
            uris.manifest_rsync_uri.ends_with(".mft"),
            "manifest URI should look like an mft: {}",
            uris.manifest_rsync_uri
        );

        if let Some(n) = &uris.rrdp_notification_uri {
            assert_eq!(Url::parse(n).unwrap().scheme(), "https");
        }
    }
}

#[test]
fn ca_instance_uris_rejects_ee_certificate() {
    let mft_der = std::fs::read(
        "tests/fixtures/repository/rpki.cernet.net/repo/cernet/0/05FC9C5B88506F7C0D3F862C8895BED67E9F8EBA.mft",
    )
    .expect("read manifest fixture");
    let mft = ManifestObject::decode_der(&mft_der).expect("decode manifest");
    let ee = &mft.signed_object.signed_data.certificates[0].resource_cert;

    let err = ca_instance_uris_from_ca_certificate(ee).unwrap_err();
    assert!(
        matches!(err, CaInstanceUrisError::NotCa),
        "expected NotCa, got: {err}"
    );
}
