from fastapi import APIRouter, Depends, Query, HTTPException from sqlalchemy import text from sqlalchemy.ext.asyncio import AsyncSession from core.database import get_session router = APIRouter() @router.get("") async def list_alarms( site_id: str = Query(...), state: str = Query("active", description="active | resolved | acknowledged | all"), limit: int = Query(50, ge=1, le=200), session: AsyncSession = Depends(get_session), ): where = "WHERE site_id = :site_id" if state != "all": where += " AND state = :state" result = await session.execute(text(f""" SELECT id, sensor_id, site_id, room_id, rack_id, severity, message, state, triggered_at, acknowledged_at, resolved_at FROM alarms {where} ORDER BY triggered_at DESC LIMIT :limit """), {"site_id": site_id, "state": state, "limit": limit}) return [dict(r) for r in result.mappings().all()] @router.post("/{alarm_id}/acknowledge") async def acknowledge_alarm( alarm_id: int, session: AsyncSession = Depends(get_session), ): result = await session.execute(text(""" UPDATE alarms SET state = 'acknowledged', acknowledged_at = NOW() WHERE id = :id AND state = 'active' RETURNING id """), {"id": alarm_id}) await session.commit() if not result.fetchone(): raise HTTPException(status_code=404, detail="Alarm not found or not active") return {"id": alarm_id, "state": "acknowledged"} @router.post("/{alarm_id}/resolve") async def resolve_alarm( alarm_id: int, session: AsyncSession = Depends(get_session), ): result = await session.execute(text(""" UPDATE alarms SET state = 'resolved', resolved_at = NOW() WHERE id = :id AND state IN ('active', 'acknowledged') RETURNING id """), {"id": alarm_id}) await session.commit() if not result.fetchone(): raise HTTPException(status_code=404, detail="Alarm not found or already resolved") return {"id": alarm_id, "state": "resolved"} @router.get("/stats") async def alarm_stats( site_id: str = Query(...), session: AsyncSession = Depends(get_session), ): result = await session.execute(text(""" SELECT COUNT(*) FILTER (WHERE state = 'active') AS active, COUNT(*) FILTER (WHERE state = 'acknowledged') AS acknowledged, COUNT(*) FILTER (WHERE state = 'resolved') AS resolved, COUNT(*) FILTER (WHERE state = 'active' AND severity = 'critical') AS critical, COUNT(*) FILTER (WHERE state = 'active' AND severity = 'warning') AS warning FROM alarms WHERE site_id = :site_id """), {"site_id": site_id}) row = result.mappings().one() return {k: int(v) for k, v in row.items()}