"""权限点常量与 FastAPI Depends 权限校验（对齐 02-architecture-design.md §6.1）.

Python 服务无 NestJS 装饰器，权限校验用 FastAPI Depends 等价物
（coord-cross-review.md §5.3 已仲裁认可）.

DataScope 6 级：SELF / CLASS / GRADE / SCHOOL / DISTRICT / ALL
iam.GetEffectiveDataScope gRPC 解析用户可见数据范围（P4 补全，未就绪时降级兜底）.
"""

from dataclasses import dataclass, field
from enum import StrEnum

from fastapi import Header


class Permission:
    """权限点常量（与 iam 权限点对齐）."""

    ANALYTICS_CLASS_READ = "analytics:class:read"
    ANALYTICS_STUDENT_READ = "analytics:student:read"
    ANALYTICS_TEACHER_DASHBOARD = "analytics:teacher:dashboard"
    ANALYTICS_STUDENT_DASHBOARD = "analytics:student:dashboard"
    ANALYTICS_PARENT_DASHBOARD = "analytics:parent:dashboard"
    ANALYTICS_ADMIN_DASHBOARD = "analytics:admin:dashboard"
    ANALYTICS_WARNING_READ = "analytics:warning:read"


class DataScopeLevel(StrEnum):
    """DataScope 6 级."""

    SELF = "SELF"
    CLASS = "CLASS"
    GRADE = "GRADE"
    SCHOOL = "SCHOOL"
    DISTRICT = "DISTRICT"
    ALL = "ALL"


# 角色 → 默认 DataScope 降级映射（iam gRPC 不可达时使用）
_ROLE_DATASCOPE_FALLBACK: dict[str, DataScopeLevel] = {
    "admin": DataScopeLevel.ALL,
    "school_admin": DataScopeLevel.SCHOOL,
    "teacher": DataScopeLevel.CLASS,
    "student": DataScopeLevel.SELF,
    "parent": DataScopeLevel.SELF,
}


@dataclass
class UserContext:
    """用户上下文（从请求头提取）."""

    user_id: str
    roles: list[str] = field(default_factory=list)


@dataclass
class DataScope:
    """数据范围（查询层注入 WHERE）."""

    level: DataScopeLevel
    scope_ids: list[str] = field(default_factory=list)  # class_id 列表 / grade_id 列表
    school_id: str = ""
    degraded: bool = False  # iam 不可达时降级标记
    degraded_reason: str = ""


async def get_user_context(
    x_user_id: str = Header("", alias="x-user-id"),
    x_user_roles: str = Header("", alias="x-user-roles"),
) -> UserContext:
    """从请求头提取用户上下文（FastAPI Depends）.

    Gateway 注入 x-user-id / x-user-roles 头（JWT 校验后）.
    """
    roles = [r.strip() for r in x_user_roles.split(",") if r.strip()] if x_user_roles else []
    return UserContext(user_id=x_user_id, roles=roles)


def get_datascope_fallback(user: UserContext) -> DataScope:
    """按角色映射默认 DataScope（降级兜底，iam gRPC 不可达时使用）."""
    for role in user.roles:
        if role in _ROLE_DATASCOPE_FALLBACK:
            level = _ROLE_DATASCOPE_FALLBACK[role]
            return DataScope(
                level=level,
                degraded=True,
                degraded_reason="iam_grpc_unavailable_fallback",
            )
    # 默认最保守范围
    return DataScope(
        level=DataScopeLevel.SELF,
        degraded=True,
        degraded_reason="unknown_role_fallback_self",
    )


def build_datascope_where(
    scope: DataScope,
    student_col: str = "student_id",
) -> tuple[str, dict[str, str]]:
    """构建 DataScope WHERE 子句（注入到 ClickHouse 查询）.

    返回 (where_clause, parameters).
    """
    params: dict[str, str] = {}
    if scope.level == DataScopeLevel.ALL:
        return "", params
    if scope.level == DataScopeLevel.SELF:
        # SELF 范围需要 user_id，由调用方注入
        return "", params
    if scope.level == DataScopeLevel.CLASS and scope.scope_ids:
        # 班级范围：class_id IN (...)
        placeholders = []
        for i, cid in enumerate(scope.scope_ids):
            key = f"class_id_{i}"
            params[key] = cid
            placeholders.append(f"{{{key}:String}}")
        return f"class_id IN ({', '.join(placeholders)})", params
    if scope.level == DataScopeLevel.SCHOOL:
        # 学校范围：不做过滤（单租户场景下等价 ALL）
        return "", params
    # GRADE / DISTRICT 暂按 ALL 处理（P6 细化）
    return "", params
