#!/usr/bin/env bash
# Regression tests for hooks/main-checkout-guard.sh — the PreToolUse gate that blocks
# agent mutation of the SHARED main checkout (Edit/Write into it, and destructive git
# verbs run against it), while leaving worktrees and read-only ops untouched.
# Run: bash main-checkout-guard.test.sh (exit 0 = all pass).
set -uo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
HOOK="$ROOT/hooks/main-checkout-guard.sh"
PASS=0; FAIL=0
ok()  { PASS=$((PASS+1)); printf 'PASS %s\n' "$1"; }
bad() { FAIL=$((FAIL+1)); printf 'FAIL %s\n     %s\n' "$1" "$2"; }

TMP=$(mktemp -d "${TMPDIR:-/tmp}/mcg-test-XXXX")
trap 'rm -rf "$TMP"' EXIT

REPO="$TMP/repo"
mkdir -p "$REPO"
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
mkdir -p "$REPO/.worktrees/wt1"

WT="$REPO/.worktrees/wt1"

decision() {
  # decision <json> -> "deny" | "allow"
  local out
  out=$(printf '%s' "$1" | bash "$HOOK")
  if [[ -z "$out" ]]; then
    echo allow
  elif printf '%s' "$out" | jq -e '.hookSpecificOutput.permissionDecision == "deny"' >/dev/null 2>&1; then
    echo deny
  else
    echo "unexpected:$out"
  fi
}

edit_json() { jq -n --arg cwd "$1" --arg fp "$2" '{tool_name:"Edit", cwd:$cwd, tool_input:{file_path:$fp}}'; }
bash_json()  { jq -n --arg cwd "$1" --arg cmd "$2" '{tool_name:"Bash", cwd:$cwd, tool_input:{command:$cmd}}'; }

# A. Edit into the main checkout is blocked.
got=$(decision "$(edit_json "$REPO" "$REPO/f")")
[[ "$got" == deny ]] && ok "main-checkout Edit blocked" || bad "main-checkout Edit blocked" "$got"

# B. Edit into a worktree is allowed.
got=$(decision "$(edit_json "$WT" "$WT/f")")
[[ "$got" == allow ]] && ok "worktree Edit allowed" || bad "worktree Edit allowed" "$got"

# C. Read-only git in the main checkout is allowed.
got=$(decision "$(bash_json "$REPO" "git status")")
[[ "$got" == allow ]] && ok "read-only git in main checkout allowed" || bad "read-only git allowed" "$got"

# D. Destructive git in the main checkout is blocked (each verb).
for verb in "git restore ." "git checkout -- f" "git checkout ." "git stash" "git stash push" "git stash drop" "git clean -fd" "git reset --hard"; do
  got=$(decision "$(bash_json "$REPO" "$verb")")
  [[ "$got" == deny ]] && ok "main-checkout blocked: $verb" || bad "main-checkout blocked: $verb" "$got"
done

# E. Destructive git in a worktree is allowed (no ownership dimension here — that's
#    worktree-lock-gate's job; this gate only cares about main-checkout vs worktree).
got=$(decision "$(bash_json "$WT" "git reset --hard")")
[[ "$got" == allow ]] && ok "destructive git in worktree allowed" || bad "destructive git in worktree allowed" "$got"

# F. cd-prefix bypass: session cwd is the worktree, but the command cd's into the
#    main checkout before running the destructive verb.
got=$(decision "$(bash_json "$WT" "cd $REPO && git checkout -- f")")
[[ "$got" == deny ]] && ok "cd-prefix bypass into main checkout blocked" || bad "cd-prefix bypass blocked" "$got"

# G. A repo that never opted into worktree isolation (no .worktrees dir) is left alone.
REPO2="$TMP/repo2"; mkdir -p "$REPO2"; git -C "$REPO2" init -q
got=$(decision "$(edit_json "$REPO2" "$REPO2/f")")
[[ "$got" == allow ]] && ok "non-opted-in repo left alone" || bad "non-opted-in repo left alone" "$got"

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