#!/usr/bin/env bash
# Usage: run-row.sh <tree: main-8d3b061|pr-23571> <row: r1|r2a|r2b|r2c|r3|r7>
# Starts one isolated dev:desktop session, derives PIDs by parentage under our own session,
# runs one matrix row, and tears down only PIDs in our session. r3 also runs r0 (baseline)
# and r1b (row 1 on the rebuilt supervisor) on the same start.
set -u
T=$1; ROW=$2
EV=/tmp/ev-23571/$T/${EVTAG:-}$ROW; H=/tmp/ev-23571/home-$T-${EVTAG:-}$ROW; mkdir -p "$EV" "$H"
TREE=$HOME/wt/$T
cd "$TREE" || exit 1
export PATH="$HOME/.bun/bin:$HOME/.local/bin:$PATH"
for v in $(env | sed -n 's/^\(T3CODE_[A-Za-z0-9_]*\)=.*/\1/p'); do unset "$v"; done
LOG=$EV/transcript.txt
ts() { date +%T.%3N; }
say() { echo "[$(ts)] $*" | tee -a "$LOG"; }
snap() { { echo "== $(ts) $1"; ps -o pid,ppid,pgid,sid,etimes,stat,cmd --forest --sid "$SID"; } >> "$EV/$2.tree.txt"; }
supof() { ps -o pid=,cmd= --sid "$SID" | awk '$2 !~ /(^|\/)sh$/ && /scripts\/dev-electron\.mjs/ {print $1}'; }

say "tree=$T row=$ROW HEAD=$(git rev-parse HEAD) /bin/sh=$(readlink -f /bin/sh)"
env | grep ^T3CODE_ >> "$LOG" || say "no T3CODE_ vars"

setsid headless-desktop vp run dev:desktop --home-dir "$H" --no-seed > "$EV/run.log" 2>&1 &
ROOT=$!; echo "$ROOT" > "$EV/root.pid"
sleep 1; SID=$(ps -o sid= -p "$ROOT" | tr -d ' ')
say "ROOT=$ROOT SID=$SID"
[ "$SID" = "$ROOT" ] || { say "SID != ROOT, abort"; exit 1; }

derive() {
  SUP=""; ELEC=""
  for i in $(seq 240); do
    SUP=$(supof | head -1)
    if [ -n "$SUP" ]; then
      ELEC=$(ps -o pid=,cmd= --ppid "$SUP" | awk '/electron/ {print $1; exit}')
      [ -n "$ELEC" ] && grep -q "runtime logging configured\|before-quit\|\[desktop\]" "$EV/run.log" && break
    fi
    sleep 1
  done
  [ -n "$SUP" ] && [ -n "$ELEC" ] || { say "derive failed (SUP=$SUP ELEC=$ELEC)"; return 1; }
  sleep 4
  SUPCWD=$(readlink /proc/$SUP/cwd)
  [ "$SUPCWD" = "$TREE/apps/desktop" ] || { say "SUP cwd $SUPCWD not in tree, STOP"; return 1; }
  P1=$(ps -o ppid= -p "$SUP" | tr -d ' ')
  case "$(ps -o cmd= -p "$P1")" in /bin/sh*|sh\ -c*) VPPACK=$(ps -o ppid= -p "$P1" | tr -d ' ');; *) VPPACK=$P1;; esac
  ELEC=$(ps -o pid=,cmd= --ppid "$SUP" | awk '/electron/ {print $1; exit}')
  {
    echo "SUP=$SUP P1=$P1 VPPACK=$VPPACK ELEC=$ELEC SUPCWD=$SUPCWD"
    echo "P1:     $(ps -o pid=,pgid=,cmd= -p "$P1")"
    echo "VPPACK: $(ps -o pid=,pgid=,cmd= -p "$VPPACK")"
    echo "ELEC:   $(ps -o pid=,pgid=,cmd= -p "$ELEC" | cut -c1-200)"
    echo "SUP status: $(grep PPid /proc/$SUP/status)"
    echo "ancestry SUP->ROOT:"; p=$SUP; while [ -n "$p" ] && [ "$p" != 1 ] && [ "$p" != 0 ]; do ps -o pid=,ppid=,pgid=,cmd= -p "$p" | cut -c1-200; [ "$p" = "$ROOT" ] && break; p=$(ps -o ppid= -p "$p" | tr -d ' '); done
  } | tee -a "$LOG" > "$EV/pids-$1.txt"
}

strace_on() { strace -tt -e trace=exit_group,kill -p "$SUP" -o "$EV/$1.strace.txt" 2>>"$EV/strace-$1.err" & STRACE=$!; sleep 0.5; }
alive() { kill -0 "$1" 2>/dev/null && echo alive || echo gone; }
poll() { # <row> <seconds...>
  local r=$1; shift; local last=0
  for s in "$@"; do sleep $((s - last)); last=$s; snap "+${s}s" "$r"
    say "$r +${s}s SUP=$(alive $SUP) ELEC=$(alive $ELEC) VPPACK=$(alive $VPPACK) sups_in_sid=$(supof | wc -l)"; done
}
bq() { grep -c "before-quit received" "$EV/run.log"; }

teardown() {
  say "teardown: leftover processes in SID $SID:"
  ps -o pid,ppid,pgid,cmd --sid "$SID" | cut -c1-200 | tee -a "$LOG"
  for p in $(ps -o pid= --sid "$SID"); do
    [ "$(ps -o sid= -p "$p" | tr -d ' ')" = "$SID" ] || continue
    cwd=$(readlink /proc/$p/cwd 2>/dev/null)
    case "$cwd" in "$TREE"*) ;; *) continue;; esac
    ps -o cmd= -p "$p" | grep -q "electron\|dev-electron.mjs" && { say "kill -TERM $p ($(ps -o cmd= -p $p | cut -c1-80))"; kill -TERM "$p"; }
  done
  sleep 2
  say "kill -TERM -- -$SID"; kill -TERM -- -"$SID" 2>/dev/null
  sleep 4
  for p in $(ps -o pid= --sid "$SID"); do
    [ "$(ps -o sid= -p "$p" | tr -d ' ')" = "$SID" ] || continue
    say "still alive after group TERM: $(ps -o pid=,cmd= -p $p | cut -c1-120) cwd=$(readlink /proc/$p/cwd)"; kill -KILL "$p"
  done
  [ -n "${STRACE:-}" ] && kill "$STRACE" 2>/dev/null
  say "teardown done; remaining in SID: $(ps -o pid= --sid "$SID" | wc -l)"
}
trap teardown EXIT

derive start || exit 1
snap baseline r0

row1() { # <rowname>
  local r=$1
  strace_on "$r"; snap pre "$r"
  say "$r t0: kill -KILL VPPACK=$VPPACK (before-quit count=$(bq))"; ts > "$EV/$r.t0"
  kill -KILL "$VPPACK"
  poll "$r" 1 2 3 4 6
  say "$r P1 now: $(ps -o pid=,ppid=,cmd= -p $P1)  SUP ppid now: $(ps -o ppid= -p $SUP)"
  say "$r before-quit count=$(bq)"
  say "$r touch dist-electron/main.cjs"; touch apps/desktop/dist-electron/main.cjs; sleep 4; snap after-touch "$r"
  say "$r after-touch SUP=$(alive $SUP) ELEC(old)=$(alive $ELEC) electron children of SUP: $(ps -o pid= --ppid $SUP 2>/dev/null | tr '\n' ' ') sups_in_sid=$(supof | wc -l)"
  sleep 1; say "$r strace:"; cat "$EV/$r.strace.txt" >> "$LOG" 2>/dev/null
}

sigrow() { # <rowname> <signal> <target>
  local r=$1 sig=$2 tgt=$3
  say "$r PGIDs: SUP=$(ps -o pgid= -p $SUP) VPPACK=$(ps -o pgid= -p $VPPACK) ELEC=$(ps -o pgid= -p $ELEC)"
  strace_on "$r"; snap pre "$r"
  say "$r t0: kill -$sig $tgt (before-quit count=$(bq))"; ts > "$EV/$r.t0"
  kill -"$sig" $tgt
  poll "$r" 1 2 3 4 5 6
  say "$r before-quit count=$(bq) remaining in SID=$(ps -o pid= --sid $SID | wc -l)"
  sleep 1; say "$r strace:"; cat "$EV/$r.strace.txt" >> "$LOG" 2>/dev/null
}

case $ROW in
  r1) row1 r1 ;;
  r3)
    OLDSUP=$SUP; OLDELEC=$ELEC; OLDVP=$VPPACK
    strace_on r3; snap pre r3
    say "r3 touch apps/desktop/src/main.ts"; touch apps/desktop/src/main.ts
    for i in $(seq 60); do s=$(supof | grep -vx "$OLDSUP" | head -1); [ -n "$s" ] && break; sleep 1; done
    say "r3 new SUP after ${i}s: $s"; sleep 1; snap after-rebuild r3
    kill "$STRACE" 2>/dev/null; STRACE=
    derive rebuilt || exit 1
    say "r3 OLDSUP=$OLDSUP $(alive $OLDSUP) OLDELEC=$OLDELEC $(alive $OLDELEC); SUP2=$SUP PPid: $(grep PPid /proc/$SUP/status) parent cmd: $(ps -o cmd= -p $(ps -o ppid= -p $SUP))"
    say "r3 VPPACK unchanged: $([ "$VPPACK" = "$OLDVP" ] && echo yes || echo "no ($OLDVP -> $VPPACK)")"
    say "r3 dev-electron.mjs count in SID: $(supof | wc -l); electron mains (children of SUP2): $(ps -o pid=,cmd= --ppid $SUP | grep -c electron)"
    snap rebuilt r0b
    say "r3 strace:"; cat "$EV/r3.strace.txt" >> "$LOG"
    row1 r1b ;;
  r2a) sigrow r2a INT "-- -$(ps -o pgid= -p $SUP | tr -d ' ')" ;;
  r2b) sigrow r2b TERM "$VPPACK" ;;
  r2c) sigrow r2c TERM "-- -$SID" ;;
  r7)
    GP=$(ps -o ppid= -p "$VPPACK" | tr -d ' ')
    say "r7 grandparent GP=$GP: $(ps -o pid=,cmd= -p $GP) cwd=$(readlink /proc/$GP/cwd)"
    case "$(readlink /proc/$GP/cwd)" in "$TREE"*) ;; *) say "GP cwd not in tree, skip"; exit 0;; esac
    sigrow r7 KILL "$GP" ;;
esac
