"""FastAPI 依赖注入：JWT 解析、当前用户、数据库会话"""
from typing import AsyncGenerator
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.database import AsyncSessionLocal
from app.config import settings
from app.core.models.user import User

bearer = HTTPBearer(auto_error=True)
optional_bearer = HTTPBearer(auto_error=False)


async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with AsyncSessionLocal() as session:
        try:
            yield session
        finally:
            await session.close()


def _decode_token(token: str) -> dict:
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=401, detail="Token 已过期")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=401, detail="Token 无效")


async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(bearer),
    db: AsyncSession = Depends(get_db),
) -> User:
    payload = _decode_token(credentials.credentials)
    user_id: int = payload.get("sub")
    if not user_id:
        raise HTTPException(status_code=401, detail="Token 载荷无效")

    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user or not user.is_active:
        raise HTTPException(status_code=401, detail="用户不存在或已禁用")
    return user


async def get_admin_user(current_user: User = Depends(get_current_user)) -> User:
    if current_user.role not in ("owner", "admin", "staff"):
        raise HTTPException(status_code=403, detail="权限不足")
    return current_user


# ── 前台商城顾客 JWT 认证 ────────────────────────────────────────

from app.core.models.customer import Customer


async def get_current_customer(
    credentials: HTTPAuthorizationCredentials = Depends(bearer),
    db: AsyncSession = Depends(get_db),
) -> Customer:
    """前台商城顾客 JWT 认证（用于 /store/* 路由）"""
    payload = _decode_token(credentials.credentials)
    if payload.get("role") not in (None, "customer"):
        raise HTTPException(status_code=403, detail="权限不足")
    customer_id = payload.get("sub")
    if not customer_id:
        raise HTTPException(status_code=401, detail="Token 载荷无效")
    result = await db.execute(select(Customer).where(Customer.id == int(customer_id)))
    customer = result.scalar_one_or_none()
    if not customer or not customer.is_active:
        raise HTTPException(status_code=401, detail="用户不存在或已禁用")
    return customer


async def get_optional_customer(
    credentials: HTTPAuthorizationCredentials | None = Depends(optional_bearer),
    db: AsyncSession = Depends(get_db),
) -> Customer | None:
    """可选顾客认证：无 token 时返回 None；有 token 但无效时仍返回 401。"""
    if credentials is None:
        return None
    payload = _decode_token(credentials.credentials)
    if payload.get("role") not in (None, "customer"):
        raise HTTPException(status_code=403, detail="权限不足")
    customer_id = payload.get("sub")
    if not customer_id:
        raise HTTPException(status_code=401, detail="Token 载荷无效")
    result = await db.execute(select(Customer).where(Customer.id == int(customer_id)))
    customer = result.scalar_one_or_none()
    if not customer or not customer.is_active:
        raise HTTPException(status_code=401, detail="用户不存在或已禁用")
    return customer
