"""
Phone call event receiver + WebSocket broadcaster.

The Grandstream UCM sends a simple HTTP GET to /api/phone/call-event
with caller ID and extension details. We broadcast that to all connected
WebSocket clients (manager dashboard Phone page).

The call-event endpoint is intentionally unauthenticated so the UCM device
(which has no JWT) can POST to it directly on the local LAN.
"""

import asyncio
import json
import logging

from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query

router = APIRouter()
logger = logging.getLogger(__name__)

# In-memory list of active WebSocket connections to the Phone page.
_connections: list[WebSocket] = []


@router.websocket("/ws")
async def phone_ws(websocket: WebSocket):
    await websocket.accept()
    _connections.append(websocket)
    logger.debug("phone_ws: client connected (%d total)", len(_connections))
    try:
        # Keep the connection alive; client drives nothing, server pushes events.
        while True:
            await asyncio.sleep(25)
            await websocket.send_text(json.dumps({"type": "ping"}))
    except (WebSocketDisconnect, Exception):
        pass
    finally:
        _connections.remove(websocket)
        logger.debug("phone_ws: client disconnected (%d total)", len(_connections))


@router.get("/call-event")
async def call_event(
    caller: str = Query(..., description="Caller ID number from UCM"),
    ext: str = Query("", description="Dialled extension"),
):
    """
    Called by the Grandstream UCM Action URL on every incoming call.
    Example: GET /api/phone/call-event?caller=2106001234&ext=100
    """
    payload = json.dumps({"type": "incoming_call", "caller": caller, "ext": ext})
    dead = []
    for ws in list(_connections):
        try:
            await ws.send_text(payload)
        except Exception:
            dead.append(ws)
    for ws in dead:
        try:
            _connections.remove(ws)
        except ValueError:
            pass
    logger.info("phone call-event: caller=%s ext=%s  (notified %d clients)", caller, ext, len(_connections) - len(dead))
    return {"status": "ok", "notified": len(_connections) - len(dead)}
