    user = await db.get(User, int(payload["sub"]))
    if not user or not user.is_active:
        raise HTTPException(status_code=401, detail="User not found or inactive")
    return user


async def get_current_user_csrf(user: "User" = Depends(get_current_user),
                                _: None = Depends(require_csrf)) -> "User":
    """Combined dependency: authenticate first (401 for anonymous), then CSRF (403).

    Used by state-changing endpoints in routers where CSRF must be enforced but
    anonymous callers should still receive the semantically-correct 401.
    """
    return user


async def get_optional_user(request: Request, db: AsyncSession = Depends(get_db)):
    from app.models import User
    token = request.cookies.get(settings.SESSION_COOKIE_NAME)
    authz = request.headers.get("authorization", "")
    if authz.lower().startswith("bearer "):
        token = authz[7:]
    if not token:
        return None
    payload = decode_token(token)
    if not payload:
        return None
    return await db.get(User, int(payload["sub"]))


def require_csrf(request: Request, x_csrf_token: Optional[str] = Header(None)) -> None:
    """Double-submit cookie CSRF check for state-changing API calls from the browser."""
    if request.method in ("GET", "HEAD", "OPTIONS"):
        return
    # Exempt token-based API access (Authorization header present) and OAuth callback.
    if request.headers.get("authorization", "").lower().startswith("bearer "):
        return
    if request.url.path.startswith("/auth/google/callback"):
        return
    cookie = request.cookies.get(settings.CSRF_COOKIE_NAME, "")
    if not cookie or not x_csrf_token or cookie != x_csrf_token:
        raise HTTPException(status_code=403, detail="CSRF token missing or invalid")


async def get_current_user_csrf(user: "User" = Depends(get_current_user),
                                _: None = Depends(require_csrf)) -> "User":
    """Combined dependency: authenticate first (401 for anonymous), then CSRF (403).

    Used by state-changing endpoints in routers where CSRF must be enforced but
    anonymous callers should still receive the semantically-correct 401.
    """
    return user


def rate_limit_user(request: Request, user=Depends(get_current_user)):
    key = f"u:{user.id}:{request.url.path.split('?')[0]}"
    allowed, remaining = rate_limit(key)
