from fastapi import APIRouter, Depends, Request from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from sqlalchemy.orm import selectinload from app.dependencies import get_db from app.limiter import limiter from app.models.user import User from app.models.entry import EntryType from app.schemas.entry import PublicUserStats router = APIRouter(prefix="/api/public", tags=["public"]) @router.get("/stats", response_model=list[PublicUserStats]) @limiter.limit("30/minute") async def public_stats(request: Request, db: AsyncSession = Depends(get_db)): users_result = await db.execute( select(User).options(selectinload(User.entries)) ) users = users_result.scalars().all() stats: list[PublicUserStats] = [] for user in users: entries = user.entries adds = [e for e in entries if e.entry_type == EntryType.add] removes = [e for e in entries if e.entry_type == EntryType.remove] total_add_shots = sum(e.amount_shots for e in adds) total_remove_shots = sum(e.amount_shots for e in removes) current_total = total_add_shots - total_remove_shots weighted_proof_sum = sum(e.proof * e.amount_shots for e in adds if e.proof is not None) proof_shot_total = sum(e.amount_shots for e in adds if e.proof is not None) estimated_proof = round(weighted_proof_sum / proof_shot_total, 1) if proof_shot_total > 0 else None bourbons = sorted({e.bourbon_name for e in adds if e.bourbon_name}, key=str.casefold) stats.append(PublicUserStats( display_name=user.display_name or user.email.split("@")[0], total_add_entries=len(adds), current_total_shots=round(current_total, 2), estimated_proof=estimated_proof, bottle_size=user.bottle_size, bourbons=bourbons, )) return stats