#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# Idempotent bare-metal cutover/refresh for one POC environment.
#
# Run by the CI deploy job AFTER rsync (as root on the server), once per env:
#     bash /srv/www/digt/<host>/deploy/server-setup.sh <host>
#   e.g.  …/deploy/server-setup.sh stage.poc.digt.ch
#
# It (re)builds the apps, prepares the backend DB, installs the systemd units +
# Apache vhosts, and (re)starts ONLY the web tier (portal + product-ai frontend +
# php8.3-fpm backend). The worker/poller units are installed but NOT started — they
# do real Vertex processing; enable them by hand when ready.
#
# Safe to re-run: builds happen BEFORE any service restart, so a failed build
# leaves the running site untouched; Apache is only reloaded after `apache2ctl
# configtest` passes and the portal answers a health check.
#
# One-time host prerequisites (NOT done here — see deploy/CUTOVER.md):
#   Apache (+ mods proxy_http/proxy_fcgi/rewrite/headers/ssl), PHP 8.3 + php8.3-fpm
#   (+ ext: sqlite3, gd, intl, mbstring, xml, curl, zip), Node 20 + npm, composer,
#   a TLS cert for the host (certbot certonly), and the per-app secret env files.
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail

HOST="${1:?usage: server-setup.sh <web-root-dir, e.g. stage.poc.digt.ch>}"
ROOT="/srv/www/digt/${HOST}"
DEPLOY="${ROOT}/deploy"

# Box-specific knobs (override via env in the CI job if your box differs).
RUN_USER="${RUN_USER:-www-data}"
PHP_BIN="${PHP_BIN:-php8.3}"          # pin to 8.3 — the box may also carry a 7.4 CLI default for legacy
NPM_BIN="${NPM_BIN:-npm}"
COMPOSER_BIN="${COMPOSER_BIN:-composer}"
PHP_FPM_SERVICE="${PHP_FPM_SERVICE:-php8.3-fpm}"
APACHE_SERVICE="${APACHE_SERVICE:-apache2}"
APACHE_SITES_AVAILABLE="${APACHE_SITES_AVAILABLE:-/etc/apache2/sites-available}"

# This script runs as root over SSH. Composer disables plugins when run as root in a
# non-interactive shell — which silently skips symfony/runtime's post-autoload-dump
# hook, so vendor/autoload_runtime.php is never written and bin/console fatals. Allow
# plugins to run as root:
export COMPOSER_ALLOW_SUPERUSER=1

log() { echo "[server-setup:${HOST}] $*"; }

[ -d "$ROOT" ]    || { log "FATAL: $ROOT missing (rsync didn't run?)"; exit 1; }
[ -d "$DEPLOY" ]  || { log "FATAL: $DEPLOY missing"; exit 1; }

# 1. Persistent data dirs (rsync-excluded → survive deploys).
log "ensure data dirs"
mkdir -p "${ROOT}/data/portal" "${ROOT}/data/product-ai-automation" "${ROOT}/data/secrets"

# 1b. Secrets: kept under data/secrets (rsync-excluded) and symlinked to each app's
#     .env.local (which Next + Symfony auto-load). A real .env.local in the synced
#     tree would be deleted by `rsync --delete`, since secrets are git-ignored.
link_secret() { # <persistent-file> <app .env.local path>
  if [ -f "$1" ]; then ln -sfn "$1" "$2"; else log "WARN: secrets file $1 missing — create it (see deploy/CUTOVER.md); not linking $2"; fi
}
link_secret "${ROOT}/data/secrets/portal.env"              "${ROOT}/portal/.env.local"
link_secret "${ROOT}/data/secrets/product-ai-frontend.env" "${ROOT}/product-ai-automation/frontend/.env.local"
link_secret "${ROOT}/data/secrets/product-ai-backend.env"  "${ROOT}/product-ai-automation/backend/.env.local"

# 1c. Fail fast on missing/old runtimes (clearer than a deep build/composer error).
node_major="$(node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0)"
[ "${node_major:-0}" -ge 20 ] || { log "FATAL: Node >= 20 required for Next (found $(node -v 2>/dev/null || echo none)). See deploy/CUTOVER.md step 1."; exit 1; }
command -v "$PHP_BIN" >/dev/null 2>&1 || { log "FATAL: '$PHP_BIN' not found. Install PHP 8.3 (php8.3-cli/fpm + extensions). See deploy/CUTOVER.md step 1."; exit 1; }
"$PHP_BIN" -m | grep -qi pdo_sqlite || { log "FATAL: $PHP_BIN missing pdo_sqlite (install php8.3-sqlite3). See deploy/CUTOVER.md step 1."; exit 1; }
COMPOSER_PATH="$(command -v "$COMPOSER_BIN" 2>/dev/null || true)"
[ -n "$COMPOSER_PATH" ] || { log "FATAL: composer not found (install it). See deploy/CUTOVER.md step 1."; exit 1; }

# 2. Build the portal (served at root → no BASE_PATH).
log "build portal"
( cd "${ROOT}/portal" && $NPM_BIN ci --no-audit --no-fund && $NPM_BIN run build )

# 3. Build the product-ai frontend UNDER its subpath (basePath is baked at build).
log "build product-ai frontend (BASE_PATH=/product-ai-automation)"
( cd "${ROOT}/product-ai-automation/frontend" \
    && $NPM_BIN ci --no-audit --no-fund \
    && BASE_PATH=/product-ai-automation NEXT_PUBLIC_BASE_PATH=/product-ai-automation $NPM_BIN run build )

# 4. Backend: deps, prod cache, schema, idempotent seed.
#    SQLite needs no database:create — schema:update creates the .db on first connect
#    and applies the schema (verified: 31 queries, "schema updated successfully"). For
#    a non-SQLite DB, add `doctrine:database:create --if-not-exists` before this.
log "backend composer + schema + seed"
( cd "${ROOT}/product-ai-automation/backend" \
    && $PHP_BIN "$COMPOSER_PATH" install --no-dev --optimize-autoloader --no-interaction \
    && $PHP_BIN bin/console cache:clear --env=prod --no-debug \
    && $PHP_BIN bin/console doctrine:schema:update --force --no-interaction \
    && $PHP_BIN bin/console app:seed --no-interaction )

# 5. Ownership: services + php-fpm run as RUN_USER and need to write .next/cache,
#    backend/var, and the data dir.
log "chown runtime paths to ${RUN_USER}"
chown -R "${RUN_USER}:${RUN_USER}" \
  "${ROOT}/data" \
  "${ROOT}/portal/.next" \
  "${ROOT}/product-ai-automation/frontend/.next" \
  "${ROOT}/product-ai-automation/backend/var" 2>/dev/null || true

# 6. Install systemd units (rendered from templates).
render() { sed -e "s#__ROOT__#${ROOT}#g" -e "s#__HOST__#${HOST}#g" -e "s#__USER__#${RUN_USER}#g" "$1"; }
log "install systemd units"
render "${DEPLOY}/systemd/poc-portal.service.tmpl"              > /etc/systemd/system/poc-portal.service
render "${DEPLOY}/systemd/poc-product-ai-frontend.service.tmpl" > /etc/systemd/system/poc-product-ai-frontend.service
render "${DEPLOY}/systemd/poc-product-ai-worker.service.tmpl"   > /etc/systemd/system/poc-product-ai-worker.service
render "${DEPLOY}/systemd/poc-product-ai-poller.service.tmpl"   > /etc/systemd/system/poc-product-ai-poller.service
systemctl daemon-reload

# 7. (Re)start the WEB tier only. NOT the worker/poller (real Vertex processing —
#    enable by hand when ready).
log "restart web tier"
systemctl enable poc-portal.service poc-product-ai-frontend.service >/dev/null 2>&1 || true
systemctl restart "${PHP_FPM_SERVICE}"
systemctl restart poc-portal.service
systemctl restart poc-product-ai-frontend.service

# 8. Health gate before flipping Apache (so a broken boot never takes the site down).
log "health check"
ok=0
for i in $(seq 1 15); do
  if curl -fsS -o /dev/null "http://127.0.0.1:3000/login"; then ok=1; break; fi
  sleep 1
done
[ "$ok" = 1 ] || { log "FATAL: portal not healthy on :3000 — leaving Apache untouched"; exit 1; }
curl -fsS -o /dev/null "http://127.0.0.1:3001/product-ai-automation/" \
  || log "WARN: product-ai frontend not answering on :3001 yet (check 'journalctl -u poc-product-ai-frontend')"

# 9. Apache: internal backend vhost (:8000) + the public host vhost. Enable mods,
#    back up the old vhost, test, reload. Apache only reloads after configtest passes.
log "install Apache config"
a2enmod proxy proxy_http proxy_fcgi rewrite headers ssl setenvif >/dev/null 2>&1 || true
# Remove any leftover mod_php (we serve PHP via php-fpm/proxy_fcgi). An OS upgrade can
# leave a dangling phpX.Y.load whose .so was removed, which breaks `apache2ctl configtest`.
for _m in /etc/apache2/mods-enabled/php*.load; do
  [ -e "$_m" ] || continue
  a2dismod "$(basename "$_m" .load)" >/dev/null 2>&1 || true
done
render "${DEPLOY}/apache/product-ai-backend.conf.tmpl" > "${APACHE_SITES_AVAILABLE}/poc-product-ai-backend.conf"
vhost="${APACHE_SITES_AVAILABLE}/poc-${HOST}.conf"
[ -f "$vhost" ] && cp -a "$vhost" "${vhost}.bak.$(date +%s 2>/dev/null || echo prev)" || true
render "${DEPLOY}/apache/poc-host.conf.tmpl" > "$vhost"
a2ensite "poc-product-ai-backend" "poc-${HOST}" >/dev/null 2>&1 || true
# NOTE: if an OLD vhost still claims ${HOST} (e.g. product-ai served at the web root
# pre-cutover), disable it once — `a2dissite <old-name> && systemctl reload apache2` —
# or Apache will keep serving it instead of this one (same ServerName).
if apache2ctl configtest; then
  systemctl reload "${APACHE_SERVICE}"
  log "DONE — ${HOST} cut over (portal at /, product-ai-automation at /product-ai-automation/)"
else
  log "FATAL: apache configtest failed — NOT reloading (often: TLS cert for ${HOST} not yet obtained — run certbot certonly). Fix and re-run."
  exit 1
fi
