#!/usr/bin/env bash
# scripts/manual/run_tethys_downstream_audio_sanity.sh - inspect the Tethys Lesavka speaker sink
# Manual: downstream audio host sanity probe; not part of CI; no sudo or in-cluster changes.
set -euo pipefail

TETHYS_HOST=${LESAVKA_TETHYS_HOST:-tethys@titan-24}
REPAIR_WIREPLUMBER=${LESAVKA_TETHYS_AUDIO_REPAIR:-0}
RESTART_AUDIO=${LESAVKA_TETHYS_AUDIO_RESTART:-0}

ssh "$TETHYS_HOST" \
  LESAVKA_TETHYS_AUDIO_REPAIR="$REPAIR_WIREPLUMBER" \
  LESAVKA_TETHYS_AUDIO_RESTART="$RESTART_AUDIO" \
  'bash -s' <<'REMOTE'
set -euo pipefail

export XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}
export DBUS_SESSION_BUS_ADDRESS=${DBUS_SESSION_BUS_ADDRESS:-unix:path=$XDG_RUNTIME_DIR/bus}
PULSE_TIMEOUT=${LESAVKA_TETHYS_AUDIO_TIMEOUT_SECONDS:-5}

failures=0
warn() { printf '⚠️  %s\n' "$*" >&2; }
fail() { printf '❌ %s\n' "$*" >&2; failures=$((failures + 1)); }
pass() { printf '✅ %s\n' "$*" >&2; }
run_pactl() { timeout "${PULSE_TIMEOUT}s" pactl "$@"; }
run_wpctl() { timeout "${PULSE_TIMEOUT}s" wpctl "$@"; }

print_rebind_hint() {
  local card iface driver device_root audio_ifaces
  card=$({
    aplay -l 2>/dev/null | awk '/Lesavka|Composite|UAC2|USB Audio/ {if (match($0, /card [0-9]+/)) {print substr($0, RSTART + 5, RLENGTH - 5); exit}}'
    awk '/Lesavka|Composite|UAC2|USB Device 0x1d6b:0x104|1d6b:0x104/ {print $1; exit}' /proc/asound/cards 2>/dev/null
  } | awk 'NF {print; exit}' || true)
  if [[ -n ${card:-} && -e /sys/class/sound/card${card}/device ]]; then
    iface=$(basename "$(readlink -f "/sys/class/sound/card${card}/device")")
    driver=$(basename "$(readlink -f "/sys/class/sound/card${card}/device/driver" 2>/dev/null || true)")
    device_root=${iface%:*}
    if [[ -n $iface && -n $driver && -n $device_root ]]; then
      audio_ifaces=$(for candidate in "/sys/bus/usb/devices/${device_root}":*; do
        [[ -e $candidate/bInterfaceClass && -e $candidate/bInterfaceSubClass ]] || continue
        [[ $(cat "$candidate/bInterfaceClass" 2>/dev/null) == "01" ]] || continue
        case "$(cat "$candidate/bInterfaceSubClass" 2>/dev/null)" in
          01|02) basename "$candidate" ;;
        esac
      done | sort -V | xargs echo)
      [[ -n $audio_ifaces ]] || audio_ifaces=$iface
      echo "Tethys root-level audio-interface rebind, if the UAC graph is wedged:" >&2
      echo "  sudo sh -c 'for i in $audio_ifaces; do echo -n \"\$i\" > /sys/bus/usb/drivers/$driver/unbind 2>/dev/null || true; done; sleep 2; for i in $audio_ifaces; do echo -n \"\$i\" > /sys/bus/usb/drivers/$driver/bind 2>/dev/null || true; done'" >&2
      echo "Tethys full composite re-enumeration, if audio interfaces bind but ALSA creates no PCM:" >&2
      echo "  sudo sh -c 'echo 0 > /sys/bus/usb/devices/$device_root/authorized; sleep 3; echo 1 > /sys/bus/usb/devices/$device_root/authorized'" >&2
    fi
  fi
}

if ! command -v pactl >/dev/null 2>&1; then
  fail "pactl is unavailable in the Tethys desktop session"
  exit 1
fi

if ! run_pactl info >/dev/null 2>&1; then
  fail "Pulse/PipeWire is unreachable for $(id -un); XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR"
  print_rebind_hint
  exit 1
fi

sink_line=$(run_pactl list short sinks | awk '/alsa_output\.usb-Lesavka|Lesavka|Composite|UAC2/ {print; exit}')
if [[ -z ${sink_line:-} ]]; then
  fail "no Lesavka USB speaker sink is visible to PipeWire/Pulse"
  run_pactl list short sinks >&2 || true
  print_rebind_hint
  exit 1
fi
sink_name=$(awk '{print $2}' <<<"$sink_line")
pass "found Lesavka sink: $sink_name"

sink_dump=$(mktemp)
trap 'rm -f "$sink_dump"' EXIT
run_pactl list sinks >"$sink_dump"

sink_block=$(awk -v sink="$sink_name" '
  /^Sink #[0-9]+/ {printing=0}
  $0 ~ "Name: " sink {printing=1}
  printing {print}
' "$sink_dump")

if grep -q 'State: RUNNING' <<<"$sink_block"; then
  pass "Lesavka sink is RUNNING"
elif grep -q 'State: SUSPENDED' <<<"$sink_block"; then
  warn "Lesavka sink is SUSPENDED; this is okay only when no stream is actively playing"
else
  warn "Lesavka sink state is not RUNNING"
fi

if grep -Eq 'Volume:.* / 0% /' <<<"$sink_block"; then
  fail "Lesavka sink volume is persisted at 0%; Tethys can route audio into digital silence"
else
  pass "Lesavka sink Pulse volume is not 0%"
fi

if grep -Eq 'Mute: yes' <<<"$sink_block"; then
  fail "Lesavka sink is muted in Pulse/PipeWire"
else
  pass "Lesavka sink is not muted"
fi

if command -v wpctl >/dev/null 2>&1; then
  object_id=$(awk -F' = ' '/object.id =/ {gsub(/"/, "", $2); print $2; exit}' <<<"$sink_block")
  if [[ -n ${object_id:-} ]]; then
    wp_dump=$(run_wpctl inspect "$object_id" 2>/dev/null || true)
    if grep -Eq 'audio\.channels = "?0"?' <<<"$wp_dump"; then
      fail "WirePlumber reports audio.channels=0 for the Lesavka sink"
    elif [[ -n $wp_dump ]]; then
      pass "WirePlumber exposes a non-zero channel count for the Lesavka sink"
    fi
  fi
fi

state_file="$HOME/.local/state/wireplumber/stream-properties"
if [[ -r $state_file ]] && grep -Eq 'Audio/(Sink|Source):node\.name:.*(usb-Lesavka|Lesavka).*"channelVolumes":\[\]' "$state_file"; then
  fail "WirePlumber has persisted empty Lesavka channelVolumes/channelMap in $state_file"
  if [[ ${LESAVKA_TETHYS_AUDIO_REPAIR:-0} == 1 ]]; then
    backup="$state_file.lesavka-audio.$(date +%Y%m%d%H%M%S).bak"
    cp "$state_file" "$backup"
    python3 - "$state_file" <<'PY'
import sys
from pathlib import Path
path = Path(sys.argv[1])
fixed = []
for line in path.read_text().splitlines():
    if line.startswith("Audio/Sink:node.name:") and "Lesavka" in line and '"channelVolumes":[]' in line:
        key = line.split("=", 1)[0]
        line = key + '={"mute":false, "volume":1.000000, "channelVolumes":[1.000000, 1.000000], "channelMap":["FL", "FR"]}'
    elif line.startswith("Audio/Source:node.name:") and "Lesavka" in line and '"channelVolumes":[]' in line:
        key = line.split("=", 1)[0]
        line = key + '={"mute":false, "volume":1.000000, "channelVolumes":[1.000000, 1.000000], "channelMap":["FL", "FR"]}'
    fixed.append(line)
path.write_text("\n".join(fixed) + "\n")
PY
    pass "repaired WirePlumber Lesavka channel state; backup: $backup"
    if [[ ${LESAVKA_TETHYS_AUDIO_RESTART:-0} == 1 ]]; then
      systemctl --user restart wireplumber pipewire-pulse pipewire || true
    else
      warn "restart Tethys user audio or replug/rebind the Lesavka USB audio interface before retesting"
    fi
  fi
else
  pass "WirePlumber stream-properties has no empty Lesavka channel map"
fi

if ps -eo stat,comm,args | awk '$1 ~ /D/ && $2 ~ /wireplumber|pipewire/ {found=1} END {exit !found}'; then
  fail "Tethys has PipeWire/WirePlumber stuck in uninterruptible I/O sleep"
fi

print_rebind_hint

if [[ $failures -gt 0 ]]; then
  exit 1
fi
pass "Tethys downstream audio host checks passed"
REMOTE
