#!/usr/bin/env bash
# Offline tests for the M24-10 prod post-deploy smoke checks (scripts/deploy/smoke-prod.sh).
# No live target, no network: a stub `curl` on PATH serves canned fixture responses keyed by
# URL path (the same stub-binary harness as test_e2e_promote_rollback.sh's ssh) and records
# every URL it was asked for, so the check matrix - health contract, the testLogin:false
# security guard, the login-page shell, and asset loading - is asserted end to end against
# both a healthy prod shape and each failure shape.
#
# Run from anywhere: bash scripts/deploy/tests/test_smoke_prod.sh
set -euo pipefail

cd "$(dirname "${BASH_SOURCE[0]}")/../../.."
repo_root="$PWD"

failures=0
pass() { echo "  ok: $1"; }
fail() { echo "  FAIL: $1" >&2; failures=$((failures + 1)); }
check() { # <description> <command...>
  local desc="$1"
  shift
  if "$@" >/dev/null 2>&1; then pass "$desc"; else fail "$desc"; fi
}

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

# Stub curl: parse out -o <file> and the URL, serve $SMOKE_FIXTURES/<munged-path>.{body,code}
# (missing fixture -> empty body + 404), record the URL in $CURL_CALLS. Path munging: strip the
# leading slash, then each remaining / becomes __ ('/' itself is 'root').
mkdir -p "$workdir/bin"
cat > "$workdir/bin/curl" <<'STUB'
#!/usr/bin/env bash
out=/dev/null
url=""
while [ $# -gt 0 ]; do
  case "$1" in
    -o) out="$2"; shift ;;
    -w | --max-time) shift ;;
    -*) ;;
    *) url="$1" ;;
  esac
  shift
done
printf '%s\n' "$url" >> "$CURL_CALLS"
rest="${url#*://}"
case "$rest" in
  */*) path="/${rest#*/}" ;;
  *) path="/" ;;
esac
name="${path#/}"
name="${name//\//__}"
[ -n "$name" ] || name=root
if [ -f "$SMOKE_FIXTURES/$name.body" ]; then cat "$SMOKE_FIXTURES/$name.body" > "$out"; else : > "$out"; fi
if [ -f "$SMOKE_FIXTURES/$name.code" ]; then cat "$SMOKE_FIXTURES/$name.code"; else printf '404'; fi
STUB
chmod +x "$workdir/bin/curl"

make_fixtures() { # <dir> - a healthy prod-shaped target; tests mutate copies of this
  local d="$1"
  mkdir -p "$d"
  cat > "$d/health.body" <<'JSON'
{"status":"ok","version":"1.2.3","llm_provider":"fake","engine":{"mode":"claude_code","ready":true,"checks":[]}}
JSON
  echo 200 > "$d/health.code"
  cat > "$d/api__auth__config.body" <<'JSON'
{"google":true,"testLogin":false,"testLoginRequiresPassword":false}
JSON
  echo 200 > "$d/api__auth__config.code"
  cat > "$d/root.body" <<'HTML'
<!doctype html><html><head><title>Bloom</title><link rel="stylesheet" crossorigin href="/assets/index-C3xY.css"></head><body><div id="root" class="h-full"></div><script type="module" crossorigin src="/assets/index-B2aZ.js"></script></body></html>
HTML
  echo 200 > "$d/root.code"
  echo 'console.log("bloom")' > "$d/assets__index-B2aZ.js.body"
  echo 200 > "$d/assets__index-B2aZ.js.code"
  echo 'body{color:#000}' > "$d/assets__index-C3xY.css.body"
  echo 200 > "$d/assets__index-C3xY.css.code"
}

rc=0
run_smoke() { # <fixtures-dir> [extra env assignments...] - rc + calls.txt + summary.md result
  local fixtures="$1"
  shift
  : > "$workdir/calls.txt"
  : > "$workdir/summary.md"
  rc=0
  env PATH="$workdir/bin:$PATH" CURL_CALLS="$workdir/calls.txt" SMOKE_FIXTURES="$fixtures" \
    GITHUB_STEP_SUMMARY="$workdir/summary.md" SMOKE_BASE_URL="https://prod.example" "$@" \
    bash "$repo_root/scripts/deploy/smoke-prod.sh" \
    > "$workdir/out.log" 2> "$workdir/err.log" || rc=$?
}
called() { grep -q "$1" "$workdir/calls.txt"; }

echo "smoke-prod.sh: input validation"
run_smoke "$workdir/none" SMOKE_BASE_URL=
check "empty SMOKE_BASE_URL is rejected" test "$rc" -ne 0
check "no request is made for a rejected invocation" test ! -s "$workdir/calls.txt"

echo "smoke-prod.sh: healthy prod-shaped target is green"
make_fixtures "$workdir/healthy"
run_smoke "$workdir/healthy"
check "exit 0 against a healthy target" test "$rc" -eq 0
check "no check row failed" bash -c '! grep -q "❌" "$1"' _ "$workdir/summary.md"
check "the summary records the green verdict" grep -q "All checks passed" "$workdir/summary.md"
check "the security guard row is in the summary" grep -q "testLogin is false" "$workdir/summary.md"
check "the shell-referenced JS bundle was fetched" called "/assets/index-B2aZ.js"
check "the shell-referenced CSS bundle was fetched" called "/assets/index-C3xY.css"

echo "smoke-prod.sh: /health goes through the API origin when one is configured"
run_smoke "$workdir/healthy" SMOKE_API_BASE_URL="https://api.prod.example"
check "health is probed on the API origin" called "https://api.prod.example/health"
check "auth config stays on the dashboard origin" \
  called "https://prod.example/api/auth/config"

echo "smoke-prod.sh: the testLogin:false security guard fails loudly"
cp -r "$workdir/healthy" "$workdir/bypass"
echo '{"google":true,"testLogin":true,"testLoginRequiresPassword":true}' \
  > "$workdir/bypass/api__auth__config.body"
run_smoke "$workdir/bypass"
check "testLogin:true reds the run" test "$rc" -ne 0
check "the failure names the security regression" \
  grep -q "SECURITY REGRESSION" "$workdir/err.log"
check "later checks still ran (no fail-fast)" called "/assets/index-B2aZ.js"
cp -r "$workdir/healthy" "$workdir/keyless"
echo '{"google":true}' > "$workdir/keyless/api__auth__config.body"
run_smoke "$workdir/keyless"
check "a missing testLogin key fails closed" test "$rc" -ne 0

echo "smoke-prod.sh: health failures red the run"
cp -r "$workdir/healthy" "$workdir/api500"
echo 500 > "$workdir/api500/health.code"
run_smoke "$workdir/api500"
check "a non-200 /health reds the run" test "$rc" -ne 0
cp -r "$workdir/healthy" "$workdir/noversion"
echo '{"status":"ok","engine":{"mode":"local","ready":true}}' \
  > "$workdir/noversion/health.body"
run_smoke "$workdir/noversion"
check "a /health body without a version reds the run" test "$rc" -ne 0
rm -rf "$workdir/gone"
mkdir -p "$workdir/gone"
run_smoke "$workdir/gone"
check "an entirely unreachable target reds the run" test "$rc" -ne 0

echo "smoke-prod.sh: login-page shell and asset failures red the run"
cp -r "$workdir/healthy" "$workdir/nomount"
sed -i 's/id="root"/id="app"/' "$workdir/nomount/root.body"
run_smoke "$workdir/nomount"
check "a shell without the SPA mount reds the run" test "$rc" -ne 0
cp -r "$workdir/healthy" "$workdir/noassets"
echo '<!doctype html><html><head><title>Bloom</title></head><body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body></html>' \
  > "$workdir/noassets/root.body"
run_smoke "$workdir/noassets"
check "a shell with no built /assets bundle reds the run (not a production build)" \
  test "$rc" -ne 0
cp -r "$workdir/healthy" "$workdir/asset404"
rm "$workdir/asset404/assets__index-B2aZ.js.body" "$workdir/asset404/assets__index-B2aZ.js.code"
run_smoke "$workdir/asset404"
check "a 404 on a referenced asset reds the run" test "$rc" -ne 0

echo "smoke-prod.sh: a red run's summary points at the manual rollback path"
run_smoke "$workdir/bypass"
check "the summary counts the failed checks" grep -q "smoke check(s) failed" "$workdir/summary.md"
check "the summary names the manual API rollback" grep -q "mode: rollback" "$workdir/summary.md"
check "the summary names the web rollback path" grep -q "Cloudflare Pages" "$workdir/summary.md"

echo
if [ "$failures" -gt 0 ]; then
  echo "$failures test(s) FAILED" >&2
  exit 1
fi
echo "all tests passed"
