#!/usr/bin/env bash
# Local checks for hsc-setup.sh: syntax, and the pure functions that decide
# what ends up in keys.json and in the nginx map. Everything root-only is
# stubbed; this never touches the system.
set -uo pipefail

# Absolute, because sourcing the script's functions below moves us to /: the
# installer stands somewhere every user can reach, and so must the path we
# then hand to bash.
SCRIPT_ARG="${1:?usage: hsc-setup-check.sh <path to hsc-setup.sh>}"
SCRIPT="$(cd -- "$(dirname -- "$SCRIPT_ARG")" && pwd)/$(basename -- "$SCRIPT_ARG")"
[ -f "$SCRIPT" ] || { printf 'no such script: %s\n' "$SCRIPT_ARG" >&2; exit 2; }
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
fail=0
check() { # check <name> <expected> <actual>
  if [ "$2" = "$3" ]; then printf '  ok   %s\n' "$1"
  else printf '  FAIL %s\n       expected: %s\n       actual:   %s\n' "$1" "$2" "$3"; fail=1; fi
}

printf '\nsyntax\n'
if bash -n "$SCRIPT"; then printf '  ok   bash -n\n'; else printf '  FAIL bash -n\n'; fail=1; fi

# Source everything above the entry point, so the functions exist but nothing runs.
sed '/^# Entry point$/,$d' "$SCRIPT" >"$WORK/lib.sh"
# shellcheck disable=SC1090
DIR="$WORK" NGINX_KEYS="$WORK/hsc-keys.conf" SERVICE_USER="$(id -un)" . "$WORK/lib.sh"
DIR="$WORK"; NGINX_KEYS="$WORK/hsc-keys.conf"; SERVICE_USER="$(id -un)"
trap 'rm -rf "$WORK"' EXIT ERR # the script installs its own ERR trap; drop it here

# `install` needs root for -o/-g; keep the last two arguments and copy.
install() { local args=("$@") n=$#; cp "${args[n-2]}" "${args[n-1]}"; }
chmod_stub() { :; }

printf '\nsites\n'
check "four sites are configured" "4" "$(site_names | wc -l | tr -d ' ')"
check "names" "elevaseo seoinsight dash-seoinsight public-demo" "$(site_names | tr '\n' ' ' | sed 's/ $//')"
# The public form's key. "*" is the whole entry, never one origin among several:
# "these, plus anything" is "anything" with the fact hidden, and server.ts
# refuses to load such a file.
check "the public site audits any origin" "*" "$(site_origins public-demo)"
check "PUBLIC_SITE names a site that exists" "1" "$(site_names | grep -cx "$PUBLIC_SITE")"
check "elevaseo origins" "https://elevaseo.com https://www.elevaseo.com" "$(site_origins elevaseo)"
check "dash origins" "https://dash.seoinsight.app" "$(site_origins dash-seoinsight)"
check "unknown site has no origins" "" "$(site_origins nope)"

printf '\nkeys\n'
key="$(new_key elevaseo)"
if printf '%s' "$key" | grep -Eq '^hsc_[A-Za-z0-9_-]{27}$'; then
  printf '  ok   a key is hsc_<27 base64url> (160 bits)\n'
else
  printf '  FAIL key shape: %s\n' "$key"; fail=1
fi
check "two keys differ" "different" "$([ "$(new_key x)" != "$(new_key x)" ] && echo different || echo same)"

printf '\nnginx map round-trip\n'
k1="$(new_key elevaseo)"; k2="$(new_key seoinsight)"; k3="$(new_key dash-seoinsight)"
write_nginx_keys "elevaseo=$k1" "seoinsight=$k2" "dash-seoinsight=$k3"
check "elevaseo key reads back" "$k1" "$(existing_key elevaseo)"
check "dash-seoinsight key reads back" "$k3" "$(existing_key dash-seoinsight)"
check "an unconfigured site has no key" "" "$(existing_key client9)"
check "the map has a default" "1" "$(grep -c 'default ""' "$WORK/hsc-keys.conf")"
check "one line per site" "3" "$(grep -c "^    \"Bearer hsc_" "$WORK/hsc-keys.conf")"
check "no key leaks into a comment" "0" "$(grep -c "^#.*$k1" "$WORK/hsc-keys.conf")"
# nginx hashes map keys in 64-byte buckets and the directive that raises that
# is not ours to declare, so the key is built to fit instead.
longest="$(printf 'Bearer %s' "$k3" | wc -c | tr -d ' ')"
needed="$(nginx_hash_entry_size "$longest")"
# ngx_hash_init: sizeof(void*) + ngx_align(len + 2, sizeof(void*)) + sizeof(void*)
check "the entry cost is computed as nginx does (len 54 → 72)" "72" "$(nginx_hash_entry_size 54)"
check "and at the documented ceiling (len 46 → 64)" "64" "$(nginx_hash_entry_size 46)"
check "a key line of $longest chars costs $needed of 64 bytes" "yes" \
  "$([ "$needed" -le 64 ] && echo yes || echo no)"
check "we declare no global nginx tuning" "0" \
  "$(grep -c 'map_hash_bucket_size' "$WORK/hsc-keys.conf")"

printf '\nkeys.json\n'
write_keys_json
if bun -e 'JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"))' "$WORK/keys.json" 2>/dev/null; then
  printf '  ok   valid JSON\n'
else
  printf '  FAIL keys.json is not valid JSON:\n'; cat "$WORK/keys.json"; fail=1
fi
check "elevaseo has both origins" "2" \
  "$(bun -e 'const k=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log(k.elevaseo.length)' "$WORK/keys.json" 2>/dev/null)"
check "dash has one origin" "https://dash.seoinsight.app" \
  "$(bun -e 'const k=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log(k["dash-seoinsight"][0])' "$WORK/keys.json" 2>/dev/null)"
check "no key material in keys.json" "0" "$(grep -c 'hsc_' "$WORK/keys.json")"
check "the public entry is exactly [\"*\"]" '["*"]' \
  "$(bun -e 'const k=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log(JSON.stringify(k["public-demo"]))' "$WORK/keys.json" 2>/dev/null)"
# The regression that would matter most: one permissive entry must not widen
# the others. A named site keeps exactly the origins it was given.
check "the wildcard does not spread to named sites" '["https://dash.seoinsight.app"]' \
  "$(bun -e 'const k=JSON.parse(require("fs").readFileSync(process.argv[1],"utf8"));console.log(JSON.stringify(k["dash-seoinsight"]))' "$WORK/keys.json" 2>/dev/null)"

printf '\ncli\n'
check "help exits 0" "0" "$(bash "$SCRIPT" --help >/dev/null 2>&1; echo $?)"
check "unknown command is refused" "1" "$(bash "$SCRIPT" frobnicate >/dev/null 2>&1; echo $?)"

printf '\n'
[ $fail -eq 0 ] && printf 'all checks passed\n' || printf 'FAILURES\n'
exit $fail
