//! `IntoResponse` implementation for [`AuthError`].
//!
//! Maps every [`AuthError`] variant to a structured JSON body + appropriate
//! HTTP status code so handlers can simply propagate `AuthError` with `?`.

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

use crate::AuthError;

impl IntoResponse for AuthError {
    fn into_response(self) -> Response {
        let (status, code, extra) = match &self {
            AuthError::InvalidToken => (StatusCode::UNAUTHORIZED, "invalid_token", None),
            AuthError::TokenExpired => (StatusCode::UNAUTHORIZED, "token_expired", None),
            AuthError::Forbidden(_) => (StatusCode::FORBIDDEN, "forbidden", None),
            AuthError::InvalidCredentials => {
                (StatusCode::UNAUTHORIZED, "invalid_credentials", None)
            }
            AuthError::HashError(_) => (StatusCode::INTERNAL_SERVER_ERROR, "hash_error", None),
            AuthError::Internal(_) => (StatusCode::INTERNAL_SERVER_ERROR, "internal_error", None),
            AuthError::TotpRequired(challenge) => (
                StatusCode::UNAUTHORIZED,
                "totp_required",
                Some(json!({
                    "pending_token": challenge.pending_token,
                    "expires_at": challenge.expires_at.to_rfc3339(),
                })),
            ),
        };

        let mut body = json!({ "error": code, "message": self.to_string() });
        if let Some(extra) = extra {
            body["challenge"] = extra;
        }

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