#![deny(unsafe_code)]
// Test files use unwrap() for simplicity - test failures will show clear panics
#![allow(clippy::unwrap_used)]
// Test files may use eprintln for diagnostic output
#![allow(clippy::print_stderr)]

//! Integration tests for zeroization security features
//!
//! These tests verify that secret key material is properly zeroized
//! when keys are dropped or explicitly zeroized.

use latticearc::hybrid::{kem_hybrid as kem, sig_hybrid as sig};
use zeroize::Zeroize;

#[test]
fn test_hybrid_kem_secret_key_zeroization_before_drop_succeeds() {
    let (_pk, sk) = kem::generate_keypair().unwrap();

    // Verify public key accessors work (private keys are in aws-lc-rs, not exposed as bytes)
    let mut pk_bytes = sk.ml_kem_pk_bytes();
    assert!(!pk_bytes.iter().all(|&x| x == 0), "ML-KEM PK should be non-zero");
    pk_bytes.zeroize();
    assert!(pk_bytes.iter().all(|&x| x == 0), "Zeroization of PK copy failed");

    let mut ecdh_pk = sk.ecdh_public_key_bytes();
    assert!(!ecdh_pk.iter().all(|&x| x == 0), "ECDH PK should be non-zero");
    ecdh_pk.zeroize();
    assert!(ecdh_pk.iter().all(|&x| x == 0), "Zeroization of ECDH PK copy failed");

    // Drop triggers aws-lc-rs cleanup for both ML-KEM DecapsulationKey and X25519 PrivateKey
    drop(sk);
}

#[test]
fn test_hybrid_sig_secret_key_zeroization_before_drop_succeeds() {
    let (_pk, sk) = sig::generate_keypair().unwrap();

    // Verify zeroization works before drop
    let mut sk_bytes = sk.ml_dsa_sk_bytes();
    sk_bytes.zeroize();
    // assert!(!sk_bytes.is_empty(), "Zeroized bytes should not be empty");
    assert!(sk_bytes.iter().all(|&x| x == 0), "Zeroization failed - not all bytes are zero");

    let mut sk_bytes2 = sk.ed25519_sk_bytes();
    sk_bytes2.zeroize();
    // assert!(!sk_bytes2.is_empty(), "Zeroized bytes should not be empty");
    assert!(sk_bytes2.iter().all(|&x| x == 0), "Zeroization failed - not all bytes are zero");
}

#[test]
fn test_hybrid_kem_secret_key_no_clone_succeeds() {
    let (_pk, sk) = kem::generate_keypair().unwrap();

    // Verify type exists and does not have Clone at compile time
    // The fact that this code compiles without sk.clone() confirms
    // that Clone is not implemented
    let _sk = sk;

    // Attempting to call sk.clone() would result in a compile error:
    // error[E0599]: no method named `clone` found for struct `HybridSecretKey` in the current scope
}

#[test]
fn test_hybrid_sig_secret_key_no_clone_succeeds() {
    let (_pk, sk) = sig::generate_keypair().unwrap();

    // Verify type exists and does not have Clone at compile time
    // The fact that this code compiles without sk.clone() confirms
    // that Clone is not implemented
    let _sk = sk;

    // Attempting to call sk.clone() would result in a compile error:
    // error[E0599]: no method named `clone` found for struct `HybridSecretKey` in the current scope
}

#[test]
fn test_encapsulated_key_shared_secret_zeroization_succeeds() {
    let (pk, _sk) = kem::generate_keypair().unwrap();

    let enc_result = kem::encapsulate(&pk);
    if let Ok(enc_key) = enc_result {
        // Get the shared secret and verify it can be zeroized
        let mut secret = enc_key.shared_secret().to_vec();
        secret.zeroize();
        // assert!(!secret.is_empty(), "Zeroized secret should not be empty");
        assert!(secret.iter().all(|&x| x == 0), "Zeroization failed - not all bytes are zero");
    } else {
        // If encapsulation fails (e.g., ML-KEM not available), skip this test gracefully
        eprintln!("Encapsulation failed, skipping test: {:?}", enc_result);
    }
}

#[test]
fn test_hybrid_kem_public_key_bytes_not_zero_before_use_succeeds() {
    let (_pk, sk): (_, kem::HybridKemSecretKey) = kem::generate_keypair().unwrap();

    // Verify that public key bytes are NOT all zeros (real keys were generated)
    let ml_kem_pk = sk.ml_kem_pk_bytes();
    let ecdh_pk = sk.ecdh_public_key_bytes();

    assert!(ml_kem_pk.iter().any(|&x| x != 0), "ML-KEM public key should contain non-zero bytes");
    assert!(ecdh_pk.iter().any(|&x| x != 0), "ECDH public key should contain non-zero bytes");
}

#[test]
fn test_hybrid_sig_secret_key_bytes_not_zero_before_use_succeeds() {
    let (_pk, sk): (_, sig::HybridSigSecretKey) = sig::generate_keypair().unwrap();

    // Verify that secret key bytes are NOT all zeros initially (they should be non-zero)
    let ml_dsa_bytes = sk.ml_dsa_sk_bytes();
    let ed25519_bytes = sk.ed25519_sk_bytes();

    // At least one of the bytes should be non-zero for a proper key
    let ml_dsa_has_non_zero = ml_dsa_bytes.iter().any(|&x| x != 0);
    let ed25519_has_non_zero = ed25519_bytes.iter().any(|&x| x != 0);

    assert!(ml_dsa_has_non_zero, "ML-DSA secret key should contain non-zero bytes");
    assert!(ed25519_has_non_zero, "Ed25519 secret key should contain non-zero bytes");
}
