import argparse
import base64
import json
import socket

from .run import MoonlightPairing
from .state import add_sunshine_host, gen_pin, get_moonlight_certificate
from .uri import parse_moonlight_uri


def send_join_request(host: str, port: int, cert: str) -> bool:
    tries = 0
    max_tries = 3
    response = False
    for tries in range(max_tries):
        response = send_join_request_api(host, port)
        if response:
            return response
    if send_join_request_native(host, port, cert):
        return True

    return False


# This is the preferred join method, but sunshines pin mechanism
# seems to be somewhat brittle in repeated testing, retry then fallback to native
def send_join_request_api(host: str, port: int) -> bool:
    moonlight = MoonlightPairing()
    # is_paired = moonlight.check(host)
    is_paired = False
    if is_paired:
        print(f"Moonlight is already paired with this host: {host}")
        return True
    pin = gen_pin()
    moonlight.init_pairing(host, pin)
    moonlight.wait_until_started()

    with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
        s.connect((host, port))
        json_body = {"type": "api", "pin": pin}
        json_body = json.dumps(json_body)
        request = (
            f"POST / HTTP/1.1\r\n"
            f"Content-Type: application/json\r\n"
            f"Content-Length: {len(json_body)}\r\n"
            f"Connection: close\r\n\r\n"
            f"{json_body}"
        )
        try:
            s.sendall(request.encode("utf-8"))
            response = s.recv(16384).decode("utf-8")
            print(response)
            body = response.split("\n")[-1]
            print(body)
            moonlight.terminate()
            return True
        except Exception as e:
            print(f"An error occurred: {e}")
            moonlight.terminate()
            return False


def send_join_request_native(host: str, port: int, cert: str) -> bool:
    # This is the hardcoded UUID for the moonlight client
    uuid = "123456789ABCD"
    with socket.socket(socket.AF_INET6, socket.SOCK_STREAM) as s:
        s.connect((host, port))
        encoded_cert = base64.urlsafe_b64encode(cert.encode("utf-8")).decode("utf-8")
        json_body = {"type": "native", "uuid": uuid, "cert": encoded_cert}
        json_body = json.dumps(json_body)
        request = (
            f"POST / HTTP/1.1\r\n"
            f"Content-Type: application/json\r\n"
            f"Content-Length: {len(json_body)}\r\n"
            f"Connection: close\r\n\r\n"
            f"{json_body}"
        )
        try:
            s.sendall(request.encode("utf-8"))
            response = s.recv(16384).decode("utf-8")
            print(response)
            lines = response.split("\n")
            body = "\n".join(lines[2:])[2:]
            print(body)
            return body
        except Exception as e:
            print(f"An error occurred: {e}")
    # TODO: fix
    try:
        print(f"response: {response}")
        data = json.loads(response)
        print(f"Data: {data}")
        print(f"Host uuid: {data['uuid']}")
        print(f"Host certificate: {data['cert']}")
        print("Joining sunshine host")
        cert = data["cert"]
        cert = base64.urlsafe_b64decode(cert).decode("utf-8")
        uuid = data["uuid"]
        hostname = data["hostname"]
        add_sunshine_host(hostname, host, cert, uuid)
    except json.JSONDecodeError as e:
        print(f"Failed to decode JSON: {e}")
        pos = e.pos
        print(f"Failed to decode JSON: unexpected character {response[pos]}")


def join(args: argparse.Namespace) -> None:
    if args.url:
        (host, port) = parse_moonlight_uri(args.url)
        if port is None:
            port = 48011
    else:
        port = args.port
        host = args.host

    print(f"Host: {host}, port: {port}")
    # TODO: If cert is not provided parse from config
    # cert = args.cert
    cert = get_moonlight_certificate()
    if send_join_request(host, port, cert):
        print(f"Successfully joined sunshine host: {host}")
    else:
        print(f"Failed to join sunshine host: {host}")


def register_join_parser(parser: argparse.ArgumentParser) -> None:
    parser.add_argument("url", nargs="?")
    parser.add_argument("--port", type=int, default=48011)
    parser.add_argument("--host")
    parser.add_argument("--cert")
    parser.set_defaults(func=join)
