#!/usr/bin/python3
"""test-capture — demande un partage d'écran au système, comme le fait un
outil d'assistance à distance (portail ScreenCast + PipeWire).

Code de sortie 0 si un flux vidéo de l'écran est obtenu. Affiche aussi si une
confirmation a été demandée à l'utilisateur (délai de réponse long).
"""
import sys
import time
from gi.repository import Gio, GLib

BUS = "org.freedesktop.portal.Desktop"
OBJ = "/org/freedesktop/portal/desktop"
SC = "org.freedesktop.portal.ScreenCast"
DELAI = 60  # secondes laissées à une éventuelle confirmation


def main():
    conn = Gio.bus_get_sync(Gio.BusType.SESSION, None)
    moi = conn.get_unique_name()[1:].replace(".", "_")
    boucle = GLib.MainLoop()
    etat = {"n": 0}

    def appel(methode, params, jeton):
        """Appelle une méthode du portail et attend sa réponse (signal Response)."""
        chemin = f"/org/freedesktop/portal/desktop/request/{moi}/{jeton}"
        rep = {}

        def recu(_c, _s, _p, _i, _sig, args):
            rep["code"], rep["res"] = args.unpack()
            boucle.quit()

        sid = conn.signal_subscribe(BUS, "org.freedesktop.portal.Request", "Response",
                                    chemin, None, Gio.DBusSignalFlags.NONE, recu)
        conn.call_sync(BUS, OBJ, SC, methode, params, None,
                       Gio.DBusCallFlags.NONE, -1, None)
        garde = GLib.timeout_add_seconds(DELAI, boucle.quit)
        boucle.run()
        GLib.source_remove(garde)
        conn.signal_unsubscribe(sid)
        if "code" not in rep:
            sys.exit(f"ÉCHEC : pas de réponse du portail à {methode} en {DELAI} s")
        if rep["code"] != 0:
            raison = "refusé par l'utilisateur" if rep["code"] == 1 else "erreur du portail"
            sys.exit(f"ÉCHEC : {methode} — {raison}")
        return rep["res"]

    def opts(**k):
        etat["n"] += 1
        d = {"handle_token": GLib.Variant("s", f"p2i{etat['n']}")}
        d.update(k)
        return d, f"p2i{etat['n']}"

    o, j = opts(session_handle_token=GLib.Variant("s", "p2isession"))
    session = appel("CreateSession", GLib.Variant("(a{sv})", (o,)), j)["session_handle"]

    o, j = opts(types=GLib.Variant("u", 1), multiple=GLib.Variant("b", False))
    appel("SelectSources", GLib.Variant("(oa{sv})", (session, o)), j)

    debut = time.monotonic()
    o, j = opts()
    res = appel("Start", GLib.Variant("(osa{sv})", (session, "", o)), j)
    duree = time.monotonic() - debut

    flux = res.get("streams", [])
    if not flux:
        sys.exit("ÉCHEC : le portail n'a fourni aucun flux vidéo")
    for noeud, props in flux:
        taille = props.get("size")
        t = f"{taille[0]}x{taille[1]}" if taille else "taille inconnue"
        print(f"flux vidéo de l'écran obtenu (PipeWire n° {noeud}, {t})")
    if duree > 2:
        print(f"une confirmation a probablement été demandée ({duree:.0f} s d'attente)")
    else:
        print("aucune confirmation demandée à l'utilisateur")
    conn.call_sync(BUS, session, "org.freedesktop.portal.Session", "Close", None, None,
                   Gio.DBusCallFlags.NONE, -1, None)


if __name__ == "__main__":
    try:
        main()
    except GLib.Error as e:
        sys.exit(f"ÉCHEC : {e.message}")
