#!/usr/bin/env bash
# Non-browser live-check for the host: spins up an EPHEMERAL host server (this
# worktree's binary + lib + web, a temp persist dir), logs in, seeds one post, then
# runs a sequence of HTTP checks printing status | content-type | body-head for each.
# Catches what conformance can't — the real http-listen serving path (serving-JIT
# divergence, VmSuspended renders, content-type regressions) — without a browser and
# without touching live data. The non-Playwright counterpart to run-picker-check.sh.
#
#   bash lib/host/live-check.sh                      # default smoke: /health /posts /feed / /<seeded>/
#   bash lib/host/live-check.sh /tags /article/      # check specific GET paths instead
#
# Asserts: reads are text/sx (the SX-native wire), pages are non-empty, no 5xx.
# Requires the OCaml binary built (hosts/ocaml/_build/default/bin/sx_server.exe).
set -uo pipefail
cd "$(git rev-parse --show-toplevel)"

PORT="${LIVE_PORT:-8914}"
USER="admin"; PASS="live-check-pw"; SECRET="live-check-secret"
PDIR=$(mktemp -d); JAR=$(mktemp); LOG=$(mktemp); HDR=$(mktemp)
BASE="http://127.0.0.1:$PORT"
RC=0

cleanup() {
  local pid
  pid=$(ss -lptn "sport = :$PORT" 2>/dev/null | grep -oE 'pid=[0-9]+' | head -1 | cut -d= -f2)
  [ -n "$pid" ] && kill "$pid" 2>/dev/null
  rm -f "$JAR" "$LOG" "$HDR"; rm -rf "$PDIR"
}
trap cleanup EXIT

echo "== booting ephemeral host on :$PORT (persist=$PDIR) =="
# SX_SERVING_JIT=1 to MATCH THE CONTAINER: it gates the http-listen IO resolver, so
# without it perform-heavy paths (e.g. reach-down's BFS over the type graph — the is-a/
# tags picker) falsely raise VmSuspended -> 500. The live container sets it; the harness
# must too, or it reports false 500s the live site never shows.
SX_SERVING_JIT=1 HOST_PORT="$PORT" SX_PERSIST_DIR="$PDIR" \
  SX_ADMIN_USER="$USER" SX_ADMIN_PASSWORD="$PASS" SX_SESSION_SECRET="$SECRET" \
  bash lib/host/serve.sh >"$LOG" 2>&1 &
for i in $(seq 1 60); do
  curl -sf -o /dev/null "$BASE/health" 2>/dev/null && break
  sleep 1; [ "$i" = "60" ] && { echo "server never came up:"; cat "$LOG"; exit 1; }
done
echo "== up =="

# Log in + seed one post (also exercises the form-ingest write path).
curl -s -c "$JAR" -o /dev/null -X POST "$BASE/login" --data "username=$USER&password=$PASS"
curl -s -b "$JAR" -o /dev/null -X POST "$BASE/new" \
  --data 'title=Live Check Post&sx_content=(article (h1 "Live Check Post") (p "ok"))&status=published'

# A GET check: prints "<status> <content-type> | <body-head>" and flags problems.
check() {
  local path="$1" body ct code
  body=$(curl -s -b "$JAR" -D "$HDR" "$BASE$path")
  code=$(awk 'NR==1{print $2}' "$HDR")
  ct=$(grep -i '^content-type:' "$HDR" | head -1 | tr -d '\r' | sed 's/content-type: *//I')
  printf '  %-20s %s  %-26s | %s\n' "$path" "${code:-???}" "${ct:-?}" "$(printf '%s' "$body" | tr '\n' ' ' | cut -c1-70)"
  case "$code" in 5*) echo "    !! 5xx"; RC=1 ;; esac
  [ -z "$body" ] && { echo "    !! empty body"; RC=1; }
  # data endpoints must be SX, never JSON
  case "$path" in
    /posts|/feed) echo "$ct" | grep -qi 'text/sx' || { echo "    !! expected text/sx, got '$ct'"; RC=1; }
                  printf '%s' "$body" | grep -q '"ok":' && { echo "    !! JSON leaked"; RC=1; } ;;
  esac
}

echo "== checks =="
if [ "$#" -gt 0 ]; then
  for p in "$@"; do check "$p"; done
else
  for p in /health /posts /feed / /live-check-post/; do check "$p"; done
fi

echo "== done (rc $RC) =="
exit $RC
