#!/usr/bin/env bash
# gig-up — ordered 1-click gig launch.
#
# The problem it kills: at the start of a gig/reboot, whichever of SuperDirt or
# Ardour opens the LaunchControl XL first wins it; when Ardour wins, sclang can't
# get the controller and you're stuck doing the "disconnect MIDI / reconnect MIDI"
# dance mid-setup. So: bring SuperDirt up FIRST, WAIT until it has actually claimed
# MIDI, and only THEN start Ardour + Pulsar.
#
# Order:
#   1. sclang start_and_midi.scd  (SuperDirt on :57120 + LCXL CC->OSC bridge) in a terminal
#   2. wait for READY = scsynth alive + :57120 listening + a SuperCollider MIDI client
#   3. Ardour (the Tidal Multi session)   — now it can't beat SuperDirt to the LCXL
#   4. Pulsar (the Tidal folder)
#
# Everything is best-effort: a step that can't run warns and the rest still proceeds.

set -u
DIR="$(cd "$(dirname "$0")" && pwd)"                     # repo root (this script lives here)
ARDOUR_SESSION="$HOME/Work/Sound/Ardour/Tidal Live/Tidal Live.ardour"   # lean per-gig session (Tidal Multi = fat archive, retiring)
READY_TIMEOUT="${READY_TIMEOUT:-120}"                    # s to wait for SuperDirt (samples can be slow)

C_OK=$'\e[32m'; C_WARN=$'\e[33m'; C_INFO=$'\e[36m'; C_DIM=$'\e[2m'; C_RST=$'\e[0m'
ok(){ printf '%s✓ %s%s\n' "$C_OK" "$*" "$C_RST"; }
info(){ printf '%s• %s%s\n' "$C_INFO" "$*" "$C_RST"; }
warn(){ printf '%s! %s%s\n' "$C_WARN" "$*" "$C_RST"; }

# --- readiness probes (the three signals that mean "SuperDirt owns the rig") ---
scsynth_up(){ pgrep -x scsynth >/dev/null 2>&1; }
osc_up(){ ss -uln 2>/dev/null | grep -q ':57120'; }
# SuperCollider's ALSA-seq client appears once MIDIClient.init has run.
midi_claimed(){ aconnect -l 2>/dev/null | grep -qiE "client [0-9]+: 'SuperCollider'"; }
# GUI apps — so re-running gig-up converges the rig instead of spawning dupes
# (a 2nd Ardour on the same session = an annoying "already open/locked" dialog).
ardour_up(){ pgrep -f 'ardour-[0-9]' >/dev/null 2>&1; }
pulsar_up(){ pgrep -x pulsar >/dev/null 2>&1; }

# --- terminal for the sclang post window ---
pick_term(){
  if [ -n "${TERMINAL:-}" ] && command -v "$TERMINAL" >/dev/null 2>&1; then echo "$TERMINAL"; return; fi
  for t in konsole kitty alacritty wezterm gnome-terminal xterm; do
    command -v "$t" >/dev/null 2>&1 && { echo "$t"; return; }
  done
  echo ""
}

open_term(){  # open a new terminal running the headless sclang gig-boot
  local term; term="$(pick_term)"
  if [ -z "$term" ]; then
    warn "no terminal emulator found — running SuperDirt in the background (post → $DIR/gig-sclang.log)"
    ( cd "$DIR" && QT_QPA_PLATFORM=offscreen setsid sclang start_and_midi.scd >gig-sclang.log 2>&1 & )
    return
  fi
  # konsole/gnome-terminal want `-e`; most others accept it too.
  setsid "$term" -e bash -lc "cd '$DIR'; QT_QPA_PLATFORM=offscreen sclang start_and_midi.scd; exec bash" \
    >/dev/null 2>&1 &
}

launch_bin(){  # launch_bin "<label>" <binary names...> — first found, detached, with LAUNCH_ARGS
  local label="$1"; shift
  local bin
  for bin in "$@"; do
    if command -v "$bin" >/dev/null 2>&1; then
      info "launching $label ($bin)…"
      setsid "$bin" "${LAUNCH_ARGS[@]}" >/dev/null 2>&1 &
      return 0
    fi
  done
  warn "$label not found (tried: $*) — start it by hand."
  return 1
}

# ---------------------------------------------------------------------------
echo
info "gig-up — ordered launch from $DIR"

# 1) SuperDirt (skip if already running)
if scsynth_up; then
  ok "SuperDirt already running — skipping boot."
else
  info "starting SuperDirt (sclang start_and_midi.scd, headless)…"
  open_term
fi

# 2) wait for the rig to own MIDI
info "waiting for SuperDirt to boot & claim the LaunchControl (timeout ${READY_TIMEOUT}s)…"
deadline=$(( $(date +%s) + READY_TIMEOUT ))
while :; do
  if scsynth_up && osc_up && midi_claimed; then
    sleep 1.5   # settle: let MIDIIn.connectAll + CC bridge attach
    ok "SuperDirt ready — scsynth up, :57120 listening, MIDI claimed."
    break
  fi
  if [ "$(date +%s)" -ge "$deadline" ]; then
    warn "timed out — proceeding anyway. Check the sclang window; if MIDI isn't claimed,"
    warn "you may still need the disconnect/reconnect dance for the LaunchControl."
    printf '%s  (scsynth=%s  :57120=%s  midi=%s)%s\n' "$C_DIM" \
      "$(scsynth_up && echo y || echo n)" "$(osc_up && echo y || echo n)" \
      "$(midi_claimed && echo y || echo n)" "$C_RST"
    break
  fi
  sleep 1
done

# 3) Ardour — now safe to open (SuperDirt already holds the controller)
if ardour_up; then
  ok "Ardour already running — skipping."
elif [ -f "$ARDOUR_SESSION" ]; then
  LAUNCH_ARGS=("$ARDOUR_SESSION"); launch_bin "Ardour" ardour ardour9 ardour8 Ardour
else
  warn "Ardour session not found at: $ARDOUR_SESSION"
fi

# 4) Pulsar — the Tidal folder
if pulsar_up; then
  ok "Pulsar already running — skipping."
else
  LAUNCH_ARGS=("$DIR"); launch_bin "Pulsar" pulsar
fi

echo
ok "gig-up done. SuperDirt owns the LaunchControl; Ardour + Pulsar are coming up."
