#!/usr/bin/env bash
# Deploy the Hub to a host: rsync the repo, install deps, build, restart service.
#
# Configure these env vars (e.g. in CI secrets):
#   PLATFORM_DEPLOY_HOST     required
#   PLATFORM_DEPLOY_SSH_KEY  required (private key for the deploy user)
#   PLATFORM_DEPLOY_USER     optional, defaults to deploy
#   PLATFORM_DEPLOY_PORT     optional SSH port, defaults to 22
#   PLATFORM_DEPLOY_HUB_PORT required Silo listener port
#   PLATFORM_DEPLOY_BASE     optional, defaults to /srv/curriculum-project-hub
#   PLATFORM_DEPLOY_RELEASE  optional immutable release id, defaults to git HEAD
#   PLATFORM_DEPLOY_INSTANCE required, Silo instance id
#   PLATFORM_DEPLOY_WORKSPACE_ROOT required short per-Silo path (for example /w/997)
#   PLATFORM_DEPLOY_MEMORY_MAX / CPU_QUOTA / TASKS_MAX required ceilings
#   PLATFORM_DEPLOY_HEALTH_URL optional, defaults to http://127.0.0.1:8788/api/healthz
# The target host must have Node.js 24+, npm, rsync, PostgreSQL client tools
# (`pg_isready`), systemd, bubblewrap (`bwrap`) and `socat` (for the ADR-0018 agent sandbox),
# and a compatible `cph` binary named by platform.env. The service installer
# provisions the dedicated non-root identity and persistent directories.
# Use a dedicated `deploy` user that has passwordless sudo for systemctl and
# writing the named /etc/systemd/system/cph-hub-<instance>.service through the installer.
set -euo pipefail

HOST="${PLATFORM_DEPLOY_HOST:?PLATFORM_DEPLOY_HOST required}"
SSH_KEY="${PLATFORM_DEPLOY_SSH_KEY:?PLATFORM_DEPLOY_SSH_KEY required}"
DEPLOY_USER="${PLATFORM_DEPLOY_USER:-deploy}"
PORT="${PLATFORM_DEPLOY_PORT:-22}"
HUB_PORT="${PLATFORM_DEPLOY_HUB_PORT:?PLATFORM_DEPLOY_HUB_PORT required}"
BASE="${PLATFORM_DEPLOY_BASE:-/srv/curriculum-project-hub}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
RELEASE_ID="${PLATFORM_DEPLOY_RELEASE:-$(git -C "$REPO_ROOT" rev-parse --verify HEAD)}"
[[ "$RELEASE_ID" =~ ^[A-Za-z0-9._-]+$ ]] || { echo "invalid PLATFORM_DEPLOY_RELEASE" >&2; exit 1; }
INSTANCE_ID="${PLATFORM_DEPLOY_INSTANCE:?PLATFORM_DEPLOY_INSTANCE required}"
WORKSPACE_ROOT="${PLATFORM_DEPLOY_WORKSPACE_ROOT:?PLATFORM_DEPLOY_WORKSPACE_ROOT required}"
SERVICE_UNIT="cph-hub-$INSTANCE_ID.service"
MEMORY_MAX="${PLATFORM_DEPLOY_MEMORY_MAX:?PLATFORM_DEPLOY_MEMORY_MAX required}"
CPU_QUOTA="${PLATFORM_DEPLOY_CPU_QUOTA:?PLATFORM_DEPLOY_CPU_QUOTA required}"
TASKS_MAX="${PLATFORM_DEPLOY_TASKS_MAX:?PLATFORM_DEPLOY_TASKS_MAX required}"
HEALTH_URL="${PLATFORM_DEPLOY_HEALTH_URL:-http://127.0.0.1:$HUB_PORT/api/healthz}"
HUB_DIR="$BASE/releases/$RELEASE_ID/hub"
RELEASE_DIR="$BASE/releases/$RELEASE_ID"

SSH_OPTS=(-i "$SSH_KEY" -p "$PORT" -o StrictHostKeyChecking=accept-new)

release_ready=false
if ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "test -f '$RELEASE_DIR/.complete'"; then
  release_ready=true
elif ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "test -e '$RELEASE_DIR'"; then
  echo "incomplete release already exists: $RELEASE_DIR" >&2
  exit 1
else
  ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "mkdir -p '$HUB_DIR'"
fi

if [ "$release_ready" = false ]; then
  # 1. Populate a new release directory. A completed release is never mutated.
  rsync -az --delete \
    --exclude node_modules --exclude dist --exclude .env \
    -e "ssh ${SSH_OPTS[*]}" \
    "$REPO_ROOT/hub/" "$DEPLOY_USER@$HOST:$HUB_DIR/"

  # 2. Install deps (hub + admin-web), audit hub prod, build tsc + SPA, mark complete.
  # `npm run build` → tsc then admin:build → admin-web/build for registerStaticSpa.
  ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" \
    "cd '$HUB_DIR' && PUPPETEER_SKIP_DOWNLOAD=1 npm ci && npm ci --prefix admin-web && npm run audit:production && npm run build && touch '$RELEASE_DIR/.complete'"
fi

# 3. Ensure the service is installed (idempotent), then restart.
ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "
  set -euo pipefail
  if [ \"\$(id -u)\" = \"0\" ]; then
    BASE='$BASE' HUB_DIR='$HUB_DIR' INSTANCE_ID='$INSTANCE_ID' WORKSPACE_ROOT='$WORKSPACE_ROOT' PORT='$HUB_PORT' MEMORY_MAX='$MEMORY_MAX' CPU_QUOTA='$CPU_QUOTA' TASKS_MAX='$TASKS_MAX' bash '$HUB_DIR/deploy/install_service.sh'
    systemctl restart '$SERVICE_UNIT'
    systemctl is-active --quiet '$SERVICE_UNIT'
  else
    sudo -n BASE='$BASE' HUB_DIR='$HUB_DIR' INSTANCE_ID='$INSTANCE_ID' WORKSPACE_ROOT='$WORKSPACE_ROOT' PORT='$HUB_PORT' MEMORY_MAX='$MEMORY_MAX' CPU_QUOTA='$CPU_QUOTA' TASKS_MAX='$TASKS_MAX' bash '$HUB_DIR/deploy/install_service.sh'
    sudo -n systemctl restart '$SERVICE_UNIT'
    sudo -n systemctl is-active --quiet '$SERVICE_UNIT'
  fi
  for attempt in \$(seq 1 30); do
    if curl --fail --silent '$HEALTH_URL' >/dev/null 2>&1; then
      exit 0
    fi
    sleep 1
  done
  curl --fail --silent --show-error '$HEALTH_URL' >/dev/null
"

echo "Deployed cph-hub to $HOST ($HUB_DIR)"
