//! Shared API error type and Actix `ResponseError` integration.
//!
//! Handlers can return `Result<T, ApiError>` and use `?`; Actix converts
//! `ApiError` into an HTTP response with the standard envelope via [`crate::api::response`].

use actix_web::{HttpResponse, ResponseError};
use thiserror::Error;

use crate::api::response::{
    bad_gateway, bad_request, conflict, forbidden, internal_error, not_found, service_unavailable,
    unauthorized,
};

/// Result type for API handlers that can fail with a structured error.
pub type ApiResult<T> = Result<T, ApiError>;

/// Structured API error; maps to HTTP status and standard JSON envelope.
#[derive(Debug, Error)]
pub enum ApiError {
    #[error("{0}")]
    Validation(String),

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

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

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

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

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

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

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

impl ResponseError for ApiError {
    fn error_response(&self) -> HttpResponse {
        match self {
            ApiError::Validation(msg) => bad_request("Bad request", msg),
            ApiError::NotFound(msg) => not_found("Not found", msg),
            ApiError::Unauthorized(msg) => unauthorized("Unauthorized", msg),
            ApiError::Forbidden(msg) => forbidden("Forbidden", msg),
            ApiError::Conflict(msg) => conflict("Conflict", msg),
            ApiError::Backend(msg) => internal_error("Backend error", msg),
            ApiError::ServiceUnavailable(msg) => service_unavailable("Service unavailable", msg),
            ApiError::BadGateway(msg) => bad_gateway("Bad gateway", msg),
        }
    }
}

impl From<String> for ApiError {
    fn from(s: String) -> Self {
        ApiError::Validation(s)
    }
}

impl From<&str> for ApiError {
    fn from(s: &str) -> Self {
        ApiError::Validation(s.to_string())
    }
}
