use rpki::data_model::ta::{
    TaCertificateVerifyError, TrustAnchor, TrustAnchorBindError, TrustAnchorError,
};
use rpki::data_model::tal::Tal;
use url::Url;

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

    for (tal_path, ta_path) in cases {
        let tal_raw = std::fs::read(tal_path).expect("read TAL fixture");
        let tal = Tal::decode_bytes(&tal_raw).expect("decode TAL fixture");
        let ta_der = std::fs::read(ta_path).expect("read TA fixture");

        TrustAnchor::bind_der(tal.clone(), &ta_der, None).expect("bind without resolved uri");

        // Also exercise the resolved-uri-in-TAL check using one URI from the TAL list.
        let resolved = tal
            .ta_uris
            .iter()
            .find(|u| u.scheme() == "https")
            .or_else(|| tal.ta_uris.first())
            .expect("tal has ta uris");
        let resolved = resolved.clone();
        TrustAnchor::bind_der(tal, &ta_der, Some(&resolved)).expect("bind with resolved uri");
    }
}

#[test]
fn bind_rejects_spki_mismatch() {
    let tal_raw = std::fs::read("tests/fixtures/tal/ripe-ncc.tal").expect("read TAL fixture");
    let mut tal = Tal::decode_bytes(&tal_raw).expect("decode TAL fixture");
    let ta_der = std::fs::read("tests/fixtures/ta/ripe-ncc-ta.cer").expect("read TA fixture");

    // Flip a byte in TAL SPKI to force mismatch.
    tal.subject_public_key_info_der[0] ^= 0x01;
    assert!(matches!(
        TrustAnchor::bind_der(tal, &ta_der, None),
        Err(TrustAnchorError::Bind(
            TrustAnchorBindError::TalSpkiMismatch
        ))
    ));
}

#[test]
fn bind_rejects_resolved_uri_not_listed_in_tal() {
    let tal_raw = std::fs::read("tests/fixtures/tal/afrinic.tal").expect("read TAL fixture");
    let tal = Tal::decode_bytes(&tal_raw).expect("decode TAL fixture");
    let ta_der = std::fs::read("tests/fixtures/ta/afrinic-ta.cer").expect("read TA fixture");

    let bad = Url::parse("https://example.invalid/not-in-tal.cer").unwrap();
    assert!(matches!(
        TrustAnchor::bind_der(tal, &ta_der, Some(&bad)),
        Err(TrustAnchorError::Bind(
            TrustAnchorBindError::ResolvedUriNotInTal(_)
        ))
    ));
}

#[test]
fn bind_rejects_tampered_ta_self_signature() {
    let tal_raw =
        std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal").expect("read TAL fixture");
    let tal = Tal::decode_bytes(&tal_raw).expect("decode TAL fixture");
    let mut ta_der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read TA fixture");

    let last = ta_der.last_mut().expect("TA fixture must not be empty");
    *last ^= 0x01;

    assert!(matches!(
        TrustAnchor::bind_der(tal, &ta_der, None),
        Err(TrustAnchorError::TaSelfSignature(
            TaCertificateVerifyError::InvalidSelfSignature(_)
        ))
    ));
}
