import os
import websockets
import asyncio
import concurrent.futures
from datetime import datetime
from typing import Tuple
from contextlib import AsyncContextDecorator

DEFAULT_PELINK_SERVER = "ws://localhost:7892"
DEFAULT_PELINK_SERVER = "wss://pelink.kitsune.cat/ws"
SECRET_KEY = os.environ.get('PELINK_KEY', "pelink69vjOE6tHfKSwUwgVMx8eDEvUw")


class ConnectionError(Exception):
    pass


class ConnectionSetupError(Exception):
    pass


class PelinkClient(AsyncContextDecorator):
    """
    EXAMPLE:

    async with PelinkClient("club") as pc:
        cmd, payload = await pc.wait_command()
        print("Command:", cmd, 'data:', payload)
    """
    def __init__(self, club):
        self.club = club
        self.id = None
        self.ws = None # WebSocket

    def get_server_url(self) -> str:
        """
        Returns "ws://{host}:{port}"
        """
        return os.environ.get("PELINK_SERVER", DEFAULT_PELINK_SERVER)

    async def ws_salude(self):
        await self.ws.send(f"hola:{SECRET_KEY}:{self.club}") 
        msg = await self.ws.recv()
        if not msg.startswith('welcome'):
            raise ValueError("Not welcomed")
        self.id = msg.split(':', 1)[-1]
        return True

    async def connect(self):
        print("[Pelink] client awake, looking for server")
        try:
            self.ws = await websockets.connect(self.get_server_url())
        except OSError as e:
            raise ConnectionSetupError(e)
        await self.ws_salude()
        print("[Pelink] client connected :)")

    async def wait_command(self) -> Tuple[str, str]:
        """
        Returns ("command", "payload")
        """
        msg = await self.ws.recv()
        if ':' not in msg:
            raise ValueError("Invalid data recieved")
        cmd, payload = msg.split(':', 1)
        return (cmd, payload)

    async def send_command(self, cmd, payload) -> Tuple[str, str]:
        """
        Returns ("command", "payload")
        """
        await self.ws.send(f"{cmd}:{payload}")
        return (cmd, payload)

    async def __aenter__(self):
        await self.connect()
        return self

    async def __aexit__(self, *args, **kwargs):
        if self.ws:
            await self.ws.close()
