#!/bin/bash
# Build Fieldbook and verify the result actually serves.
#
# Usage:  ./selfhost-build.sh          build and verify
#         ./selfhost-build.sh --no-verify
#
# Then:   sudo systemctl restart fieldbook
set -euo pipefail

cd "$(dirname "$(readlink -f "$0")")"

PORT_SMOKE=8479          # never 8478 - that is the running service
SSR_ASSETS="node_modules/.nitro/vite/services/ssr/assets"
PUB_ASSETS=".output/public/assets"

echo "==> Clearing previous output"
# All build scratch. A stale mix of these has produced asset hashes that
# disagree with the freshly rendered HTML.
rm -rf .output .tanstack

echo "==> Building"
npm run build

echo "==> Publishing SSR-emitted stylesheets"
# src/routes/__root.tsx does `import appCss from "../styles.css?url"`. That
# module is compiled in BOTH the client and SSR environments, and each emits
# its own hashed stylesheet. The SSR render is what writes the <link href>, so
# the page asks for the SSR hash - but only the client asset is copied into
# .output/public, and the stylesheet 404s (app renders completely unstyled).
# Copy the SSR stylesheets across so the rendered href resolves. Only *.css:
# the SSR .js chunks are server-side and must not be exposed publicly.
shopt -s nullglob
copied=0
for css in "$SSR_ASSETS"/*.css; do
  dest="$PUB_ASSETS/$(basename "$css")"
  if [[ ! -f "$dest" ]]; then
    cp "$css" "$dest"
    echo "    + $(basename "$css")"
    copied=$((copied + 1))
  fi
done
shopt -u nullglob
[[ $copied -eq 0 ]] && echo "    (nothing to copy - the two builds agreed this time)"

if [[ "${1:-}" == "--no-verify" ]]; then
  echo "==> Skipping verification (--no-verify)"
  exit 0
fi

echo "==> Verifying the built server renders with every asset resolving"
PORT=$PORT_SMOKE HOST=127.0.0.1 NODE_ENV=production node .output/server/index.mjs &
smoke_pid=$!
trap 'kill $smoke_pid 2>/dev/null || true' EXIT

for _ in $(seq 1 40); do
  curl -sf -o /dev/null --max-time 2 "http://127.0.0.1:$PORT_SMOKE/" && break
  sleep 0.5
done

html=$(curl -sf --max-time 10 "http://127.0.0.1:$PORT_SMOKE/" | tr -d '\0')
[[ -n "$html" ]] || { echo "FAIL: server returned nothing for /"; exit 1; }

broken=0
# Model the deployed topology exactly:
#   /assets/*  -> Apache Alias, served straight off .output/public/assets
#   everything else -> the Node server
# The split matters. .output/server/index.mjs embeds a BUILD-TIME manifest of
# public assets, so the SSR stylesheet copied in above is invisible to Node and
# 404s there - which is why Apache owns /assets. Checking those over HTTP here
# would report a failure that does not exist in production, and checking them
# on disk is what actually catches the bug this guards against.
while read -r url; do
  [[ -z "$url" ]] && continue
  if [[ "$url" == /assets/* ]]; then
    if [[ ! -f "$PUB_ASSETS/$(basename "$url")" ]]; then
      echo "    MISSING ON DISK $url"
      broken=$((broken + 1))
    fi
    continue
  fi
  # The trailing \n matters: without it `read` hits EOF, returns non-zero and
  # `set -e` aborts the whole script with no diagnostic.
  read -r code ctype < <(curl -s -o /dev/null -w '%{http_code} %{content_type}\n' \
    --max-time 10 "http://127.0.0.1:$PORT_SMOKE$url")
  if [[ "$code" != "200" || "$ctype" == text/html* ]]; then
    echo "    BROKEN $code $ctype $url"
    broken=$((broken + 1))
  fi
done < <(grep -oE '(src|href)="/[^"]+\.(js|mjs|css)"' <<<"$html" \
         | sed -E 's/^(src|href)="//; s/"$//' | sort -u)

# Served by the Node server, so a plain HTTP check is the right one.
for path in /favicon.svg /manifest.webmanifest; do
  read -r code ctype < <(curl -s -o /dev/null -w '%{http_code} %{content_type}\n' \
    --max-time 10 "http://127.0.0.1:$PORT_SMOKE$path")
  if [[ "$code" != "200" ]]; then
    echo "    BROKEN $code $ctype $path"
    broken=$((broken + 1))
  fi
done

# The storage API must exist, and must be wired to a database. 503 means
# FIELDBOOK_DATABASE_URL is missing, which silently degrades the app to
# browser-only storage - the failure this whole design exists to prevent.
read -r code < <(curl -s -o /dev/null -w '%{http_code}\n' --max-time 10 \
  "http://127.0.0.1:$PORT_SMOKE/api/book")
if [[ "$code" == "503" ]]; then
  echo "    NOTE /api/book returned 503 - no FIELDBOOK_DATABASE_URL in this shell."
  echo "         Expected here; systemd supplies it from /etc/fieldbook.env."
elif [[ "$code" != "200" ]]; then
  echo "    BROKEN $code /api/book"
  broken=$((broken + 1))
fi

if [[ $broken -gt 0 ]]; then
  echo "FAIL: $broken referenced asset(s) do not resolve"
  exit 1
fi

grep -q '<title>' <<<"$html" || { echo "FAIL: no <title> in rendered HTML"; exit 1; }

echo "==> OK: build verified"
