"""GET /api/examples and /api/examples/summary. `/examples` returns the raw FireExample rows (filterable by country, fi_status, with a sane limit). `/examples/summary` is the aggregated view the UI / simulator overlay actually wants. """ from __future__ import annotations from typing import Annotated from fastapi import APIRouter, Depends, Query from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from fire_planner.api.dependencies import get_session from fire_planner.db import FireExample from fire_planner.examples.models import Summary from fire_planner.examples.service import summary_for_country router = APIRouter(prefix="/examples", tags=["examples"]) @router.get("") async def list_examples( country: Annotated[str | None, Query()] = None, fi_status: Annotated[str | None, Query()] = None, limit: Annotated[int, Query(ge=1, le=500)] = 100, session: AsyncSession = Depends(get_session), ) -> list[dict[str, object]]: stmt = select(FireExample) if country is not None: stmt = stmt.where(FireExample.country == country) if fi_status is not None: stmt = stmt.where(FireExample.fi_status == fi_status) stmt = stmt.order_by(FireExample.post_date.desc()).limit(limit) rows = (await session.execute(stmt)).scalars().all() return [ { "reddit_id": r.reddit_id, "source_sub": r.source_sub, "post_url": r.post_url, "post_date": r.post_date.isoformat(), "country": r.country, "city": r.city, "portfolio_gbp": float(r.portfolio_gbp) if r.portfolio_gbp else None, "annual_exp_gbp": float(r.annual_exp_gbp) if r.annual_exp_gbp else None, "age": r.age, "family_size": r.family_size, "fi_status": r.fi_status, "is_retired": r.is_retired, } for r in rows ] @router.get("/summary", response_model=Summary) async def get_summary( country: Annotated[str, Query(min_length=2)], session: AsyncSession = Depends(get_session), ) -> Summary: return await summary_for_country(session, country)