//! Error types for pqc-py cryptographic operations

use thiserror::Error;

/// Unified error type for all cryptographic operations
#[derive(Error, Debug, Clone, PartialEq, Eq)]
pub enum CryptoError {
    /// Invalid key length provided
    #[error("Invalid key length: expected {expected}, got {actual}")]
    InvalidKeyLength {
        /// Expected key length in bytes
        expected: usize,
        /// Actual key length provided
        actual: usize,
    },

    /// Invalid nonce length for AES-GCM
    #[error("Invalid nonce length: expected {expected}, got {actual}")]
    InvalidNonceLength {
        /// Expected nonce length in bytes
        expected: usize,
        /// Actual nonce length provided
        actual: usize,
    },

    /// Encryption operation failed
    #[error("Encryption failed: {0}")]
    EncryptionFailed(String),

    /// Decryption operation failed (authentication tag mismatch)
    #[error("Decryption failed: authentication tag mismatch")]
    DecryptionFailed,

    /// HMAC verification failed
    #[error("HMAC verification failed")]
    HmacVerificationFailed,

    /// Key derivation failed
    #[error("Key derivation failed: {0}")]
    KeyDerivationFailed(String),

    /// Invalid output length for key derivation
    #[error("Invalid output length: {0}")]
    InvalidOutputLength(String),

    /// Key not found in key manager
    #[error("Key not found: {0}")]
    KeyNotFound(String),

    /// Key has expired
    #[error("Key expired: {0}")]
    KeyExpired(String),

    /// Key has been revoked
    #[error("Key revoked: {0}")]
    KeyRevoked(String),

    /// Hash chain verification failed
    #[error("Hash chain verification failed at index {index}")]
    HashChainVerificationFailed {
        /// Index where verification failed
        index: usize,
    },

    /// Post-quantum key generation failed
    #[error("PQC key generation failed: {0}")]
    PqcKeyGenFailed(String),

    /// Post-quantum encapsulation failed
    #[error("PQC encapsulation failed: {0}")]
    PqcEncapsFailed(String),

    /// Post-quantum decapsulation failed
    #[error("PQC decapsulation failed: {0}")]
    PqcDecapsFailed(String),

    /// Post-quantum signature failed
    #[error("PQC signature failed: {0}")]
    PqcSignFailed(String),

    /// Post-quantum verification failed
    #[error("PQC verification failed")]
    PqcVerifyFailed,

    /// Invalid public key format
    #[error("Invalid public key: {0}")]
    InvalidPublicKey(String),

    /// Invalid secret key format
    #[error("Invalid secret key: {0}")]
    InvalidSecretKey(String),

    /// Invalid signature format
    #[error("Invalid signature: {0}")]
    InvalidSignature(String),

    /// Invalid ciphertext format
    #[error("Invalid ciphertext: {0}")]
    InvalidCiphertext(String),

    /// Random number generation failed
    #[error("RNG failed: {0}")]
    RngFailed(String),

    /// Serialization error
    #[error("Serialization failed: {0}")]
    SerializationFailed(String),

    /// Deserialization error
    #[error("Deserialization failed: {0}")]
    DeserializationFailed(String),
}

/// Result type alias for cryptographic operations
pub type CryptoResult<T> = Result<T, CryptoError>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_error_display() {
        let err = CryptoError::InvalidKeyLength {
            expected: 32,
            actual: 16,
        };
        assert_eq!(
            err.to_string(),
            "Invalid key length: expected 32, got 16"
        );
    }

    #[test]
    fn test_error_equality() {
        let err1 = CryptoError::DecryptionFailed;
        let err2 = CryptoError::DecryptionFailed;
        assert_eq!(err1, err2);
    }

    #[test]
    fn test_result_type() {
        let result: CryptoResult<Vec<u8>> = Ok(vec![1, 2, 3]);
        assert!(result.is_ok());

        let err_result: CryptoResult<Vec<u8>> = Err(CryptoError::DecryptionFailed);
        assert!(err_result.is_err());
    }
}
