"""API balance / consumption endpoints.""" from __future__ import annotations from fastapi import APIRouter, Depends from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import require_readonly, require_support from app.database import get_db from app.models.balance import BalanceSnapshot from app.models.user import User from app.schemas import BalanceOut from app.services import balance as balance_service router = APIRouter(prefix="/api/balance", tags=["balance"]) async def _latest_snapshot(db: AsyncSession, provider: str) -> BalanceSnapshot | None: """Prefer the newest successful snapshot; fall back to latest error row.""" res = await db.execute( select(BalanceSnapshot) .where(BalanceSnapshot.provider == provider) .where(BalanceSnapshot.error.is_(None)) .where(BalanceSnapshot.remaining.is_not(None)) .order_by(BalanceSnapshot.created_at.desc()) .limit(1) ) snap = res.scalar_one_or_none() if snap: return snap res = await db.execute( select(BalanceSnapshot) .where(BalanceSnapshot.provider == provider) .order_by(BalanceSnapshot.created_at.desc()) .limit(1) ) return res.scalar_one_or_none() @router.get("", response_model=list[BalanceOut]) async def latest_balances(db: AsyncSession = Depends(get_db), _: User = Depends(require_readonly)): """Latest snapshot per provider.""" out: list[BalanceSnapshot] = [] for provider in ("openrouter", "deepseek"): snap = await _latest_snapshot(db, provider) if snap: out.append(snap) return out @router.post("/refresh", response_model=list[BalanceOut]) async def refresh_balances(db: AsyncSession = Depends(get_db), _: User = Depends(require_support)): await balance_service.poll_once() return await latest_balances(db) # type: ignore[arg-type]