//! Random nonce for challenge uniqueness.

/// A random nonce for challenge uniqueness.
///
/// 128 bits provides sufficient collision resistance for replay protection
/// within a ~5 minute window, especially when combined with timestamps.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[cfg_attr(feature = "bolero", derive(bolero::generator::TypeGenerator))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Nonce([u8; 16]);

impl Nonce {
    /// Create a random nonce using `getrandom`.
    ///
    /// This is the recommended constructor for production use.
    ///
    /// # Panics
    ///
    /// Panics if the system random number generator fails.
    #[allow(clippy::expect_used)]
    #[must_use]
    pub fn random() -> Self {
        let mut bytes = [0u8; 16];
        getrandom::getrandom(&mut bytes).expect("getrandom failed");
        Self(bytes)
    }

    /// Create a nonce from a raw `u128` value.
    ///
    /// This is intended for testing and deserialization. Production code should
    /// use [`Nonce::random()`] to ensure cryptographic uniqueness.
    #[must_use]
    pub const fn from_u128(value: u128) -> Self {
        Self(value.to_le_bytes())
    }

    /// Get the raw nonce value as `u128`.
    #[must_use]
    pub const fn as_u128(&self) -> u128 {
        u128::from_le_bytes(self.0)
    }

    /// Create a nonce from raw bytes.
    ///
    /// This is intended for deserialization. Production code should use
    /// [`Nonce::random()`] to ensure cryptographic uniqueness.
    #[must_use]
    pub const fn from_bytes(bytes: [u8; 16]) -> Self {
        Self(bytes)
    }

    /// Get the raw bytes.
    #[must_use]
    pub const fn as_bytes(&self) -> &[u8; 16] {
        &self.0
    }
}
