"""Report and statistics endpoints.""" from __future__ import annotations from datetime import date, timedelta from fastapi import APIRouter, Query from app.api.deps import DbSession, Settings from app.api.schemas import SendReportRequest, TestNotificationRequest from app.services import notify as notify_service from app.services import report, scheduler, stats from app.timeutil import ensure_utc, local_date router = APIRouter(prefix="/api", tags=["reports"]) @router.get("/reports/daily") def daily( session: DbSession, settings: Settings, day: date | None = Query(default=None), rebuild: bool = Query(default=True), ) -> dict: target = day or local_date(settings.timezone) row, payload = report.get_or_build_daily(session, settings, target, rebuild=rebuild) return { "report": payload, "sent_at": ensure_utc(row.sent_at).isoformat() if row.sent_at else None, "telegram_preview": report.render_daily_telegram(payload, settings), } @router.post("/reports/daily/send") def send_daily(body: SendReportRequest, session: DbSession, settings: Settings) -> dict: target = body.report_date or local_date(settings.timezone) return report.send_daily(session, settings, target, force=body.force) @router.get("/reports/weekly") def weekly( session: DbSession, settings: Settings, end: date | None = Query(default=None), ) -> dict: target = end or local_date(settings.timezone) payload = report.build_weekly(session, settings, target) return {"report": payload, "telegram_preview": report.render_weekly_telegram(payload, settings)} @router.post("/reports/weekly/send") def send_weekly(session: DbSession, settings: Settings) -> dict: payload = report.build_weekly(session, settings, local_date(settings.timezone)) text = report.render_weekly_telegram(payload, settings) deliveries = notify_service.notify(settings, text, urgent=True) return {"sent": any(d.ok for d in deliveries), "deliveries": [d.as_dict() for d in deliveries]} @router.post("/reports/briefing/send") def send_briefing(session: DbSession, settings: Settings) -> dict: text = report.render_morning_briefing(session, settings) deliveries = notify_service.notify(settings, text, urgent=True) return { "sent": any(d.ok for d in deliveries), "deliveries": [d.as_dict() for d in deliveries], "text": text, } @router.get("/stats/summary") def summary(session: DbSession, settings: Settings, days: int = Query(default=30, ge=1, le=365)) -> dict: today = local_date(settings.timezone) return { "today": stats.day_metrics(session, settings, today), "streak": stats.streak(session, settings), "lifetime": stats.lifetime(session, settings), "average_7d": stats.averages(session, settings, 7, until=today), "range": stats.range_metrics(session, settings, today - timedelta(days=days - 1), today), "heatmap": stats.heatmap(session, settings, weeks=12), } @router.get("/stats/day") def day_stats(session: DbSession, settings: Settings, day: date | None = Query(default=None)) -> dict: return stats.day_metrics(session, settings, day or local_date(settings.timezone)) @router.post("/notifications/test") def test_notification(body: TestNotificationRequest, settings: Settings) -> dict: text = body.text or ( "🍅 Kadence\nNotifications are wired up correctly." ) deliveries = notify_service.notify(settings, text, urgent=True) return {"deliveries": [d.as_dict() for d in deliveries]} @router.get("/scheduler/jobs") def scheduler_jobs() -> dict: """What the background jobs are, and when they next fire.""" return {"jobs": scheduler.describe()}