//! Unified error handling for the application

use actix_web::{HttpResponse, ResponseError};
use std::fmt;

/// Application-level error type
#[derive(Debug)]
pub struct AppError {
    /// HTTP status code
    pub status: u16,
    /// Error code for API clients
    pub code: &'static str,
    /// Human-readable message
    pub message: String,
}

impl AppError {
    /// Create a new AppError
    pub fn new(status: u16, code: &'static str, message: impl Into<String>) -> Self {
        Self {
            status,
            code,
            message: message.into(),
        }
    }

    // Convenience constructors
    pub fn bad_request(msg: impl Into<String>) -> Self {
        Self::new(400, "BAD_REQUEST", msg)
    }
    pub fn unauthorized(msg: impl Into<String>) -> Self {
        Self::new(401, "UNAUTHORIZED", msg)
    }
    pub fn forbidden(msg: impl Into<String>) -> Self {
        Self::new(403, "FORBIDDEN", msg)
    }
    pub fn not_found(msg: impl Into<String>) -> Self {
        Self::new(404, "NOT_FOUND", msg)
    }
    pub fn conflict(msg: impl Into<String>) -> Self {
        Self::new(409, "CONFLICT", msg)
    }
    pub fn internal(msg: impl Into<String>) -> Self {
        Self::new(500, "INTERNAL_ERROR", msg)
    }
    pub fn server_error(msg: impl Into<String>) -> Self {
        Self::new(500, "SERVER_ERROR", msg)
    }
}

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

impl std::error::Error for AppError {}

impl ResponseError for AppError {
    fn error_response(&self) -> HttpResponse {
        HttpResponse::build(
            actix_web::http::StatusCode::from_u16(self.status)
                .unwrap_or(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR),
        )
        .json(serde_json::json!({
            "code": self.code,
            "message": self.message,
        }))
    }
}

/// Result alias using AppError
pub type AppResult<T> = Result<T, AppError>;