//! # LatticeArc Logging Utilities
//!
//! Security-conscious logging utilities for LatticeArc Core.
//! Provides structured logging with tracing while ensuring no sensitive
//! cryptographic material is logged.
//!
//! ## Security Features
//!
//! - **No Sensitive Data**: Automatic sanitization of cryptographic keys and secrets
//! - **Structured Logging**: Consistent log format across all components
//! - **Performance Conscious**: Minimal overhead in cryptographic operations
//! - **Configurable**: Environment-based log levels and output formats
//!
//! ## Usage
//!
//! `init_tracing` is gated behind the `tracing-init` Cargo feature
//! (off by default — subscriber wiring is the binary's responsibility,
//! not the library's). The doctest below is `ignore`d so it doesn't
//! force the feature on every test config.
//!
//! ```rust,ignore
//! // Requires `latticearc = { ..., features = ["tracing-init"] }`
//! // — example is `ignore`-gated rather than `no_run` because the
//! //   `init_tracing` / `sanitize_data` symbols only exist when that
//! //   feature is on.
//! use latticearc::unified_api::logging::{init_tracing, sanitize_data};
//!
//! // Initialize logging (sets global tracing subscriber — call once per process)
//! init_tracing().expect("Failed to init tracing");
//!
//! // Log with automatic sanitization
//! let key_data = b"sensitive_key_material";
//! tracing::info!("Key operation completed: {}", sanitize_data(key_data));
//! ```

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::sync::atomic::{AtomicU64, Ordering};
// `tracing::info` is only used inside the `init_tracing*` helpers, which
// are themselves gated behind the `tracing-init` feature. The subscriber
// wiring (and its tracing-subscriber + tracing-appender deps) is the
// binary's job — see the feature comment in `latticearc/Cargo.toml`.
#[cfg(feature = "tracing-init")]
use tracing::info;
#[cfg(feature = "tracing-init")]
use tracing_subscriber::{EnvFilter, layer::SubscriberExt, util::SubscriberInitExt};
use uuid::Uuid;

/// Stable operation-name tags for `log_crypto_operation_error!`.
///
/// Operators filter crypto observability logs by this tag (e.g. grepping
/// logs by `operation="hybrid_decrypt"`). Defining these as `const` — rather
/// than bare string literals at each call site — prevents typos from
/// silently losing a stage's logs.
///
/// When adding a new crypto entry point, add its tag here and use the const
/// at all `log_crypto_operation_error!` call sites within that function.
pub mod op {
    // AEAD
    /// Tag for `aes_gcm::decrypt_aes_gcm_with_aad_internal` observability events.
    pub const AES_GCM_DECRYPT_AAD: &str = "aes_gcm_decrypt_aad";
    /// Tag for `aes_gcm::encrypt_aes_gcm_with_aad_internal` observability events.
    pub const AES_GCM_ENCRYPT_AAD: &str = "aes_gcm_encrypt_aad";
    /// Tag for `api::decrypt_chacha20_internal` observability events.
    pub const CHACHA20_DECRYPT: &str = "chacha20_decrypt";

    // KEM
    /// Tag for `primitives::kem::ml_kem::encapsulate` observability events.
    pub const ML_KEM_ENCAP: &str = "ml_kem_encap";
    /// Tag for `hybrid::kem_hybrid::derive_hybrid_shared_secret` observability events.
    pub const HYBRID_KEM_DERIVE: &str = "hybrid_kem_derive";
    /// Tag for `hybrid::kem_hybrid::encapsulate` observability events.
    pub const HYBRID_KEM_ENCAPSULATE: &str = "hybrid_kem_encapsulate";
    /// Tag for `hybrid::kem_hybrid::decapsulate` observability events.
    /// Used for the per-stage internal trace when an opaque
    /// `DecapsulationFailed` is returned to the caller (Pattern 6:
    /// opaque return + internal trace so operators can correlate via
    /// `correlation_id` while the API stays oracle-free).
    pub const HYBRID_KEM_DECAPSULATE: &str = "hybrid_kem_decapsulate";

    // Hybrid encryption (KEM + AEAD)
    /// Tag for `hybrid::encrypt_hybrid::encrypt_hybrid` observability events.
    pub const HYBRID_ENCRYPT: &str = "hybrid_encrypt";
    /// Tag for `hybrid::encrypt_hybrid::decrypt_hybrid` observability events.
    pub const HYBRID_DECRYPT: &str = "hybrid_decrypt";
    /// Tag for `hybrid::encrypt_hybrid::derive_encryption_key` observability events.
    pub const HYBRID_DERIVE_KEY: &str = "hybrid_derive_key";

    // PQ-only encryption
    /// Tag for `hybrid::pq_only::encrypt_pq_only` observability events.
    pub const PQ_ONLY_ENCRYPT: &str = "pq_only_encrypt";
    /// Tag for `hybrid::pq_only::decrypt_pq_only` observability events.
    pub const PQ_ONLY_DECRYPT: &str = "pq_only_decrypt";
    /// Tag for `pq_kem::encrypt_pq_ml_kem_internal` observability events.
    pub const ENCRYPT_PQ_ML_KEM: &str = "encrypt_pq_ml_kem";
    /// Tag for `pq_kem::decrypt_pq_ml_kem_internal` observability events.
    pub const DECRYPT_PQ_ML_KEM: &str = "decrypt_pq_ml_kem";

    // Signatures
    /// Tag for `hybrid::sig_hybrid::sign` observability events.
    pub const HYBRID_SIGN: &str = "hybrid_sign";
    /// Tag for `hybrid::sig_hybrid::verify` observability events.
    pub const HYBRID_VERIFY: &str = "hybrid_verify";
    /// Tag for `primitives::sig::ml_dsa::sign` observability events.
    pub const ML_DSA_SIGN: &str = "ml_dsa_sign";
    /// Tag for `primitives::sig::ml_dsa::verify` observability events.
    pub const ML_DSA_VERIFY: &str = "ml_dsa_verify";
    /// Tag for `primitives::sig::slh_dsa` signing observability events.
    pub const SLH_DSA_SIGN: &str = "slh_dsa_sign";
    /// Tag for `primitives::sig::slh_dsa` verification observability events.
    pub const SLH_DSA_VERIFY: &str = "slh_dsa_verify";
    /// Tag for `primitives::sig::fndsa` signing observability events.
    pub const FN_DSA_SIGN: &str = "fn_dsa_sign";
    /// Tag for `primitives::sig::fndsa` verification observability events.
    pub const FN_DSA_VERIFY: &str = "fn_dsa_verify";
    /// Tag for Ed25519 signing observability events.
    pub const ED25519_SIGN: &str = "ed25519_sign";
    /// Tag for Ed25519 verification observability events.
    pub const ED25519_VERIFY: &str = "ed25519_verify";

    // MAC
    /// Tag for HMAC computation observability events.
    pub const HMAC: &str = "hmac";
    /// Tag for HMAC verification observability events.
    pub const HMAC_VERIFY: &str = "hmac_verify";

    // KDF
    /// Tag for generic key-derivation observability events.
    pub const KEY_DERIVATION: &str = "key_derivation";
    /// Tag for key-derivation events where `info` binding is the key concern.
    pub const KEY_DERIVATION_INFO: &str = "key_derivation_info";

    // Unified API
    /// Tag for the unified `encrypt` entry point observability events.
    pub const ENCRYPT: &str = "encrypt";
    /// Tag for the unified `decrypt` entry point observability events.
    pub const DECRYPT: &str = "decrypt";
    /// Tag for the unified `sign_with_key` entry point observability events.
    pub const SIGN_WITH_KEY: &str = "sign_with_key";
    /// Tag for the unified `verify` entry point observability events.
    pub const VERIFY: &str = "verify";
}

#[cfg(test)]
mod op_constants_pin {
    //! Pin every `op::*` constant value to its expected literal. The
    //! constants are SIEM rule keys — a search-replace that touches a
    //! constant value but not the corresponding rule is unrecoverable
    //! post-deploy. This test fails loudly if any constant drifts
    //! from its documented string.
    //!
    //! When adding a new `op::*` constant, also add its expected
    //! literal here.

    use super::op;

    #[test]
    fn op_aead_constants_match_expected_literals() {
        assert_eq!(op::AES_GCM_DECRYPT_AAD, "aes_gcm_decrypt_aad");
        assert_eq!(op::AES_GCM_ENCRYPT_AAD, "aes_gcm_encrypt_aad");
        assert_eq!(op::CHACHA20_DECRYPT, "chacha20_decrypt");
    }

    #[test]
    fn op_kem_constants_match_expected_literals() {
        assert_eq!(op::ML_KEM_ENCAP, "ml_kem_encap");
        assert_eq!(op::HYBRID_KEM_DERIVE, "hybrid_kem_derive");
        assert_eq!(op::HYBRID_KEM_ENCAPSULATE, "hybrid_kem_encapsulate");
        assert_eq!(op::HYBRID_KEM_DECAPSULATE, "hybrid_kem_decapsulate");
        assert_eq!(op::HYBRID_ENCRYPT, "hybrid_encrypt");
        assert_eq!(op::HYBRID_DECRYPT, "hybrid_decrypt");
        assert_eq!(op::HYBRID_DERIVE_KEY, "hybrid_derive_key");
        assert_eq!(op::PQ_ONLY_ENCRYPT, "pq_only_encrypt");
        assert_eq!(op::PQ_ONLY_DECRYPT, "pq_only_decrypt");
        assert_eq!(op::ENCRYPT_PQ_ML_KEM, "encrypt_pq_ml_kem");
        assert_eq!(op::DECRYPT_PQ_ML_KEM, "decrypt_pq_ml_kem");
    }

    #[test]
    fn op_sig_constants_match_expected_literals() {
        assert_eq!(op::HYBRID_SIGN, "hybrid_sign");
        assert_eq!(op::HYBRID_VERIFY, "hybrid_verify");
        assert_eq!(op::ML_DSA_SIGN, "ml_dsa_sign");
        assert_eq!(op::ML_DSA_VERIFY, "ml_dsa_verify");
        assert_eq!(op::SLH_DSA_SIGN, "slh_dsa_sign");
        assert_eq!(op::SLH_DSA_VERIFY, "slh_dsa_verify");
        assert_eq!(op::FN_DSA_SIGN, "fn_dsa_sign");
        assert_eq!(op::FN_DSA_VERIFY, "fn_dsa_verify");
        assert_eq!(op::ED25519_SIGN, "ed25519_sign");
        assert_eq!(op::ED25519_VERIFY, "ed25519_verify");
    }

    #[test]
    fn op_mac_kdf_constants_match_expected_literals() {
        assert_eq!(op::HMAC, "hmac");
        assert_eq!(op::HMAC_VERIFY, "hmac_verify");
        assert_eq!(op::KEY_DERIVATION, "key_derivation");
        assert_eq!(op::KEY_DERIVATION_INFO, "key_derivation_info");
    }

    #[test]
    fn op_unified_constants_match_expected_literals() {
        assert_eq!(op::ENCRYPT, "encrypt");
        assert_eq!(op::DECRYPT, "decrypt");
        assert_eq!(op::SIGN_WITH_KEY, "sign_with_key");
        assert_eq!(op::VERIFY, "verify");
    }
}

// ============================================================================
// Key Lifecycle Event Types for Audit Logging
// ============================================================================

/// Key type classification for lifecycle events.
///
/// Distinguishes between different key categories for proper audit logging
/// and compliance reporting.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum KeyType {
    /// Symmetric keys (e.g., AES-256)
    Symmetric,
    /// Asymmetric public keys (can be shared)
    AsymmetricPublic,
    /// Asymmetric private keys (must be protected)
    AsymmetricPrivate,
    /// Complete keypair (public + private)
    KeyPair,
}

impl fmt::Display for KeyType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            KeyType::Symmetric => write!(f, "Symmetric"),
            KeyType::AsymmetricPublic => write!(f, "AsymmetricPublic"),
            KeyType::AsymmetricPrivate => write!(f, "AsymmetricPrivate"),
            KeyType::KeyPair => write!(f, "KeyPair"),
        }
    }
}

/// Key purpose classification per NIST SP 800-57.
///
/// Defines the intended use of a cryptographic key for audit and
/// compliance tracking.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum KeyPurpose {
    /// Key used for encryption operations
    Encryption,
    /// Key used for digital signature creation
    Signing,
    /// Key used for key exchange protocols (e.g., KEM, DH)
    KeyExchange,
    /// Key used for authentication operations
    Authentication,
    /// Key used for wrapping other keys
    KeyWrapping,
}

impl fmt::Display for KeyPurpose {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            KeyPurpose::Encryption => write!(f, "Encryption"),
            KeyPurpose::Signing => write!(f, "Signing"),
            KeyPurpose::KeyExchange => write!(f, "KeyExchange"),
            KeyPurpose::Authentication => write!(f, "Authentication"),
            KeyPurpose::KeyWrapping => write!(f, "KeyWrapping"),
        }
    }
}

/// Reason for key rotation.
///
/// Tracks why a key was rotated for compliance and audit purposes.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RotationReason {
    /// Scheduled rotation per policy
    Scheduled,
    /// Key was potentially compromised
    Compromised,
    /// Policy or compliance requirements changed
    PolicyChange,
    /// Key reached its cryptoperiod end
    Expiration,
    /// Manual rotation by administrator
    Manual,
}

impl fmt::Display for RotationReason {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            RotationReason::Scheduled => write!(f, "Scheduled"),
            RotationReason::Compromised => write!(f, "Compromised"),
            RotationReason::PolicyChange => write!(f, "PolicyChange"),
            RotationReason::Expiration => write!(f, "Expiration"),
            RotationReason::Manual => write!(f, "Manual"),
        }
    }
}

/// Method used for key destruction.
///
/// Documents how key material was destroyed for compliance verification.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum DestructionMethod {
    /// Memory zeroization (software)
    Zeroization,
    /// Cryptographic erasure (key deletion from encrypted storage)
    CryptoErase,
    /// Manual destruction by administrator
    Manual,
}

impl fmt::Display for DestructionMethod {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DestructionMethod::Zeroization => write!(f, "Zeroization"),
            DestructionMethod::CryptoErase => write!(f, "CryptoErase"),
            DestructionMethod::Manual => write!(f, "Manual"),
        }
    }
}

/// Key lifecycle events for comprehensive audit logging.
///
/// These events track all significant operations on cryptographic keys
/// throughout their lifecycle, from generation to destruction.
///
/// # Audit Trail Compliance
///
/// This enum supports compliance with:
/// - NIST SP 800-57 (Key Management)
/// - FIPS 140-3 (Cryptographic Module Security)
/// - SOC 2 Type II (Security Controls)
/// - PCI DSS (Payment Card Industry)
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::{KeyLifecycleEvent, KeyType, KeyPurpose};
///
/// let event = KeyLifecycleEvent::Generated {
///     key_id: "key-001".to_string(),
///     algorithm: "ML-KEM-768".to_string(),
///     key_type: KeyType::KeyPair,
///     purpose: KeyPurpose::KeyExchange,
/// };
///
/// // Log the event using the provided macros
/// // log_key_generated!("key-001", "ML-KEM-768", KeyType::KeyPair, KeyPurpose::KeyExchange);
/// ```
#[non_exhaustive]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KeyLifecycleEvent {
    /// Key was generated.
    ///
    /// Logged when new cryptographic key material is created.
    Generated {
        /// Unique identifier for the key
        key_id: String,
        /// Algorithm used (e.g., "ML-KEM-768", "AES-256-GCM")
        algorithm: String,
        /// Type of key generated
        key_type: KeyType,
        /// Intended purpose of the key
        purpose: KeyPurpose,
    },

    /// Key was rotated (old key deprecated, new key active).
    ///
    /// Logged when a key is replaced with a new key while
    /// maintaining service continuity.
    Rotated {
        /// ID of the key being replaced
        old_key_id: String,
        /// ID of the replacement key
        new_key_id: String,
        /// Algorithm (should match for proper rotation)
        algorithm: String,
        /// Reason for the rotation
        reason: RotationReason,
    },

    /// Key was marked as deprecated.
    ///
    /// Logged when a key is scheduled for retirement but
    /// may still be used for decryption of existing data.
    Deprecated {
        /// ID of the deprecated key
        key_id: String,
        /// When the deprecation takes effect
        deprecation_date: DateTime<Utc>,
        /// Human-readable reason for deprecation
        reason: String,
    },

    /// Key was suspended (temporarily disabled).
    ///
    /// Logged when a key is temporarily disabled, typically
    /// due to a suspected security incident.
    Suspended {
        /// ID of the suspended key
        key_id: String,
        /// Reason for suspension
        reason: String,
    },

    /// Key was destroyed/zeroized.
    ///
    /// Logged when key material is permanently destroyed.
    /// This is a critical audit event.
    Destroyed {
        /// ID of the destroyed key
        key_id: String,
        /// Method used for destruction
        method: DestructionMethod,
    },

    /// Key was accessed for an operation.
    ///
    /// Logged when a key is used for a cryptographic operation.
    /// This may be logged at DEBUG level to avoid log volume issues.
    Accessed {
        /// ID of the accessed key
        key_id: String,
        /// Type of operation (e.g., "encrypt", "sign", "decrypt")
        operation: String,
        /// Optional accessor identity (user, service, etc.)
        accessor: Option<String>,
    },

    /// Key was exported (if allowed by policy).
    ///
    /// Logged when a key is exported from the system.
    /// This is a security-sensitive event.
    Exported {
        /// ID of the exported key
        key_id: String,
        /// Export format (e.g., "PEM", "PKCS#12", "raw")
        format: String,
        /// Destination identifier
        destination: String,
    },

    /// Key was imported into the system.
    ///
    /// Logged when external key material is imported.
    Imported {
        /// ID assigned to the imported key
        key_id: String,
        /// Algorithm of the imported key
        algorithm: String,
        /// Source of the key material
        source: String,
    },
}

impl KeyLifecycleEvent {
    /// Get the key ID associated with this event.
    #[must_use]
    pub fn key_id(&self) -> &str {
        match self {
            KeyLifecycleEvent::Generated { key_id, .. }
            | KeyLifecycleEvent::Deprecated { key_id, .. }
            | KeyLifecycleEvent::Suspended { key_id, .. }
            | KeyLifecycleEvent::Destroyed { key_id, .. }
            | KeyLifecycleEvent::Accessed { key_id, .. }
            | KeyLifecycleEvent::Exported { key_id, .. }
            | KeyLifecycleEvent::Imported { key_id, .. } => key_id,
            KeyLifecycleEvent::Rotated { new_key_id, .. } => new_key_id,
        }
    }

    /// Get the event type as a string for logging.
    #[must_use]
    pub fn event_type(&self) -> &'static str {
        match self {
            KeyLifecycleEvent::Generated { .. } => "generated",
            KeyLifecycleEvent::Rotated { .. } => "rotated",
            KeyLifecycleEvent::Deprecated { .. } => "deprecated",
            KeyLifecycleEvent::Suspended { .. } => "suspended",
            KeyLifecycleEvent::Destroyed { .. } => "destroyed",
            KeyLifecycleEvent::Accessed { .. } => "accessed",
            KeyLifecycleEvent::Exported { .. } => "exported",
            KeyLifecycleEvent::Imported { .. } => "imported",
        }
    }

    /// Create a new Generated event.
    #[must_use]
    pub fn generated(
        key_id: impl Into<String>,
        algorithm: impl Into<String>,
        key_type: KeyType,
        purpose: KeyPurpose,
    ) -> Self {
        Self::Generated { key_id: key_id.into(), algorithm: algorithm.into(), key_type, purpose }
    }

    /// Create a new Rotated event.
    #[must_use]
    pub fn rotated(
        old_key_id: impl Into<String>,
        new_key_id: impl Into<String>,
        algorithm: impl Into<String>,
        reason: RotationReason,
    ) -> Self {
        Self::Rotated {
            old_key_id: old_key_id.into(),
            new_key_id: new_key_id.into(),
            algorithm: algorithm.into(),
            reason,
        }
    }

    /// Create a new Destroyed event.
    #[must_use]
    pub fn destroyed(key_id: impl Into<String>, method: DestructionMethod) -> Self {
        Self::Destroyed { key_id: key_id.into(), method }
    }

    /// Create a new Accessed event.
    #[must_use]
    pub fn accessed(
        key_id: impl Into<String>,
        operation: impl Into<String>,
        accessor: Option<String>,
    ) -> Self {
        Self::Accessed { key_id: key_id.into(), operation: operation.into(), accessor }
    }

    /// Create a new Imported event.
    #[must_use]
    pub fn imported(
        key_id: impl Into<String>,
        algorithm: impl Into<String>,
        source: impl Into<String>,
    ) -> Self {
        Self::Imported { key_id: key_id.into(), algorithm: algorithm.into(), source: source.into() }
    }

    /// Create a new Exported event.
    #[must_use]
    pub fn exported(
        key_id: impl Into<String>,
        format: impl Into<String>,
        destination: impl Into<String>,
    ) -> Self {
        Self::Exported {
            key_id: key_id.into(),
            format: format.into(),
            destination: destination.into(),
        }
    }

    /// Create a new Deprecated event.
    #[must_use]
    pub fn deprecated(
        key_id: impl Into<String>,
        deprecation_date: DateTime<Utc>,
        reason: impl Into<String>,
    ) -> Self {
        Self::Deprecated { key_id: key_id.into(), deprecation_date, reason: reason.into() }
    }

    /// Create a new Suspended event.
    #[must_use]
    pub fn suspended(key_id: impl Into<String>, reason: impl Into<String>) -> Self {
        Self::Suspended { key_id: key_id.into(), reason: reason.into() }
    }
}

// ============================================================================
// Correlation ID Infrastructure
// ============================================================================
//
// Thread-local correlation ID storage for async context propagation.
// The correlation ID is stored per-thread and can be propagated across async
// task boundaries using the `CorrelationGuard` RAII guard or the
// `with_correlation_id` function.
// ============================================================================

thread_local! {
    static CORRELATION_ID: RefCell<Option<String>> = const { RefCell::new(None) };
}

/// Global counter for generating lightweight correlation IDs.
///
/// This counter is used by [`generate_lightweight_correlation_id`] when
/// UUID generation overhead is not acceptable.
static CORRELATION_COUNTER: AtomicU64 = AtomicU64::new(0);

/// Generate a new correlation ID using UUID v4.
///
/// This function generates a cryptographically random UUID v4 string
/// suitable for distributed tracing and audit logging.
///
/// # Returns
///
/// A UUID v4 string in the format `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::generate_correlation_id;
///
/// let id = generate_correlation_id();
/// assert_eq!(id.len(), 36); // UUID format with hyphens
/// ```
#[must_use]
pub fn generate_correlation_id() -> String {
    Uuid::new_v4().to_string()
}

/// Generate a lightweight correlation ID using an atomic counter.
///
/// This function generates a correlation ID based on an atomic counter,
/// which is faster than UUID generation but provides less uniqueness
/// across distributed systems.
///
/// # Returns
///
/// A string in the format `corr-{counter:016x}`.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::generate_lightweight_correlation_id;
///
/// let id1 = generate_lightweight_correlation_id();
/// let id2 = generate_lightweight_correlation_id();
/// assert_ne!(id1, id2);
/// assert!(id1.starts_with("corr-"));
/// ```
#[must_use]
pub fn generate_lightweight_correlation_id() -> String {
    // Relaxed is sufficient: the counter only needs uniqueness, not
    // a happens-before relationship with any other atomic. SeqCst
    // would emit a full memory fence per call on weakly-ordered
    // archs.
    let counter = CORRELATION_COUNTER.fetch_add(1, Ordering::Relaxed);
    format!("corr-{counter:016x}")
}

/// Set the correlation ID for the current thread/task.
///
/// This function stores a correlation ID in thread-local storage,
/// making it available to all logging calls on the current thread.
///
/// # Arguments
///
/// * `id` - The correlation ID to set.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::{set_correlation_id, current_correlation_id};
///
/// set_correlation_id("request-12345");
/// assert_eq!(current_correlation_id(), Some("request-12345".to_string()));
/// ```
pub fn set_correlation_id(id: impl Into<String>) {
    CORRELATION_ID.with(|cell| {
        *cell.borrow_mut() = Some(id.into());
    });
}

/// Get the current correlation ID, if set.
///
/// This function retrieves the correlation ID from thread-local storage.
///
/// # Returns
///
/// `Some(id)` if a correlation ID is set, `None` otherwise.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::{set_correlation_id, current_correlation_id, clear_correlation_id};
///
/// assert_eq!(current_correlation_id(), None);
/// set_correlation_id("test-id".to_string());
/// assert_eq!(current_correlation_id(), Some("test-id".to_string()));
/// clear_correlation_id();
/// assert_eq!(current_correlation_id(), None);
/// ```
#[must_use]
pub fn current_correlation_id() -> Option<String> {
    CORRELATION_ID.with(|cell| cell.borrow().clone())
}

/// Clear the correlation ID for the current thread.
///
/// This function removes the correlation ID from thread-local storage.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::{set_correlation_id, current_correlation_id, clear_correlation_id};
///
/// set_correlation_id("test-id".to_string());
/// clear_correlation_id();
/// assert_eq!(current_correlation_id(), None);
/// ```
pub fn clear_correlation_id() {
    CORRELATION_ID.with(|cell| {
        *cell.borrow_mut() = None;
    });
}

/// Execute a closure with a specific correlation ID.
///
/// This function sets the correlation ID for the duration of the closure
/// execution, then restores the previous correlation ID (if any) afterward.
///
/// # Arguments
///
/// * `id` - The correlation ID to use during the closure execution.
/// * `f` - The closure to execute.
///
/// # Returns
///
/// The return value of the closure.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::{with_correlation_id, current_correlation_id};
///
/// let result = with_correlation_id("request-123".to_string(), || {
///     assert_eq!(current_correlation_id(), Some("request-123".to_string()));
///     42
/// });
/// assert_eq!(result, 42);
/// assert_eq!(current_correlation_id(), None);
/// ```
pub fn with_correlation_id<F, R>(id: String, f: F) -> R
where
    F: FnOnce() -> R,
{
    let old = current_correlation_id();
    set_correlation_id(id);
    let result = f();
    match old {
        Some(prev_id) => set_correlation_id(prev_id),
        None => clear_correlation_id(),
    }
    result
}

/// RAII guard for correlation ID scope management.
///
/// This guard automatically sets a correlation ID when created and restores
/// the previous correlation ID (if any) when dropped. This is useful for
/// propagating correlation IDs across async task boundaries.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::{CorrelationGuard, current_correlation_id};
///
/// {
///     let guard = CorrelationGuard::new();
///     let id = guard.id();
///     assert!(id.is_some());
///     // Correlation ID is automatically set
/// }
/// // Correlation ID is restored to previous value (None in this case)
/// ```
pub struct CorrelationGuard {
    previous: Option<String>,
}

impl CorrelationGuard {
    /// Create a new correlation scope with an automatically generated UUID v4.
    ///
    /// # Returns
    ///
    /// A new `CorrelationGuard` that sets and manages the correlation ID.
    #[must_use]
    pub fn new() -> Self {
        let previous = current_correlation_id();
        set_correlation_id(generate_correlation_id());
        Self { previous }
    }

    /// Create a new correlation scope with a specific ID.
    ///
    /// # Arguments
    ///
    /// * `id` - The correlation ID to use.
    ///
    /// # Returns
    ///
    /// A new `CorrelationGuard` that sets and manages the correlation ID.
    #[must_use]
    pub fn with_id(id: impl Into<String>) -> Self {
        let previous = current_correlation_id();
        set_correlation_id(id);
        Self { previous }
    }

    /// Create a new correlation scope with a lightweight counter-based ID.
    ///
    /// # Returns
    ///
    /// A new `CorrelationGuard` with a lightweight correlation ID.
    #[must_use]
    pub fn lightweight() -> Self {
        let previous = current_correlation_id();
        set_correlation_id(generate_lightweight_correlation_id());
        Self { previous }
    }

    /// Get the current correlation ID.
    ///
    /// # Returns
    ///
    /// The current correlation ID, if set.
    #[must_use]
    pub fn id(&self) -> Option<String> {
        current_correlation_id()
    }

    /// Get the previous correlation ID that will be restored on drop.
    ///
    /// # Returns
    ///
    /// The previous correlation ID, if any.
    #[must_use]
    pub fn previous_id(&self) -> Option<&String> {
        self.previous.as_ref()
    }
}

impl Drop for CorrelationGuard {
    fn drop(&mut self) {
        match &self.previous {
            Some(id) => set_correlation_id(id.clone()),
            None => clear_correlation_id(),
        }
    }
}

impl Default for CorrelationGuard {
    fn default() -> Self {
        Self::new()
    }
}

// ============================================================================
// Metadata Sanitization Constants and Functions
// ============================================================================

/// Keys that indicate potentially sensitive data.
///
/// Any metadata key containing these patterns (case-insensitive) will be redacted
/// to prevent sensitive data leakage in audit logs.
pub const SENSITIVE_KEY_PATTERNS: &[&str] = &[
    "key",
    "secret",
    "password",
    "token",
    "credential",
    "private",
    "auth",
    "session",
    "bearer",
    "api_key",
    "apikey",
    "passphrase",
];

/// Maximum length for metadata values before truncation.
///
/// Values longer than this will be truncated with a length indicator.
pub const MAX_METADATA_VALUE_LENGTH: usize = 1000;

/// Check if a metadata key might contain sensitive data.
///
/// Performs a case-insensitive check against known sensitive key patterns.
///
/// # Arguments
///
/// * `key` - The metadata key to check
///
/// # Returns
///
/// `true` if the key matches any sensitive pattern, `false` otherwise.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::is_potentially_sensitive;
///
/// assert!(is_potentially_sensitive("api_key"));
/// assert!(is_potentially_sensitive("user_password"));
/// assert!(is_potentially_sensitive("AuthToken"));
/// assert!(!is_potentially_sensitive("username"));
/// assert!(!is_potentially_sensitive("operation_id"));
/// ```
#[must_use]
pub fn is_potentially_sensitive(key: &str) -> bool {
    let lower = key.to_lowercase();
    SENSITIVE_KEY_PATTERNS.iter().any(|pattern| lower.contains(pattern))
}

/// Sanitize a single metadata value based on its key.
///
/// This function applies the following rules:
/// 1. If the key is potentially sensitive, the value is replaced with `[REDACTED]`
/// 2. If the value exceeds `MAX_METADATA_VALUE_LENGTH`, it is truncated
/// 3. Otherwise, the value is returned as-is
///
/// # Arguments
///
/// * `key` - The metadata key (used to determine if the value is sensitive)
/// * `value` - The metadata value to sanitize
///
/// # Returns
///
/// A sanitized string safe for logging.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::sanitize_value;
///
/// // Sensitive keys are redacted
/// assert_eq!(sanitize_value("api_key", "sk-12345"), "[REDACTED]");
///
/// // Normal keys pass through
/// assert_eq!(sanitize_value("operation", "encrypt"), "encrypt");
///
/// // Long values are truncated
/// let long_value = "x".repeat(2000);
/// assert!(sanitize_value("data", &long_value).contains("chars truncated"));
/// ```
#[must_use]
pub fn sanitize_value(key: &str, value: &str) -> String {
    if is_potentially_sensitive(key) {
        "[REDACTED]".to_string()
    } else if value.len() > MAX_METADATA_VALUE_LENGTH {
        format!("[{} chars truncated]", value.len())
    } else {
        value.to_string()
    }
}

/// Sanitize byte data for logging.
///
/// Emits exactly `[<N> bytes]` for any input length — no fingerprint, no
/// preview, no per-secret correlation token. An earlier revision included
/// a `sha256_first_16_hex(data)` fingerprint for inputs longer than 32
/// bytes for "correlation across log lines"; that fingerprint is a
/// deterministic, content-dependent function of the secret, so a reader
/// with log access can brute-force candidate secrets against the
/// fingerprint to recover the original. Sister function `sanitize_data`
/// was fixed in the round-4 audit follow-up; this leak survived in
/// `sanitize_bytes` and is closed here.
///
/// # Arguments
///
/// * `data` - The byte data to sanitize
///
/// # Returns
///
/// A safe string representation of the data — length only.
///
/// # Example
///
/// ```rust
/// use latticearc::unified_api::logging::sanitize_bytes;
///
/// assert_eq!(sanitize_bytes(&[1, 2, 3]), "[3 bytes]");
/// assert_eq!(sanitize_bytes(&vec![0u8; 100]), "[100 bytes]");
/// ```
#[must_use]
pub fn sanitize_bytes(data: &[u8]) -> String {
    format!("[{} bytes]", data.len())
}

/// Sanitize an entire metadata map.
///
/// Applies `sanitize_value` to each key-value pair in the metadata map,
/// ensuring all sensitive values are redacted and long values are truncated.
///
/// # Arguments
///
/// * `metadata` - The metadata map to sanitize
///
/// # Returns
///
/// A new map with all values sanitized.
///
/// # Example
///
/// ```rust
/// use std::collections::HashMap;
/// use latticearc::unified_api::logging::sanitize_metadata;
///
/// let mut metadata = HashMap::new();
/// metadata.insert("operation".to_string(), "encrypt".to_string());
/// metadata.insert("api_key".to_string(), "secret-123".to_string());
///
/// let sanitized = sanitize_metadata(&metadata);
/// assert_eq!(sanitized.get("operation"), Some(&"encrypt".to_string()));
/// assert_eq!(sanitized.get("api_key"), Some(&"[REDACTED]".to_string()));
/// ```
#[must_use]
pub fn sanitize_metadata(metadata: &HashMap<String, String>) -> HashMap<String, String> {
    metadata.iter().map(|(k, v)| (k.clone(), sanitize_value(k, v))).collect()
}

/// Initialize tracing with security-conscious defaults.
///
/// **Gated behind the `tracing-init` Cargo feature** (off by default).
/// Subscriber wiring is the binary's responsibility; library consumers
/// should set up their own subscriber via the `tracing` ecosystem.
///
/// Sets up structured logging with:
/// - Environment-based filtering (RUST_LOG)
/// - JSON output for production
/// - Sensitive data sanitization
/// - Performance-optimized formatting
///
/// # Errors
///
/// Returns an error if the tracing subscriber cannot be installed —
/// typically because another subscriber is already the global default.
/// The function is safe to call multiple times: subsequent calls
/// observe the first installation and return its result, so concurrent
/// callers cannot panic via double-init.
#[cfg(feature = "tracing-init")]
pub fn init_tracing() -> Result<(), Box<dyn std::error::Error>> {
    use std::sync::OnceLock;
    static INIT_RESULT: OnceLock<Result<(), String>> = OnceLock::new();

    let result = INIT_RESULT.get_or_init(|| {
        let filter =
            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("latticearc=info"));

        let subscriber = tracing_subscriber::registry().with(filter).with(
            tracing_subscriber::fmt::layer()
                // Route to stderr (not stdout — the default) so CLI tools
                // that emit machine-parseable output on stdout don't get
                // tracing events interleaved with their data.
                .with_writer(std::io::stderr)
                .with_target(false)
                .with_thread_ids(false)
                .with_thread_names(false)
                .compact(),
        );

        // `try_init` returns a `Result` instead of panicking when the
        // global default is already set, so concurrent calls into this
        // OnceLock cannot blow up the process.
        match subscriber.try_init() {
            Ok(()) => {
                info!("LatticeArc logging initialized");
                Ok(())
            }
            Err(e) => Err(e.to_string()),
        }
    });

    match result {
        Ok(()) => Ok(()),
        Err(msg) => Err(msg.clone().into()),
    }
}

/// Sanitize data to prevent logging of sensitive information.
///
/// Wraps a byte slice in a `Display` adapter that emits the byte length
/// only — never any function of the byte contents. Used automatically by
/// the logging macros.
#[must_use]
pub fn sanitize_data(data: &[u8]) -> SanitizedData<'_> {
    SanitizedData(data)
}

/// Wrapper type for sanitized data display.
///
/// The `Display` impl emits exactly `[<N> bytes]` — no hash, no truncated
/// preview, no per-secret fingerprint. An earlier revision emitted a
/// truncated BLAKE2s digest for inputs longer than 32 bytes; that was a
/// deterministic, content-dependent fingerprint of the secret, which an
/// attacker with log access can brute-force against candidate inputs to
/// recover the original. The deterministic-fingerprint branch was removed
/// in the 0.8.x audit follow-up so the safe-logging path is purely
/// length-based regardless of input size.
pub struct SanitizedData<'a>(&'a [u8]);

impl<'a> fmt::Display for SanitizedData<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[{} bytes]", self.0.len())
    }
}

/// Security-conscious logging macros
///
/// These macros automatically sanitize sensitive data and provide
/// consistent logging across the LatticeArc codebase.
/// Log cryptographic operation start
#[doc(hidden)]
#[macro_export]
macro_rules! log_crypto_start {
    ($operation:expr) => {
        trace!("Starting crypto operation: {}", $operation);
    };
    ($operation:expr, $($field:tt)*) => {
        trace!("Starting crypto operation: {} {}", $operation, format_args!($($field)*));
    };
}

/// Log cryptographic operation completion
#[doc(hidden)]
#[macro_export]
macro_rules! log_crypto_complete {
    ($operation:expr) => {
        trace!("Completed crypto operation: {}", $operation);
    };
    ($operation:expr, $($field:tt)*) => {
        trace!("Completed crypto operation: {} {}", $operation, format_args!($($field)*));
    };
}

/// Log cryptographic operation error
#[doc(hidden)]
#[macro_export]
macro_rules! log_crypto_error {
    ($operation:expr, $error:expr) => {
        error!("Crypto operation failed: {} - {}", $operation, $error);
    };
}

/// Log key generation
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_generation {
    ($algorithm:expr, $key_type:expr) => {
        info!("Generated {} key using {}", $key_type, $algorithm);
    };
}

/// Log encryption operation
#[doc(hidden)]
#[macro_export]
macro_rules! log_encryption {
    ($algorithm:expr, $data_len:expr) => {
        debug!("Encrypted {} bytes using {}", $data_len, $algorithm);
    };
}

/// Log decryption operation
#[doc(hidden)]
#[macro_export]
macro_rules! log_decryption {
    ($algorithm:expr, $data_len:expr) => {
        debug!("Decrypted {} bytes using {}", $data_len, $algorithm);
    };
}

/// Log signature operation
#[doc(hidden)]
#[macro_export]
macro_rules! log_signature {
    ($algorithm:expr) => {
        debug!("Created signature using {}", $algorithm);
    };
}

/// Log verification operation
#[doc(hidden)]
#[macro_export]
macro_rules! log_verification {
    ($algorithm:expr, $result:expr) => {
        debug!(
            "Verification {} using {}",
            if $result { "succeeded" } else { "failed" },
            $algorithm
        );
    };
}

/// Log performance metrics
#[doc(hidden)]
#[macro_export]
macro_rules! log_performance {
    ($operation:expr, $duration:expr) => {
        debug!("Performance: {} took {:?}", $operation, $duration);
    };
}

// ============================================================================
// Key Lifecycle Audit Logging Macros
// ============================================================================

/// Log a key generation event.
///
/// Logs at INFO level when new cryptographic key material is created.
/// This is an auditable event for compliance tracking.
///
/// # Arguments
///
/// * `$key_id` - Unique identifier for the key
/// * `$algorithm` - Algorithm used (e.g., "ML-KEM-768")
/// * `$key_type` - Type of key (use `KeyType` enum)
/// * `$purpose` - Purpose of key (use `KeyPurpose` enum)
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_generated;
/// use latticearc::unified_api::logging::{KeyType, KeyPurpose};
///
/// log_key_generated!("key-001", "ML-KEM-768", KeyType::KeyPair, KeyPurpose::KeyExchange);
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_generated {
    ($key_id:expr, $algorithm:expr, $key_type:expr, $purpose:expr) => {
        tracing::info!(
            target: "key_lifecycle::generated",
            key_id = %$key_id,
            algorithm = %$algorithm,
            key_type = ?$key_type,
            purpose = ?$purpose,
            "Key generated"
        );
    };
}

/// Log a key rotation event.
///
/// Logs at WARN level (notable event requiring attention) when a key
/// is replaced with a new key. This is a critical audit event.
///
/// # Arguments
///
/// * `$old_key_id` - ID of the key being replaced
/// * `$new_key_id` - ID of the replacement key
/// * `$algorithm` - Algorithm (should match)
/// * `$reason` - Reason for rotation (use `RotationReason` enum)
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_rotated;
/// use latticearc::unified_api::logging::RotationReason;
///
/// log_key_rotated!("key-001", "key-002", "ML-KEM-768", RotationReason::Scheduled);
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_rotated {
    ($old_key_id:expr, $new_key_id:expr, $algorithm:expr, $reason:expr) => {
        tracing::warn!(
            target: "key_lifecycle::rotated",
            old_key_id = %$old_key_id,
            new_key_id = %$new_key_id,
            algorithm = %$algorithm,
            reason = ?$reason,
            "Key rotated"
        );
    };
}

/// Log a key destruction event.
///
/// Logs at WARN level (critical audit event) when key material is
/// permanently destroyed. This is required for compliance verification.
///
/// # Arguments
///
/// * `$key_id` - ID of the destroyed key
/// * `$method` - Method used (use `DestructionMethod` enum)
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_destroyed;
/// use latticearc::unified_api::logging::DestructionMethod;
///
/// log_key_destroyed!("key-001", DestructionMethod::Zeroization);
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_destroyed {
    ($key_id:expr, $method:expr) => {
        tracing::warn!(
            target: "key_lifecycle::destroyed",
            key_id = %$key_id,
            method = ?$method,
            "Key destroyed"
        );
    };
}

/// Log a key access event.
///
/// Logs at DEBUG level (high volume, may be rate-limited) when a key
/// is used for a cryptographic operation. Useful for access auditing.
///
/// # Arguments
///
/// * `$key_id` - ID of the accessed key
/// * `$operation` - Type of operation (e.g., "encrypt", "sign")
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_accessed;
///
/// log_key_accessed!("key-001", "encrypt");
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_accessed {
    ($key_id:expr, $operation:expr) => {
        tracing::debug!(
            target: "key_lifecycle::accessed",
            key_id = %$key_id,
            operation = %$operation,
            "Key accessed"
        );
    };
    ($key_id:expr, $operation:expr, $accessor:expr) => {
        tracing::debug!(
            target: "key_lifecycle::accessed",
            key_id = %$key_id,
            operation = %$operation,
            accessor = %$accessor,
            "Key accessed"
        );
    };
}

/// Log a key deprecation event.
///
/// Logs at INFO level when a key is scheduled for retirement.
/// The key may still be used for decryption of existing data.
///
/// # Arguments
///
/// * `$key_id` - ID of the deprecated key
/// * `$reason` - Human-readable reason for deprecation
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_deprecated;
///
/// log_key_deprecated!("key-001", "Scheduled retirement per policy");
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_deprecated {
    ($key_id:expr, $reason:expr) => {
        tracing::info!(
            target: "key_lifecycle::deprecated",
            key_id = %$key_id,
            reason = %$reason,
            "Key deprecated"
        );
    };
}

/// Log a key suspension event.
///
/// Logs at WARN level when a key is temporarily disabled,
/// typically due to a suspected security incident.
///
/// # Arguments
///
/// * `$key_id` - ID of the suspended key
/// * `$reason` - Reason for suspension
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_suspended;
///
/// log_key_suspended!("key-001", "Suspected compromise");
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_suspended {
    ($key_id:expr, $reason:expr) => {
        tracing::warn!(
            target: "key_lifecycle::suspended",
            key_id = %$key_id,
            reason = %$reason,
            "Key suspended"
        );
    };
}

/// Log a key export event.
///
/// Logs at WARN level (security-sensitive) when a key is exported.
/// This is a critical audit event requiring special attention.
///
/// # Arguments
///
/// * `$key_id` - ID of the exported key
/// * `$format` - Export format (e.g., "PEM", "PKCS#12")
/// * `$destination` - Destination identifier
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_exported;
///
/// log_key_exported!("key-001", "PEM", "backup-hsm-01");
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_exported {
    ($key_id:expr, $format:expr, $destination:expr) => {
        tracing::warn!(
            target: "key_lifecycle::exported",
            key_id = %$key_id,
            format = %$format,
            destination = %$destination,
            "Key exported"
        );
    };
}

/// Log a key import event.
///
/// Logs at INFO level when external key material is imported.
/// Important for tracking key provenance.
///
/// # Arguments
///
/// * `$key_id` - ID assigned to the imported key
/// * `$algorithm` - Algorithm of the imported key
/// * `$source` - Source of the key material
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_key_imported;
///
/// log_key_imported!("key-001", "ML-KEM-768", "external-hsm-02");
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_key_imported {
    ($key_id:expr, $algorithm:expr, $source:expr) => {
        tracing::info!(
            target: "key_lifecycle::imported",
            key_id = %$key_id,
            algorithm = %$algorithm,
            source = %$source,
            "Key imported"
        );
    };
}

// ============================================================================
// Correlation-Aware Crypto Logging Macros
// ============================================================================

/// Log a cryptographic operation with automatic correlation ID inclusion.
///
/// This macro automatically includes the current correlation ID (if set)
/// in log events, enabling distributed tracing across async boundaries.
///
/// # Example
///
/// ```rust,no_run
/// use latticearc::log_crypto_operation;
/// use latticearc::unified_api::logging::{op, set_correlation_id, CorrelationGuard};
///
/// // Set a correlation ID
/// let _guard = CorrelationGuard::new();
///
/// // Log includes correlation_id automatically
/// log_crypto_operation!(op::ENCRYPT, algorithm = "AES-256-GCM", data_size = 1024);
/// ```
#[doc(hidden)]
#[macro_export]
macro_rules! log_crypto_operation {
    ($op:expr, $($field:tt)*) => {
        if tracing::enabled!(target: "crypto::operation", tracing::Level::DEBUG) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::debug!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                    $($field)*
                );
            } else {
                tracing::debug!(
                    target: "crypto::operation",
                    operation = $op,
                    $($field)*
                );
            }
        }
    };
    ($op:expr) => {
        if tracing::enabled!(target: "crypto::operation", tracing::Level::DEBUG) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::debug!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                );
            } else {
                tracing::debug!(
                    target: "crypto::operation",
                    operation = $op,
                );
            }
        }
    };
}

/// Log a cryptographic operation start with correlation ID.
///
/// Similar to [`log_crypto_operation`] but at TRACE level for detailed tracing.
#[doc(hidden)]
#[macro_export]
macro_rules! log_crypto_operation_start {
    ($op:expr, $($field:tt)*) => {
        if tracing::enabled!(target: "crypto::operation", tracing::Level::TRACE) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::trace!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                    phase = "start",
                    $($field)*
                );
            } else {
                tracing::trace!(
                    target: "crypto::operation",
                    operation = $op,
                    phase = "start",
                    $($field)*
                );
            }
        }
    };
    ($op:expr) => {
        if tracing::enabled!(target: "crypto::operation", tracing::Level::TRACE) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::trace!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                    phase = "start",
                );
            } else {
                tracing::trace!(
                    target: "crypto::operation",
                    operation = $op,
                    phase = "start",
                );
            }
        }
    };
}

/// Log a cryptographic operation completion with correlation ID.
///
/// Similar to [`log_crypto_operation`] but at TRACE level for detailed tracing.
#[doc(hidden)]
#[macro_export]
macro_rules! log_crypto_operation_complete {
    ($op:expr, $($field:tt)*) => {
        if tracing::enabled!(target: "crypto::operation", tracing::Level::TRACE) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::trace!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                    phase = "complete",
                    $($field)*
                );
            } else {
                tracing::trace!(
                    target: "crypto::operation",
                    operation = $op,
                    phase = "complete",
                    $($field)*
                );
            }
        }
    };
    ($op:expr) => {
        if tracing::enabled!(target: "crypto::operation", tracing::Level::TRACE) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::trace!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                    phase = "complete",
                );
            } else {
                tracing::trace!(
                    target: "crypto::operation",
                    operation = $op,
                    phase = "complete",
                );
            }
        }
    };
}

/// Log a cryptographic operation error with correlation ID.
///
/// Logs at DEBUG level with structured fields (operation, error, phase,
/// correlation_id when present).
///
/// Level rationale: adversary-reachable crypto failures (bad ciphertext,
/// bad signature, bad wire format) are NORMAL under attack. Emitting at
/// `error!` would let an attacker DoS the log aggregator by sending
/// garbage. Operators enable `RUST_LOG=crypto::operation=debug` on demand
/// when investigating a specific correlation ID.
///
/// This mirrors the **rustls** convention (`debug!`/`trace!` on
/// decrypt-failure paths). aws-lc-rs achieves the same intent — opaque
/// external, detailed internal — through the aws-lc C library's
/// `ERR_put_error` thread-local queue; we use `tracing` because that's
/// the Rust-native equivalent mechanism. See `docs/DESIGN_PATTERNS.md`
/// Pattern 6.
#[doc(hidden)]
#[macro_export]
macro_rules! log_crypto_operation_error {
    ($op:expr, $error:expr, $($field:tt)*) => {
        // Fast path: skip TLS read + correlation-id clone when subscribers
        // don't care. `tracing::enabled!` is a single atomic load.
        if tracing::enabled!(target: "crypto::operation", tracing::Level::DEBUG) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::debug!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                    error = %$error,
                    phase = "error",
                    $($field)*
                );
            } else {
                tracing::debug!(
                    target: "crypto::operation",
                    operation = $op,
                    error = %$error,
                    phase = "error",
                    $($field)*
                );
            }
        }
    };
    ($op:expr, $error:expr) => {
        if tracing::enabled!(target: "crypto::operation", tracing::Level::DEBUG) {
            if let Some(corr_id) = $crate::unified_api::logging::current_correlation_id() {
                tracing::debug!(
                    target: "crypto::operation",
                    correlation_id = %corr_id,
                    operation = $op,
                    error = %$error,
                    phase = "error",
                );
            } else {
                tracing::debug!(
                    target: "crypto::operation",
                    operation = $op,
                    error = %$error,
                    phase = "error",
                );
            }
        }
    };
}

// ============================================================================
// Zero Trust Audit Logging Macros
// ============================================================================

/// Log Zero Trust authentication attempt.
///
/// Logs the initiation of a Zero Trust authentication attempt with session ID.
/// Session ID is logged as hex string for audit traceability.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_auth_attempt {
    ($session_id_hex:expr) => {
        tracing::info!(
            target: "zero_trust::auth",
            session_id = %$session_id_hex,
            "Zero Trust authentication attempt initiated"
        );
    };
}

/// Log Zero Trust authentication success.
///
/// Logs successful authentication with session ID and achieved trust level.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_auth_success {
    ($session_id_hex:expr, $trust_level:expr) => {
        tracing::info!(
            target: "zero_trust::auth",
            session_id = %$session_id_hex,
            trust_level = ?$trust_level,
            "Zero Trust authentication succeeded"
        );
    };
}

/// Log Zero Trust authentication failure.
///
/// Logs failed authentication attempts with session ID and reason.
/// Reason should never contain sensitive data.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_auth_failure {
    ($session_id_hex:expr, $reason:expr) => {
        // Adversary-reachable: a remote prober can trigger this branch
        // at line rate; emitting at `error!` (most aggregator default
        // forwarders ship at WARN+) lets a flooder DoS the SIEM. Same
        // rationale as `log_crypto_operation_error!` (Pattern-6 plus
        // observability budget — see that macro's doc comment for the
        // rustls/aws-lc precedent).
        tracing::debug!(
            target: "zero_trust::auth",
            session_id = %$session_id_hex,
            reason = %$reason,
            "Zero Trust authentication failed"
        );
    };
}

/// Log Zero Trust session creation.
///
/// Logs the creation of a new verified session with trust level and expiration.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_session_created {
    ($session_id_hex:expr, $trust_level:expr, $expires_at:expr) => {
        tracing::info!(
            target: "zero_trust::session",
            session_id = %$session_id_hex,
            trust_level = ?$trust_level,
            expires_at = %$expires_at,
            "Zero Trust session created"
        );
    };
}

/// Log Zero Trust session verification success.
///
/// Logs successful session verification for ongoing trust validation.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_session_verified {
    ($session_id_hex:expr) => {
        tracing::info!(
            target: "zero_trust::session",
            session_id = %$session_id_hex,
            "Zero Trust session verified"
        );
    };
}

/// Log Zero Trust session verification failure.
///
/// Logs failed session verification with session ID and reason.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_session_verification_failed {
    ($session_id_hex:expr, $reason:expr) => {
        // Adversary-reachable: see `log_zero_trust_auth_failure!` for
        // the same DoS-amplification rationale. A remote prober can
        // flood verify endpoints; emitting at `error!` would forward
        // every miss to the SIEM under typical WARN+ filters.
        tracing::debug!(
            target: "zero_trust::session",
            session_id = %$session_id_hex,
            reason = %$reason,
            "Zero Trust session verification failed"
        );
    };
}

/// Log Zero Trust session expiration.
///
/// Logs when a session has expired during a validation check.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_session_expired {
    ($session_id_hex:expr) => {
        tracing::warn!(
            target: "zero_trust::session",
            session_id = %$session_id_hex,
            "Zero Trust session expired"
        );
    };
}

/// Log Zero Trust trust level transition.
///
/// Logs trust level changes (upgrades or downgrades) for audit trail.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_trust_level_changed {
    ($session_id_hex:expr, $from_level:expr, $to_level:expr) => {
        tracing::info!(
            target: "zero_trust::trust",
            session_id = %$session_id_hex,
            from_level = ?$from_level,
            to_level = ?$to_level,
            "Zero Trust trust level changed"
        );
    };
}

/// Log SecurityMode::Unverified usage (warning).
///
/// Logs when an operation is performed in Unverified mode.
/// This is a security-relevant event that should trigger audit review.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_unverified_mode {
    ($operation:expr) => {
        tracing::warn!(
            target: "zero_trust::security",
            operation = %$operation,
            "Operation performed in SecurityMode::Unverified - no session verification"
        );
    };
}

/// Log Zero Trust challenge generation.
///
/// Logs challenge generation for authentication flows.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_challenge_generated {
    ($complexity:expr) => {
        tracing::debug!(
            target: "zero_trust::auth",
            complexity = ?$complexity,
            "Zero Trust challenge generated"
        );
    };
}

/// Log Zero Trust proof verification result.
///
/// Logs the outcome of proof verification attempts.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_proof_verified {
    ($result:expr) => {
        if $result {
            tracing::debug!(
                target: "zero_trust::auth",
                "Zero Trust proof verification succeeded"
            );
        } else {
            tracing::warn!(
                target: "zero_trust::auth",
                "Zero Trust proof verification failed"
            );
        }
    };
}

/// Log Zero Trust access control decision.
///
/// Logs access control decisions for audit trail compliance.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_access_decision {
    ($session_id_hex:expr, $allowed:expr, $reason:expr) => {
        if $allowed {
            tracing::info!(
                target: "zero_trust::access",
                session_id = %$session_id_hex,
                allowed = $allowed,
                reason = %$reason,
                "Zero Trust access granted"
            );
        } else {
            tracing::warn!(
                target: "zero_trust::access",
                session_id = %$session_id_hex,
                allowed = $allowed,
                reason = %$reason,
                "Zero Trust access denied"
            );
        }
    };
}

/// Log Zero Trust session revocation.
///
/// Logs when a session is explicitly revoked.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_session_revoked {
    ($session_id_hex:expr) => {
        tracing::info!(
            target: "zero_trust::session",
            session_id = %$session_id_hex,
            "Zero Trust session revoked"
        );
    };
}

/// Log Zero Trust continuous verification status.
///
/// Logs periodic verification status updates.
#[doc(hidden)]
#[macro_export]
macro_rules! log_zero_trust_continuous_verification {
    ($session_id_hex:expr, $status:expr) => {
        tracing::debug!(
            target: "zero_trust::session",
            session_id = %$session_id_hex,
            status = ?$status,
            "Zero Trust continuous verification status"
        );
    };
}

// ============================================================================
// Zero Trust Logging Utility Functions
// ============================================================================

/// Initialize tracing with file output for persistent logging.
///
/// **Gated behind the `tracing-init` Cargo feature** (off by default).
/// See [`init_tracing`] for rationale; the same library-vs-binary
/// boundary applies to the file-output variant.
///
/// # Errors
///
/// Returns an error if:
/// - The tracing subscriber cannot be initialized
/// - The log file cannot be created or written to
#[cfg(feature = "tracing-init")]
pub fn init_tracing_with_file(log_file: &str) -> Result<(), Box<dyn std::error::Error>> {
    use tracing_appender::rolling::{RollingFileAppender, Rotation};

    let file_appender = RollingFileAppender::new(Rotation::DAILY, "logs", log_file);

    let filter =
        EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("latticearc=info"));

    let subscriber = tracing_subscriber::registry()
        .with(filter)
        .with(tracing_subscriber::fmt::layer().with_target(false).with_writer(file_appender));

    subscriber.init();

    info!("LatticeArc logging to file initialized: {}", log_file);
    Ok(())
}

#[cfg(test)]
#[expect(
    clippy::panic,
    clippy::unnecessary_map_or,
    clippy::option_as_ref_deref,
    reason = "test/bench scaffolding: lints suppressed for this module"
)]
mod tests {
    use super::*;

    #[test]
    fn test_sanitize_data_small_has_correct_format() {
        let data = b"short";
        let sanitized = sanitize_data(data);
        assert_eq!(format!("{sanitized}"), "[5 bytes]");
    }

    #[test]
    fn test_sanitize_data_large_emits_length_only() {
        // Large inputs (previously hashed for a "fingerprint") must now emit
        // length only — no content-dependent output. Two different secrets of
        // the same length must render identically so log access never reveals
        // a brute-forceable per-secret fingerprint.
        let data_a = vec![0u8; 100];
        let data_b = vec![0xFFu8; 100];
        let out_a = format!("{}", sanitize_data(&data_a));
        let out_b = format!("{}", sanitize_data(&data_b));
        assert_eq!(out_a, "[100 bytes]");
        assert_eq!(out_b, "[100 bytes]");
        assert_eq!(out_a, out_b);
    }

    // ========================================================================
    // Metadata Sanitization Tests
    // ========================================================================

    #[test]
    fn test_is_potentially_sensitive_matches_sensitive_keys_succeeds() {
        // Direct matches
        assert!(is_potentially_sensitive("key"));
        assert!(is_potentially_sensitive("secret"));
        assert!(is_potentially_sensitive("password"));
        assert!(is_potentially_sensitive("token"));
        assert!(is_potentially_sensitive("credential"));
        assert!(is_potentially_sensitive("private"));
        assert!(is_potentially_sensitive("auth"));
        assert!(is_potentially_sensitive("session"));
        assert!(is_potentially_sensitive("bearer"));
        assert!(is_potentially_sensitive("api_key"));
        assert!(is_potentially_sensitive("apikey"));
        assert!(is_potentially_sensitive("passphrase"));
    }

    #[test]
    fn test_is_potentially_sensitive_matches_compound_keys_succeeds() {
        // Compound keys containing sensitive patterns
        assert!(is_potentially_sensitive("user_password"));
        assert!(is_potentially_sensitive("api_key_header"));
        assert!(is_potentially_sensitive("auth_token"));
        assert!(is_potentially_sensitive("private_key_pem"));
        assert!(is_potentially_sensitive("session_id"));
        assert!(is_potentially_sensitive("bearer_token"));
        assert!(is_potentially_sensitive("encryption_key"));
        assert!(is_potentially_sensitive("secret_value"));
        assert!(is_potentially_sensitive("credential_store"));
    }

    #[test]
    fn test_is_potentially_sensitive_case_insensitive_succeeds() {
        // Case insensitive matching
        assert!(is_potentially_sensitive("API_KEY"));
        assert!(is_potentially_sensitive("Password"));
        assert!(is_potentially_sensitive("SECRET"));
        assert!(is_potentially_sensitive("AuthToken"));
        assert!(is_potentially_sensitive("BEARER_TOKEN"));
        assert!(is_potentially_sensitive("PrivateKey"));
    }

    #[test]
    fn test_is_potentially_sensitive_non_sensitive_keys_returns_false_succeeds() {
        // Keys that should NOT be flagged
        assert!(!is_potentially_sensitive("username"));
        assert!(!is_potentially_sensitive("operation"));
        assert!(!is_potentially_sensitive("timestamp"));
        assert!(!is_potentially_sensitive("request_id"));
        assert!(!is_potentially_sensitive("user_id"));
        assert!(!is_potentially_sensitive("algorithm"));
        assert!(!is_potentially_sensitive("data_size"));
        assert!(!is_potentially_sensitive("operation_type"));
        assert!(!is_potentially_sensitive("status"));
        assert!(!is_potentially_sensitive("result"));
    }

    #[test]
    fn test_sanitize_value_redacts_sensitive_keys_succeeds() {
        assert_eq!(sanitize_value("api_key", "sk-12345abcdef"), "[REDACTED]");
        assert_eq!(sanitize_value("password", "super_secret_123"), "[REDACTED]");
        assert_eq!(sanitize_value("auth_token", "Bearer xyz"), "[REDACTED]");
        assert_eq!(sanitize_value("private_key", "-----BEGIN PRIVATE KEY-----"), "[REDACTED]");
    }

    #[test]
    fn test_sanitize_value_passes_normal_values_unchanged_succeeds() {
        assert_eq!(sanitize_value("operation", "encrypt"), "encrypt");
        assert_eq!(sanitize_value("algorithm", "ML-KEM-768"), "ML-KEM-768");
        assert_eq!(sanitize_value("user_id", "user123"), "user123");
        assert_eq!(sanitize_value("status", "success"), "success");
    }

    #[test]
    fn test_sanitize_value_truncates_long_values_succeeds() {
        let long_value = "x".repeat(2000);
        let result = sanitize_value("data", &long_value);
        assert_eq!(result, "[2000 chars truncated]");

        // Exactly at limit should pass through
        let exact_value = "x".repeat(MAX_METADATA_VALUE_LENGTH);
        let result = sanitize_value("data", &exact_value);
        assert_eq!(result, exact_value);

        // One over limit should truncate
        let over_value = "x".repeat(MAX_METADATA_VALUE_LENGTH + 1);
        let result = sanitize_value("data", &over_value);
        assert!(result.contains("chars truncated"));
    }

    #[test]
    fn test_sanitize_value_sensitive_key_takes_precedence_succeeds() {
        // Even long sensitive values are just redacted, not truncated
        let long_secret = "x".repeat(5000);
        let result = sanitize_value("api_key", &long_secret);
        assert_eq!(result, "[REDACTED]");
    }

    #[test]
    fn test_sanitize_bytes_small_data_succeeds() {
        assert_eq!(sanitize_bytes(&[]), "[0 bytes]");
        assert_eq!(sanitize_bytes(&[1]), "[1 bytes]");
        assert_eq!(sanitize_bytes(&[1, 2, 3]), "[3 bytes]");
        assert_eq!(sanitize_bytes(&[0u8; 32]), "[32 bytes]");
    }

    #[test]
    fn test_sanitize_bytes_large_data_emits_length_only() {
        // Inputs larger than 32 bytes previously got a SHA-256-derived
        // fingerprint appended for "correlation"; that was a brute-force
        // oracle on the secret content. The output is now length-only for
        // any length — verify by checking two distinct inputs of the same
        // length render identically.
        let data_a = vec![0u8; 100];
        let data_b = vec![0xFFu8; 100];
        let out_a = sanitize_bytes(&data_a);
        let out_b = sanitize_bytes(&data_b);
        assert_eq!(out_a, "[100 bytes]");
        assert_eq!(out_b, "[100 bytes]");
        assert_eq!(out_a, out_b);
    }

    #[test]
    fn test_sanitize_metadata_full_map_succeeds() {
        let mut metadata = HashMap::new();
        metadata.insert("operation".to_string(), "encrypt".to_string());
        metadata.insert("api_key".to_string(), "sk-secret-123".to_string());
        metadata.insert("user_id".to_string(), "user_456".to_string());
        metadata.insert("password_hash".to_string(), "hashed_value".to_string());
        metadata.insert("algorithm".to_string(), "ML-KEM-768".to_string());

        let sanitized = sanitize_metadata(&metadata);

        // Non-sensitive keys pass through
        assert_eq!(sanitized.get("operation"), Some(&"encrypt".to_string()));
        assert_eq!(sanitized.get("user_id"), Some(&"user_456".to_string()));
        assert_eq!(sanitized.get("algorithm"), Some(&"ML-KEM-768".to_string()));

        // Sensitive keys are redacted
        assert_eq!(sanitized.get("api_key"), Some(&"[REDACTED]".to_string()));
        assert_eq!(sanitized.get("password_hash"), Some(&"[REDACTED]".to_string()));
    }

    #[test]
    fn test_sanitize_metadata_empty_map_succeeds() {
        let metadata = HashMap::new();
        let sanitized = sanitize_metadata(&metadata);
        assert!(sanitized.is_empty());
    }

    #[test]
    fn test_sanitize_metadata_preserves_all_keys_succeeds() {
        let mut metadata = HashMap::new();
        metadata.insert("key1".to_string(), "value1".to_string());
        metadata.insert("key2".to_string(), "value2".to_string());
        metadata.insert("secret".to_string(), "hidden".to_string());

        let sanitized = sanitize_metadata(&metadata);

        // All keys should still be present
        assert_eq!(sanitized.len(), 3);
        assert!(sanitized.contains_key("key1"));
        assert!(sanitized.contains_key("key2"));
        assert!(sanitized.contains_key("secret"));
    }

    #[test]
    fn test_sanitize_metadata_with_long_values_succeeds() {
        let mut metadata = HashMap::new();
        let long_value = "x".repeat(2000);
        metadata.insert("description".to_string(), long_value);
        metadata.insert("short".to_string(), "brief".to_string());

        let sanitized = sanitize_metadata(&metadata);

        assert!(sanitized.get("description").map_or(false, |v| v.contains("chars truncated")));
        assert_eq!(sanitized.get("short"), Some(&"brief".to_string()));
    }

    // (Test for `session_id_to_hex` removed alongside the wrapper —
    // `hex::encode` is well-tested in the `hex` crate; we don't gain
    // anything by re-pinning its behavior here.)

    // ========================================================================
    // Correlation ID Tests
    // ========================================================================

    #[test]
    fn test_generate_correlation_id_is_valid_uuid_succeeds() {
        let id = generate_correlation_id();
        // UUID v4 format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (36 chars with hyphens)
        assert_eq!(id.len(), 36);
        assert_eq!(id.chars().filter(|c| *c == '-').count(), 4);
        // Verify it parses as a valid UUID
        assert!(Uuid::parse_str(&id).is_ok());
    }

    #[test]
    fn test_generate_correlation_id_is_unique_succeeds() {
        let id1 = generate_correlation_id();
        let id2 = generate_correlation_id();
        assert_ne!(id1, id2);
    }

    #[test]
    fn test_generate_lightweight_correlation_id_has_correct_format() {
        let id = generate_lightweight_correlation_id();
        assert!(id.starts_with("corr-"));
        // corr- (5 chars) + 16 hex chars = 21 chars total
        assert_eq!(id.len(), 21);
        // Verify the hex part is valid
        let hex_part = &id[5..];
        assert!(hex_part.chars().all(|c| c.is_ascii_hexdigit()));
    }

    #[test]
    fn test_generate_lightweight_correlation_id_increments_succeeds() {
        let id1 = generate_lightweight_correlation_id();
        let id2 = generate_lightweight_correlation_id();
        assert_ne!(id1, id2);
        // Extract counter values and verify they're sequential
        let counter1 = u64::from_str_radix(&id1[5..], 16);
        let counter2 = u64::from_str_radix(&id2[5..], 16);
        assert!(counter1.is_ok());
        assert!(counter2.is_ok());
    }

    #[test]
    fn test_set_and_get_correlation_id_succeeds() {
        // Clear any existing correlation ID
        clear_correlation_id();
        assert_eq!(current_correlation_id(), None);

        // Set a correlation ID
        set_correlation_id("test-correlation-123".to_string());
        assert_eq!(current_correlation_id(), Some("test-correlation-123".to_string()));

        // Clean up
        clear_correlation_id();
        assert_eq!(current_correlation_id(), None);
    }

    #[test]
    fn test_clear_correlation_id_succeeds() {
        set_correlation_id("to-be-cleared".to_string());
        assert!(current_correlation_id().is_some());

        clear_correlation_id();
        assert_eq!(current_correlation_id(), None);
    }

    #[test]
    fn test_with_correlation_id_executes_closure_succeeds() {
        clear_correlation_id();

        let result = with_correlation_id("request-456".to_string(), || {
            assert_eq!(current_correlation_id(), Some("request-456".to_string()));
            42
        });

        assert_eq!(result, 42);
        // After closure, correlation ID should be cleared (was None before)
        assert_eq!(current_correlation_id(), None);
    }

    #[test]
    fn test_with_correlation_id_restores_previous_succeeds() {
        clear_correlation_id();
        set_correlation_id("outer-id".to_string());

        with_correlation_id("inner-id".to_string(), || {
            assert_eq!(current_correlation_id(), Some("inner-id".to_string()));
        });

        // Should restore the outer ID
        assert_eq!(current_correlation_id(), Some("outer-id".to_string()));

        // Clean up
        clear_correlation_id();
    }

    #[test]
    fn test_correlation_guard_new_sets_uuid_succeeds() {
        clear_correlation_id();

        {
            let guard = CorrelationGuard::new();
            let id = guard.id();
            assert!(id.is_some());
            let id_str = id.as_ref().map(String::as_str);
            // Should be a valid UUID
            assert!(id_str.map_or(false, |s| Uuid::parse_str(s).is_ok()));
        }

        // After guard drops, should be cleared
        assert_eq!(current_correlation_id(), None);
    }

    #[test]
    fn test_correlation_guard_with_id_succeeds() {
        clear_correlation_id();

        {
            let guard = CorrelationGuard::with_id("custom-id-789".to_string());
            assert_eq!(guard.id(), Some("custom-id-789".to_string()));
            assert_eq!(current_correlation_id(), Some("custom-id-789".to_string()));
        }

        // After guard drops, should be cleared
        assert_eq!(current_correlation_id(), None);
    }

    #[test]
    fn test_correlation_guard_lightweight_succeeds() {
        clear_correlation_id();

        {
            let guard = CorrelationGuard::lightweight();
            let id = guard.id();
            assert!(id.is_some());
            assert!(id.as_ref().map_or(false, |s| s.starts_with("corr-")));
        }

        // After guard drops, should be cleared
        assert_eq!(current_correlation_id(), None);
    }

    #[test]
    fn test_correlation_guard_restores_previous_on_drop_succeeds() {
        clear_correlation_id();
        set_correlation_id("original-id".to_string());

        {
            let guard = CorrelationGuard::with_id("temporary-id".to_string());
            assert_eq!(guard.previous_id(), Some(&"original-id".to_string()));
            assert_eq!(current_correlation_id(), Some("temporary-id".to_string()));
        }

        // Should restore original ID after guard drops
        assert_eq!(current_correlation_id(), Some("original-id".to_string()));

        // Clean up
        clear_correlation_id();
    }

    #[test]
    fn test_correlation_guard_nested_succeeds() {
        clear_correlation_id();

        {
            let guard1 = CorrelationGuard::with_id("level-1".to_string());
            assert_eq!(current_correlation_id(), Some("level-1".to_string()));

            {
                let guard2 = CorrelationGuard::with_id("level-2".to_string());
                assert_eq!(current_correlation_id(), Some("level-2".to_string()));
                assert_eq!(guard2.previous_id(), Some(&"level-1".to_string()));
            }

            // After inner guard drops, should restore level-1
            assert_eq!(current_correlation_id(), Some("level-1".to_string()));
            assert_eq!(guard1.previous_id(), None);
        }

        // After outer guard drops, should be cleared
        assert_eq!(current_correlation_id(), None);
    }

    #[test]
    fn test_correlation_guard_default_succeeds() {
        clear_correlation_id();

        {
            let guard = CorrelationGuard::default();
            let id = guard.id();
            assert!(id.is_some());
            // Default should create a UUID
            assert!(id.as_ref().map_or(false, |s| Uuid::parse_str(s).is_ok()));
        }

        assert_eq!(current_correlation_id(), None);
    }

    // ========================================================================
    // Key Lifecycle Event Tests
    // ========================================================================

    #[test]
    fn test_key_type_display_has_correct_format() {
        assert_eq!(KeyType::Symmetric.to_string(), "Symmetric");
        assert_eq!(KeyType::AsymmetricPublic.to_string(), "AsymmetricPublic");
        assert_eq!(KeyType::AsymmetricPrivate.to_string(), "AsymmetricPrivate");
        assert_eq!(KeyType::KeyPair.to_string(), "KeyPair");
    }

    #[test]
    fn test_key_purpose_display_has_correct_format() {
        assert_eq!(KeyPurpose::Encryption.to_string(), "Encryption");
        assert_eq!(KeyPurpose::Signing.to_string(), "Signing");
        assert_eq!(KeyPurpose::KeyExchange.to_string(), "KeyExchange");
        assert_eq!(KeyPurpose::Authentication.to_string(), "Authentication");
        assert_eq!(KeyPurpose::KeyWrapping.to_string(), "KeyWrapping");
    }

    #[test]
    fn test_rotation_reason_display_has_correct_format() {
        assert_eq!(RotationReason::Scheduled.to_string(), "Scheduled");
        assert_eq!(RotationReason::Compromised.to_string(), "Compromised");
        assert_eq!(RotationReason::PolicyChange.to_string(), "PolicyChange");
        assert_eq!(RotationReason::Expiration.to_string(), "Expiration");
        assert_eq!(RotationReason::Manual.to_string(), "Manual");
    }

    #[test]
    fn test_destruction_method_display_has_correct_format() {
        assert_eq!(DestructionMethod::Zeroization.to_string(), "Zeroization");
        assert_eq!(DestructionMethod::CryptoErase.to_string(), "CryptoErase");
        assert_eq!(DestructionMethod::Manual.to_string(), "Manual");
    }

    #[test]
    fn test_key_lifecycle_event_generated_has_correct_format() {
        let event = KeyLifecycleEvent::generated(
            "key-001",
            "ML-KEM-768",
            KeyType::KeyPair,
            KeyPurpose::KeyExchange,
        );

        assert_eq!(event.key_id(), "key-001");
        assert_eq!(event.event_type(), "generated");

        // Verify internal structure
        match event {
            KeyLifecycleEvent::Generated { key_id, algorithm, key_type, purpose } => {
                assert_eq!(key_id, "key-001");
                assert_eq!(algorithm, "ML-KEM-768");
                assert_eq!(key_type, KeyType::KeyPair);
                assert_eq!(purpose, KeyPurpose::KeyExchange);
            }
            _ => panic!("Expected Generated event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_rotated_has_correct_format() {
        let event = KeyLifecycleEvent::rotated(
            "old-key-001",
            "new-key-002",
            "ML-KEM-768",
            RotationReason::Scheduled,
        );

        assert_eq!(event.key_id(), "new-key-002");
        assert_eq!(event.event_type(), "rotated");

        match event {
            KeyLifecycleEvent::Rotated { old_key_id, new_key_id, algorithm, reason } => {
                assert_eq!(old_key_id, "old-key-001");
                assert_eq!(new_key_id, "new-key-002");
                assert_eq!(algorithm, "ML-KEM-768");
                assert_eq!(reason, RotationReason::Scheduled);
            }
            _ => panic!("Expected Rotated event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_destroyed_has_correct_format() {
        let event = KeyLifecycleEvent::destroyed("key-001", DestructionMethod::Zeroization);

        assert_eq!(event.key_id(), "key-001");
        assert_eq!(event.event_type(), "destroyed");

        match event {
            KeyLifecycleEvent::Destroyed { key_id, method } => {
                assert_eq!(key_id, "key-001");
                assert_eq!(method, DestructionMethod::Zeroization);
            }
            _ => panic!("Expected Destroyed event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_accessed_has_correct_format() {
        // Without accessor
        let event = KeyLifecycleEvent::accessed("key-001", "encrypt", None);
        assert_eq!(event.key_id(), "key-001");
        assert_eq!(event.event_type(), "accessed");

        // With accessor
        let event_with_accessor =
            KeyLifecycleEvent::accessed("key-002", "sign", Some("user-123".to_string()));
        match event_with_accessor {
            KeyLifecycleEvent::Accessed { key_id, operation, accessor } => {
                assert_eq!(key_id, "key-002");
                assert_eq!(operation, "sign");
                assert_eq!(accessor, Some("user-123".to_string()));
            }
            _ => panic!("Expected Accessed event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_imported_has_correct_format() {
        let event = KeyLifecycleEvent::imported("key-001", "ML-KEM-768", "external-hsm");

        assert_eq!(event.key_id(), "key-001");
        assert_eq!(event.event_type(), "imported");

        match event {
            KeyLifecycleEvent::Imported { key_id, algorithm, source } => {
                assert_eq!(key_id, "key-001");
                assert_eq!(algorithm, "ML-KEM-768");
                assert_eq!(source, "external-hsm");
            }
            _ => panic!("Expected Imported event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_exported_has_correct_format() {
        let event = KeyLifecycleEvent::exported("key-001", "PEM", "backup-server");

        assert_eq!(event.key_id(), "key-001");
        assert_eq!(event.event_type(), "exported");

        match event {
            KeyLifecycleEvent::Exported { key_id, format, destination } => {
                assert_eq!(key_id, "key-001");
                assert_eq!(format, "PEM");
                assert_eq!(destination, "backup-server");
            }
            _ => panic!("Expected Exported event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_deprecated_has_correct_format() {
        let deprecation_date = Utc::now();
        let event = KeyLifecycleEvent::deprecated("key-001", deprecation_date, "End of life");

        assert_eq!(event.key_id(), "key-001");
        assert_eq!(event.event_type(), "deprecated");

        match event {
            KeyLifecycleEvent::Deprecated { key_id, deprecation_date: date, reason } => {
                assert_eq!(key_id, "key-001");
                assert_eq!(date, deprecation_date);
                assert_eq!(reason, "End of life");
            }
            _ => panic!("Expected Deprecated event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_suspended_has_correct_format() {
        let event = KeyLifecycleEvent::suspended("key-001", "Suspected compromise");

        assert_eq!(event.key_id(), "key-001");
        assert_eq!(event.event_type(), "suspended");

        match event {
            KeyLifecycleEvent::Suspended { key_id, reason } => {
                assert_eq!(key_id, "key-001");
                assert_eq!(reason, "Suspected compromise");
            }
            _ => panic!("Expected Suspended event"),
        }
    }

    #[test]
    fn test_key_lifecycle_event_serializes_correctly_succeeds() {
        let event = KeyLifecycleEvent::generated(
            "key-001",
            "ML-KEM-768",
            KeyType::KeyPair,
            KeyPurpose::KeyExchange,
        );

        // Test JSON serialization
        let json = serde_json::to_string(&event);
        assert!(json.is_ok());

        let json_str = json.as_ref().map(String::as_str);
        assert!(json_str.map_or(false, |s| s.contains("key-001")));
        assert!(json_str.map_or(false, |s| s.contains("ML-KEM-768")));
        assert!(json_str.map_or(false, |s| s.contains("KeyPair")));
        assert!(json_str.map_or(false, |s| s.contains("KeyExchange")));

        // Test deserialization
        let deserialized: Result<KeyLifecycleEvent, _> =
            serde_json::from_str(json.as_ref().map_or("", String::as_str));
        assert!(deserialized.is_ok());

        if let Ok(KeyLifecycleEvent::Generated { key_id, algorithm, key_type, purpose }) =
            deserialized
        {
            assert_eq!(key_id, "key-001");
            assert_eq!(algorithm, "ML-KEM-768");
            assert_eq!(key_type, KeyType::KeyPair);
            assert_eq!(purpose, KeyPurpose::KeyExchange);
        } else {
            panic!("Failed to deserialize Generated event");
        }
    }

    #[test]
    fn test_key_type_serializes_correctly_succeeds() {
        for key_type in [
            KeyType::Symmetric,
            KeyType::AsymmetricPublic,
            KeyType::AsymmetricPrivate,
            KeyType::KeyPair,
        ] {
            let json = serde_json::to_string(&key_type);
            assert!(json.is_ok());
            let deserialized: Result<KeyType, _> =
                serde_json::from_str(json.as_ref().map_or("", String::as_str));
            assert!(deserialized.is_ok());
            assert_eq!(
                deserialized.unwrap_or_else(|_| panic!("Failed to deserialize {:?}", key_type)),
                key_type
            );
        }
    }

    #[test]
    fn test_key_purpose_serializes_correctly_succeeds() {
        for purpose in [
            KeyPurpose::Encryption,
            KeyPurpose::Signing,
            KeyPurpose::KeyExchange,
            KeyPurpose::Authentication,
            KeyPurpose::KeyWrapping,
        ] {
            let json = serde_json::to_string(&purpose);
            assert!(json.is_ok());
            let deserialized: Result<KeyPurpose, _> =
                serde_json::from_str(json.as_ref().map_or("", String::as_str));
            assert!(deserialized.is_ok());
            assert_eq!(
                deserialized.unwrap_or_else(|_| panic!("Failed to deserialize {:?}", purpose)),
                purpose
            );
        }
    }

    #[test]
    fn test_rotation_reason_serializes_correctly_succeeds() {
        for reason in [
            RotationReason::Scheduled,
            RotationReason::Compromised,
            RotationReason::PolicyChange,
            RotationReason::Expiration,
            RotationReason::Manual,
        ] {
            let json = serde_json::to_string(&reason);
            assert!(json.is_ok());
            let deserialized: Result<RotationReason, _> =
                serde_json::from_str(json.as_ref().map_or("", String::as_str));
            assert!(deserialized.is_ok());
            assert_eq!(
                deserialized.unwrap_or_else(|_| panic!("Failed to deserialize {:?}", reason)),
                reason
            );
        }
    }

    #[test]
    fn test_destruction_method_serializes_correctly_succeeds() {
        for method in [
            DestructionMethod::Zeroization,
            DestructionMethod::CryptoErase,
            DestructionMethod::Manual,
        ] {
            let json = serde_json::to_string(&method);
            assert!(json.is_ok());
            let deserialized: Result<DestructionMethod, _> =
                serde_json::from_str(json.as_ref().map_or("", String::as_str));
            assert!(deserialized.is_ok());
            assert_eq!(
                deserialized.unwrap_or_else(|_| panic!("Failed to deserialize {:?}", method)),
                method
            );
        }
    }
}
