#!/bin/bash
# Deploy for the franchisee frontend, run on the server (licenseeweb
# account) inside one of three independent checkouts:
#   ~/public_html/franchisees-website          (PORT 3003, PM2 app franchisee-global-app, tracks main)
#   ~/public_html/preview.youngengineers.org   (PORT 3002, PM2 app franchisee-preview-app, tracks main)
#   ~/public_html/staging-web.youngengineers.org (PORT 3007, PM2 app franchisee-global-app-staging, tracks staging)
#
# Each checkout deploys whichever branch IT has checked out, not a
# hardcoded one - it was previously hardcoded to always pull main, which
# silently meant the staging checkout deployed main's content, not
# staging's, on every single deploy since staging was first set up.
# Idempotent: safe on first bootstrap (right after the repo is
# force-reset in place) or on every deploy after.
set -euo pipefail
cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

PM2_PORT="${1:?Usage: bin/deploy.sh <port> <pm2-app-name>}"
PM2_NAME="${2:?Usage: bin/deploy.sh <port> <pm2-app-name>}"

# Repo is private - use the dedicated read-only deploy key generated once
# directly on the server (~/.ssh/franchisees_repo_deploy), registered as a
# read-only GitHub deploy key on this repo - never given write access.
export GIT_SSH_COMMAND="ssh -i ~/.ssh/franchisees_repo_deploy -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new"

BRANCH="$(git rev-parse --abbrev-ref HEAD)"
echo "--- Pulling latest ${BRANCH} ---"
git fetch origin "$BRANCH" -q
git reset --hard "origin/${BRANCH}" -q

echo "--- Syncing .htaccess (blocks direct access to .env etc.) ---"
cp -f deploy/htaccess .htaccess

echo "--- Checking if dependencies changed ---"
# --include=dev is not optional here, and NODE_ENV must not be allowed to
# decide: tailwindcss and @tailwindcss/postcss are devDependencies, and the
# latter pulls in lightningcss, whose platform binary
# (lightningcss.linux-x64-gnu.node) the build needs to compile any CSS at all.
# Installed without dev dependencies, `next build` fails on every stylesheet
# with "Cannot find module '../lightningcss.linux-x64-gnu.node'". A login shell
# on this account may export NODE_ENV=production, which silently omits them.
if ! cmp -s package-lock.json node_modules/.package-lock.json-copy 2>/dev/null; then
  echo "Changes detected - installing dependencies"
  NODE_ENV=development npm ci --include=dev
  cp package-lock.json node_modules/.package-lock.json-copy
else
  echo "No dependency changes - skipping npm install"
fi

# Guard the skip path too: a node_modules left without dev dependencies by an
# earlier install would otherwise sail past the check above (the lockfile is
# unchanged) and fail deep in the build instead of here, with a clear message.
if ! ls node_modules/lightningcss/*.node >/dev/null 2>&1; then
  echo "lightningcss native binary missing - reinstalling with dev dependencies"
  NODE_ENV=development npm ci --include=dev
  cp package-lock.json node_modules/.package-lock.json-copy
fi

echo "--- Backing up previous build ---"
# next.config.ts sets distDir: 'build' (LiteSpeed won't serve static files
# out of a dot-directory), so the build output lives in build/, not the
# Next.js default .next/ - this used to back up/restore .next, which no
# longer exists, so a failed build silently had nothing to roll back to.
rm -rf build_backup
cp -r build build_backup 2>/dev/null || true

echo "--- Building ---"
# Wipe build/ first so every deploy is a clean build. next build does not
# clear build/cache between runs, and that cache was observed serving
# pre-rendered HTML (old chunk hashes) from a previous build after the
# matching static/chunks files had already been replaced/removed by a
# later build - browsers then 404'd requesting those old chunks
# (ChunkLoadError) even though the app itself was up and serving 200s.
rm -rf build
if npm run build && [ -f build/BUILD_ID ]; then
  echo "Build succeeded"
  rm -rf build_backup

  echo "--- Writing deploy-info.json (public, so anyone can confirm what's live) ---"
  # Written only here, after a confirmed-successful build - not earlier in
  # the script - so it can never claim a commit/build is live when the
  # build actually failed and the old build got restored instead.
  # nextBuildId comes from build/BUILD_ID, which next build generates
  # fresh from the actual compiled output (not copied metadata like the
  # git fields below) - it's independently checkable by viewing the live
  # page's source and finding the same id in Next's embedded buildId. If
  # it doesn't match, the page in front of you isn't from this deploy.
  # Lives in public/ - Next.js serves files from there directly at the
  # site root (e.g. public/deploy-info.json -> /deploy-info.json), no app
  # code or extra step needed for this to show up. Not committed to git
  # (see .gitignore). This app has no public/ dir in the repo at all (its
  # assets come from an external CDN), so it has to be created here first.
  mkdir -p public
  cat > public/deploy-info.json <<EOF
{
  "branch": "${BRANCH}",
  "commit": "$(git rev-parse HEAD)",
  "commitShort": "$(git rev-parse --short HEAD)",
  "commitMessage": "$(git log -1 --format=%s | sed 's/"/\\"/g')",
  "deployedAtUtc": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
  "nextBuildId": "$(cat build/BUILD_ID)",
  "pm2App": "${PM2_NAME}",
  "port": "${PM2_PORT}"
}
EOF
else
  echo "Build failed (or produced no build/BUILD_ID) - restoring previous build"
  rm -rf build
  mv build_backup build
  echo "Old build restored - PM2 left untouched"
  exit 1
fi

echo "--- Starting/reloading PM2 ($PM2_NAME on port $PM2_PORT) ---"
PORT="$PM2_PORT" pm2 restart "$PM2_NAME" || PORT="$PM2_PORT" pm2 start npm --name "$PM2_NAME" -- start
pm2 save

echo "--- Deploy complete ($PM2_NAME) ---"
