from __future__ import annotations

import json
from pathlib import Path
from typing import Any, Dict, Set

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import JSONResponse
import uvicorn

from agix.qualia.constants import QUALIA_WS_PATH


class EmotionalState(dict):
    """Representa el estado emocional compartido con dimensiones PAD."""

    def __init__(self, *args: Any, **kwargs: Any) -> None:  # type: ignore[override]
        """Inicializa el estado asegurando la presencia del vector PAD."""
        super().__init__(*args, **kwargs)
        self._ensure_pad()

    def _ensure_pad(self) -> None:
        self.setdefault(
            "pad",
            {"pleasure": 0.0, "arousal": 0.0, "dominance": 0.0},
        )

    def update(self, *args: Any, **kwargs: Any) -> None:  # type: ignore[override]
        """Actualiza el estado, separando el bloque PAD si existe."""
        pad = None
        if args:
            arg = dict(args[0])
            pad = arg.pop("pad", None)
            super().update(arg)
        if kwargs:
            pad = kwargs.pop("pad", pad)
            super().update(kwargs)
        if pad:
            self["pad"].update(pad)
        self._ensure_pad()

    def clear(self) -> None:  # type: ignore[override]
        """Resetea el estado dejando el vector PAD por defecto."""
        super().clear()
        self._ensure_pad()


def _state_path() -> Path:
    return Path(__file__).with_name("emotional_state.json")


EMOTIONAL_STATE = EmotionalState()


class EmotionHub:
    """Gestiona y sincroniza el estado emocional del sistema."""

    def __init__(self) -> None:
        self.state = EMOTIONAL_STATE
        self.app = FastAPI(title="Emotion Hub")
        self.clients: Set[WebSocket] = set()
        self._load_state()
        self._setup_routes()

    # ------------------------------------------------------------------
    def _load_state(self) -> None:
        path = _state_path()
        if path.exists():
            try:
                data = json.loads(path.read_text())
                if isinstance(data, dict):
                    self.state.update(data)
            except Exception:
                pass

    def _save_state(self) -> None:
        path = _state_path()
        path.write_text(json.dumps(self.state))

    # ------------------------------------------------------------------
    def _setup_routes(self) -> None:
        @self.app.get("/qualia")
        def _get_state():
            state = dict(self.state)
            pad = state.pop("pad", self.state["pad"])
            return JSONResponse({"state": state, "pad": pad})

        @self.app.post("/qualia")
        def _set_state(payload: Dict[str, Any]):
            self.state.update(payload)
            self._save_state()
            state = dict(self.state)
            pad = state.pop("pad", self.state["pad"])
            return JSONResponse({"status": "ok", "state": state, "pad": pad})

        @self.app.post("/qualia/sync")
        def _sync_state(payload: Dict[str, Any]):
            self.state.clear()
            self.state.update(payload)
            self._save_state()
            state = dict(self.state)
            pad = state.pop("pad", self.state["pad"])
            return JSONResponse({"status": "ok", "state": state, "pad": pad})

        @self.app.websocket(QUALIA_WS_PATH)
        async def _ws(ws: WebSocket):
            await ws.accept()
            self.clients.add(ws)
            state = dict(self.state)
            pad = state.pop("pad", self.state["pad"])
            await ws.send_json({"state": state, "pad": pad})
            try:
                while True:
                    data = await ws.receive_json()
                    if isinstance(data, dict):
                        pad = data.pop("pad", None)
                        self.state.update(data)
                        if pad:
                            self.state.update({"pad": pad})
                        self._save_state()
                        current = dict(self.state)
                        p = current.pop("pad", self.state["pad"])
                        for client in list(self.clients):
                            await client.send_json({"state": current, "pad": p})
            except WebSocketDisconnect:
                self.clients.remove(ws)

    # ------------------------------------------------------------------
    def run(self, host: str = "127.0.0.1", port: int = 9010) -> None:
        """Arranca el servidor HTTP de EmotionHub."""
        uvicorn.run(self.app, host=host, port=port)
