#!/usr/bin/env bash
# Regression test for askuserquestion-investigate-gate.sh.
#
# Covers (per .tasks/241):
#   1. Non-AskUserQuestion tool                                  → ALLOW (early exit)
#   2. AskUserQuestion + earlier ToolSearch this turn            → ALLOW (allowlist-hit)
#   3. AskUserQuestion + earlier write-only tool                 → BLOCK
#   4. Turn-1 fixture (zero tool_use this turn)                  → BLOCK
#   5. Allowlisted tool in EARLIER turn only                     → BLOCK
#   6. Namespaced alias mcp__plugin_admin_admin__skill-find      → ALLOW
#   7. Missing CLAUDE_SESSION_ID / JSONL not found               → ALLOW (fail-open-no-transcript)
#   8. Malformed JSONL line                                      → ALLOW (fail-open-parse-error)
#
# All cases assert exit code AND the decision-log signature on stderr.

set -u

HOOK="$(cd "$(dirname "$0")/.." && pwd)/askuserquestion-investigate-gate.sh"
if [ ! -x "$HOOK" ]; then
  echo "FAIL: $HOOK not executable" >&2
  exit 1
fi

TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT

PASS=0
FAIL=0

# Run one case. Args:
#   $1 = name
#   $2 = stdin payload
#   $3 = transcript path (set env so hook reads it) or "" for none
#   $4 = expected exit code
#   $5 = expected log signature regex (matched against stderr)
run_case() {
  local name="$1" stdin="$2" transcript="$3" expected_exit="$4" expected_log_re="$5"
  local stderr_file actual_exit
  stderr_file="$(mktemp)"
  if [ -n "$transcript" ]; then
    printf '%s' "$stdin" | ASK_GATE_TRANSCRIPT_PATH="$transcript" bash "$HOOK" >/dev/null 2>"$stderr_file"
  else
    printf '%s' "$stdin" | bash "$HOOK" >/dev/null 2>"$stderr_file"
  fi
  actual_exit=$?
  local stderr_content
  stderr_content=$(cat "$stderr_file")
  rm -f "$stderr_file"

  local exit_ok=0 log_ok=0
  if [ "$actual_exit" -eq "$expected_exit" ]; then exit_ok=1; fi
  if [ -z "$expected_log_re" ] || printf '%s' "$stderr_content" | grep -Eq "$expected_log_re"; then log_ok=1; fi

  if [ $exit_ok -eq 1 ] && [ $log_ok -eq 1 ]; then
    echo "PASS: $name (exit=$actual_exit)"
    PASS=$((PASS + 1))
  else
    echo "FAIL: $name" >&2
    [ $exit_ok -eq 0 ] && echo "  expected exit=$expected_exit, got=$actual_exit" >&2
    [ $log_ok -eq 0 ]  && echo "  expected log regex: $expected_log_re" >&2 && \
                          echo "  actual stderr: $stderr_content" >&2
    FAIL=$((FAIL + 1))
  fi
}

# ---------- Fixtures ----------

# c085ec2c turn-1 fixture: header lines + user prompt only.
TURN1="$TMP_DIR/turn1.jsonl"
cat > "$TURN1" <<'JSONL'
{"type":"summary","summary":"session start","leafUuid":"00000000-0000-0000-0000-000000000000"}
{"type":"user","message":{"role":"user","content":"change remote access password"},"uuid":"aaaaaaaa-1111-1111-1111-111111111111","timestamp":"2026-05-22T09:07:18.247Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
JSONL

# c085ec2c turn-2 fixture: turn-1 + AskUserQuestion + user correction + status + ToolSearch
TURN2="$TMP_DIR/turn2.jsonl"
cat > "$TURN2" <<'JSONL'
{"type":"summary","summary":"session start","leafUuid":"00000000-0000-0000-0000-000000000000"}
{"type":"user","message":{"role":"user","content":"change remote access password"},"uuid":"aaaaaaaa-1111-1111-1111-111111111111","timestamp":"2026-05-22T09:07:18.247Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_ask_01","name":"AskUserQuestion","input":{"questions":[]}}]},"uuid":"bbbbbbbb-2222-2222-2222-222222222222","timestamp":"2026-05-22T09:07:32.387Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_ask_01","content":"...the remote admin route. Obviously."}]},"uuid":"cccccccc-3333-3333-3333-333333333333","timestamp":"2026-05-22T09:08:45.400Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"user","message":{"role":"user","content":"...the remote admin route. Obviously."},"uuid":"dddddddd-4444-4444-4444-444444444444","timestamp":"2026-05-22T09:08:45.500Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_status_02","name":"mcp__admin__remote-auth-status","input":{}}]},"uuid":"eeeeeeee-5555-5555-5555-555555555555","timestamp":"2026-05-22T09:08:50.826Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_status_02","content":"Remote access password is configured."}]},"uuid":"ffffffff-6666-6666-6666-666666666666","timestamp":"2026-05-22T09:08:51.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_search_03","name":"ToolSearch","input":{"query":"select:mcp__admin__remote-auth-set-password"}}]},"uuid":"99999999-7777-7777-7777-777777777777","timestamp":"2026-05-22T09:08:54.306Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
JSONL

# Single user turn with a non-investigation prior tool (write-only).
WRITE_ONLY="$TMP_DIR/write_only.jsonl"
cat > "$WRITE_ONLY" <<'JSONL'
{"type":"user","message":{"role":"user","content":"new password"},"uuid":"aaaaaaaa-1111-1111-1111-111111111111","timestamp":"2026-05-22T09:00:00.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_set_01","name":"mcp__admin__remote-auth-set-password","input":{"password":"x"}}]},"uuid":"bbbbbbbb-2222-2222-2222-222222222222","timestamp":"2026-05-22T09:00:01.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
JSONL

# Investigation tool in EARLIER turn only — current turn has no tool_use yet.
EARLIER_ONLY="$TMP_DIR/earlier_only.jsonl"
cat > "$EARLIER_ONLY" <<'JSONL'
{"type":"user","message":{"role":"user","content":"what is the status?"},"uuid":"aaaaaaaa-1111-1111-1111-111111111111","timestamp":"2026-05-22T09:00:00.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_status_01","name":"mcp__admin__remote-auth-status","input":{}}]},"uuid":"bbbbbbbb-2222-2222-2222-222222222222","timestamp":"2026-05-22T09:00:01.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"user","message":{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_status_01","content":"ok"}]},"uuid":"cccccccc-3333-3333-3333-333333333333","timestamp":"2026-05-22T09:00:02.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"user","message":{"role":"user","content":"change it"},"uuid":"dddddddd-4444-4444-4444-444444444444","timestamp":"2026-05-22T09:01:00.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
JSONL

# Namespaced alias `mcp__plugin_admin_admin__skill-find`.
ALIAS_FIXTURE="$TMP_DIR/alias.jsonl"
cat > "$ALIAS_FIXTURE" <<'JSONL'
{"type":"user","message":{"role":"user","content":"how do I X"},"uuid":"aaaaaaaa-1111-1111-1111-111111111111","timestamp":"2026-05-22T09:00:00.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
{"type":"assistant","message":{"role":"assistant","content":[{"type":"tool_use","id":"toolu_find_01","name":"mcp__plugin_admin_admin__skill-find","input":{"query":"X"}}]},"uuid":"bbbbbbbb-2222-2222-2222-222222222222","timestamp":"2026-05-22T09:00:01.000Z","sessionId":"c085ec2c-46fb-4b73-8865-68cf85866ea8"}
JSONL

# Malformed JSONL line.
BAD="$TMP_DIR/bad.jsonl"
cat > "$BAD" <<'JSONL'
{"type":"user","message":{"role":"user","content":"hi"},"uuid":"a","timestamp":"t","sessionId":"s"}
{ this is not valid json
JSONL

# Stdin payloads.
PRE_ASK='{"hook_event_name":"PreToolUse","tool_name":"AskUserQuestion","session_id":"c085ec2c-46fb-4b73-8865-68cf85866ea8","tool_input":{"questions":[]}}'
PRE_OTHER='{"hook_event_name":"PreToolUse","tool_name":"Read","session_id":"c085ec2c-46fb-4b73-8865-68cf85866ea8","tool_input":{"file_path":"/tmp/x"}}'

# ---------- Cases ----------

# 1. Non-AskUserQuestion early exit.
run_case "Non-AskUserQuestion tool → ALLOW (silent)" \
  "$PRE_OTHER" "$TURN1" 0 ""

# 2. AskUserQuestion + earlier ToolSearch this turn → ALLOW.
run_case "Earlier ToolSearch in same turn → ALLOW allowlist-hit" \
  "$PRE_ASK" "$TURN2" 0 \
  '\[ask-gate\] decision=allow sessionId=c085ec2c seen=mcp__admin__remote-auth-status,ToolSearch reason=allowlist-hit'

# 3. Earlier write-only tool only → BLOCK.
run_case "Earlier write-only tool only → BLOCK no-investigation" \
  "$PRE_ASK" "$WRITE_ONLY" 2 \
  '\[ask-gate\] decision=block sessionId=c085ec2c seen=mcp__admin__remote-auth-set-password reason=no-investigation'

# 4. Turn-1 fixture (zero tool_use this turn) → BLOCK.
run_case "Turn 1 fixture (no tool_use this turn) → BLOCK no-investigation seen=-" \
  "$PRE_ASK" "$TURN1" 2 \
  '\[ask-gate\] decision=block sessionId=c085ec2c seen=- reason=no-investigation'

# 5. Allowlisted tool in EARLIER turn only → BLOCK.
run_case "Allowlisted tool in earlier turn only → BLOCK no-investigation seen=-" \
  "$PRE_ASK" "$EARLIER_ONLY" 2 \
  '\[ask-gate\] decision=block sessionId=c085ec2c seen=- reason=no-investigation'

# 6. Namespaced alias → ALLOW.
run_case "Namespaced alias mcp__plugin_admin_admin__skill-find → ALLOW" \
  "$PRE_ASK" "$ALIAS_FIXTURE" 0 \
  '\[ask-gate\] decision=allow sessionId=c085ec2c seen=mcp__plugin_admin_admin__skill-find reason=allowlist-hit'

# 7. Missing transcript path → ALLOW fail-open-no-transcript.
MISSING_PATH="$TMP_DIR/does-not-exist.jsonl"
run_case "Missing transcript file → ALLOW fail-open-no-transcript" \
  "$PRE_ASK" "$MISSING_PATH" 0 \
  '\[ask-gate\] decision=allow sessionId=c085ec2c seen=- reason=fail-open-no-transcript'

# 7b. Empty transcript path (no env override AND no transcript_path in stdin).
PRE_ASK_NO_PATH='{"hook_event_name":"PreToolUse","tool_name":"AskUserQuestion","session_id":"c085ec2c-46fb-4b73-8865-68cf85866ea8","tool_input":{"questions":[]}}'
run_case "No transcript_path in stdin → ALLOW fail-open-no-transcript" \
  "$PRE_ASK_NO_PATH" "" 0 \
  '\[ask-gate\] decision=allow sessionId=c085ec2c seen=- reason=fail-open-no-transcript'

# 8. Malformed JSONL → ALLOW fail-open-parse-error.
run_case "Malformed JSONL line → ALLOW fail-open-parse-error" \
  "$PRE_ASK" "$BAD" 0 \
  '\[ask-gate\] decision=allow sessionId=c085ec2c seen=- reason=fail-open-parse-error'

echo
echo "──────── askuserquestion-investigate-gate test summary ────────"
echo "PASS: $PASS"
echo "FAIL: $FAIL"

[ "$FAIL" -gt 0 ] && exit 1
exit 0
