//! FIPS example — check whether the FIPS provider is active, and demonstrate
//! algorithm fetching from a FIPS-isolated library context.
//!
//! Run with: cargo run --example fips -p native-ossl

use native_ossl::digest::DigestAlg;
use native_ossl::fips;
use native_ossl::lib_ctx::LibCtx;
use std::sync::Arc;

#[allow(clippy::unnecessary_wraps)]
fn main() -> Result<(), Box<dyn std::error::Error>> {
    // ── Process-wide FIPS status ───────────────────────────────────────────────

    // `fips::is_running()` checks whether the FIPS provider is currently active
    // in the default library context.  No feature flag is needed.
    let running = fips::is_running(None);
    println!("FIPS provider active in default context: {running}");

    // ── FIPS-isolated context ──────────────────────────────────────────────────

    // Build an isolated context that loads ONLY the FIPS + base providers.
    // If the FIPS provider is not installed this will return an error.
    match try_fips_context() {
        Ok(()) => println!("FIPS-isolated context: OK"),
        Err(e) => println!("FIPS provider not available ({e}) — skipping isolation demo"),
    }

    Ok(())
}

fn try_fips_context() -> Result<(), Box<dyn std::error::Error>> {
    let ctx = Arc::new(LibCtx::new()?);
    let _fips = ctx.load_provider(c"fips")?;
    let _base = ctx.load_provider(c"base")?;

    // SHA-256 is FIPS-approved — fetch succeeds.
    let sha256 = DigestAlg::fetch_in(&ctx, c"SHA2-256", None)?;
    let mut digest_ctx = sha256.new_context()?;
    digest_ctx.update(b"FIPS test")?;
    let mut out = [0u8; 32];
    digest_ctx.finish(&mut out)?;
    println!(
        "SHA-256 in FIPS context: {}",
        native_ossl::util::hex_encode(out)
    );

    // MD5 is NOT FIPS-approved — fetch fails.
    let md5_result = DigestAlg::fetch_in(&ctx, c"MD5", None);
    assert!(
        md5_result.is_err(),
        "MD5 must not be available in a FIPS context"
    );
    println!("MD5 correctly rejected in FIPS context: OK");

    Ok(())
}
