import sys
import threading
from io import BytesIO
from typing import Tuple

from clarabot_nano_common.utility.serialize import bytes2uint, msgpack_loads

from clarabot_nano.common.spawn.constants import SECRET_ARGUMENTS_PREAMBLE


def _read_secret_config(preamble, stream, arguments):  # TODO: limits
    try:
        preamble_state = 0
        while preamble_state < len(preamble):
            b = stream.read(1)
            if b[0] == preamble[preamble_state]:
                preamble_state += 1
            else:
                preamble_state = 0
        arguments_number = bytes2uint(stream.read(4))
        for _ in range(arguments_number):
            argument_len = bytes2uint(stream.read(4))
            bio = BytesIO()
            while argument_len > 0:
                part = stream.read(argument_len)
                bio.write(part)
                argument_len -= len(part)
            arguments.append(bio.getvalue())
            bio.close()
    except Exception:
        arguments.append(None)
        raise


def read_secret_arguments(preamble=SECRET_ARGUMENTS_PREAMBLE, stream=sys.stdin.buffer, timeout=5.0):
    arguments = []
    t = threading.Thread(target=_read_secret_config, args=(preamble, stream, arguments), daemon=True)
    t.start()
    t.join(timeout)
    if t.is_alive():
        raise Exception("Secret arguments not retrieved within time limit")
    elif not arguments or arguments[-1] is None:
        raise Exception("Failed to receive secret arguments properly")
    return arguments


def read_tight_python_arguments() -> Tuple[int, dict]:
    arguments = read_secret_arguments()
    if len(arguments) != 2:
        raise Exception("Incorrect number of arguments received")
    auth_data = msgpack_loads(arguments[1])
    if not isinstance(auth_data, dict):
        raise Exception("Invalid auth data argument received")
    return int(arguments[0].decode("ascii")), auth_data
