from lchttp.json import json_loads
import logging
from typing import TypedDict
from channels.consumer import AsyncConsumer

logger = logging.getLogger(__name__)


class MessageEvent(TypedDict):
    type: str
    room: str
    body: str


class ClarionConsumer(AsyncConsumer):
    """
    ClarionConsumer to be subclassed by other consumers.
    """

    async def connect(self) -> None:
        """
        Connect method to be subclassed by consumers.
        """
        pass

    async def disconnect(self, event: int) -> None:
        """
        Disconnect method to be subclassed by consumers.
        """
        pass

    async def receive(self, clarion_message: MessageEvent) -> None:
        """
        Receive method to be subclassed by consumers.
        """
        pass

    async def clarion_connect(self, event: int) -> None:
        """
        Initialize connection.
        """
        await self.connect()

    async def clarion_disconnect(self, event: int) -> None:
        """
        Initialize disconnection.
        """
        await self.disconnect(0)

    async def clarion_receive(self, event: MessageEvent) -> None:
        """
        Handle an incoming message from Clarion and
        forward it to Channels.
        """
        try:
            event["body"] = json_loads(event["body"])
        except (KeyError, ValueError):
            pass

        await self.receive(event)

    async def clarion_send(self, room: str, body: str) -> None:
        """
        Handle an incoming message from Channels: forward it to Clarion.
        """
        await self.send({"type": "clarion.send", "room": room, "body": body})
