//! Infrastructure and System Errors

use axum::http::StatusCode;
use thiserror::Error;

/// Infrastructure and system specific errors
#[derive(Error, Debug, Clone)]
pub enum InfrastructureError {
    /// Internal server error
    #[error("Internal server error: {0}")]
    Internal(String),

    /// Configuration errors
    #[error("Configuration error: {0}")]
    Configuration(String),

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

    /// External errors
    #[error("External error: {0}")]
    External(String),

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

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

    /// KMS errors
    #[error("KMS error: {0}")]
    Kms(String),
}

impl InfrastructureError {
    pub fn status_code(&self) -> StatusCode {
        match self {
            Self::Internal(_) => StatusCode::INTERNAL_SERVER_ERROR,
            Self::Configuration(_) => StatusCode::INTERNAL_SERVER_ERROR,
            Self::ExternalService(_) => StatusCode::BAD_GATEWAY,
            Self::External(_) => StatusCode::BAD_GATEWAY,
            Self::Serialization(_) => StatusCode::INTERNAL_SERVER_ERROR,
            Self::Io(_) => StatusCode::INTERNAL_SERVER_ERROR,
            Self::Kms(_) => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }

    pub fn error_code(&self) -> &'static str {
        match self {
            Self::Internal(_) => "INTERNAL_ERROR",
            Self::Configuration(_) => "CONFIGURATION_ERROR",
            Self::ExternalService(_) => "EXTERNAL_SERVICE_ERROR",
            Self::External(_) => "EXTERNAL_ERROR",
            Self::Serialization(_) => "SERIALIZATION_ERROR",
            Self::Io(_) => "IO_ERROR",
            Self::Kms(_) => "KMS_ERROR",
        }
    }

    pub fn should_log_error(&self) -> bool {
        true // All infrastructure errors should be logged at ERROR level
    }
}

// Conversions from external infrastructure errors
impl From<serde_json::Error> for InfrastructureError {
    fn from(error: serde_json::Error) -> Self {
        Self::Serialization(error.to_string())
    }
}

impl From<std::io::Error> for InfrastructureError {
    fn from(error: std::io::Error) -> Self {
        Self::Io(error.to_string())
    }
}

impl From<toml::de::Error> for InfrastructureError {
    fn from(error: toml::de::Error) -> Self {
        Self::Configuration(format!("TOML parsing error: {}", error))
    }
}

impl From<reqwest::Error> for InfrastructureError {
    fn from(error: reqwest::Error) -> Self {
        Self::ExternalService(error.to_string())
    }
}

impl From<crate::kms::KmsClientError> for InfrastructureError {
    fn from(error: crate::kms::KmsClientError) -> Self {
        Self::Kms(format!("KMS client error: {}", error))
    }
}

impl From<crate::kms::KmsError> for InfrastructureError {
    fn from(error: crate::kms::KmsError) -> Self {
        Self::Kms(format!("KMS error: {}", error))
    }
}

// Helper function for creating internal errors
pub fn internal_error(message: &str) -> InfrastructureError {
    InfrastructureError::Internal(message.to_string())
}
