import asyncio, json, requests, websockets
from .message import Message, Channel

class Bot:
    def __init__(self, token: str, api_base="https://api.maxrealm.cc"):
        self.token = token
        self.api_base = api_base.rstrip("/")
        self.events = {}
        self.ws = None
        self.bot_id = None

    def event(self, func):
        self.events[func.__name__] = func
        return func

    async def _heartbeat(self, interval_ms: int):
        while True:
            await asyncio.sleep(interval_ms / 1000)
            await self.ws.send(json.dumps({"op": "HEARTBEAT", "d": int(asyncio.get_event_loop().time()*1000)}))

    def _headers(self):
        return {"Authorization": f"Bearer {self.token}", "Content-Type": "application/json"}

    def _bootstrap(self):
        res = requests.get(f"{self.api_base}/api/bot/bootstrap", headers=self._headers())
        return res.json()

    async def _connect(self):
        gw_url = self._bootstrap().get("gatewayUrl")
        async with websockets.connect(gw_url) as ws:
            self.ws = ws
            hello = json.loads(await ws.recv())
            hb_interval = hello["d"]["heartbeat_interval"]
            asyncio.create_task(self._heartbeat(hb_interval))
            await ws.send(json.dumps({"op": "IDENTIFY", "d": {"token": self.token}}))

            async for raw in ws:
                payload = json.loads(raw)
                if payload.get("t") == "MESSAGE_CREATE":
                    data = payload.get("d")
                    msg = Message.from_data(data, self)
                    if "on_message" in self.events:
                        await self.events["on_message"](msg)
                elif payload.get("op") == "READY":
                    self.bot_id = str(payload.get("d")["user"]["id"])
                    if "on_ready" in self.events:
                        await self.events["on_ready"]()

    def run(self):
        asyncio.run(self._connect())