use actix_web::{http::StatusCode, HttpResponse};
use thiserror::Error;

#[derive(Debug, Error)]
pub enum ApplicationError {
    #[error("unsupported value '{value}' for enum '{enum_name}'")]
    UnsupportedEnumValue { value: String, enum_name: String },
    #[error("unauthorized")]
    Unauthorized,
    #[error("database error")]
    Database(#[from] sqlx::Error),
    #[error("environment variable not present or not unicode")]
    EnvVariable(#[from] std::env::VarError),
    #[error("email address not conform")]
    EmailAdress(#[from] lettre::address::AddressError),
    #[error("email content not right")]
    Email(#[from] lettre::error::Error),
    #[error("email transport not working")]
    EmailTransport(#[from] lettre::transport::smtp::Error),
    #[error("hashfunction failed")]
    Hash(#[from] argon2::password_hash::Error),
    #[error("templating failed")]
    Template(#[from] rinja::Error),
}

impl actix_web::error::ResponseError for ApplicationError {
    fn status_code(&self) -> StatusCode {
        match *self {
            ApplicationError::UnsupportedEnumValue { .. } => StatusCode::BAD_REQUEST,
            ApplicationError::Unauthorized { .. } => StatusCode::UNAUTHORIZED,
            ApplicationError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR,
            ApplicationError::EnvVariable(_) => StatusCode::INTERNAL_SERVER_ERROR,
            ApplicationError::EmailAdress(_) => StatusCode::INTERNAL_SERVER_ERROR,
            ApplicationError::Email(_) => StatusCode::INTERNAL_SERVER_ERROR,
            ApplicationError::EmailTransport(_) => StatusCode::INTERNAL_SERVER_ERROR,
            ApplicationError::Hash(_) => StatusCode::INTERNAL_SERVER_ERROR,
            ApplicationError::Template(_) => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }

    fn error_response(&self) -> HttpResponse {
        let mut response = HttpResponse::build(self.status_code());

        match self {
            ApplicationError::Database(e) => response.body(format!("{self} - {e}")),
            ApplicationError::EmailAdress(e) => response.body(format!("{self} - {e}")),
            ApplicationError::Email(e) => response.body(format!("{self} - {e}")),
            ApplicationError::EmailTransport(e) => response.body(format!("{self} - {e}")),
            ApplicationError::Template(e) => response.body(format!("{self} - {e}")),
            _ => response.body(self.to_string()),
        }
    }
}
