import asyncio
import json
import logging

import socketio


class GSCNodeFunctionReceiverSocket:
    @classmethod
    async def create(cls, sio, gsdbs, oncnodefunction):
        self = GSCNodeFunctionReceiverSocket()
        self.sio = sio
        self.gsdbs = gsdbs
        self.oncnodefunction = oncnodefunction
        self._logger = logging.getLogger(__name__)

        @self.sio.event
        async def connect():
            self._logger.info('oncnodefunction connected')

        @self.sio.event
        async def oncnodefunction(id, msg):
            self.oncnodefunction(self.gsdbs, id, msg)

        connectURL = ""

        if "localhost" in self.gsdbs.credentials["signalserver"]:
            connectURL = f'{self.gsdbs.credentials["signalserver"]}:{str(self.gsdbs.credentials["signalport"])}'
        else:
            connectURL = self.gsdbs.credentials["signalserver"]

        await self.sio.connect(
            f'{connectURL}?gssession={self.gsdbs.cookiejar.get("session")}.{self.gsdbs.cookiejar.get("signature")}{self.gsdbs.credentials["cnode"]}&global=true')
        await self.sio.wait()

    def sendcnodefunctionResult(self, id, msg):
        self.sio.emit("answer", id, msg)


class GSCNodeFunctionReceiver:
    def __init__(self, gsdbs, oncnodefunction):
        self.sio = socketio.AsyncClient()
        self.gsdbs = gsdbs
        self.oncnodefunction = oncnodefunction

    def startSocket(self):
        loop = asyncio.get_event_loop()
        loop.run_until_complete(GSCNodeFunctionReceiverSocket.create(self.sio, self.gsdbs, self.oncnodefunction))
        # asyncio.run(GSCNodeFunctionReceiverSocket.create(self.sio, self.gsdbs, self.oncnodefunction))

    async def sendcnodefunctionanswer(self, id, msg):
        await self.sio.emit("answer", {"id": id, "message": json.dumps(msg)})


class GSCNodeFunctionCallerSocket:
    @classmethod
    async def create(cls, sio, gsdbs, oncnodefunctionanswer):
        self = GSCNodeFunctionCallerSocket()
        self.sio = sio
        self.gsdbs = gsdbs
        self._logger = logging.getLogger(__name__)
        self.oncnodefunctionanswer = oncnodefunctionanswer

        @self.sio.event
        async def connect():
            self._logger.info('oncnodefunction connected')

        @self.sio.event
        async def answer(id, message):
            self.oncnodefunctionanswer(self.gsdbs, message)

        connectURL = ""

        if "localhost" in self.gsdbs.credentials["signalserver"]:
            connectURL = f'{self.gsdbs.credentials["signalserver"]}:{str(self.gsdbs.credentials["signalport"])}'
        else:
            connectURL = self.gsdbs.credentials["signalserver"]

        await self.sio.connect(
            f'{connectURL}?gssession={self.gsdbs.cookiejar.get("session")}.{self.gsdbs.cookiejar.get("signature")}{self.gsdbs.credentials["cnode"]}&caller=true')
        await self.sio.wait()


class GSCNodeFunctionCaller:
    def __init__(self, gsdbs, oncnodefunctionanswer):
        self.sio = socketio.AsyncClient()
        self.gsdbs = gsdbs
        self.oncnodefunctionanswer = oncnodefunctionanswer

    def startSocket(self):
        asyncio.run()
        loop = asyncio.get_event_loop()
        loop.run_until_complete(
            GSCNodeFunctionCallerSocket.create(self.sio, self.gsdbs, self.oncnodefunctionanswer))

    async def sendcnodefunction(self, target, msg):
        await self.sio.emit("oncnodefunction", {"target": target, "message": json.dumps(msg)})
