#!/usr/bin/env python3
"""Backglow OSC fixture. Sends /avatar/parameters/Backglow* to the daemon.

Default target: 127.0.0.1:9001 (D-19 fallback port). Override with --port if
the daemon bound an ephemeral OSCQuery-assigned UDP port (D-18).

Modes:
  --led N --r F [--g F --b F]  Set one LED's channels (N in 0..9, F in 0..1)
  --bri F                      Set BackglowBri
  --sweep                      Iterate all 31 params, each sent at 0.5
  --silence SECONDS            Send one frame then sleep for --silence seconds
  --bri-dedup                  Send BackglowBri=0.5 ten times rapidly (dedup check)

Addresses sent:
  /avatar/parameters/BackglowR0 .. BackglowR9   (10 floats, per-LED red)
  /avatar/parameters/BackglowG0 .. BackglowG9   (10 floats, per-LED green)
  /avatar/parameters/BackglowB0 .. BackglowB9   (10 floats, per-LED blue)
  /avatar/parameters/BackglowBri                (1 float, global brightness)

Total 31 unsynced avatar parameters per Phase 16 D-07/D-08/D-09. Values are
clamped to [0.0, 1.0] by the daemon; this fixture does not pre-clamp.

Install dependency:
  py -m pip install python-osc

See .planning/phases/16-vrchat-osc-bridge/16-SMOKE.md for the SMOKE rows
that drive this fixture (VRCH-02a..d).
"""
import argparse
import time
from pythonosc import udp_client


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--host", default="127.0.0.1")
    ap.add_argument("--port", type=int, default=9001)
    ap.add_argument("--led", type=int, default=None)
    ap.add_argument("--r", type=float, default=None)
    ap.add_argument("--g", type=float, default=None)
    ap.add_argument("--b", type=float, default=None)
    ap.add_argument("--bri", type=float, default=None)
    ap.add_argument("--sweep", action="store_true")
    ap.add_argument("--silence", type=float, default=None)
    ap.add_argument("--bri-dedup", dest="bri_dedup", action="store_true")
    args = ap.parse_args()

    client = udp_client.SimpleUDPClient(args.host, args.port)

    if args.sweep:
        for i in range(10):
            client.send_message(f"/avatar/parameters/BackglowR{i}", 0.5)
            client.send_message(f"/avatar/parameters/BackglowG{i}", 0.5)
            client.send_message(f"/avatar/parameters/BackglowB{i}", 0.5)
            time.sleep(0.01)
        client.send_message("/avatar/parameters/BackglowBri", 0.5)
        print("sweep complete: 31 params -> 0.5")
        return

    if args.bri_dedup:
        for _ in range(10):
            client.send_message("/avatar/parameters/BackglowBri", 0.5)
            time.sleep(0.005)
        print("bri-dedup complete: sent 10 x BackglowBri=0.5")
        return

    if args.led is not None:
        if args.r is not None:
            client.send_message(f"/avatar/parameters/BackglowR{args.led}", args.r)
        if args.g is not None:
            client.send_message(f"/avatar/parameters/BackglowG{args.led}", args.g)
        if args.b is not None:
            client.send_message(f"/avatar/parameters/BackglowB{args.led}", args.b)
        print(f"sent LED{args.led} R={args.r} G={args.g} B={args.b}")

    if args.bri is not None:
        client.send_message("/avatar/parameters/BackglowBri", args.bri)
        print(f"sent BackglowBri={args.bri}")

    if args.silence is not None:
        print(f"sent initial frame, sleeping {args.silence}s (silence test)...")
        time.sleep(args.silence)
        print("silence complete -- LEDs should have faded off by now")


if __name__ == "__main__":
    main()
