"""
FastAPI dependency injection 共用元件。

最常用的是 `get_current_user`:
任何需要登入才能存取的 endpoint,只要在參數加 `current_user: User = Depends(get_current_user)`
就會自動驗證 Authorization header 的 access token、查資料庫拿到使用者物件。
"""

from typing import Annotated

from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.security import TokenError, decode_token
from app.database import get_db
from app.models.user import User


# HTTPBearer 會自動從請求 header 拿 "Authorization: Bearer <token>"
# auto_error=False 讓我們自己控制錯誤訊息(預設訊息英文,我們要繁中)
_bearer_scheme = HTTPBearer(auto_error=False)


async def get_current_user(
    credentials: Annotated[HTTPAuthorizationCredentials | None, Depends(_bearer_scheme)],
    db: Annotated[AsyncSession, Depends(get_db)],
) -> User:
    """從 Authorization header 解出當前使用者。

    流程:
      1. 確認有帶 Bearer token
      2. 驗證並解析 token,拿到 user_id
      3. 從資料庫撈 User
      4. 確認帳號還在(沒被軟刪、沒被停用)
      5. 都 OK,回傳 User 物件

    任何一步失敗都丟 401 Unauthorized,前端應該導回登入頁。
    """
    if credentials is None or not credentials.credentials:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="缺少授權 token",
            headers={"WWW-Authenticate": "Bearer"},
        )

    try:
        user_id = decode_token(credentials.credentials, expected_type="access")
    except TokenError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=str(e),
            headers={"WWW-Authenticate": "Bearer"},
        ) from e

    # 從資料庫撈使用者(過濾軟刪除)
    stmt = select(User).where(User.id == user_id, User.deleted_at.is_(None))
    result = await db.execute(stmt)
    user = result.scalar_one_or_none()

    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="使用者不存在或已刪除",
            headers={"WWW-Authenticate": "Bearer"},
        )

    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="帳號已停用,請聯絡管理員",
        )

    return user


# 型別別名:讓 endpoint 簽名乾淨一點
# 用法:`async def my_endpoint(current_user: CurrentUser): ...`
CurrentUser = Annotated[User, Depends(get_current_user)]
DBSession = Annotated[AsyncSession, Depends(get_db)]
