#!/usr/bin/env bash
# Regression tests for run-plan-resume-detect.mjs — the SessionStart hook AFTER the self-only rework.
# The hook now pushes ONLY runs THIS session owns (owner beacon == session_id); every other class
# (alive other-session, dead orphan, legacy) is DELIBERATELY silent here — those surface via the
# statusline count and `/run-plan status`, not by poisoning an unrelated session's context. The
# liveness/classify branches themselves are covered in test-run-plan-scan.sh (the shared module).
# Run: bash test-resume-detect.sh (exit 0 = all pass).
set -uo pipefail
HOOK="$(cd "$(dirname "$0")" && pwd)/run-plan-resume-detect.mjs"
PASS=0; FAIL=0
ok()  { PASS=$((PASS+1)); printf '  ok   %s\n' "$1"; }
bad() { FAIL=$((FAIL+1)); printf '  FAIL %s\n     %s\n' "$1" "$2"; }

SB=$(mktemp -d "${TMPDIR:-/tmp}/rpd-test-XXXX")
export RUN_PLAN_RUN_DIR="$SB/run" RUN_PLAN_CLAUDE_PROJECTS="$SB/projects" RUN_PLAN_RESUME_PROJECTS="$SB/Projects"
mkdir -p "$RUN_PLAN_RUN_DIR" "$RUN_PLAN_CLAUDE_PROJECTS/proj-a"
HOST=$(node -e 'console.log(require("os").hostname())')

# fake project repo: integration branch plan/demo + incomplete plan JSONL == an in-flight run.
REPO="$SB/Projects/demo"; mkdir -p "$REPO/docs/plans"
git -C "$REPO" init -q; git -C "$REPO" config user.email t@t; git -C "$REPO" config user.name t
git -C "$REPO" config commit.gpgsign false
echo x > "$REPO/f"; git -C "$REPO" add -A; git -C "$REPO" commit -qm init
git -C "$REPO" branch plan/demo
printf '%s\n' '{"type":"task","id":"t1","status":"PENDING"}' \
              '{"type":"task","id":"t2","status":"COMMITTED"}' > "$REPO/docs/plans/2026-06-27-demo.jsonl"

owner()  { printf '%s\n' "$1" > "$RUN_PLAN_RUN_DIR/demo.owner"; }
pidf()   { printf '%s\n' "$1" > "$RUN_PLAN_RUN_DIR/demo.pid"; }      # "<host> <pid> <start>"
live()   { touch "$RUN_PLAN_RUN_DIR/demo.live"; }
nobeacon(){ rm -f "$RUN_PLAN_RUN_DIR"/demo.*; }
# run_hook <session_id> [source]
run_hook() { printf '{"source":"%s","session_id":"%s"}' "${2:-resume}" "$1" | node "$HOOK"; }

# A. THIS session owns it → surfaced, slug + ownership banner + progress shown
nobeacon; owner sess-OWNER; live
out=$(run_hook sess-OWNER)
[[ "$out" == *"THIS session owns"* && "$out" == *"demo"* ]] \
  && ok "self-owned run surfaced" || bad "self-owned surfaced" "$out"

# B. a DIFFERENT session owns it, owner process ALIVE → SILENT (not ours)
sleep 300 & LP=$!
nobeacon; owner sess-OWNER; pidf "$HOST $LP"; live
out=$(run_hook sess-OTHER)
[[ -z "$out" ]] && ok "alive other-session run → silent (not self)" || bad "alive other silent" "$out"
kill "$LP" 2>/dev/null

# C. a DIFFERENT session owns it, owner process DEAD (orphan) → SILENT here (surfaces via statusline/pull)
nobeacon; owner sess-OWNER; pidf "$HOST 2147483647 0"; live
out=$(run_hook sess-OTHER)
[[ -z "$out" ]] && ok "dead orphan → silent in hook (self-only)" || bad "orphan silent" "$out"

# D. legacy run (no owner beacon) → cannot be proven self → SILENT
nobeacon
out=$(run_hook sess-OTHER)
[[ -z "$out" ]] && ok "legacy (no owner) → silent" || bad "legacy silent" "$out"

# E. no session_id at all → cannot prove ownership → SILENT (fail-closed)
nobeacon; owner sess-OWNER; live
out=$(printf '{"source":"resume"}' | node "$HOOK")
[[ -z "$out" ]] && ok "no session_id → silent (fail-closed)" || bad "no session_id silent" "$out"

# F. transcript_path supplies identity when session_id absent → self still matches
nobeacon; owner sess-FROMPATH; live
out=$(printf '{"source":"resume","transcript_path":"/x/y/sess-FROMPATH.jsonl"}' | node "$HOOK")
[[ "$out" == *"THIS session owns"* ]] && ok "transcript_path identity matches self" || bad "transcript_path self" "$out"

# G. source filter: startup fires for self; unknown source no-ops even for self
nobeacon; owner sess-OWNER; live
out=$(run_hook sess-OWNER startup)
[[ "$out" == *"THIS session owns"* ]] && ok "startup source fires for self" || bad "startup fires" "$out"
out=$(run_hook sess-OWNER somethingelse)
[[ -z "$out" ]] && ok "unknown source no-ops" || bad "unknown source should no-op" "$out"

# H. malformed stdin → no crash, silent
out=$(printf 'not-json' | node "$HOOK"); rc=$?
[[ "$rc" -eq 0 && -z "$out" ]] && ok "malformed stdin → rc0, silent" || bad "malformed stdin" "rc=$rc out=$out"

rm -rf "$SB"
echo
echo "PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]]
