//! Params example — build and pass `OSSL_PARAM` arrays to algorithm contexts.
//!
//! `OSSL_PARAM` is OpenSSL 3.x's generic key-value mechanism for passing
//! configuration to algorithm contexts.  `ParamBuilder` constructs typed
//! arrays; `Params` passes them to the API.
//!
//! Run with: cargo run --example params -p native-ossl

use native_ossl::mac::{MacAlg, MacCtx};
use native_ossl::params::ParamBuilder;
use native_ossl::pkey::KeygenCtx;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ── Build a params array with mixed types ─────────────────────────────────

    // push_octet_slice copies; push_octet_ptr borrows (zero-copy).
    let salt = b"random-salt-value";
    let _params = ParamBuilder::new()?
        .push_utf8_string(c"digest", c"SHA2-256")?
        .push_uint(c"iterations", 600_000)?
        .push_octet_slice(c"salt", salt)?
        .build()?;
    println!("Params array with string, uint, and octet built: OK");

    // ── Configure an HMAC context via params ──────────────────────────────────

    let hmac_alg = MacAlg::fetch(c"HMAC", None)?;
    let mut mac_ctx = MacCtx::new(&hmac_alg)?;

    // MacCtx::init takes key + optional params.
    let mac_params = ParamBuilder::new()?
        .push_utf8_string(c"digest", c"SHA2-256")?
        .build()?;
    mac_ctx.init(b"secret key", Some(&mac_params))?;
    mac_ctx.update(b"authenticated data")?;

    let size = mac_ctx.mac_size();
    let mut out = vec![0u8; size];
    let n = mac_ctx.finish(&mut out)?;
    println!(
        "HMAC result ({n} bytes): {}",
        native_ossl::util::hex_encode(&out[..n])
    );

    // ── Configure RSA key generation via params ───────────────────────────────

    let rsa_params = ParamBuilder::new()?.push_uint(c"bits", 2048)?.build()?;
    let mut kgen = KeygenCtx::new(c"RSA")?;
    kgen.set_params(&rsa_params)?;
    let key = kgen.generate()?;
    println!("RSA key generated: {} bits", key.bits());

    // ── EC group selection via params ─────────────────────────────────────────

    let ec_params = ParamBuilder::new()?
        .push_utf8_string(c"group", c"P-256")?
        .build()?;
    let mut ec_kgen = KeygenCtx::new(c"EC")?;
    ec_kgen.set_params(&ec_params)?;
    let ec_key = ec_kgen.generate()?;
    println!("EC P-256 key generated: {} bits", ec_key.bits());

    Ok(())
}
