from fastapi import Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import HTTPException, RequestValidationError
from mysql.connector import Error as MySQLError
from jose import JWTError

from schema.response_schema import APIResponse


async def global_exception_handler(request: Request, exc: Exception):
    """全局异常处理器：所有未捕获的异常都会在这里统一处理"""
    # 1. 请求参数验证错误（Pydantic 校验失败）
    if isinstance(exc, RequestValidationError):
        error_details = []
        for err in exc.errors():
            error_details.append(f"{err['loc'][1]}: {err['msg']}")
        return JSONResponse(
            status_code=status.HTTP_400_BAD_REQUEST,
            content=APIResponse(
                code=400,
                message=f"请求参数错误：{'; '.join(error_details)}",
                data=None
            ).model_dump()
        )

    # 2. HTTP 异常（主动抛出的业务错误、如 401/404）
    if isinstance(exc, HTTPException):
        return JSONResponse(
            status_code=exc.status_code,
            content=APIResponse(
                code=exc.status_code,
                message=exc.detail,
                data=None
            ).model_dump()
        )

    # 3. JWT 相关错误（Token 无效/过期）
    if isinstance(exc, JWTError):
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content=APIResponse(
                code=401,
                message="Token 无效或已过期",
                data=None
            ).model_dump(),
            headers={"WWW-Authenticate": "Bearer"},
        )

    # 4. MySQL 数据库错误
    if isinstance(exc, MySQLError):
        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content=APIResponse(
                code=500,
                message=f"数据库错误：{str(exc)}",
                data=None
            ).model_dump()
        )

    # 5. 其他未知错误（兜底处理）
    return JSONResponse(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content=APIResponse(
            code=500,
            message=f"服务器内部错误：{str(exc)}",
            data=None
        ).model_dump()
    )
