"""
Gestor de conexiones WebSocket.
Mantiene un registro de qué clientes están conectados y a qué zona pertenecen.
El simulador llama a broadcast_zona() para empujar eventos sin polling.
"""
import json
from collections import defaultdict

from fastapi import WebSocket


class WebSocketManager:
    def __init__(self):
        # zona_id -> lista de WebSockets activos
        self._conexiones: dict[str, list[WebSocket]] = defaultdict(list)

    async def conectar(self, websocket: WebSocket, zona_id: str) -> None:
        await websocket.accept()
        self._conexiones[zona_id].append(websocket)

    def desconectar(self, websocket: WebSocket, zona_id: str) -> None:
        conexiones = self._conexiones.get(zona_id, [])
        if websocket in conexiones:
            conexiones.remove(websocket)

    async def broadcast_zona(self, zona_id: str, payload: dict) -> None:
        """Envía un mensaje a todos los clientes de una zona."""
        mensaje = json.dumps(payload, ensure_ascii=False)
        muertos: list[WebSocket] = []

        for ws in self._conexiones.get(zona_id, []):
            try:
                await ws.send_text(mensaje)
            except Exception:
                muertos.append(ws)

        for ws in muertos:
            self.desconectar(ws, zona_id)

    async def broadcast_ruta(self, ruta_id: str, payload: dict) -> None:
        """
        Envía a TODAS las zonas de una ruta.
        El filtro real de privacidad está en el backend (RBAC del endpoint REST).
        Aquí simplemente distribuimos por zona registrada.
        """
        for zona_id, conexiones in self._conexiones.items():
            if conexiones:
                await self.broadcast_zona(zona_id, payload)

    def zonas_activas(self) -> list[str]:
        return [z for z, ws in self._conexiones.items() if ws]


# Singleton global compartido por el simulador y el router de WebSocket
ws_manager = WebSocketManager()
