#!/usr/bin/env bash
#
# Production deploy script. Runs ON THE SERVER, streamed in over SSH by the
# GitHub Actions workflow (.github/workflows/deploy.yml).
#
# One Node process serves both the API and the built React app (client/dist),
# managed by pm2 via ecosystem.config.cjs. Runtime config lives in server/.env
# on the server only (gitignored).
#
# Required environment:
#   PROJECT_PATH  absolute path of the checkout on the server
#
set -euo pipefail

: "${PROJECT_PATH:?PROJECT_PATH is not set}"
cd "$PROJECT_PATH"

# Non-interactive SSH sessions skip ~/.bashrc, so node installed through nvm
# is not on PATH unless we load it ourselves.
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
if [ -s "$NVM_DIR/nvm.sh" ]; then
  # shellcheck disable=SC1091
  . "$NVM_DIR/nvm.sh"
fi

for cmd in git node npm pm2 curl; do
  command -v "$cmd" >/dev/null 2>&1 || { echo "!! $cmd not found on PATH"; exit 1; }
done

echo "==> Deploying in $PROJECT_PATH (node $(node -v))"

# Without server/.env the app would boot with no JWT_SECRET (and refuse to
# start in production). Fail before touching the running release.
if [ ! -f server/.env ]; then
  echo "!! server/.env missing — create it first (see .env.example)"
  exit 1
fi
set -a
# shellcheck disable=SC1091
. server/.env
set +a
PORT="${PORT:-4000}"

# SQLite is the only copy of the data. Snapshot it with the online backup API
# (safe while the app is running in WAL mode) before new code can migrate it.
# Relative DB_PATH values resolve from server/, same as the pm2 process cwd.
echo "==> Backing up database"
DB_FILE="${DB_PATH:-data.db}"
BACKUP_DIR="${BACKUP_DIR:-$PROJECT_PATH/backups}"
if (cd server && [ -f "$DB_FILE" ] && [ -d node_modules/better-sqlite3 ]); then
  mkdir -p "$BACKUP_DIR"
  BACKUP_FILE="$BACKUP_DIR/data-$(date +%Y%m%d-%H%M%S).db"
  (cd server && node -e "
    require('better-sqlite3')(process.argv[1], { readonly: true })
      .backup(process.argv[2])
      .then(() => console.log('    saved ' + process.argv[2]));
  " "$DB_FILE" "$BACKUP_FILE")
  # Keep the 14 most recent backups.
  ls -1t "$BACKUP_DIR"/data-*.db 2>/dev/null | tail -n +15 | xargs -r rm -f --
else
  echo "    no database yet — skipping backup"
fi

# data.db and uploads/ are gitignored, so reset --hard leaves them alone.
# Never add `git clean` here: it would delete them.
echo "==> Fetching origin/main"
git fetch --prune origin
git reset --hard origin/main
echo "    now at $(git log -1 --format='%h %s')"

# Building here needs ~1 GB and a couple of minutes of CPU. On a small server
# that is the slowest and most fragile step, so SKIP_CLIENT_BUILD=1 lets you
# build somewhere else and copy client/dist over (it is gitignored, so the
# reset above leaves it alone).
if [ "${SKIP_CLIENT_BUILD:-0}" = "1" ]; then
  echo "==> Skipping frontend build — using the client/dist already on the server"
  [ -f client/dist/index.html ] || { echo "!! client/dist/index.html is missing"; exit 1; }
else
  # --include=dev: vite and tsc are devDependencies, and NODE_ENV=production
  # from server/.env would otherwise make npm skip them.
  echo "==> Building frontend"
  npm --prefix client ci --include=dev --no-audit --no-fund
  npm --prefix client run build
fi

# A half-written dist (an interrupted or killed build) leaves index.html
# pointing at files that are not there, and the site loads to a blank page.
# Check every asset it asks for before the new code goes live.
missing=0
for asset in $(grep -o '/assets/[A-Za-z0-9._-]*' client/dist/index.html | sort -u); do
  [ -f "client/dist$asset" ] || { echo "!! client/dist$asset is missing"; missing=1; }
done
if [ "$missing" -ne 0 ]; then
  echo "!! frontend build is incomplete — not restarting the app"
  exit 1
fi
echo "    build looks complete"

echo "==> Installing server dependencies"
npm --prefix server ci --omit=dev --no-audit --no-fund

echo "==> Restarting app"
pm2 startOrReload ecosystem.config.cjs --update-env
pm2 save

# Only a server that actually answers counts as deployed.
echo "==> Health check on port $PORT"
for i in $(seq 1 20); do
  if curl -fsS "http://127.0.0.1:$PORT/api/health" >/dev/null 2>&1; then
    echo "    healthy"
    echo "==> Deploy finished"
    exit 0
  fi
  sleep 1
done

echo "!! App did not become healthy — recent logs:"
pm2 logs rider-platform --lines 50 --nostream || true
exit 1
