#!/usr/bin/env bash
# Regression test for account-settings-pdf-conformance.sh (Task 1929).
#
# The lib retrofits the quote-render PDF-conformance PostToolUse matcher onto
# existing accounts' .claude/settings.json on every install/upgrade. Task 1922
# added the matcher to provision-account-dir.sh, but that writer only runs at
# account-provision time and the upgrade path re-provisions only the house
# account -- so an account provisioned before 1922 keeps a settings.json without
# the browser-pdf-save PostToolUse matcher and never runs the PDF gate (live
# glsmith is such an account).
#
# Covers:
#   1. Stale matcher (browser-pdf-save present, conformance cmd absent) -> updated, appended, idempotent
#   2. Correct matcher (conformance cmd present)                        -> already-set, byte-identical
#   3. browser-pdf-save matcher absent (broad mcp__.* present)          -> updated, matcher added, wildcard untouched
#   4. No .hooks.PostToolUse                                            -> no-hooks, untouched
#   5. File absent                                                      -> absent
#   6. Malformed JSON                                                   -> rewrite-failed, untouched, no temp
#   7. reconcile_all_accounts_pdf_conformance                          -> patches every account.json dir, skips others
#
# All cases assert the [backfill-1929] status token and the post-state of the file.

set -u

LIB="$(cd "$(dirname "$0")/.." && pwd)/account-settings-pdf-conformance.sh"
if [ ! -f "$LIB" ]; then
  echo "FAIL: $LIB not found" >&2
  exit 1
fi
# shellcheck source=/dev/null
. "$LIB"

MATCHER='mcp__plugin_browser_browser__browser-pdf-save'
CONFORMANCE='bash $PLATFORM_ROOT/plugins/admin/hooks/quote-render-pdf-conformance.sh'

PASS=0
FAIL=0
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT

ok()   { PASS=$((PASS+1)); }
bad()  { FAIL=$((FAIL+1)); echo "FAIL: $1" >&2; }

# settings.json with a PostToolUse browser-pdf-save matcher carrying the given
# command list. Args after $1 are command strings for that matcher.
write_settings() {
  local file="$1"; shift
  local cmds="" c
  for c in "$@"; do
    [ -n "$cmds" ] && cmds="$cmds,"
    cmds="$cmds{\"type\":\"command\",\"command\":\"$c\"}"
  done
  mkdir -p "$(dirname "$file")"
  cat > "$file" <<EOF
{
  "permissions": { "defaultMode": "bypassPermissions", "allow": [], "deny": [] },
  "hooks": {
    "PostToolUse": [
      { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash \$P/b.sh" } ] },
      { "matcher": "$MATCHER", "hooks": [ $cmds ] },
      { "matcher": "mcp__.*", "hooks": [ { "type": "command", "command": "bash \$P/missing.sh" } ] }
    ]
  }
}
EOF
}

conformance_count() { grep -cF 'quote-render-pdf-conformance.sh' "$1" 2>/dev/null || true; }
pdfmatcher_present() {
  jq -e --arg m "$MATCHER" '.hooks.PostToolUse | any(.[]; .matcher == $m)' "$1" >/dev/null 2>&1
}
wildcard_present() {
  jq -e '.hooks.PostToolUse | any(.[]; .matcher == "mcp__.*")' "$1" >/dev/null 2>&1
}

# --- 1. stale matcher -> updated, then idempotent ---------------------------
F="$TMP/stale/.claude/settings.json"
write_settings "$F"
OUT="$(ensure_pdf_conformance_matcher "$F")"
case "$OUT" in *status=updated*) ok;; *) bad "1a stale should be updated, got: $OUT";; esac
[ "$(conformance_count "$F")" -eq 1 ] && ok || bad "1b conformance not appended (count=$(conformance_count "$F"))"
OUT2="$(ensure_pdf_conformance_matcher "$F")"
case "$OUT2" in *status=already-set*) ok;; *) bad "1c re-run should be already-set, got: $OUT2";; esac
[ "$(conformance_count "$F")" -eq 1 ] && ok || bad "1d conformance duplicated on re-run (count=$(conformance_count "$F"))"

# --- 2. correct matcher -> already-set, byte-identical ----------------------
F="$TMP/good/.claude/settings.json"
write_settings "$F" "$CONFORMANCE"
BEFORE="$(cat "$F")"
OUT="$(ensure_pdf_conformance_matcher "$F")"
case "$OUT" in *status=already-set*) ok;; *) bad "2a good should be already-set, got: $OUT";; esac
[ "$BEFORE" = "$(cat "$F")" ] && ok || bad "2b already-set file was rewritten"

# --- 3. browser-pdf-save matcher absent (wildcard present) -> updated, added --
F="$TMP/nomatcher/.claude/settings.json"
mkdir -p "$(dirname "$F")"
cat > "$F" <<'EOF'
{ "permissions": {}, "hooks": { "PostToolUse": [
  { "matcher": "Bash", "hooks": [] },
  { "matcher": "mcp__.*", "hooks": [ { "type": "command", "command": "bash $P/missing.sh" } ] }
] } }
EOF
OUT="$(ensure_pdf_conformance_matcher "$F")"
case "$OUT" in *status=updated*) ok;; *) bad "3a nomatcher should be updated, got: $OUT";; esac
pdfmatcher_present "$F" && ok || bad "3b browser-pdf-save matcher not added"
[ "$(conformance_count "$F")" -eq 1 ] && ok || bad "3c conformance missing after add"
wildcard_present "$F" && ok || bad "3d wildcard matcher was disturbed"
# added matcher carries exactly the one conformance command
if jq -e --arg m "$MATCHER" '.hooks.PostToolUse[] | select(.matcher==$m) | .hooks | length == 1' "$F" >/dev/null 2>&1; then ok; else bad "3e added matcher should carry exactly one command"; fi

# --- 4. no PostToolUse -> no-hooks, untouched -------------------------------
F="$TMP/nohooks/.claude/settings.json"
mkdir -p "$(dirname "$F")"
echo '{ "permissions": {}, "hooks": {} }' > "$F"
BEFORE="$(cat "$F")"
OUT="$(ensure_pdf_conformance_matcher "$F")"
case "$OUT" in *status=no-hooks*) ok;; *) bad "4a should be no-hooks, got: $OUT";; esac
[ "$BEFORE" = "$(cat "$F")" ] && ok || bad "4b no-hooks file was rewritten"

# --- 5. file absent -> absent ------------------------------------------------
OUT="$(ensure_pdf_conformance_matcher "$TMP/does-not-exist/.claude/settings.json")"
case "$OUT" in *status=absent*) ok;; *) bad "5 should be absent, got: $OUT";; esac

# --- 6. malformed JSON -> rewrite-failed, untouched -------------------------
F="$TMP/bad/.claude/settings.json"
mkdir -p "$(dirname "$F")"
printf '{ this is not json ' > "$F"
BEFORE="$(cat "$F")"
OUT="$(ensure_pdf_conformance_matcher "$F")"
case "$OUT" in *status=rewrite-failed*) ok;; *) bad "6a malformed should be rewrite-failed, got: $OUT";; esac
[ "$BEFORE" = "$(cat "$F")" ] && ok || bad "6b malformed file was mutated"
[ ! -e "$F.1929.tmp" ] && ok || bad "6c temp file left behind"

# --- 7. reconcile_all_accounts_pdf_conformance ------------------------------
ROOT="$TMP/accts"
mkdir -p "$ROOT/acctA/.claude" "$ROOT/acctB/.claude" "$ROOT/notanaccount/.claude"
echo '{"role":"house"}'  > "$ROOT/acctA/account.json"
echo '{"role":"client"}' > "$ROOT/acctB/account.json"
# notanaccount has no account.json -> must be skipped
write_settings "$ROOT/acctA/.claude/settings.json"
write_settings "$ROOT/acctB/.claude/settings.json" "$CONFORMANCE"
write_settings "$ROOT/notanaccount/.claude/settings.json"
RECOUT="$(reconcile_all_accounts_pdf_conformance "$ROOT")"
[ "$(conformance_count "$ROOT/acctA/.claude/settings.json")" -eq 1 ] && ok || bad "7a acctA not patched"
[ "$(conformance_count "$ROOT/acctB/.claude/settings.json")" -eq 1 ] && ok || bad "7b acctB disturbed"
[ "$(conformance_count "$ROOT/notanaccount/.claude/settings.json")" -eq 0 ] && ok || bad "7c non-account dir was patched"
case "$RECOUT" in *acctA*status=updated*) ok;; *) bad "7d reconcile did not log acctA updated";; esac

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