//! Random number example — `Rand` simple helpers and `RandCtx` DRBG.
//!
//! Run with: cargo run --example rand -p native-ossl

use native_ossl::rand::{GenerateRequest, Rand, RandAlg, RandCtx, RandState};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ── Rand — simple fill helpers ────────────────────────────────────────────

    let mut buf = [0u8; 32];
    Rand::fill(&mut buf)?;
    println!(
        "Random bytes:         {}",
        native_ossl::util::hex_encode(buf)
    );

    let key_bytes = Rand::bytes_private(32)?;
    println!(
        "Private random bytes: {}",
        native_ossl::util::hex_encode(&key_bytes)
    );

    // ── RandCtx — explicit DRBG instance ─────────────────────────────────────

    let alg = RandAlg::fetch(c"CTR-DRBG", None)?;
    let mut ctx = RandCtx::new(&alg, None)?;

    // Configure AES-128-CTR so the context can be seeded from the system
    // SEED-SRC, which caps at 128 bits of entropy.
    let params = native_ossl::params::ParamBuilder::new()?
        .push_utf8_string(c"cipher", c"AES-128-CTR")?
        .build()?;

    assert_eq!(ctx.state(), RandState::Uninitialised);
    ctx.instantiate(128, false, Some(&params))?;
    assert_eq!(ctx.state(), RandState::Ready);
    println!("DRBG strength: {} bits", ctx.strength());

    let req = GenerateRequest {
        strength: 128,
        ..Default::default()
    };
    let mut a = [0u8; 32];
    let mut b = [0u8; 32];
    ctx.generate(&mut a, &req)?;
    ctx.generate(&mut b, &req)?;
    assert_ne!(a, b, "consecutive generates must differ");
    println!("CTR-DRBG output 1: {}", native_ossl::util::hex_encode(a));
    println!("CTR-DRBG output 2: {}", native_ossl::util::hex_encode(b));

    // Clone shares the reference count — both handles produce independent output.
    let mut ctx2 = ctx.clone();
    let mut c = [0u8; 32];
    ctx2.generate(&mut c, &req)?;
    println!("Cloned DRBG output: {}", native_ossl::util::hex_encode(c));

    Ok(())
}
