#!/usr/bin/env bash
# Regression test for archive-ingest-surface-gate.sh.
#
# Covers:
#   Preserved-from-Task-846:
#     1. Edit on /platform/plugins/<x>/lib/* → BLOCKED
#     2. Edit on benign path → ALLOWED
#     3. Bash with `npx vitest`/`bun test`/`npm test` → BLOCKED
#     4. PostToolUse on whatsapp-export-parse with isError:true sets flag
#     5. Subsequent PreToolUse on ANY tool → BLOCKED
#     6. UserPromptSubmit clears flag → normal allow resumes
#     7. PostToolUse with isError:false → flag absent
#     8. Stale flag (>600s) auto-clears
#   New:
#     A. PreToolUse mcp__memory__whatsapp-export-parse → BLOCKED
#     B. PreToolUse mcp__memory__whatsapp-export-insight-write → BLOCKED
#     C. PreToolUse mcp__memory__memory-archive-write w/ archiveType=whatsapp-export → BLOCKED
#     D. PreToolUse mcp__memory__memory-archive-write w/ archiveType=linkedin-connections → ALLOWED
#     E. PreToolUse Bash invoking conversation-archive-ingest.sh → ALLOWED
#     F. Default-allow emits a [archive-ingest-gate] decision=allow log line

set -u

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

STATE_DIR=$(mktemp -d)
export ARCHIVE_INGEST_GATE_STATE_DIR="$STATE_DIR"
FLAG_FILE="$STATE_DIR/archive-ingest-parse-error.flag"

cleanup() { rm -rf "$STATE_DIR"; }
trap cleanup EXIT

PASS=0
FAIL=0

run_case() {
  local name="$1" stdin="$2" expected_exit="$3"
  local actual_exit
  printf '%s' "$stdin" | bash "$HOOK" >/dev/null 2>/dev/null
  actual_exit=$?
  if [[ "$actual_exit" -eq "$expected_exit" ]]; then
    echo "PASS: $name (exit=$actual_exit)"
    PASS=$((PASS + 1))
  else
    echo "FAIL: $name (expected exit=$expected_exit, got=$actual_exit)" >&2
    FAIL=$((FAIL + 1))
  fi
}

# Preserved cases ---------------------------------------------------------

run_case "Edit on platform/plugins/memory/mcp/src/lib/conversation-normalisers/whatsapp-text.ts → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/Users/x/repo/platform/plugins/memory/mcp/src/lib/conversation-normalisers/whatsapp-text.ts","old_string":"a","new_string":"b"}}' \
  2

run_case "Edit on README.md → ALLOWED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/Users/x/repo/README.md","old_string":"a","new_string":"b"}}' \
  0

run_case "Bash 'npx vitest run' → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"npx vitest run parse-export.test.ts"}}' \
  2

run_case "Bash 'ls -la' → ALLOWED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"ls -la"}}' \
  0

run_case "Bash 'bun test' → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"bun test"}}' \
  2

run_case "Bash 'npm test' → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"npm test"}}' \
  2

# New cases ----------------------------------------------------

run_case "PreToolUse mcp__memory__whatsapp-export-parse → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__whatsapp-export-parse","tool_input":{"filePath":"/tmp/_chat.txt","accountId":"acct1","timezone":"Europe/London"}}' \
  2

run_case "PreToolUse mcp__memory__whatsapp-export-insight-write → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__whatsapp-export-insight-write","tool_input":{"kind":"MENTIONS","name":"Joel"}}' \
  2

run_case "PreToolUse memory-archive-write w/ archiveType=whatsapp-export → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"archiveType":"whatsapp-export","ownerNodeId":"x","accountId":"a","rows":[]}}' \
  2

run_case "PreToolUse memory-archive-write w/ archiveType=linkedin-connections → ALLOWED" \
  '{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"archiveType":"linkedin-connections","ownerNodeId":"x","accountId":"a","rows":[]}}' \
  0

# Bypass attempts (code-review C1): nested archiveType in rows[0]
# or conversation must NOT defeat the block. The gate must read the
# top-level tool_input.archiveType, not the first textual occurrence.
run_case "BYPASS: nested rows[0].archiveType=linkedin + top-level archiveType=whatsapp-export → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"rows":[{"archiveType":"linkedin-connections"}],"archiveType":"whatsapp-export","ownerNodeId":"x","accountId":"a"}}' \
  2

run_case "BYPASS: conversation.archiveType=linkedin + top-level archiveType=whatsapp-export → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"mcp__memory__memory-archive-write","tool_input":{"conversation":{"archiveType":"linkedin-connections","sessionId":"x"},"archiveType":"whatsapp-export","ownerNodeId":"x","accountId":"a","rows":[]}}' \
  2

# Plugin-source-edit path block must read tool_input.file_path top-level,
# not a nested file_path in old_string/new_string.
run_case "BYPASS: nested file_path in old_string + top-level file_path in lib/* → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Edit","tool_input":{"file_path":"/repo/platform/plugins/memory/mcp/src/lib/conversation-normalisers/whatsapp-text.ts","old_string":"file_path:/safe/path","new_string":"x"}}' \
  2

run_case "PreToolUse Bash invoking conversation-archive-ingest.sh → ALLOWED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"bash platform/plugins/memory/bin/conversation-archive-ingest.sh /tmp/chat.zip --source whatsapp --owner-element-id 4:abc:1 --participant-person-ids 4:abc:2 --scope admin"}}' \
  0

# Default-allow log-line check
LOG=$(printf '%s' '{"hook_event_name":"PreToolUse","tool_name":"Read","tool_input":{"file_path":"/tmp/foo"}}' | bash "$HOOK" 2>&1 1>/dev/null)
if printf '%s' "$LOG" | grep -q '\[archive-ingest-gate\] decision=allow tool=Read reason=default'; then
  echo "PASS: default-allow emits decision-log line"
  PASS=$((PASS + 1))
else
  echo "FAIL: default-allow missing decision-log line. Got: $LOG" >&2
  FAIL=$((FAIL + 1))
fi

# Block-log line includes command field for Bash
LOG=$(printf '%s' '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"npx vitest run"}}' | bash "$HOOK" 2>&1 1>/dev/null)
if printf '%s' "$LOG" | grep -q '\[archive-ingest-gate\] decision=block tool=Bash reason=test-runner'; then
  echo "PASS: block emits decision-log line with reason"
  PASS=$((PASS + 1))
else
  echo "FAIL: block missing decision-log line. Got: $LOG" >&2
  FAIL=$((FAIL + 1))
fi

# Parse-error flag lifecycle (preserved)
rm -f "$FLAG_FILE"
run_case "PostToolUse parse-error sets flag (exit 0)" \
  '{"hook_event_name":"PostToolUse","tool_name":"mcp__memory__whatsapp-export-parse","tool_input":{"filePath":"_chat.txt"},"tool_response":{"isError":true,"content":[{"type":"text","text":"parse-error file=_chat.txt line=1 reason=not-a-_chat.txt"}]}}' \
  0
[[ -f "$FLAG_FILE" ]] && { echo "PASS: parse-error flag created"; PASS=$((PASS+1)); } \
                      || { echo "FAIL: parse-error flag NOT created" >&2; FAIL=$((FAIL+1)); }

run_case "PreToolUse Read after parse-error → BLOCKED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Read","tool_input":{"file_path":"/tmp/foo"}}' \
  2

run_case "UserPromptSubmit clears flag" \
  '{"hook_event_name":"UserPromptSubmit","prompt":"retry"}' \
  0
[[ ! -f "$FLAG_FILE" ]] && { echo "PASS: UserPromptSubmit cleared flag"; PASS=$((PASS+1)); } \
                        || { echo "FAIL: UserPromptSubmit did NOT clear flag" >&2; FAIL=$((FAIL+1)); }

run_case "PreToolUse Read after clearance → ALLOWED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Read","tool_input":{"file_path":"/tmp/foo"}}' \
  0

# Stale flag auto-clears
PAST=$(( $(date -u +%s) - 700 ))
echo "$PAST" > "$FLAG_FILE"
run_case "Stale flag auto-clears, PreToolUse Read → ALLOWED" \
  '{"hook_event_name":"PreToolUse","tool_name":"Read","tool_input":{"file_path":"/tmp/foo"}}' \
  0

# PostToolUse parse-success leaves flag absent
rm -f "$FLAG_FILE"
run_case "PostToolUse parse-success (isError:false) does NOT set flag" \
  '{"hook_event_name":"PostToolUse","tool_name":"mcp__memory__whatsapp-export-parse","tool_input":{"filePath":"_chat.txt"},"tool_response":{"isError":false,"content":[{"type":"text","text":"{\"parsedLines\":[]}"}]}}' \
  0
[[ ! -f "$FLAG_FILE" ]] && { echo "PASS: parse-success leaves flag absent"; PASS=$((PASS+1)); } \
                        || { echo "FAIL: parse-success incorrectly created flag" >&2; FAIL=$((FAIL+1)); }

# Fail-closed terminal check
if grep -q '\[ -t 0 \]' "$HOOK"; then
  echo "PASS: fail-closed terminal check is present"
  PASS=$((PASS + 1))
else
  echo "FAIL: fail-closed terminal check missing" >&2
  FAIL=$((FAIL + 1))
fi

echo
echo "──────── archive-ingest-surface-gate test summary ────────"
echo "PASS: $PASS"
echo "FAIL: $FAIL"

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