use crate::models::ErrorResponse;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum TypecastError {
#[error("Bad Request - {detail}")]
BadRequest { detail: String },
#[error("Unauthorized - Invalid or missing API key")]
Unauthorized { detail: String },
#[error("Payment Required - Insufficient credits")]
PaymentRequired { detail: String },
#[error("Forbidden - Access denied")]
Forbidden { detail: String },
#[error("Not Found - {detail}")]
NotFound { detail: String },
#[error("Validation Error - {detail}")]
ValidationError { detail: String },
#[error("Too Many Requests - Rate limit exceeded")]
RateLimited { detail: String },
#[error("Internal Server Error - {detail}")]
ServerError { detail: String },
#[error("HTTP error: {0}")]
HttpError(#[from] reqwest::Error),
#[error("JSON error: {0}")]
JsonError(#[from] serde_json::Error),
#[error("API error (status {status_code}): {detail}")]
Unknown { status_code: u16, detail: String },
#[error("Decode error: {0}")]
DecodeError(String),
#[error("I/O error: {0}")]
IoError(String),
#[error("Captioning error: {0}")]
CaptioningError(String),
}
impl TypecastError {
pub fn from_response(status_code: u16, error_response: Option<ErrorResponse>) -> Self {
let detail = error_response
.map(|e| e.detail)
.unwrap_or_else(|| "Unknown error".to_string());
match status_code {
400 => TypecastError::BadRequest { detail },
401 => TypecastError::Unauthorized { detail },
402 => TypecastError::PaymentRequired { detail },
403 => TypecastError::Forbidden { detail },
404 => TypecastError::NotFound { detail },
422 => TypecastError::ValidationError { detail },
429 => TypecastError::RateLimited { detail },
500..=599 => TypecastError::ServerError { detail },
_ => TypecastError::Unknown { status_code, detail },
}
}
pub fn is_bad_request(&self) -> bool {
matches!(self, TypecastError::BadRequest { .. })
}
pub fn is_unauthorized(&self) -> bool {
matches!(self, TypecastError::Unauthorized { .. })
}
pub fn is_payment_required(&self) -> bool {
matches!(self, TypecastError::PaymentRequired { .. })
}
pub fn is_forbidden(&self) -> bool {
matches!(self, TypecastError::Forbidden { .. })
}
pub fn is_not_found(&self) -> bool {
matches!(self, TypecastError::NotFound { .. })
}
pub fn is_validation_error(&self) -> bool {
matches!(self, TypecastError::ValidationError { .. })
}
pub fn is_rate_limited(&self) -> bool {
matches!(self, TypecastError::RateLimited { .. })
}
pub fn is_server_error(&self) -> bool {
matches!(self, TypecastError::ServerError { .. })
}
pub fn status_code(&self) -> Option<u16> {
match self {
TypecastError::BadRequest { .. } => Some(400),
TypecastError::Unauthorized { .. } => Some(401),
TypecastError::PaymentRequired { .. } => Some(402),
TypecastError::Forbidden { .. } => Some(403),
TypecastError::NotFound { .. } => Some(404),
TypecastError::ValidationError { .. } => Some(422),
TypecastError::RateLimited { .. } => Some(429),
TypecastError::ServerError { .. } => Some(500),
TypecastError::Unknown { status_code, .. } => Some(*status_code),
_ => None,
}
}
}
pub type Result<T> = std::result::Result<T, TypecastError>;