"""Run: python3 smoke-test.py /path/to/godot [unused-udp-port]."""
import pathlib
import os
import subprocess
import sys
import tempfile
import time

binary = sys.argv[1] if len(sys.argv) > 1 else "godot"
port = int(sys.argv[2]) if len(sys.argv) > 2 else 17000
project = pathlib.Path(__file__).resolve().parent
command = [binary, "--headless", "--path", str(project)]

with tempfile.TemporaryDirectory(prefix="godot-check-") as data, tempfile.TemporaryFile(mode="w+") as log:
    environment = dict(os.environ, XDG_DATA_HOME=data)
    server = subprocess.Popen(command + ["--", "--server", f"--port={port}"], stdout=log, stderr=log, env=environment)
    clients = []
    try:
        deadline = time.monotonic() + 10
        while time.monotonic() < deadline:
            log.seek(0)
            if f"LISTENING UDP {port}" in log.read():
                break
            if server.poll() is not None:
                log.seek(0)
                raise RuntimeError("Server exited before listening: " + log.read()[:2000])
            time.sleep(0.05)
        else:
            raise RuntimeError("Server startup timed out")
        for token in ("client-one", "client-two"):
            clients.append((token, subprocess.Popen(command + ["--", f"--port={port}", f"--token={token}"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, env=environment)))
        for token, client in clients:
            output, _ = client.communicate(timeout=15)
            if client.returncode != 0 or f"PASS echoed {token}" not in output:
                raise RuntimeError(output[:2000])
            print(next(line for line in output.splitlines() if line.startswith("PASS")))
        deadline = time.monotonic() + 5
        while time.monotonic() < deadline:
            log.seek(0)
            output = log.read()
            if output.count("DISCONNECTED ") == 2:
                break
            time.sleep(0.05)
        assert output.count("CONNECTED ") - output.count("DISCONNECTED ") == 2, output[:2000]
        assert output.count("DISCONNECTED ") == 2, output[:2000]
        print("PASS two connections and two disconnects")
    finally:
        for _, client in clients:
            if client.poll() is None:
                client.kill()
                client.wait()
        server.terminate()
        server.wait(timeout=5)
    # With the server stopped, an attempted client must fail within its deadline.
    failed = subprocess.run(command + ["--", f"--port={port}", "--timeout=1"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, timeout=10, env=environment)
    assert failed.returncode != 0 and "Connection failed or timed out" in failed.stdout, failed.stdout[:2000]
    print("PASS unreachable server exits nonzero")
