"""认证上下文提取.

ai 服务不直接校验 JWT（Gateway 负责），从 Gateway/BFF 透传的 header 提取用户上下文。

透传 header（Gateway 注入）：
  X-User-Id: 用户 ID
  X-User-Role: 用户角色
  X-School-Id: 学校 ID
  X-Data-Scope: 数据权限范围（JSON）
  X-Request-Id: 请求 ID
"""

from dataclasses import dataclass
from typing import Any

import structlog
from starlette.requests import Request

logger = structlog.get_logger()


@dataclass
class UserContext:
    """用户上下文（从 Gateway 透传 header 提取）."""

    user_id: str = ""
    role: str = ""
    school_id: str = ""
    data_scope: str = ""
    request_id: str = ""

    @property
    def is_authenticated(self) -> bool:
        return bool(self.user_id)

    @property
    def is_empty(self) -> bool:
        return not self.user_id and not self.role and not self.school_id


def extract_user_context(request: Request) -> UserContext:
    """从 HTTP 请求 header 提取用户上下文.

    全并行模式：开发期间无 Gateway，允许空上下文（标记为 dev 调用）。
    """
    return UserContext(
        user_id=request.headers.get("X-User-Id", ""),
        role=request.headers.get("X-User-Role", ""),
        school_id=request.headers.get("X-School-Id", ""),
        data_scope=request.headers.get("X-Data-Scope", ""),
        request_id=getattr(request.state, "request_id", "")
        or request.headers.get("X-Request-Id", ""),
    )


def extract_user_context_from_metadata(metadata: Any) -> UserContext:
    """从 gRPC metadata 提取用户上下文.

    gRPC metadata key 统一小写。
    """
    if metadata is None:
        return UserContext()

    def _get(key: str) -> str:
        if hasattr(metadata, "get"):
            val = metadata.get(key)
            return val if isinstance(val, str) else ""
        # grpc metadata 是 list[tuple[str, str]]
        try:
            for k, v in metadata:  # type: ignore[union-attr]
                if k.lower() == key.lower():
                    return str(v)
        except (TypeError, ValueError):
            pass
        return ""

    return UserContext(
        user_id=_get("x-user-id"),
        role=_get("x-user-role"),
        school_id=_get("x-school-id"),
        data_scope=_get("x-data-scope"),
        request_id=_get("x-request-id"),
    )
