use rpki::data_model::manifest::ManifestObject;
use rpki::data_model::rc::{AsIdOrRange, AsIdentifierChoice, AsResourceSet, ResourceCertificate};
use rpki::data_model::roa::{IpPrefix, RoaAfi};
use rpki::data_model::ta::{TaCertificate, TaCertificateParsed, TaCertificateProfileError};
use rpki::data_model::tal::{Tal, TalDecodeError, TalProfileError};

#[test]
fn tal_validate_profile_noop_is_callable() {
    let raw = std::fs::read("tests/fixtures/tal/apnic-rfc7730-https.tal").expect("read tal");
    let tal = Tal::decode_bytes(&raw).expect("decode tal");
    tal.validate_profile().expect("validate_profile is no-op");
}

#[test]
fn tal_invalid_uri_after_valid_uri_is_reported_as_missing_separator() {
    let s = "https://example.invalid/ta.cer\nnot a url\n\nAQ==\n";
    assert!(matches!(
        Tal::decode_bytes(s.as_bytes()),
        Err(TalDecodeError::Validate(
            TalProfileError::MissingSeparatorEmptyLine
        ))
    ));
}

#[test]
fn tal_missing_separator_empty_line_is_rejected() {
    let s = "https://example.invalid/ta.cer\nAQ==\n";
    assert!(matches!(
        Tal::decode_bytes(s.as_bytes()),
        Err(TalDecodeError::Validate(
            TalProfileError::MissingSeparatorEmptyLine
        ))
    ));
}

#[test]
fn tal_missing_spki_is_rejected() {
    let s = "https://example.invalid/ta.cer\n\n\n";
    assert!(matches!(
        Tal::decode_bytes(s.as_bytes()),
        Err(TalDecodeError::Validate(TalProfileError::MissingSpki))
    ));
}

#[test]
fn tal_missing_separator_due_to_eof_is_rejected() {
    // One URI and then EOF: should fail at the mandatory empty-line separator check.
    let s = "https://example.invalid/ta.cer";
    assert!(matches!(
        Tal::decode_bytes(s.as_bytes()),
        Err(TalDecodeError::Validate(
            TalProfileError::MissingSeparatorEmptyLine
        ))
    ));
}

#[test]
fn ta_validate_profile_noop_is_callable() {
    let der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read ta");
    let ta = TaCertificate::decode_der(&der).expect("decode ta");
    ta.validate_profile().expect("validate_profile is no-op");
}

#[test]
fn ta_parsed_validate_profile_rejects_ee_resource_certificate() {
    // Extract an embedded EE certificate from a real manifest fixture and feed it into the TA
    // profile validator to hit the `NotCa` branch in `TaCertificateParsed::validate_profile`.
    let mft_der = std::fs::read(
        "tests/fixtures/repository/ca.rg.net/rpki/RGnet-OU/bW-_qXU9uNhGQz21NR2ansB8lr0.mft",
    )
    .expect("read manifest fixture");
    let mft = ManifestObject::decode_der(&mft_der).expect("decode manifest");
    let ee_der = mft.signed_object.signed_data.certificates[0]
        .resource_cert
        .raw_der
        .clone();

    let rc_parsed = ResourceCertificate::parse_der(&ee_der).expect("parse embedded EE cert");
    let ta_parsed = TaCertificateParsed { rc_parsed };
    let err = ta_parsed.validate_profile().unwrap_err();
    assert!(matches!(err, TaCertificateProfileError::NotCa));
}

#[test]
fn ta_rc_constraints_exercise_rdi_non_empty_branch() {
    let der = std::fs::read("tests/fixtures/ta/apnic-ta.cer").expect("read ta");
    let ta = TaCertificate::decode_der(&der).expect("decode ta");

    let mut rc = ta.rc_ca.clone();
    rc.tbs.extensions.as_resources = Some(AsResourceSet {
        asnum: rc
            .tbs
            .extensions
            .as_resources
            .as_ref()
            .and_then(|v| v.asnum.clone()),
        rdi: Some(AsIdentifierChoice::AsIdsOrRanges(vec![AsIdOrRange::Id(
            64496,
        )])),
    });

    TaCertificate::validate_rc_constraints(&rc).expect("constraints should still pass");
}

#[test]
fn audit_helpers_format_roa_ip_prefix_smoke() {
    let v4 = IpPrefix {
        afi: RoaAfi::Ipv4,
        prefix_len: 24,
        addr: [192, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    };
    assert_eq!(rpki::audit::format_roa_ip_prefix(&v4), "192.0.2.0/24");

    let v6 = IpPrefix {
        afi: RoaAfi::Ipv6,
        prefix_len: 32,
        addr: [0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    };
    assert!(rpki::audit::format_roa_ip_prefix(&v6).ends_with("/32"));
}

#[test]
fn audit_helpers_sha256_hex_smoke() {
    let h = rpki::audit::sha256_hex(b"abc");
    assert_eq!(h.len(), 64);

    let bytes = [0x11u8; 32];
    let h2 = rpki::audit::sha256_hex_from_32(&bytes);
    assert_eq!(h2, "11".repeat(32));
}
