from datetime import date, datetime from typing import Any, Optional import httpx from fastapi import APIRouter, HTTPException from app.config import settings from app.db import execute, fetch_all, fetch_one from app.services.briefing import collect_briefing_data, generate_daily_briefing, serialize_stats router = APIRouter(prefix="/api", tags=["api"]) def _stats_payload() -> dict[str, Any]: stats: dict[str, Any] = { "deals": 0, "clients": 0, "pending_approvals": 0, "pipeline_value": 0, } try: row = fetch_one("SELECT COUNT(*) AS c FROM deals") stats["deals"] = int(row["c"]) if row else 0 except Exception: pass try: row = fetch_one("SELECT COUNT(*) AS c FROM clients") stats["clients"] = int(row["c"]) if row else 0 except Exception: pass try: row = fetch_one("SELECT COUNT(*) AS c FROM agent_events WHERE status = 'needs_approval'") stats["pending_approvals"] = int(row["c"]) if row else 0 except Exception: pass try: row = fetch_one( "SELECT COALESCE(SUM(value), 0) AS total FROM deals WHERE stage NOT IN ('won', 'lost')" ) stats["pipeline_value"] = float(row["total"]) if row else 0 except Exception: pass return stats @router.get("/herman/briefing/stats") async def herman_briefing_stats(): """Live stats from DB — always fresh for dashboard panels.""" return {"ok": True, "stats": serialize_stats(collect_briefing_data()), "at": datetime.utcnow().isoformat()} @router.post("/herman/briefing") async def herman_briefing(): try: content, stats = await generate_daily_briefing() except Exception as exc: raise HTTPException(status_code=502, detail=str(exc)) from exc return {"ok": True, "content": content, "stats": stats, "generated_at": datetime.utcnow().isoformat()} @router.get("/herman/briefing/latest") async def herman_briefing_latest(): try: row = fetch_one( "SELECT id, content, generated_by, metadata, created_at FROM daily_briefings ORDER BY created_at DESC LIMIT 1" ) except Exception as exc: raise HTTPException(status_code=500, detail=str(exc)) from exc live_stats = serialize_stats(collect_briefing_data()) if not row: return {"ok": True, "content": None, "stats": live_stats} if row.get("created_at") and hasattr(row["created_at"], "isoformat"): row["created_at"] = row["created_at"].isoformat() return {"ok": True, **row, "stats": live_stats} @router.get("/events") async def list_events(limit: int = 50): limit = max(1, min(limit, 200)) try: rows = fetch_all( """ SELECT id, agent_name, event_type, title, body, status, created_at FROM agent_events ORDER BY created_at DESC LIMIT %s """, (limit,), ) except Exception as exc: raise HTTPException(status_code=500, detail=str(exc)) from exc for row in rows: if row.get("created_at"): row["created_at"] = row["created_at"].isoformat() return {"events": rows}