"""
FastAPI 依赖注入：从 JWT 提取当前用户信息。

用法：
    @router.get("/protected")
    async def protected_endpoint(user: CurrentUser = Depends(get_current_user)):
        print(user.user_id, user.site_id)

    # 允许 pending 用户（受限令牌）访问
    @router.get("/apply")
    async def apply_endpoint(user: CurrentUser = Depends(get_current_user_or_limited)):
        if user.limited:
            ...  # 受限逻辑
"""

from dataclasses import dataclass, field

from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from jose import JWTError

from app.auth.jwt import decode_access_token

# Bearer token 提取器
_bearer_scheme = HTTPBearer(auto_error=True)


@dataclass(frozen=True)
class CurrentUser:
    """从 JWT 解析出的当前用户上下文。"""

    user_id: int
    site_id: int = 0
    roles: list[str] = field(default_factory=list)
    status: str = "pending"
    limited: bool = False


async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(_bearer_scheme),
) -> CurrentUser:
    """
    FastAPI 依赖：从 Authorization header 提取 JWT，验证后返回用户信息。

    要求完整令牌（非 limited），失败时抛出 401。
    """
    token = credentials.credentials
    try:
        payload = decode_access_token(token)
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的令牌",
            headers={"WWW-Authenticate": "Bearer"},
        )

    # 受限令牌不允许通过此依赖
    if payload.get("limited"):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="受限令牌无法访问此端点",
            headers={"WWW-Authenticate": "Bearer"},
        )

    user_id_raw = payload.get("sub")
    site_id = payload.get("site_id")

    if user_id_raw is None or site_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌缺少必要字段",
            headers={"WWW-Authenticate": "Bearer"},
        )

    try:
        user_id = int(user_id_raw)
    except (TypeError, ValueError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌中 user_id 格式无效",
            headers={"WWW-Authenticate": "Bearer"},
        )

    roles = payload.get("roles", [])

    return CurrentUser(
        user_id=user_id,
        site_id=site_id,
        roles=roles,
        status="approved",
        limited=False,
    )


async def get_current_user_or_limited(
    credentials: HTTPAuthorizationCredentials = Depends(_bearer_scheme),
) -> CurrentUser:
    """
    FastAPI 依赖：允许 pending 用户（受限令牌）访问。

    - 受限令牌（limited=True）：返回 CurrentUser(limited=True, roles=[], status="pending")
    - 完整令牌：正常返回 CurrentUser
    """
    token = credentials.credentials
    try:
        payload = decode_access_token(token)
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="无效的令牌",
            headers={"WWW-Authenticate": "Bearer"},
        )

    user_id_raw = payload.get("sub")
    if user_id_raw is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌缺少必要字段",
            headers={"WWW-Authenticate": "Bearer"},
        )

    try:
        user_id = int(user_id_raw)
    except (TypeError, ValueError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌中 user_id 格式无效",
            headers={"WWW-Authenticate": "Bearer"},
        )

    # 受限令牌：pending 用户
    if payload.get("limited"):
        return CurrentUser(
            user_id=user_id,
            site_id=0,
            roles=[],
            status="pending",
            limited=True,
        )

    # 完整令牌：要求 site_id
    site_id = payload.get("site_id")
    if site_id is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌缺少必要字段",
            headers={"WWW-Authenticate": "Bearer"},
        )

    roles = payload.get("roles", [])

    return CurrentUser(
        user_id=user_id,
        site_id=site_id,
        roles=roles,
        status="approved",
        limited=False,
    )
