"""
Global exception handlers for FastAPI application.

This module provides centralized error handling that converts custom
exceptions to structured JSON responses with appropriate HTTP status codes.
"""
import logging
import traceback
from typing import Any, Dict

from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse

from src.server.exceptions import (
    AniWorldAPIException,
    AuthenticationError,
    AuthorizationError,
    BadRequestError,
    ConflictError,
    NotFoundError,
    RateLimitError,
    ValidationError,
)

logger = logging.getLogger(__name__)


def create_error_response(
    status_code: int,
    error: str,
    message: str,
    details: Dict[str, Any] | None = None,
    request_id: str | None = None,
) -> Dict[str, Any]:
    """
    Create standardized error response.

    Args:
        status_code: HTTP status code
        error: Error code/type
        message: Human-readable error message
        details: Additional error details
        request_id: Unique request identifier for tracking

    Returns:
        Dictionary containing structured error response
    """
    response = {
        "success": False,
        "error": error,
        "message": message,
    }

    if details:
        response["details"] = details

    if request_id:
        response["request_id"] = request_id

    return response


def register_exception_handlers(app: FastAPI) -> None:
    """
    Register all exception handlers with FastAPI app.

    Args:
        app: FastAPI application instance
    """

    @app.exception_handler(AuthenticationError)
    async def authentication_error_handler(
        request: Request, exc: AuthenticationError
    ) -> JSONResponse:
        """Handle authentication errors (401)."""
        logger.warning(
            "Authentication error: %s",
            exc.message,
            extra={"details": exc.details, "path": str(request.url.path)},
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(AuthorizationError)
    async def authorization_error_handler(
        request: Request, exc: AuthorizationError
    ) -> JSONResponse:
        """Handle authorization errors (403)."""
        logger.warning(
            "Authorization error: %s",
            exc.message,
            extra={"details": exc.details, "path": str(request.url.path)},
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(ValidationError)
    async def validation_error_handler(
        request: Request, exc: ValidationError
    ) -> JSONResponse:
        """Handle validation errors (422)."""
        logger.info(
            "Validation error: %s",
            exc.message,
            extra={"details": exc.details, "path": str(request.url.path)},
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(BadRequestError)
    async def bad_request_error_handler(
        request: Request, exc: BadRequestError
    ) -> JSONResponse:
        """Handle bad request errors (400)."""
        logger.info(
            "Bad request error: %s",
            exc.message,
            extra={"details": exc.details, "path": str(request.url.path)},
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(NotFoundError)
    async def not_found_error_handler(
        request: Request, exc: NotFoundError
    ) -> JSONResponse:
        """Handle not found errors (404)."""
        logger.info(
            "Not found error: %s",
            exc.message,
            extra={"details": exc.details, "path": str(request.url.path)},
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(ConflictError)
    async def conflict_error_handler(
        request: Request, exc: ConflictError
    ) -> JSONResponse:
        """Handle conflict errors (409)."""
        logger.info(
            "Conflict error: %s",
            exc.message,
            extra={"details": exc.details, "path": str(request.url.path)},
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(RateLimitError)
    async def rate_limit_error_handler(
        request: Request, exc: RateLimitError
    ) -> JSONResponse:
        """Handle rate limit errors (429)."""
        logger.warning(
            "Rate limit exceeded: %s",
            exc.message,
            extra={"details": exc.details, "path": str(request.url.path)},
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(AniWorldAPIException)
    async def api_exception_handler(
        request: Request, exc: AniWorldAPIException
    ) -> JSONResponse:
        """Handle generic API exceptions."""
        logger.error(
            "API error: %s",
            exc.message,
            extra={
                "error_code": exc.error_code,
                "details": exc.details,
                "path": str(request.url.path),
            },
        )
        return JSONResponse(
            status_code=exc.status_code,
            content=create_error_response(
                status_code=exc.status_code,
                error=exc.error_code,
                message=exc.message,
                details=exc.details,
                request_id=getattr(request.state, "request_id", None),
            ),
        )

    @app.exception_handler(Exception)
    async def general_exception_handler(
        request: Request, exc: Exception
    ) -> JSONResponse:
        """Handle unexpected exceptions."""
        logger.exception(
            "Unexpected error: %s",
            str(exc),
            extra={"path": str(request.url.path)},
        )

        # Log full traceback for debugging
        logger.debug("Traceback: %s", traceback.format_exc())

        # Return generic error response for security
        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content=create_error_response(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                error="INTERNAL_SERVER_ERROR",
                message="An unexpected error occurred",
                request_id=getattr(request.state, "request_id", None),
            ),
        )
