//! KMS Error Types
//!
//! Comprehensive error handling for the KMS system.

use thiserror::Error;

/// Result type alias for KMS operations
pub type Result<T> = std::result::Result<T, KmsError>;

/// Re-export KmsClientError from kms_service_client
pub use super::kms_service_client::KmsClientError;

/// Main KMS error type
#[derive(Error, Debug)]
pub enum KmsError {
    /// Configuration errors
    #[error("Configuration error: {message}")]
    Configuration { message: String },

    /// Cryptographic operation errors
    #[error("Cryptographic error: {operation} failed - {message}")]
    Cryptographic { operation: String, message: String },

    /// Database/storage errors
    #[error("Storage error: {message}")]
    Storage { message: String },

    /// Network/connection errors
    #[error("Network error: {message}")]
    Network { message: String },

    /// Authentication/authorization errors
    #[error("Authentication error: {message}")]
    Authentication { message: String },

    /// Key not found error
    #[error("Key not found: {key_id}")]
    KeyNotFound { key_id: String },

    /// Key already exists error
    #[error("Key already exists: {key_id}")]
    KeyAlreadyExists { key_id: String },

    /// Invalid key error
    #[error("Invalid key: {key_id} - {reason}")]
    InvalidKey { key_id: String, reason: String },

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

    /// Permission denied error
    #[error("Permission denied: {operation} on {resource}")]
    PermissionDenied { operation: String, resource: String },

    /// Validation errors
    #[error("Validation error: {field} - {message}")]
    Validation { field: String, message: String },

    /// Backend errors
    #[error("Backend error: {backend} - {message}")]
    Backend { backend: String, message: String },

    /// Cache errors
    #[error("Cache error: {operation} - {message}")]
    Cache { operation: String, message: String },

    /// Audit errors
    #[error("Audit error: {message}")]
    Audit { message: String },

    /// Rotation errors
    #[error("Rotation error: {key_id} - {message}")]
    Rotation { key_id: String, message: String },

    /// HSM errors
    #[error("HSM error: {hsm_type} - {message}")]
    Hsm { hsm_type: String, message: String },

    /// Zero-knowledge proof errors
    #[error("ZKP error: {operation} - {message}")]
    Zkp { operation: String, message: String },

    /// Migration errors
    #[error("Migration error: {migration_id} - {message}")]
    Migration {
        migration_id: String,
        message: String,
    },

    /// Timeout errors
    #[error("Timeout error: {operation} timed out after {timeout_seconds}s")]
    Timeout {
        operation: String,
        timeout_seconds: u64,
    },

    /// Rate limiting errors
    #[error("Rate limit exceeded: {operation} - try again in {retry_after_seconds}s")]
    RateLimit {
        operation: String,
        retry_after_seconds: u64,
    },

    /// Resource exhaustion errors
    #[error("Resource exhausted: {resource} - {message}")]
    ResourceExhausted { resource: String, message: String },

    /// Internal errors
    #[error("Internal error: {message}")]
    Internal { message: String },

    /// External service errors
    #[error("External service error: {service} - {message}")]
    ExternalService { service: String, message: String },

    /// Serialization/deserialization errors
    #[error("Serialization error: {message}")]
    Serialization { message: String },

    /// IO errors
    #[error("IO error: {message}")]
    Io { message: String },
}

impl KmsError {
    /// Create a configuration error
    pub fn config(message: impl Into<String>) -> Self {
        Self::Configuration {
            message: message.into(),
        }
    }

    /// Create a cryptographic error
    pub fn crypto(operation: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Cryptographic {
            operation: operation.into(),
            message: message.into(),
        }
    }

    /// Create a storage error
    pub fn storage(message: impl Into<String>) -> Self {
        Self::Storage {
            message: message.into(),
        }
    }

    /// Create a network error
    pub fn network(message: impl Into<String>) -> Self {
        Self::Network {
            message: message.into(),
        }
    }

    /// Create an authentication error
    pub fn auth(message: impl Into<String>) -> Self {
        Self::Authentication {
            message: message.into(),
        }
    }

    /// Create a key not found error
    pub fn key_not_found(key_id: impl Into<String>) -> Self {
        Self::KeyNotFound {
            key_id: key_id.into(),
        }
    }

    /// Create a key already exists error
    pub fn key_exists(key_id: impl Into<String>) -> Self {
        Self::KeyAlreadyExists {
            key_id: key_id.into(),
        }
    }

    /// Create an invalid key error
    pub fn invalid_key(key_id: impl Into<String>, reason: impl Into<String>) -> Self {
        Self::InvalidKey {
            key_id: key_id.into(),
            reason: reason.into(),
        }
    }

    /// Create a key expired error
    pub fn key_expired(key_id: impl Into<String>) -> Self {
        Self::KeyExpired {
            key_id: key_id.into(),
        }
    }

    /// Create a permission denied error
    pub fn permission_denied(operation: impl Into<String>, resource: impl Into<String>) -> Self {
        Self::PermissionDenied {
            operation: operation.into(),
            resource: resource.into(),
        }
    }

    /// Create a validation error
    pub fn validation(field: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Validation {
            field: field.into(),
            message: message.into(),
        }
    }

    /// Create a backend error
    pub fn backend(backend: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Backend {
            backend: backend.into(),
            message: message.into(),
        }
    }

    /// Create a cache error
    pub fn cache(operation: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Cache {
            operation: operation.into(),
            message: message.into(),
        }
    }

    /// Create an audit error
    pub fn audit(message: impl Into<String>) -> Self {
        Self::Audit {
            message: message.into(),
        }
    }

    /// Create a rotation error
    pub fn rotation(key_id: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Rotation {
            key_id: key_id.into(),
            message: message.into(),
        }
    }

    /// Create an HSM error
    pub fn hsm(hsm_type: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Hsm {
            hsm_type: hsm_type.into(),
            message: message.into(),
        }
    }

    /// Create a ZKP error
    pub fn zkp(operation: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Zkp {
            operation: operation.into(),
            message: message.into(),
        }
    }

    /// Create a migration error
    pub fn migration(migration_id: impl Into<String>, message: impl Into<String>) -> Self {
        Self::Migration {
            migration_id: migration_id.into(),
            message: message.into(),
        }
    }

    /// Create a timeout error
    pub fn timeout(operation: impl Into<String>, timeout_seconds: u64) -> Self {
        Self::Timeout {
            operation: operation.into(),
            timeout_seconds,
        }
    }

    /// Create a rate limit error
    pub fn rate_limit(operation: impl Into<String>, retry_after_seconds: u64) -> Self {
        Self::RateLimit {
            operation: operation.into(),
            retry_after_seconds,
        }
    }

    /// Create a resource exhausted error
    pub fn resource_exhausted(resource: impl Into<String>, message: impl Into<String>) -> Self {
        Self::ResourceExhausted {
            resource: resource.into(),
            message: message.into(),
        }
    }

    /// Create an internal error
    pub fn internal(message: impl Into<String>) -> Self {
        Self::Internal {
            message: message.into(),
        }
    }

    /// Create an external service error
    pub fn external_service(service: impl Into<String>, message: impl Into<String>) -> Self {
        Self::ExternalService {
            service: service.into(),
            message: message.into(),
        }
    }

    /// Create a serialization error
    pub fn serialization(message: impl Into<String>) -> Self {
        Self::Serialization {
            message: message.into(),
        }
    }

    /// Create an IO error
    pub fn io(message: impl Into<String>) -> Self {
        Self::Io {
            message: message.into(),
        }
    }

    /// Check if this is a retryable error
    pub fn is_retryable(&self) -> bool {
        matches!(
            self,
            KmsError::Network { .. }
                | KmsError::Timeout { .. }
                | KmsError::RateLimit { .. }
                | KmsError::ExternalService { .. }
        )
    }

    /// Check if this is a temporary error
    pub fn is_temporary(&self) -> bool {
        matches!(
            self,
            KmsError::Network { .. }
                | KmsError::Timeout { .. }
                | KmsError::RateLimit { .. }
                | KmsError::ResourceExhausted { .. }
        )
    }

    /// Get error category
    pub fn category(&self) -> ErrorCategory {
        match self {
            KmsError::Configuration { .. } => ErrorCategory::Configuration,
            KmsError::Cryptographic { .. } => ErrorCategory::Cryptographic,
            KmsError::Storage { .. } => ErrorCategory::Storage,
            KmsError::Network { .. } => ErrorCategory::Network,
            KmsError::Authentication { .. } => ErrorCategory::Authentication,
            KmsError::KeyNotFound { .. }
            | KmsError::KeyAlreadyExists { .. }
            | KmsError::InvalidKey { .. }
            | KmsError::KeyExpired { .. } => ErrorCategory::Key,
            KmsError::PermissionDenied { .. } => ErrorCategory::Authorization,
            KmsError::Validation { .. } => ErrorCategory::Validation,
            KmsError::Backend { .. } => ErrorCategory::Backend,
            KmsError::Cache { .. } => ErrorCategory::Cache,
            KmsError::Audit { .. } => ErrorCategory::Audit,
            KmsError::Rotation { .. } => ErrorCategory::Rotation,
            KmsError::Hsm { .. } => ErrorCategory::Hsm,
            KmsError::Zkp { .. } => ErrorCategory::Zkp,
            KmsError::Migration { .. } => ErrorCategory::Migration,
            KmsError::Timeout { .. } => ErrorCategory::Timeout,
            KmsError::RateLimit { .. } => ErrorCategory::RateLimit,
            KmsError::ResourceExhausted { .. } => ErrorCategory::Resource,
            KmsError::Internal { .. } => ErrorCategory::Internal,
            KmsError::ExternalService { .. } => ErrorCategory::ExternalService,
            KmsError::Serialization { .. } => ErrorCategory::Serialization,
            KmsError::Io { .. } => ErrorCategory::Io,
        }
    }

    /// Get severity level
    pub fn severity(&self) -> ErrorSeverity {
        match self {
            KmsError::Configuration { .. } => ErrorSeverity::High,
            KmsError::Cryptographic { .. } => ErrorSeverity::Critical,
            KmsError::Storage { .. } => ErrorSeverity::High,
            KmsError::Network { .. } => ErrorSeverity::Medium,
            KmsError::Authentication { .. } => ErrorSeverity::High,
            KmsError::KeyNotFound { .. } => ErrorSeverity::Low,
            KmsError::KeyAlreadyExists { .. } => ErrorSeverity::Low,
            KmsError::InvalidKey { .. } => ErrorSeverity::Medium,
            KmsError::KeyExpired { .. } => ErrorSeverity::Medium,
            KmsError::PermissionDenied { .. } => ErrorSeverity::High,
            KmsError::Validation { .. } => ErrorSeverity::Low,
            KmsError::Backend { .. } => ErrorSeverity::High,
            KmsError::Cache { .. } => ErrorSeverity::Low,
            KmsError::Audit { .. } => ErrorSeverity::Medium,
            KmsError::Rotation { .. } => ErrorSeverity::Medium,
            KmsError::Hsm { .. } => ErrorSeverity::High,
            KmsError::Zkp { .. } => ErrorSeverity::Medium,
            KmsError::Migration { .. } => ErrorSeverity::High,
            KmsError::Timeout { .. } => ErrorSeverity::Low,
            KmsError::RateLimit { .. } => ErrorSeverity::Low,
            KmsError::ResourceExhausted { .. } => ErrorSeverity::Medium,
            KmsError::Internal { .. } => ErrorSeverity::Critical,
            KmsError::ExternalService { .. } => ErrorSeverity::Medium,
            KmsError::Serialization { .. } => ErrorSeverity::Low,
            KmsError::Io { .. } => ErrorSeverity::Medium,
        }
    }
}

/// Error category enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorCategory {
    Configuration,
    Cryptographic,
    Storage,
    Network,
    Authentication,
    Authorization,
    Key,
    Validation,
    Backend,
    Cache,
    Audit,
    Rotation,
    Hsm,
    Zkp,
    Migration,
    Timeout,
    RateLimit,
    Resource,
    Internal,
    ExternalService,
    Serialization,
    Io,
}

/// Error severity enumeration
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ErrorSeverity {
    Low,
    Medium,
    High,
    Critical,
}

// Implement conversions from common error types
impl From<std::io::Error> for KmsError {
    fn from(err: std::io::Error) -> Self {
        KmsError::io(err.to_string())
    }
}

impl From<serde_json::Error> for KmsError {
    fn from(err: serde_json::Error) -> Self {
        KmsError::serialization(err.to_string())
    }
}

impl From<toml::de::Error> for KmsError {
    fn from(err: toml::de::Error) -> Self {
        KmsError::config(err.to_string())
    }
}

impl From<sqlx::Error> for KmsError {
    fn from(err: sqlx::Error) -> Self {
        KmsError::storage(err.to_string())
    }
}

impl From<aes_gcm::Error> for KmsError {
    fn from(err: aes_gcm::Error) -> Self {
        KmsError::crypto("AES-GCM", err.to_string())
    }
}

impl From<reqwest::Error> for KmsError {
    fn from(err: reqwest::Error) -> Self {
        KmsError::network(err.to_string())
    }
}

/// Result type alias for KMS operations (same as Result<T>)
pub type KmsResult<T> = std::result::Result<T, KmsError>;

/// Error context for enhanced error reporting
#[derive(Debug, Clone)]
pub struct ErrorContext {
    pub operation: String,
    pub resource: Option<String>,
    pub metadata: std::collections::HashMap<String, String>,
}

impl ErrorContext {
    pub fn new(operation: impl Into<String>) -> Self {
        Self {
            operation: operation.into(),
            resource: None,
            metadata: std::collections::HashMap::new(),
        }
    }

    pub fn with_resource(mut self, resource: impl Into<String>) -> Self {
        self.resource = Some(resource.into());
        self
    }

    pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
        self.metadata.insert(key.into(), value.into());
        self
    }
}
