"""WebSocket API endpoints"""

import asyncio
import json
import logging
from datetime import datetime
from typing import Optional

from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query
from jose import jwt, JWTError

from app.core.config import settings
from app.core.websocket.manager import manager

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


async def authenticate_token(token: str) -> Optional[dict]:
    """Authenticate WebSocket connection via token"""
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        if payload.get("type") != "access":
            logger.warning(f"WebSocket auth failed: wrong token type")
            return None
        return payload
    except JWTError as e:
        logger.warning(f"WebSocket auth failed: {e}")
        return None


@router.websocket("/ws")
async def websocket_endpoint(
    websocket: WebSocket,
    token: str = Query(...),
):
    """WebSocket endpoint for real-time data"""
    logger.info(f"WebSocket connection attempt with token: {token[:20]}...")
    payload = await authenticate_token(token)
    if payload is None:
        logger.warning("WebSocket authentication failed, closing connection")
        await websocket.close(code=4001)
        return

    user_id = str(payload.get("sub"))
    await manager.connect(websocket, user_id)

    try:
        await websocket.send_json(
            {
                "type": "connection_established",
                "data": {
                    "connection_id": f"conn_{user_id}",
                    "server_version": settings.VERSION,
                    "heartbeat_interval": 30,
                    "supported_channels": [
                        "gpu_clusters",
                        "submarine_cables",
                        "ixp_nodes",
                        "alerts",
                        "dashboard",
                    ],
                },
            }
        )

        while True:
            try:
                data = await asyncio.wait_for(websocket.receive_json(), timeout=30)

                if data.get("type") == "heartbeat":
                    await websocket.send_json(
                        {
                            "type": "heartbeat",
                            "data": {"action": "pong", "timestamp": datetime.utcnow().isoformat()},
                        }
                    )
                elif data.get("type") == "subscribe":
                    channels = data.get("data", {}).get("channels", [])
                    await websocket.send_json(
                        {
                            "type": "subscription_confirmed",
                            "data": {"action": "subscribe", "channels": channels},
                        }
                    )
                elif data.get("type") == "control_frame":
                    await websocket.send_json(
                        {"type": "control_acknowledged", "data": {"received": True}}
                    )
                else:
                    await websocket.send_json({"type": "ack", "data": {"received": True}})

            except asyncio.TimeoutError:
                await websocket.send_json({"type": "heartbeat", "data": {"action": "ping"}})

    except WebSocketDisconnect:
        pass
    finally:
        manager.disconnect(websocket, user_id)
