import os
import random
import string
from configparser import ConfigParser, DuplicateSectionError, NoOptionError


def moonlight_config_dir() -> str:
    return os.path.join(
        os.path.expanduser("~"), ".config", "Moonlight Game Streaming Project"
    )


def moonlight_state_file() -> str:
    return os.path.join(moonlight_config_dir(), "Moonlight.conf")


def load_state() -> ConfigParser | None:
    try:
        with open(moonlight_state_file()) as file:
            config = ConfigParser()
            config.read_file(file)
            print(config.sections())
            return config
    except FileNotFoundError:
        print("Sunshine state file not found.")
        return None


# prepare the string for the config file
# this is how qt handles byte arrays
def convert_string_to_bytearray(data: str) -> str:
    byte_array = '"@ByteArray('
    byte_array += data.replace("\n", "\\n")
    byte_array += ')"'
    return byte_array


def convert_bytearray_to_string(byte_array: str) -> str:
    if byte_array.startswith('"@ByteArray(') and byte_array.endswith(')"'):
        byte_array = byte_array[12:-2]
        return byte_array.replace("\\n", "\n")


# this must be created before moonlight is first run
def init_state(certificate: str, key: str) -> None:
    print("Initializing moonlight state.")
    os.makedirs(moonlight_config_dir(), exist_ok=True)
    print("Initialized moonlight config directory.")

    print("Writing moonlight state file.")
    # write the initial bootstrap config file
    with open(moonlight_state_file(), "w") as file:
        config = ConfigParser()
        # bytearray ojbects are not supported by ConfigParser,
        # so we need to adjust them ourselves
        config.add_section("General")
        config.set("General", "certificate", convert_string_to_bytearray(certificate))
        config.set("General", "key", convert_string_to_bytearray(key))
        config.set("General", "latestsupportedversion-v1", "99.99.99.99")
        config.add_section("gcmapping")
        config.set("gcmapping", "size", "0")

        config.write(file)


def write_state(data: ConfigParser) -> bool:
    with open(moonlight_state_file(), "w") as file:
        data.write(file)


def add_sunshine_host_to_parser(
    config: ConfigParser, hostname: str, manual_host: str, certificate: str, uuid: str
) -> bool:
    try:
        config.add_section("hosts")
    except DuplicateSectionError:
        pass

    # amount of hosts
    try:
        no_hosts = int(config.get("hosts", "size"))
    except NoOptionError:
        no_hosts = 0

    new_host = no_hosts + 1

    config.set("hosts", f"{new_host}\srvcert", convert_string_to_bytearray(certificate))
    config.set("hosts", "size", str(new_host))
    config.set("hosts", f"{new_host}\\uuid", uuid)
    config.set("hosts", f"{new_host}\hostname", hostname)
    config.set("hosts", f"{new_host}\\nvidiasv", "false")
    config.set("hosts", f"{new_host}\customname", "false")
    config.set("hosts", f"{new_host}\manualaddress", manual_host)
    config.set("hosts", f"{new_host}\manualport", "47989")
    config.set("hosts", f"{new_host}\\remoteport", "0")
    config.set("hosts", f"{new_host}\\remoteaddress", "")
    config.set("hosts", f"{new_host}\localaddress", "")
    config.set("hosts", f"{new_host}\localport", "0")
    config.set("hosts", f"{new_host}\ipv6port", "0")
    config.set("hosts", f"{new_host}\ipv6address", "")
    config.set(
        "hosts", f"{new_host}\mac", convert_string_to_bytearray("\\xceop\\x8d\\xfc{")
    )
    add_app(config, "Desktop", new_host, 1, 881448767)
    add_app(config, "Low Res Desktop", new_host, 2, 303580669)
    add_app(config, "Steam Big Picture", new_host, 3, 1093255277)

    print(config.items("hosts"))
    return True


# set default apps for the host for now
# TODO: do this dynamically
def add_app(
    config: ConfigParser, name: str, host_id: int, app_id: int, app_no: int
) -> None:
    identifier = f"{host_id}\\apps\{app_id}\\"
    config.set("hosts", f"{identifier}appcollector", "false")
    config.set("hosts", f"{identifier}directlaunch", "false")
    config.set("hosts", f"{identifier}hdr", "false")
    config.set("hosts", f"{identifier}hidden", "false")
    config.set("hosts", f"{identifier}id", f"{app_no}")
    config.set("hosts", f"{identifier}name", f"{name}")


def get_moonlight_certificate() -> str:
    config = load_state()
    if config is None:
        raise FileNotFoundError("Moonlight state file not found.")
    certificate = config.get("General", "certificate")
    certificate = convert_bytearray_to_string(certificate)
    return certificate


def gen_pin() -> str:
    return "".join(random.choice(string.digits) for _ in range(4))


def add_sunshine_host(
    hostname: str, manual_host: str, certificate: str, uuid: str
) -> bool:
    config = load_state()
    if config is None:
        return False
    hostname = "test"
    add_sunshine_host_to_parser(config, hostname, manual_host, certificate, uuid)
    write_state(config)
    return True
