//! PKCS#12 example — create a PFX bundle, serialise, and parse it back.
//!
//! Run with: cargo run --example pkcs12 -p native-ossl

use native_ossl::pkcs12::Pkcs12;
use native_ossl::pkey::KeygenCtx;
use native_ossl::x509::{X509Builder, X509NameOwned};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ── Generate key and self-signed certificate ───────────────────────────────

    let mut kgen = KeygenCtx::new(c"ED25519")?;
    let priv_key = kgen.generate()?;
    let pub_key = native_ossl::pkey::Pkey::<native_ossl::pkey::Public>::from(priv_key.clone());

    let mut name = X509NameOwned::new()?;
    name.add_entry_by_txt(c"CN", b"example.com")?;

    let cert = X509Builder::new()?
        .set_version(2)?
        .set_serial_number(1)?
        .set_not_before_offset(0)?
        .set_not_after_offset(365 * 86400)?
        .set_subject_name(&name)?
        .set_issuer_name(&name)?
        .set_public_key(&pub_key)?
        .sign(&priv_key, None)?
        .build();

    // ── Create the PKCS#12 bundle ─────────────────────────────────────────────

    let password = "correct horse battery staple";
    let p12 = Pkcs12::create(password, "example.com", &priv_key, &cert, &[])?;
    let der = p12.to_der()?;
    println!("PKCS#12 bundle: {} bytes", der.len());

    // ── Parse it back ─────────────────────────────────────────────────────────

    let loaded = Pkcs12::from_der(&der)?;
    let (recovered_key, recovered_cert, ca_chain) = loaded.parse(password)?;

    println!(
        "Recovered key algorithm: Ed25519 = {}",
        recovered_key.is_a(c"ED25519")
    );
    if let Some(subject) = recovered_cert.subject_name().to_string() {
        println!("Recovered cert subject:  {subject}");
    }
    println!("CA chain length: {}", ca_chain.len());

    // Public keys must match.
    assert!(priv_key.public_eq(&recovered_key));
    assert_eq!(cert.to_der()?, recovered_cert.to_der()?);
    println!("Key and certificate match original: OK");

    // ── DER round-trip ────────────────────────────────────────────────────────

    let der2 = loaded.to_der()?;
    assert_eq!(der, der2);
    println!("DER round-trip: OK");

    Ok(())
}
