"""
WebSocket Messaging Module

This module provides utilities for sending messages to WebSocket clients,
including batched updates, serialization helpers, and typed message senders.
"""

import asyncio
import json
import logging


logger = logging.getLogger(__name__)


class BatchedUpdate:
    """
    Accumulator for batched game state updates.

    Instead of sending 14+ separate messages per tick,
    batch all updates into a single message.
    """

    def __init__(self):
        self._updates = {}

    def add(self, key: str, value: any) -> None:
        """Add an update to the batch"""
        self._updates[key] = value

    def to_dict(self) -> dict:
        """Convert to dictionary for sending"""
        if not self._updates:
            return None

        return {
            'type': 'batch_update',
            'updates': self._updates
        }

    def to_json(self) -> str:
        """Convert to JSON string"""
        data = self.to_dict()
        if data is None:
            return None
        return json.dumps(data, default=ComplexHandler)

    def is_empty(self) -> bool:
        """Check if batch is empty"""
        return len(self._updates) == 0


class serverClass:
    """
    Server state tracking class.
    """
    def __init__(self):
        self.ticks = 0


def ComplexHandler(Obj):
    """
    JSON serialization handler for complex objects.

    Args:
        Obj: Object to serialize

    Returns:
        Jsonable representation if available
    """
    if hasattr(Obj, 'jsonable'):
        return Obj.jsonable()
    elif isinstance(Obj, set):
        return list(Obj)
    elif hasattr(Obj, '__dict__'):
        return Obj.__dict__
    else:
        raise TypeError(f"Object of type {type(Obj).__name__} is not JSON serializable")


async def sendToUser(websocket, message):
    """
    Send message to user (O(1) lookup).

    Args:
        websocket: WebSocket connection with userID attribute
        message: Message string to send
    """
    from server.websocket_registry import USERS

    user = USERS.get(websocket.userID)
    if user:
        try:
            await user.send(message)
        except Exception as e:
            print(f"Error sending to {websocket.userID}: {e}")
            import traceback
            traceback.print_exc()
    else:
        print(f"Warning: No active websocket found for user {websocket.userID}")


async def sendEventMessage(websocket, m):
    """
    Send event message to websocket.

    Args:
        websocket: WebSocket connection
        m: Event object with __dict__ attribute
    """
    if websocket:
        await sendToUser(websocket, json.dumps(m.__dict__, default=ComplexHandler))


async def sendUserInfo(player, websocket):
    """
    Send player information to websocket.

    Args:
        player: Player object with __dict__ attribute
        websocket: WebSocket connection
    """
    if (websocket):
        await sendToUser(websocket, json.dumps(player.__dict__, default=ComplexHandler))


async def sendDict(websocket, obj):
    """
    Send dictionary object to websocket.

    Args:
        websocket: WebSocket connection
        obj: Object to serialize and send
    """
    if (websocket):
        await sendToUser(websocket, json.dumps(obj, default=ComplexHandler))
