#!/usr/bin/python3
# SPDX-License-Identifier: GPL-2.0-or-later
"""Subscribe to InputPlumber dbus0 InputEvent signals and toggle
the joymouse/gamepad profile when the Guide button fires.

InputPlumber's DBusDevice target emits

    org.shadowblip.Input.DBusDevice.InputEvent  (string action, double value)

on path /org/shadowblip/InputPlumber/devices/target/dbus0. Both
the default gamepad profile and pocketds-joymouse.yaml route the
Guide button to `dbus: ui_guide`, so this listener fires on Guide
press regardless of which profile is currently active.
"""
import subprocess
import time

import dbus
from dbus.mainloop.glib import DBusGMainLoop
from gi.repository import GLib

DBusGMainLoop(set_as_default=True)

# 200 ms debounce — Guide press generates two events (down + up)
# at value=1.0 and value=0.0; we only act on press (value > 0.5)
# but still want a guard against held-down-fingers.
LAST_FIRE = 0.0


def bootstrap_initial_profile():
    """Kick InputPlumber off its built-in default.yaml at boot.

    The Pocket DS device YAML doesn't pin a profile, so IP starts
    on /usr/share/inputplumber/profiles/default.yaml — which only
    routes Guide → gamepad: Guide, not dbus: ui_guide. Without
    this bootstrap the listener would never see a ui_guide signal
    and the toggle would be dead from boot.

    Idempotent: only fires when the current ProfilePath is
    default.yaml. Restarting the listener while the user is in
    joymouse / gamepad mode does NOT kick them back to gamepad.
    """
    for _ in range(20):
        try:
            r = subprocess.run(
                ["busctl", "get-property",
                 "org.shadowblip.InputPlumber",
                 "/org/shadowblip/InputPlumber/CompositeDevice0",
                 "org.shadowblip.Input.CompositeDevice", "ProfilePath"],
                capture_output=True, text=True, timeout=2,
            )
            if r.returncode == 0:
                cur = ""
                if '"' in r.stdout:
                    cur = r.stdout.split('"', 2)[1]
                if cur.endswith("/default.yaml") or cur == "":
                    subprocess.run(
                        ["/usr/bin/pocketds-toggle-joymouse"], check=False,
                    )
                return
        except Exception:
            pass
        time.sleep(0.5)


def on_input_event(action, value):
    global LAST_FIRE
    if value < 0.5:  # release events: ignored (we only act on press)
        return

    if action == "ui_guide":
        now = time.monotonic()
        if now - LAST_FIRE < 0.2:
            return
        LAST_FIRE = now
        subprocess.Popen(
            ["/usr/bin/pocketds-toggle-joymouse"],
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
        )
        return

    if action in ("ui_brightness_up", "ui_brightness_down"):
        # No debounce here -- IP fires once per physical press. If we
        # want hold-to-repeat we'd need a user-space repeat timer, but
        # single-press = single 5% step is fine for a v1.
        direction = "+" if action == "ui_brightness_up" else "-"
        subprocess.Popen(
            ["/usr/bin/pocketds-brightness", direction],
            stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
        )
        return


bus = dbus.SystemBus()
bus.add_signal_receiver(
    on_input_event,
    signal_name="InputEvent",
    dbus_interface="org.shadowblip.Input.DBusDevice",
    bus_name="org.shadowblip.InputPlumber",
)

bootstrap_initial_profile()

GLib.MainLoop().run()
