"""
OBS diagnostic + reset for the boatcam sources.

Lists every input and scene OBS currently holds, then removes the ones this project creates
(`boatcam:*` inputs, the `Boat Cams` grid scene, and `Boat <sail>` per-boat scenes) so a fresh
`serve_live.py --obs` run starts clean. Run it whenever auto add/remove gets wedged by leftover
state (e.g. CreateInput error 601 "a source already exists by that input name").

    .venv-demo/Scripts/python v3/broadcast/live/obs_reset.py [--obs-host H] [--obs-port 4455] [--obs-password PW]

Prints what it finds and what it removes — paste that output if something still won't clean up.
"""
from __future__ import annotations

import argparse
import logging
import re
import sys
from pathlib import Path

_HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(_HERE))
from director_obs import OBSController  # noqa: E402

_PER_BOAT = re.compile(r"^Boat .+$")        # 'Boat 2', 'Boat 7', ... (our per-boat full-screen scenes)
_GRID = "Boat Cams"


def _input_names(client) -> list[str]:
    try:
        resp = client.send("GetInputList")              # no kind filter (kind=None can return nothing)
    except Exception:
        resp = client.get_input_list()
    out = []
    for inp in (getattr(resp, "inputs", None) or []):
        name = inp.get("inputName") if isinstance(inp, dict) else getattr(inp, "input_name", None)
        if name:
            out.append(name)
    return out


def _scene_names(client) -> list[str]:
    resp = client.get_scene_list()
    out = []
    for s in (getattr(resp, "scenes", None) or []):
        name = s.get("sceneName") if isinstance(s, dict) else (
            getattr(s, "scene_name", None) or getattr(s, "sceneName", None))
        if name:
            out.append(name)
    return out


def main():
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--obs-host", default="localhost")
    ap.add_argument("--obs-port", type=int, default=4455)
    ap.add_argument("--obs-password", default="")
    ap.add_argument("--list-only", action="store_true", help="only print inputs/scenes; remove nothing")
    args = ap.parse_args()

    logging.getLogger("obsws_python").setLevel(logging.CRITICAL)
    obs = OBSController(host=args.obs_host, port=args.obs_port, password=args.obs_password).connect()
    client = obs.client

    inputs = _input_names(client)
    scenes = _scene_names(client)
    print(f"INPUTS ({len(inputs)}):")
    for n in inputs:
        print(f"  - {n!r}{'   <- boatcam (ours)' if n.startswith('boatcam:') else ''}")
    print(f"SCENES ({len(scenes)}):")
    for n in scenes:
        tag = "   <- ours" if (n == _GRID or _PER_BOAT.match(n)) else ""
        print(f"  - {n!r}{tag}")

    if args.list_only:
        return

    # Switch the program off any boat scene first: OBS won't free a source referenced by the active
    # program scene, which is what leaves boatcam sources stuck (RemoveInput then silently no-ops).
    prog = obs.current_program_scene()
    if prog == _GRID or (prog and _PER_BOAT.match(prog)):
        safe = next((s for s in scenes if s not in (_GRID,) and not _PER_BOAT.match(s)), None)
        if safe:
            try:
                obs.set_scene(safe)
                print(f"switched program {prog!r} -> {safe!r}")
            except Exception as e:
                print(f"could not switch program off {prog!r}: {e}")

    # Remove our inputs the reliable way: scene items first (releases references), then the input.
    for n in inputs:
        if n.startswith("boatcam:"):
            obs._purge_input(n)
            print(f"removed input  {n!r}")
    # Then our scenes. A scene can share the source namespace with an input, so if a 'boatcam:*' name
    # is actually a SCENE, remove it as a scene too.
    for n in scenes:
        if n == _GRID or _PER_BOAT.match(n) or n.startswith("boatcam:"):
            try:
                client.remove_scene(n)
                print(f"removed scene  {n!r}")
            except Exception as e:
                print(f"FAILED scene   {n!r}: {e}")

    print("--- after cleanup ---")
    print("INPUTS:", _input_names(client))
    print("SCENES:", _scene_names(client))


if __name__ == "__main__":
    main()
