"""RMI Backend - exception handlers.

Clean JSON error responses for 404, 500, AppError, etc. Each
handler is isolated - one failure doesn't break the others.
"""

from __future__ import annotations

import logging

from fastapi import (  # noqa: TC002 - runtime use (matches app/core/errors.py + pre-existing project-wide pattern)
    FastAPI,
    Request,
)
from fastapi.responses import JSONResponse

from app.core.errors import (
    AppError,
    AuthError,
    NotFoundError,
    UpstreamError,
    ValidationError,
)

log = logging.getLogger(__name__)


def register_error_handlers(app: FastAPI) -> None:
    """Register every error handler. Each is isolated."""
    _register_404(app)
    _register_validation(app)
    _register_500(app)
    _register_apperror(app)


def _register_404(app: FastAPI) -> None:
    @app.exception_handler(404)
    async def _not_found(request: Request, _exc: Exception) -> JSONResponse:
        return JSONResponse(
            status_code=404,
            content={
                "error": "not_found",
                "path": request.url.path,
                "method": request.method,
                "hint": "RMI new backend. Check /docs for current API surface.",
            },
        )

    log.info("error_handler_registered name=not_found")


def _register_validation(app: FastAPI) -> None:
    """422 - Pydantic validation errors. Return structured details.

    Phase 3 of AUDIT-2026-Q3.md (router split) will wire RequestValidationError
    to RMI's typed ValidationError here. Until then, this is a logging stub.
    """
    log.info("error_handler_registered name=validation (pending phase 3)")


def _register_500(app: FastAPI) -> None:
    """Generic 500 fallback for non-AppError exceptions.

    AppError instances are routed by the more-specific handler installed in
    _register_apperror, so this only fires for plain Exception subclasses.
    """

    @app.exception_handler(Exception)
    async def handle_generic_exception(request: Request, exc: Exception) -> JSONResponse:
        log.exception("unhandled_exception path=%s", request.url.path)
        return JSONResponse(
            status_code=500,
            content={
                "error": "internal_error",
                "path": request.url.path,
                "type": type(exc).__name__,
            },
        )

    log.info("error_handler_registered name=internal_error")


def _register_apperror(app: FastAPI) -> None:
    """AppError → JSON via its declared status_code + to_dict().

    Import is at module top so a missing AppError is a hard ImportError
    at import time rather than a silently-swallowed runtime warning.
    """

    @app.exception_handler(AppError)
    async def handle_app_error(request: Request, exc: AppError) -> JSONResponse:
        body = exc.to_dict()
        body["path"] = request.url.path
        body["type"] = type(exc).__name__
        return JSONResponse(status_code=exc.status_code, content=body)

    log.info(
        "error_handler_registered name=AppError handlers=%s",
        sorted(
            {
                AuthError.__name__,
                NotFoundError.__name__,
                ValidationError.__name__,
                UpstreamError.__name__,
            }
        ),
    )
