#!/usr/bin/env bash
# Build one landing from git into a fresh release directory and swap it in.
# Install as /usr/local/bin/exo-deploy (mode 755); run as the `exo` user.
#
#   sudo -u exo exo-deploy medcenterphysio            # deploys origin/main
#   sudo -u exo exo-deploy medcenterphysio my-branch
set -Eeuo pipefail

APP="${1:?usage: exo-deploy <fitnes|hotel|medcenterphysio|medcenterstart> [git-ref]}"
REF="${2:-main}"
BASE="/srv/exo/$APP"
ENVFILE="/etc/exo/$APP.env"
BUILDENV="/etc/exo/$APP.build.env"
KEEP=3
REL="$BASE/releases/$(date -u +%Y%m%d-%H%M%S)"

for f in "$ENVFILE" "$BUILDENV"; do
  [[ -r $f ]] || { echo "FATAL: cannot read $f"; exit 1; }
done
[[ -d $BASE/repo ]] || { echo "FATAL: no bare repo at $BASE/repo"; exit 1; }

PORT="$(sed -n 's/^PORT=//p' "$ENVFILE")"
[[ -n $PORT ]] || { echo "FATAL: PORT not set in $ENVFILE"; exit 1; }

echo "==> fetching $REF"
git -C "$BASE/repo" fetch --prune origin '+refs/heads/*:refs/heads/*'
git -C "$BASE/repo" rev-parse --verify "$REF^{commit}" >/dev/null

echo "==> extracting $APP/ into $REL"
mkdir -p "$REL"
git -C "$BASE/repo" archive "$REF" "$APP" | tar -x -C "$REL" --strip-components=1
[[ -f $REL/package.json ]] || { echo "FATAL: $APP/ not found at $REF"; rm -rf "$REL"; exit 1; }

# 2.6-3.9 MB of base64-embedded reference HTML that is never served.
rm -rf "$REL/legacy"

# Public build-time vars only. The amoCRM token stays in $ENVFILE, which
# systemd injects at runtime; dotenv does not override real env vars, so the
# two never collide.
cp "$BUILDENV" "$REL/.env"

cd "$REL"

# devDependencies are REQUIRED here: vite, typescript and tailwindcss all live
# there and `npm run build` needs them. --omit=dev breaks the build.
echo "==> npm ci"
npm ci --no-audit --no-fund

echo "==> npm run build"
npm run build

# Fail loudly rather than shipping broken SEO tags or an empty bundle.
[[ -s dist/client/index.html ]] || { echo "FATAL: dist/client/index.html missing or empty"; exit 1; }
if grep -q '%VITE_SITE_URL%' dist/client/index.html; then
  echo "FATAL: VITE_SITE_URL was not substituted — check $BUILDENV"; exit 1
fi

# Runtime needs only express/zod/dotenv/tsx: ~130 MB -> ~40 MB per release.
echo "==> pruning devDependencies"
npm prune --omit=dev

# Precompress for nginx gzip_static. .webp/.woff2 omitted on purpose.
find dist/client -type f \
  \( -name '*.js' -o -name '*.css' -o -name '*.html' -o -name '*.svg' -o -name '*.json' -o -name '*.xml' -o -name '*.txt' \) \
  -exec gzip -9 -k -f {} +

echo "==> swapping $BASE/current -> $REL"
PREV="$(readlink -f "$BASE/current" 2>/dev/null || true)"
ln -sfn "$REL" "$BASE/current.tmp"
mv -Tf "$BASE/current.tmp" "$BASE/current"   # single rename(2): atomic

sudo systemctl restart "exo@$APP"

echo "==> waiting for health on 127.0.0.1:$PORT"
for _ in $(seq 1 20); do
  if curl -fsS --max-time 2 "http://127.0.0.1:$PORT/api/health" >/dev/null 2>&1; then break; fi
  sleep 1
done
HEALTH="$(curl -fsS --max-time 5 "http://127.0.0.1:$PORT/api/health")" || {
  echo "FATAL: health check failed. Rolling back."
  [[ -n $PREV ]] && { ln -sfn "$PREV" "$BASE/current.tmp"; mv -Tf "$BASE/current.tmp" "$BASE/current"; sudo systemctl restart "exo@$APP"; }
  exit 1
}
echo "    $HEALTH"
grep -q '"ok":true' <<<"$HEALTH" || { echo "FATAL: health not ok"; exit 1; }
grep -q '"amo":true' <<<"$HEALTH" || echo "    WARNING: amo=false — /api/leads/* will return 503. Check AMO_* in $ENVFILE."

# Prune old releases, never the live one.
CURRENT="$(readlink -f "$BASE/current")"
ls -1dt "$BASE"/releases/*/ 2>/dev/null | tail -n "+$((KEEP+1))" | while read -r old; do
  [[ "$(readlink -f "$old")" == "$CURRENT" ]] && continue
  rm -rf "$old"
done

echo "==> deployed $APP @ $REF ($(git -C "$BASE/repo" rev-parse --short "$REF")) -> $REL"
