"""权限校验守卫.

ai 服务的权限点（对齐 004 Permissions 常量）：
  - ai:chat: 聊天
  - ai:question:generate: 生成题目
  - ai:expression:optimize: 优化表达
  - ai:lesson:generate: 生成教案
  - ai:lesson:confirm: 确认教案

全并行模式：dev_mode=true 时跳过权限校验，仅记录警告。
"""

from collections.abc import Callable
from functools import wraps
from typing import Any

import structlog

from ..errors import AIError, ErrorCode
from .auth import UserContext

logger = structlog.get_logger()

# 权限点常量
PERMISSION_AI_CHAT = "ai:chat"
PERMISSION_AI_QUESTION_GENERATE = "ai:question:generate"
PERMISSION_AI_EXPRESSION_OPTIMIZE = "ai:expression:optimize"
PERMISSION_AI_LESSON_GENERATE = "ai:lesson:generate"
PERMISSION_AI_LESSON_CONFIRM = "ai:lesson:confirm"

# 角色 → 权限映射（简化版，P6 迁移到 iam 动态权限）
ROLE_PERMISSIONS: dict[str, set[str]] = {
    "teacher": {
        PERMISSION_AI_CHAT,
        PERMISSION_AI_QUESTION_GENERATE,
        PERMISSION_AI_EXPRESSION_OPTIMIZE,
        PERMISSION_AI_LESSON_GENERATE,
        PERMISSION_AI_LESSON_CONFIRM,
    },
    "admin": {
        PERMISSION_AI_CHAT,
        PERMISSION_AI_QUESTION_GENERATE,
        PERMISSION_AI_EXPRESSION_OPTIMIZE,
        PERMISSION_AI_LESSON_GENERATE,
        PERMISSION_AI_LESSON_CONFIRM,
    },
    "student": {
        PERMISSION_AI_CHAT,
    },
}


class PermissionGuard:
    """权限校验守卫.

    全并行模式：dev_mode=true 时跳过校验。
    生产模式：无用户上下文或权限不足时抛 AIError(AI_FORBIDDEN)。
    """

    def __init__(self, dev_mode: bool = False) -> None:
        self._dev_mode = dev_mode

    def check(
        self,
        ctx: UserContext,
        permission: str,
    ) -> None:
        """校验权限，失败抛 AIError.

        Args:
            ctx: 用户上下文
            permission: 权限点（如 PERMISSION_AI_CHAT）

        Raises:
            AIError(AI_UNAUTHORIZED): 用户未认证
            AIError(AI_FORBIDDEN): 权限不足
        """
        if self._dev_mode:
            logger.debug(
                "permission_check_skipped_dev_mode",
                permission=permission,
                user_id=ctx.user_id,
            )
            return

        if not ctx.is_authenticated:
            raise AIError(
                ErrorCode.AI_UNAUTHORIZED,
                "User not authenticated",
            )

        role = ctx.role or "student"
        allowed = ROLE_PERMISSIONS.get(role, ROLE_PERMISSIONS["student"])
        if permission not in allowed:
            logger.warning(
                "permission_denied",
                permission=permission,
                user_id=ctx.user_id,
                role=role,
            )
            raise AIError(
                ErrorCode.AI_FORBIDDEN,
                f"Permission denied: requires {permission}",
                {"required_permission": permission, "role": role},
            )


def require_permission(
    permission: str,
    guard: PermissionGuard,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """装饰器：声明端点所需权限.

    用法：
        @router.post("/chat")
        @require_permission(PERMISSION_AI_CHAT, guard)
        async def chat(...): ...
    """

    def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
        @wraps(func)
        async def wrapper(*args: Any, **kwargs: Any) -> Any:
            # 从 kwargs 提取 user_context（由依赖注入传入）
            ctx: UserContext | None = kwargs.get("user_context")
            if ctx is None:
                # 尝试从 args 查找
                for arg in args:
                    if isinstance(arg, UserContext):
                        ctx = arg
                        break
            if ctx is None:
                ctx = UserContext()
            guard.check(ctx, permission)
            return await func(*args, **kwargs)

        return wrapper

    return decorator
