# auto generated by update_py.py
import json
import subprocess
import time
import uuid
from concurrent.futures import ThreadPoolExecutor

from tlclient.linker.logger import Logger

from .websocket import WebsocketClient, WebsocketServer

RC_SERVER_NAME = 'rc_server'
RC_CLIENT_NAME = 'rc_client'


class RemoteExecRequester(WebsocketClient):

    def __init__(self):
        WebsocketClient.__init__(self, uuid.uuid4().hex[:8])

        self._rsp = None

    def send_cmd(self, cmd, cwd='/shared/runtime/'):
        data = {
            'requester': self._name,
            'cmd': cmd,
            'cwd': cwd,
        }
        self.send_data(data)
        self.log_info('to req exec (cmd){} (cwd){}'.format(cmd, cwd))
        while self._rsp is None:
            time.sleep(0.5)
        if isinstance(self._rsp, dict):
            output = self._rsp['output']
            return output
        else:
            return '[error] ' + self._rsp

    def _callback(self, data):
        self._rsp = json.loads(data)


class RemoteExecDispatcher(WebsocketServer):

    def __init__(self, hostname):
        logger = Logger.get_logger('rmt_dispatcher')
        WebsocketServer.__init__(self, RC_SERVER_NAME, logger=logger, hostname=hostname)

    def _callback(self, client_name, data):
        data = json.loads(data)
        requester = data['requester']

        # redirect rsp
        if client_name == RC_CLIENT_NAME:
            self.log_info('to redirect rsp (reqer){} (rsp){}'.format(requester, str(data)[:10]) + '...')
            self.send_data(data, client_name=requester)

        # redirect req
        else:
            self.log_info('to redirect req (reqer){} (data){}'.format(requester, str(data)[:10]) + '...')
            if not self.has_client(RC_CLIENT_NAME):
                self.send_data('remote cmd executor not connected!', client_name=requester)
                return
            self.send_data(data, client_name=RC_CLIENT_NAME)


class RemoteExecExecutor(WebsocketClient):

    def __init__(self, hostname):
        logger = Logger.get_logger('rmt_executor')
        WebsocketClient.__init__(self, RC_CLIENT_NAME, hostname=hostname, logger=logger)

        self._thread_pool = ThreadPoolExecutor()

    def _exec_and_send_back_output(self, requester, cmd, cwd):
        output = subprocess.getoutput('cd {} && {}'.format(cwd, cmd))
        self.log_info('execed (reqer){} (cmd){} (cwd){} (output){}'.format(requester, cmd, cwd, output[:10] + '...'))
        rsp = {
            'requester': requester,
            'cmd': cmd,
            'cwd': cwd,
            'output': output
        }
        self.send_data(rsp)

    def _callback(self, data):
        data = json.loads(data)
        requester = data['requester']
        cmd = data['cmd']
        cwd = data['cwd']

        self._thread_pool.submit(self._exec_and_send_back_output, requester, cmd, cwd)


if __name__ == '__main__':
    dispatcher = RemoteExecDispatcher()
    dispatcher.run()

    time.sleep(1)

    exec = RemoteExecExecutor('localhost')
    exec.run()

    time.sleep(0.5)

    requester = RemoteExecRequester()
    requester.run()
    rsp = requester.send_cmd('ls', '/shared/log')
    print('rsp:', rsp)
