"""全局错误处理.

将 AIError + 未知异常统一转换为 ActionState 错误响应。
HTTP 端点返回 JSON，gRPC interceptor 转换为 grpc.StatusCode。
"""

from collections.abc import Awaitable, Callable
from typing import Any

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

from ..errors import AIError
from ..models.action_state import ActionState, ErrorDetail

logger = structlog.get_logger()


class GlobalErrorHandler:
    """全局错误处理器."""

    @staticmethod
    def handle_ai_error(exc: AIError, trace_id: str | None = None) -> JSONResponse:
        """将 AIError 转换为 ActionState JSON 响应."""
        error_detail = ErrorDetail(
            code=exc.code.value,
            message=exc.message,
            details=exc.details or None,
            trace_id=trace_id,
        )
        body = ActionState[Any](
            success=False,
            data=None,
            error=error_detail,
        )
        return JSONResponse(
            status_code=exc.http_status,
            content=body.model_dump(by_alias=True, exclude_none=True),
        )

    @staticmethod
    def handle_unknown_error(
        exc: Exception,
        trace_id: str | None = None,
    ) -> JSONResponse:
        """未知异常兜底（500）."""
        logger.error(
            "unhandled_exception",
            error_type=type(exc).__name__,
            error=str(exc),
            trace_id=trace_id,
        )
        error_detail = ErrorDetail(
            code="AI_INTERNAL_ERROR",
            message="Internal server error",
            trace_id=trace_id,
        )
        body = ActionState[Any](
            success=False,
            data=None,
            error=error_detail,
        )
        return JSONResponse(
            status_code=500,
            content=body.model_dump(by_alias=True, exclude_none=True),
        )


def register_error_handlers(app: FastAPI) -> None:
    """注册全局错误处理器到 FastAPI app."""

    @app.exception_handler(AIError)
    async def ai_error_handler(request: Request, exc: AIError) -> JSONResponse:
        trace_id = getattr(request.state, "request_id", None)
        return GlobalErrorHandler.handle_ai_error(exc, trace_id)

    @app.exception_handler(Exception)
    async def unknown_error_handler(request: Request, exc: Exception) -> JSONResponse:
        trace_id = getattr(request.state, "request_id", None)
        return GlobalErrorHandler.handle_unknown_error(exc, trace_id)


def grpc_error_mapper(exc: Exception) -> tuple[str, str, int]:
    """gRPC 异常映射器（供 interceptor 使用）.

    Returns:
        (error_code, message, grpc_status_code)
        grpc_status_code 对应 grpc.StatusCode value：
          0=OK, 1=CANCELLED, 2=UNKNOWN, 3=INVALID_ARGUMENT, 5=NOT_FOUND,
          6=ALREADY_EXISTS, 7=PERMISSION_DENIED, 8=UNAUTHENTICATED,
          9=RESOURCE_EXHAUSTED, 10=FAILED_PRECONDITION, 13=INTERNAL,
          14=UNAVAILABLE, 15=DATA_LOSS
    """
    if isinstance(exc, AIError):
        code = exc.code.value
        msg = exc.message
        # 映射到 gRPC status code
        grpc_status = {
            "AI_UNAUTHORIZED": 8,
            "AI_FORBIDDEN": 7,
            "AI_RATE_LIMITED": 9,
            "AI_QUOTA_EXCEEDED": 9,
            "AI_LLM_UNAVAILABLE": 14,
            "AI_LLM_TIMEOUT": 14,
            "AI_LLM_ALL_PROVIDERS_FAILED": 14,
            "AI_INVALID_MODEL": 3,
            "AI_INVALID_DIFFICULTY": 3,
            "AI_INVALID_QUESTION_TYPE": 3,
            "AI_DOWNSTREAM_UNAVAILABLE": 14,
            "AI_PROMPT_RENDER_FAILED": 13,
            "AI_PROMPT_TEMPLATE_NOT_FOUND": 5,
            "AI_WORKFLOW_NOT_FOUND": 5,
            "AI_WORKFLOW_EXPIRED": 5,
            "AI_WORKFLOW_STATE_INVALID": 10,
            "AI_EVALUATION_FAILED": 14,
            "AI_PII_DETECTED": 3,
            "AI_PROMPT_INJECTION_DETECTED": 3,
            "AI_CONTENT_MODERATION_REJECTED": 14,
            "AI_INTERNAL_ERROR": 13,
        }.get(code, 13)
        return code, msg, grpc_status

    # 未知异常
    logger.error("grpc_unhandled_exception", error=str(exc))
    return "AI_INTERNAL_ERROR", "Internal server error", 13


# 供中间件链使用的通用错误处理函数类型
ErrorHandler = Callable[[Exception, str | None], Awaitable[JSONResponse]]
