use serde::Serialize;

#[derive(Debug, thiserror::Error)]
pub enum AppError {
    #[error("Database error: {0}")]
    Database(#[from] rusqlite::Error),

    #[error("Encryption error: {0}")]
    Encryption(String),

    #[error("Keyring error: {0}")]
    Keyring(String),

    #[error("Authentication error: {0}")]
    Auth(String),

    #[error("Not found: {0}")]
    NotFound(String),

    #[error("Validation error: {0}")]
    Validation(String),

    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),

    #[error("JSON error: {0}")]
    Json(#[from] serde_json::Error),

    #[error("Internal error: {0}")]
    Internal(String),
}

impl Serialize for AppError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        serializer.serialize_str(&self.user_message())
    }
}

impl AppError {
    fn user_message(&self) -> String {
        match self {
            AppError::Database(e) => e.to_string(),
            AppError::Encryption(msg)
            | AppError::Keyring(msg)
            | AppError::Auth(msg)
            | AppError::NotFound(msg)
            | AppError::Validation(msg)
            | AppError::Internal(msg) => msg.clone(),
            AppError::Io(e) => e.to_string(),
            AppError::Json(e) => e.to_string(),
        }
    }
}

pub type AppResult<T> = Result<T, AppError>;
