#!/usr/bin/env bash
# Zero-dep regression tests for handoff-base-gate.sh. Builds throwaway git repos (some with a real
# origin remote) and asserts each base-branch check FIRES on its bad input and PASSES on good input.
# Each assert encodes a real failure the gate exists to catch. Run: bash test-handoff-base-gate.sh
set -uo pipefail
LIB="$(cd "$(dirname "$0")" && pwd)/handoff-base-gate.sh"
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"; }
jget() { printf '%s' "$1" | python3 -c "import sys,json;d=json.load(sys.stdin);print($2)"; }
run() { bash "$LIB" "$@"; }

gconf() { git -C "$1" config user.email t@t.t; git -C "$1" config user.name t; git -C "$1" config commit.gpgsign false; }
# write a session-state JSONL with a meta line carrying base_branch ($2; empty => omit the key). $1=path
mkjsonl() {
  local p=$1 base=$2
  if [[ -n "$base" ]]; then
    printf '%s\n' '{"type":"meta","slug":"s","base_branch":"'"$base"'"}' '{"type":"task","id":"t0","status":"PENDING"}' > "$p"
  else
    printf '%s\n' '{"type":"meta","slug":"s"}' '{"type":"task","id":"t0","status":"PENDING"}' > "$p"
  fi
}

echo "handoff-base-gate tests:"

# Build a repo with a REAL origin remote, main pushed, carrying src/mod.ts. Echoes the work repo path.
mkremote() {
  local bare work
  bare=$(mktemp -d /tmp/hbg-bare-XXXX); git -C "$bare" init -q --bare -b main
  work=$(mktemp -d /tmp/hbg-work-XXXX); git -C "$work" init -q -b main; gconf "$work"
  mkdir -p "$work/src"; echo "export const m=1" > "$work/src/mod.ts"
  git -C "$work" add src/mod.ts; git -C "$work" commit -q -m seed
  git -C "$work" remote add origin "$bare"; git -C "$work" push -q -u origin main 2>/dev/null
  printf '%s' "$work"
}

# 1. PASS all: base=origin/main, amended path src/mod.ts exists on base → pass=true, every check ok
W=$(mkremote); J="$W/p.jsonl"; mkjsonl "$J" "origin/main"
j=$(run "$W" "$J" "src/mod.ts")
[[ "$(jget "$j" 'd["pass"]')" == "True" \
   && "$(jget "$j" 'all(c["ok"] for c in d["checks"])')" == "True" ]] \
  && ok "all checks pass (origin/main carries the amended path)" || bad "all pass" "$j"
rm -rf "$W"

# 2. SET fails: meta.base_branch absent → set ok=false, pass=false
W=$(mkremote); J="$W/p.jsonl"; mkjsonl "$J" ""
j=$(run "$W" "$J" "src/mod.ts")
[[ "$(jget "$j" 'd["pass"]')" == "False" \
   && "$(jget "$j" 'any(c["name"]=="set" and not c["ok"] for c in d["checks"])')" == "True" ]] \
  && ok "set fires on absent base_branch" || bad "set fires" "$j"
rm -rf "$W"

# 3. RESOLVES fails: base names a non-existent ref → resolves ok=false, pass=false
W=$(mkremote); J="$W/p.jsonl"; mkjsonl "$J" "origin/does-not-exist"
j=$(run "$W" "$J")
[[ "$(jget "$j" 'd["pass"]')" == "False" \
   && "$(jget "$j" 'any(c["name"]=="resolves" and not c["ok"] for c in d["checks"])')" == "True" ]] \
  && ok "resolves fires on unresolvable base" || bad "resolves fires" "$j"
rm -rf "$W"

# 4. CARRIES-DEPS fails: amended path not present on base → carries-deps ok=false, pass=false
W=$(mkremote); J="$W/p.jsonl"; mkjsonl "$J" "origin/main"
j=$(run "$W" "$J" "src/not-on-base.ts")
[[ "$(jget "$j" 'd["pass"]')" == "False" \
   && "$(jget "$j" 'any(c["name"]=="carries-deps" and not c["ok"] for c in d["checks"])')" == "True" ]] \
  && ok "carries-deps fires when base lacks the prerequisite path" || bad "carries-deps fires" "$j"
rm -rf "$W"

# 5. CARRIES-DEPS vacuous: no amended paths → that check absent, pass=true (other checks clean)
W=$(mkremote); J="$W/p.jsonl"; mkjsonl "$J" "origin/main"
j=$(run "$W" "$J")
[[ "$(jget "$j" 'd["pass"]')" == "True" \
   && "$(jget "$j" 'any(c["name"]=="carries-deps" for c in d["checks"])')" == "False" ]] \
  && ok "carries-deps vacuous when no amended paths given" || bad "carries-deps vacuous" "$j"
rm -rf "$W"

# 6. FRESHNESS fires: local 'main' provably lags origin/main → prefer-remote-tracking ok=false
W=$(mkremote); J="$W/p.jsonl"; mkjsonl "$J" "main"
# advance origin/main one commit ahead of local main, then rewind local main so it lags
echo "export const m=2" > "$W/src/mod.ts"; git -C "$W" add src/mod.ts; git -C "$W" commit -q -m advance
git -C "$W" push -q origin main 2>/dev/null
git -C "$W" reset -q --hard HEAD~1        # local main now 1 behind origin/main
j=$(run "$W" "$J" "src/mod.ts")
[[ "$(jget "$j" 'd["pass"]')" == "False" \
   && "$(jget "$j" 'any(c["name"]=="prefer-remote-tracking" and not c["ok"] for c in d["checks"])')" == "True" ]] \
  && ok "freshness fires when local base lags origin" || bad "freshness fires on lag" "$j"
rm -rf "$W"

# 7. FRESHNESS clean for a remote ref: base=origin/main → prefer-remote-tracking ok=true (never lag-flagged)
W=$(mkremote); J="$W/p.jsonl"; mkjsonl "$J" "origin/main"
j=$(run "$W" "$J")
[[ "$(jget "$j" 'any(c["name"]=="prefer-remote-tracking" and c["ok"] for c in d["checks"])')" == "True" ]] \
  && ok "freshness clean for a remote-tracking base ref" || bad "freshness clean remote ref" "$j"
rm -rf "$W"

# 8. USAGE fault: missing jsonl → non-zero exit (env fault, NOT a JSON gate result)
W=$(mkremote)
if run "$W" "$W/nope.jsonl" 2>/dev/null; then bad "usage fault exits non-zero" "exit 0"; else ok "missing jsonl → non-zero exit (usage fault)"; fi
rm -rf "$W"

echo
echo "PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]]
