#!/usr/bin/env bash
# Regression test for account-settings-askgate.sh (Task 1683).
#
# The lib retrofits the AskUserQuestion carrier gate onto existing accounts'
# .claude/settings.json on every install/upgrade. Task 1552 added the gate to
# provision-account-dir.sh, but that writer only runs at account-provision time
# and the upgrade path never re-provisions existing client sub-accounts — so an
# account provisioned before 1552 keeps a stale AskUserQuestion matcher with no
# carrier gate and re-wedges on a channel AskUserQuestion (live SiteDesk
# incident, session d39a22b0, account 2078cb54).
#
# Covers:
#   1. Stale matcher (investigate only)      -> updated, carrier appended, idempotent on re-run
#   2. Correct matcher (both gates)          -> already-set, file byte-identical
#   3. AskUserQuestion matcher absent        -> updated, matcher added with both gates
#   4. No .hooks.PreToolUse                   -> no-hooks, file untouched
#   5. File absent                            -> absent
#   6. Malformed JSON                         -> rewrite-failed, file untouched
#   7. reconcile_all_accounts_askgate         -> patches every account.json dir, skips non-account dirs
#
# All cases assert the [backfill-1683] status token and the post-state of the file.

set -u

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

CARRIER='bash $PLATFORM_ROOT/plugins/admin/hooks/askuserquestion-channel-carrier-gate.sh'
INVEST='bash $PLATFORM_ROOT/plugins/admin/hooks/askuserquestion-investigate-gate.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 an AskUserQuestion matcher carrying the given command list.
# Args after $1 are command strings for the AskUserQuestion 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": {
    "PreToolUse": [
      { "matcher": "Write", "hooks": [ { "type": "command", "command": "bash \$P/w.sh" } ] },
      { "matcher": "AskUserQuestion", "hooks": [ $cmds ] }
    ]
  }
}
EOF
}

carrier_count() { grep -cF 'askuserquestion-channel-carrier-gate.sh' "$1" 2>/dev/null || true; }
askmatcher_present() {
  jq -e '.hooks.PreToolUse | any(.[]; .matcher == "AskUserQuestion")' "$1" >/dev/null 2>&1
}

# --- 1. stale matcher -> updated, then idempotent ---------------------------
F="$TMP/stale/.claude/settings.json"
write_settings "$F" "$INVEST"
OUT="$(ensure_askgate_carrier "$F")"
case "$OUT" in *status=updated*) ok;; *) bad "1a stale should be updated, got: $OUT";; esac
[ "$(carrier_count "$F")" -eq 1 ] && ok || bad "1b carrier not appended (count=$(carrier_count "$F"))"
# investigate still present and first
if jq -e '.hooks.PreToolUse[] | select(.matcher=="AskUserQuestion") | .hooks[0].command | test("investigate-gate")' "$F" >/dev/null 2>&1; then ok; else bad "1c investigate no longer first"; fi
OUT2="$(ensure_askgate_carrier "$F")"
case "$OUT2" in *status=already-set*) ok;; *) bad "1d re-run should be already-set, got: $OUT2";; esac
[ "$(carrier_count "$F")" -eq 1 ] && ok || bad "1e carrier duplicated on re-run (count=$(carrier_count "$F"))"

# --- 2. correct matcher -> already-set, byte-identical ----------------------
F="$TMP/good/.claude/settings.json"
write_settings "$F" "$INVEST" "$CARRIER"
BEFORE="$(cat "$F")"
OUT="$(ensure_askgate_carrier "$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. AskUserQuestion matcher absent -> updated, matcher added -------------
F="$TMP/nomatcher/.claude/settings.json"
mkdir -p "$(dirname "$F")"
cat > "$F" <<'EOF'
{ "permissions": {}, "hooks": { "PreToolUse": [ { "matcher": "Write", "hooks": [] } ] } }
EOF
OUT="$(ensure_askgate_carrier "$F")"
case "$OUT" in *status=updated*) ok;; *) bad "3a nomatcher should be updated, got: $OUT";; esac
askmatcher_present "$F" && ok || bad "3b AskUserQuestion matcher not added"
[ "$(carrier_count "$F")" -eq 1 ] && ok || bad "3c carrier missing after add"
if jq -e '.hooks.PreToolUse[] | select(.matcher=="AskUserQuestion") | .hooks | length == 2' "$F" >/dev/null 2>&1; then ok; else bad "3d added matcher should carry both gates"; fi

# --- 4. no PreToolUse -> no-hooks, untouched --------------------------------
F="$TMP/nohooks/.claude/settings.json"
mkdir -p "$(dirname "$F")"
echo '{ "permissions": {}, "hooks": {} }' > "$F"
BEFORE="$(cat "$F")"
OUT="$(ensure_askgate_carrier "$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_askgate_carrier "$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_askgate_carrier "$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.1683.tmp" ] && ok || bad "6c temp file left behind"

# --- 7. reconcile_all_accounts_askgate --------------------------------------
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" "$INVEST"
write_settings "$ROOT/acctB/.claude/settings.json" "$INVEST" "$CARRIER"
write_settings "$ROOT/notanaccount/.claude/settings.json" "$INVEST"
RECOUT="$(reconcile_all_accounts_askgate "$ROOT")"
[ "$(carrier_count "$ROOT/acctA/.claude/settings.json")" -eq 1 ] && ok || bad "7a acctA not patched"
[ "$(carrier_count "$ROOT/acctB/.claude/settings.json")" -eq 1 ] && ok || bad "7b acctB disturbed"
[ "$(carrier_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 ]
