use common_utils::errors::ErrorSwitch;
use hyperswitch_domain_models::errors::api_error_response::ApiErrorResponse;

use super::{CustomersErrorResponse, StorageError};

impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for CustomersErrorResponse {
    fn switch(&self) -> api_models::errors::types::ApiErrorResponse {
        use api_models::errors::types::{ApiError, ApiErrorResponse as AER};
        match self {
            Self::CustomerRedacted => AER::BadRequest(ApiError::new(
                "IR",
                11,
                "Customer has already been redacted",
                None,
            )),
            Self::InternalServerError => {
                AER::InternalServerError(ApiError::new("HE", 0, "Something went wrong", None))
            }
            Self::InvalidRequestData { message } => AER::BadRequest(ApiError::new(
                "IR",
                7,
                format!("Invalid value provided:{}", message),
                None,
            )),
            Self::MandateActive => AER::BadRequest(ApiError::new(
                "IR",
                10,
                "Customer has active mandate/subsciption",
                None,
            )),
            Self::CustomerNotFound => AER::NotFound(ApiError::new(
                "HE",
                2,
                "Customer does not exist in our records",
                None,
            )),
            Self::CustomerAlreadyExists => AER::BadRequest(ApiError::new(
                "IR",
                12,
                "Customer with the given `customer_id` already exists",
                None,
            )),
            Self::AccessForbidden { message } => AER::ForbiddenCommonResource(ApiError::new(
                "IR",
                22,
                format!(
                    "Access forbidden. Not authorized to access this resource {}",
                    message
                ),
                None,
            )),
        }
    }
}

impl ErrorSwitch<CustomersErrorResponse> for StorageError {
    fn switch(&self) -> CustomersErrorResponse {
        use CustomersErrorResponse as CER;
        match self {
            err if err.is_db_not_found() => CER::CustomerNotFound,
            Self::CustomerRedacted => CER::CustomerRedacted,
            _ => CER::InternalServerError,
        }
    }
}

impl ErrorSwitch<CustomersErrorResponse> for common_utils::errors::CryptoError {
    fn switch(&self) -> CustomersErrorResponse {
        CustomersErrorResponse::InternalServerError
    }
}

impl ErrorSwitch<CustomersErrorResponse> for ApiErrorResponse {
    fn switch(&self) -> CustomersErrorResponse {
        use CustomersErrorResponse as CER;
        match self {
            Self::InternalServerError => CER::InternalServerError,
            Self::MandateActive => CER::MandateActive,
            Self::CustomerNotFound => CER::CustomerNotFound,
            Self::AccessForbidden { resource } => CER::AccessForbidden {
                message: resource.clone(),
            },
            _ => CER::InternalServerError,
        }
    }
}

impl From<ApiErrorResponse> for CustomersErrorResponse {
    fn from(error: ApiErrorResponse) -> Self {
        match error {
            ApiErrorResponse::InternalServerError => Self::InternalServerError,
            ApiErrorResponse::MandateActive => Self::MandateActive,
            ApiErrorResponse::CustomerNotFound => Self::CustomerNotFound,
            ApiErrorResponse::AccessForbidden { resource } => Self::AccessForbidden {
                message: resource.clone(),
            },
            _ => Self::InternalServerError,
        }
    }
}
