#!/usr/bin/env python3
"""Run the local app and its frontend watcher with one command."""

import os
import signal
import socket
import subprocess
import sys
import time
from pathlib import Path


ROOT = Path(__file__).resolve().parent


def start():
    with socket.socket() as probe:
        if probe.connect_ex(("127.0.0.1", 8778)) == 0:
            raise SystemExit("port 8778 is already in use")

    commands = [
        (["mise", "exec", "--", "python", "manage.py", "runserver", "8778"], ROOT),
        (["mise", "exec", "--", "npx", "shadow-cljs", "watch", "app"], ROOT / "frontend"),
    ]
    children = []
    stopping = False

    def stop(_signal, _frame):
        nonlocal stopping
        stopping = True

    signal.signal(signal.SIGINT, stop)
    signal.signal(signal.SIGTERM, stop)
    try:
        for command, directory in commands:
            children.append(subprocess.Popen(command, cwd=directory, start_new_session=True))
        print("arthur: http://localhost:8778  (Ctrl-C stops both processes)", flush=True)
        while not stopping:
            for child in children:
                if child.poll() is not None:
                    raise SystemExit(f"app process exited with status {child.returncode}")
            time.sleep(0.25)
    finally:
        for child in children:
            if child.poll() is None:
                os.killpg(child.pid, signal.SIGTERM)
        for child in children:
            try:
                child.wait(timeout=5)
            except subprocess.TimeoutExpired:
                os.killpg(child.pid, signal.SIGKILL)
                child.wait()


if __name__ == "__main__":
    if sys.argv[1:] == ["start"]:
        start()
    else:
        raise SystemExit("usage: ./do start")
