#!/usr/bin/env python3
"""Small explicit control surface for the X11 prototype; never auto-accept pairing."""
import argparse
import getpass
import json
import os
import pathlib
import shlex
import subprocess
import sys
import threading

HELP = """Commandes :
  appareils                       liste des pairs et de leurs identifiants
  appairer ID                     demande d'appairage
  accepter REQUEST_ID CODE        seulement après comparaison du code sur les deux postes
  refuser REQUEST_ID
  licence                         état de la licence
  activer                         saisir une clé sans l'afficher
  essai                           demander explicitement l'essai en ligne
  demarrer ID gauche|droite|haut|bas [local|remote]
  arreter                         arrêter le partage
  liberer                         relâcher les entrées
  quitter
Arrêt local d'urgence pendant la capture : Ctrl+Alt+Échap.
Prototype X11, sans presse-papiers ni éditeur de disposition clavier.
"""

def main():
    root = pathlib.Path(__file__).resolve().parent
    parser = argparse.ArgumentParser(); parser.add_argument("--name", default=os.uname().nodename)
    parser.add_argument("--data-dir", default=str(pathlib.Path(os.environ.get("XDG_DATA_HOME", str(pathlib.Path.home()/".local/share"))) / "arko-bridge-linux-prototype"))
    args = parser.parse_args()
    if os.geteuid() == 0: sys.exit("Lancer depuis la session graphique utilisateur, sans sudo.")
    if not sys.stdin.isatty(): sys.exit("Un terminal interactif est requis.")
    os.umask(0o077)
    child = subprocess.Popen([str(root/"arko-sync-node-linux"), "--name", args.name,
                              "--data-dir", args.data_dir, "--mouse-agent", str(root/"arko-input-x11.py"),
                              "--parent-pid", str(os.getpid())], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
    prompts = {}; stopped = threading.Event()
    def send(command, **fields):
        child.stdin.write(json.dumps(dict(command=command, **fields))+"\n"); child.stdin.flush()
    def output():
        for line in child.stdout:
            try: event = json.loads(line)
            except ValueError: continue
            kind = event.get("event")
            if kind == "snapshot":
                for peer in event.get("peers", []):
                    print(json.dumps(peer, ensure_ascii=False))
            elif kind == "pair_prompt":
                prompts[event["request_id"]] = str(event["code"])
                print("Appairage :", event.get("name"), "code", event["code"], "requête", event["request_id"])
                print("Comparer le code sur les DEUX postes, puis : accepter REQUEST_ID CODE")
            elif kind in ("log", "error", "fatal", "session", "license", "license_status", "license_operation", "engine_ready", "paired"):
                print(json.dumps(event, ensure_ascii=False))
            sys.stdout.flush()
        stopped.set()
    threading.Thread(target=output, daemon=True).start()
    print(HELP)
    try:
        while not stopped.is_set():
            words = shlex.split(input("arko> "))
            if not words: continue
            cmd = words[0]
            try:
                if cmd == "quitter": break
                elif cmd == "appareils": send("snapshot")
                elif cmd == "appairer" and len(words) == 2: send("pair", peer_id=words[1])
                elif cmd == "accepter" and len(words) == 3:
                    if prompts.get(words[1]) != words[2]: print("Code incorrect ou requête expirée."); continue
                    send("pair_decision", request_id=words[1], accept=True); prompts.pop(words[1], None)
                elif cmd == "refuser" and len(words) == 2: send("pair_decision", request_id=words[1], accept=False)
                elif cmd == "licence": send("license_status")
                elif cmd == "activer": send("license_activate", license_key=getpass.getpass("Clé : "))
                elif cmd == "essai": send("license_trial")
                elif cmd == "demarrer" and len(words) in (3, 4):
                    edge = {"gauche": "left", "droite": "right", "haut": "top", "bas": "bottom"}[words[2]]
                    controller = words[3] if len(words) == 4 else "local"
                    if controller not in ("local", "remote"): raise ValueError()
                    send("start", peer_id=words[1], edge=edge, controller=controller)
                elif cmd == "arreter": send("stop")
                elif cmd == "liberer": send("release_all")
                else: print(HELP)
            except (KeyError, ValueError): print("Arguments invalides.\n"+HELP)
    except (EOFError, KeyboardInterrupt, BrokenPipeError): pass
    finally:
        try: send("shutdown")
        except (BrokenPipeError, ValueError): pass
        child.stdin.close()
        try: child.wait(timeout=8)
        except subprocess.TimeoutExpired: child.terminate(); child.wait(timeout=5)
    return child.returncode

if __name__ == "__main__": sys.exit(main())
