use std::fmt;

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};

/// Registry error types
#[derive(Debug, thiserror::Error)]
pub enum RegistryError {
    #[error("Extension not found: {0}")]
    NotFound(String),

    #[error("Invalid extension type: {0}")]
    InvalidType(String),

    #[error("Invalid version format: {0}")]
    InvalidVersion(String),

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

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

    #[error("GitHub API error: {0}")]
    Github(String),

    #[error("OCI registry error: {0}")]
    Oci(String),

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

    #[error("HTTP request error: {0}")]
    Http(#[from] reqwest::Error),

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

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

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

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

    #[error("Rate limit exceeded")]
    RateLimit,

    #[error("No backends configured")]
    NoBackendsConfigured,

    #[error("All backends failed: {0}")]
    MultiBackendFailure(String),

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

/// Result type alias
pub type Result<T> = std::result::Result<T, RegistryError>;

/// API error response
#[derive(Debug, serde::Serialize)]
pub struct ApiErrorResponse {
    pub error: String,
    pub message: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub details: Option<String>,
}

impl IntoResponse for RegistryError {
    fn into_response(self) -> Response {
        let (status, error_type) = match &self {
            RegistryError::NotFound(_) => (StatusCode::NOT_FOUND, "not_found"),
            RegistryError::InvalidType(_) => (StatusCode::BAD_REQUEST, "invalid_type"),
            RegistryError::InvalidVersion(_) => (StatusCode::BAD_REQUEST, "invalid_version"),
            RegistryError::Auth(_) => (StatusCode::UNAUTHORIZED, "auth_error"),
            RegistryError::RateLimit => (StatusCode::TOO_MANY_REQUESTS, "rate_limit"),
            RegistryError::Config(_) | RegistryError::NoBackendsConfigured => {
                (StatusCode::INTERNAL_SERVER_ERROR, "config_error")
            }
            RegistryError::MultiBackendFailure(_) => {
                (StatusCode::SERVICE_UNAVAILABLE, "backend_failure")
            }
            _ => (StatusCode::INTERNAL_SERVER_ERROR, "internal_error"),
        };

        let body = ApiErrorResponse {
            error: error_type.to_string(),
            message: self.to_string(),
            details: None,
        };

        (status, axum::Json(body)).into_response()
    }
}

impl fmt::Display for ApiErrorResponse {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", self.error, self.message)
    }
}
