#!/bin/bash
set -euo pipefail

# -----------------------------
# CONFIG
# -----------------------------
NODE_VERSION="v22.14.0"
NVM_DIR="/root/.nvm"
APP_NAME="erpfrontend"             # PM2 process name used in ecosystem.cjs
MEDIASERVER_NAME="mediaserver"     # PM2 process name for media server
SRC_DIR="/root/test/workspace/erp-frontend-pipeline-production"
STAGE_DIR="/opt/erp-nuxt-frontend-temp"
LIVE_DIR="/opt/erp-nuxt-frontend"
ROLLBACK_DIR="/opt/erp-nuxt-frontend-rollback"
MEDIASERVER_DIR="/opt/mediaserver"
DB_FILE="push-subscriptions.db"
# Every SQLite DB under data/ that must survive a deploy. data/*.db is gitignored,
# so it is NOT in the build artifact — anything missing here is recreated empty
# on the next deploy (this is what silently wiped chat.db before).
DB_FILES=("push-subscriptions.db" "chat.db")
DB_LIVE_DIR="$LIVE_DIR/data"
DB_BACKUP_DIR="/opt/erp-nuxt-frontend-db-backups"
ENV_SRC="$SRC_DIR/.env-prod"
ENV_DST="$STAGE_DIR/.env"

# -----------------------------
# NVM + NODE 22
# -----------------------------
export NVM_DIR="$NVM_DIR"
# shellcheck disable=SC1090
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

nvm install "$NODE_VERSION"
nvm alias default "$NODE_VERSION"
nvm use "$NODE_VERSION"

# Ensure pm2 is installed for THIS Node version
npm install -g pm2

NODE_BIN="$NVM_DIR/versions/node/$NODE_VERSION/bin/node"
NPM_BIN="$NVM_DIR/versions/node/$NODE_VERSION/bin/npm"
PM2_BIN="$NVM_DIR/versions/node/$NODE_VERSION/bin/pm2"

echo "Using Node: $("$NODE_BIN" -v)"
echo "ABI: $("$NODE_BIN" -p 'process.versions.modules')"
echo "PM2: $("$PM2_BIN" -v)"

# -----------------------------
# STAGE WORKSPACE
# -----------------------------
mkdir -p "$STAGE_DIR"
rm -rf "$STAGE_DIR"/*
cp -r "$SRC_DIR"/* "$STAGE_DIR"/
cp "$ENV_SRC" "$ENV_DST"

# Inject build metadata
cd "$SRC_DIR"
git_hash=$(git rev-parse --short HEAD || echo "unknown")
current_datetime=$(date '+%d.%m.%Y %H:%M')

cd "$STAGE_DIR"
sed -i "s/<GIT_HASH>/$git_hash/g" "$ENV_DST"
sed -i "s/<CURRENT_DATETIME>/$current_datetime/g" "$ENV_DST"

export NODE_OPTIONS="--max-old-space-size=12288"

# Clean install + build under Node 22.
# npm ci installs EXACTLY the committed package-lock.json — no re-resolution
# against the live registry (a lockfile-less `npm install` here let a fresh
# @vitejs/devtools publish crash npm's resolver on 2026-07-25).
rm -rf node_modules .nuxt .output
$NPM_BIN ci
$NPM_BIN run build

# -----------------------------
# VERSION SERVICE WORKER CACHE
# -----------------------------
echo "Versioning service worker cache with git hash: $git_hash"
if [ -f "$STAGE_DIR/.output/public/sw-notifications.js" ]; then
  sed -i "s/const CACHE_NAME = 'logship-erp-v1'/const CACHE_NAME = 'logship-erp-$git_hash'/" \
    "$STAGE_DIR/.output/public/sw-notifications.js"
  echo "Service worker cache versioned: logship-erp-$git_hash"
else
  echo "Warning: Service worker file not found at expected location"
fi

# -----------------------------
# BACKUP SQLITE DBs
# -----------------------------
echo "Backing up SQLite databases..."
mkdir -p "$DB_BACKUP_DIR"
backup_ts="$(date +%Y%m%d-%H%M%S)"

for db in "${DB_FILES[@]}"; do
  if [ -f "$LIVE_DIR/data/$db" ]; then
    base="${db%.db}"
    cp "$LIVE_DIR/data/$db" "$DB_BACKUP_DIR/${base}-${backup_ts}.db"
    echo "Database backed up: $DB_BACKUP_DIR/${base}-${backup_ts}.db"
    # keep last 10 backups per database
    (cd "$DB_BACKUP_DIR" && ls -t "${base}-"*.db 2>/dev/null | tail -n +11 | xargs -r rm)
  else
    echo "No existing $db found - fresh deployment for it"
  fi
done

# -----------------------------
# DEPLOY (with rollback)
# -----------------------------
rm -rf "$ROLLBACK_DIR"
if [ -d "$LIVE_DIR" ]; then
  cp -rf "$LIVE_DIR" "$ROLLBACK_DIR"
fi

rm -rf "$LIVE_DIR"
mkdir -p "$LIVE_DIR"
cp -r "$STAGE_DIR"/. "$LIVE_DIR"/

# -----------------------------
# RESTORE SQLITE DBs
# -----------------------------
echo "Restoring SQLite databases..."
mkdir -p "$DB_LIVE_DIR"

for db in "${DB_FILES[@]}"; do
  if [ -f "$ROLLBACK_DIR/data/$db" ]; then
    cp "$ROLLBACK_DIR/data/$db" "$DB_LIVE_DIR"/
    # Carry over WAL sidecars too: chat.db runs in WAL mode, so the most recent
    # messages may still live in -wal and not yet be checkpointed into the .db.
    [ -f "$ROLLBACK_DIR/data/$db-wal" ] && cp "$ROLLBACK_DIR/data/$db-wal" "$DB_LIVE_DIR"/ || true
    [ -f "$ROLLBACK_DIR/data/$db-shm" ] && cp "$ROLLBACK_DIR/data/$db-shm" "$DB_LIVE_DIR"/ || true
    echo "Database $db restored from rollback"
  else
    echo "No previous $db found - will be created on first run"
  fi
done

chown -R root:root "$DB_LIVE_DIR"
chmod 755 "$DB_LIVE_DIR"
for db in "${DB_FILES[@]}"; do
  for f in "$db" "$db-wal" "$db-shm"; do
    [ -f "$DB_LIVE_DIR/$f" ] && chmod 644 "$DB_LIVE_DIR/$f" || true
  done
done

# -----------------------------
# REBUILD NATIVE MODULES FOR NODE 22
# -----------------------------
cd "$LIVE_DIR/.output/server"
echo "Rebuilding better-sqlite3 for Node $NODE_VERSION..."
$NPM_BIN rebuild better-sqlite3

# -----------------------------
# COPY RUNTIME ASSETS NITRO DOES NOT BUNDLE
# Nitro externalizes tesseract.js-core / pdfjs-dist but traces only their JS
# entry — NOT tesseract's *.wasm or pdfjs' worker. The incoming-invoice OCR
# pipeline (Eingangsrechnungen) needs them at runtime, so copy them from the
# real node_modules into .output/server/node_modules. Idempotent; safe to re-run.
# -----------------------------
echo "Copying OCR/PDF runtime assets into .output/server/node_modules..."
SERVER_NM="$LIVE_DIR/.output/server/node_modules"
SRC_NM="$LIVE_DIR/node_modules"

# tesseract.js-core: the *.wasm core files (+ JS wrappers) for OCR (scanned PDFs)
if [ -d "$SRC_NM/tesseract.js-core" ]; then
  mkdir -p "$SERVER_NM/tesseract.js-core"
  cp -rf "$SRC_NM/tesseract.js-core/." "$SERVER_NM/tesseract.js-core/"
  echo "  ✓ tesseract.js-core (wasm)"
else
  echo "  ⚠ tesseract.js-core not found in node_modules"
fi

# pdfjs-dist: the Node 'fake worker' (pdf.worker.mjs) must sit beside pdf.mjs,
# else Tier-1 text extraction throws and every PDF falls through to OCR.
if [ -d "$SRC_NM/pdfjs-dist/legacy/build" ]; then
  mkdir -p "$SERVER_NM/pdfjs-dist/legacy/build"
  cp -f "$SRC_NM/pdfjs-dist/legacy/build/"pdf*.mjs "$SERVER_NM/pdfjs-dist/legacy/build/" 2>/dev/null || true
  echo "  ✓ pdfjs-dist worker"
else
  echo "  ⚠ pdfjs-dist/legacy/build not found in node_modules"
fi

# canvas: native; ONLY the Tier-2 rasterize fallback used when pdftoppm (poppler)
# is absent on the host. Preferred path is poppler-utils — install that instead
# of relying on this copy. Copied best-effort only if present and not already there.
if [ -d "$SRC_NM/canvas" ] && [ ! -e "$SERVER_NM/canvas/build/Release/canvas.node" ]; then
  mkdir -p "$SERVER_NM/canvas"
  cp -rf "$SRC_NM/canvas/." "$SERVER_NM/canvas/" 2>/dev/null || true
  echo "  ✓ canvas (rasterize fallback)"
fi

# Sanity check (non-fatal): confirm the critical assets landed
ls "$SERVER_NM/tesseract.js-core/"*.wasm >/dev/null 2>&1 && echo "  verified: tesseract wasm present" || echo "  ⚠ tesseract wasm still missing"
[ -f "$SERVER_NM/pdfjs-dist/legacy/build/pdf.worker.mjs" ] && echo "  verified: pdfjs worker present" || echo "  ⚠ pdfjs worker still missing"

# -----------------------------
# START WITH PM2 (force Node 20)
# -----------------------------
cd "$LIVE_DIR"

# Stop old ERP frontend process if exists
$PM2_BIN delete "$APP_NAME" || true

# Start ERP frontend using Node 22 interpreter
$PM2_BIN start ecosystem.config.cjs \
  --only "$APP_NAME" \
  --update-env \
  --interpreter "$NODE_BIN"

# Start or restart mediaserver (ensure it's running with correct config)
cd "$MEDIASERVER_DIR"
if $PM2_BIN describe "$MEDIASERVER_NAME" > /dev/null 2>&1; then
  echo "Restarting existing mediaserver..."
  $PM2_BIN restart "$MEDIASERVER_NAME" --update-env --interpreter "$NODE_BIN"
else
  echo "Starting mediaserver for the first time..."
  $PM2_BIN start ecosystem.config.js --update-env --interpreter "$NODE_BIN"
fi

# Save PM2 state (both apps)
$PM2_BIN save --force

# Ensure PM2 resurrects at boot WITH the right PATH/NVM
$PM2_BIN startup systemd -u root --hp /root

# Create a systemd drop-in so PM2 finds Node on boot AND starts only after the
# iDempiere REST API (8443) answers — without the wait, every reboot produces a
# ~2 minute 502 storm in the frontend until the API is up.
# Keep this block in sync with deploy/pm2-root.service.d/override.conf.
mkdir -p /etc/systemd/system/pm2-root.service.d
cat >/etc/systemd/system/pm2-root.service.d/override.conf <<EOF
[Unit]
After=idempiere.service

[Service]
Environment=PM2_HOME=/root/.pm2
Environment=NVM_DIR=$NVM_DIR
Environment=PATH=$NVM_DIR/versions/node/$NODE_VERSION/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Wait up to 180s for the iDempiere REST API, then start anyway
ExecStartPre=/bin/sh -c 'timeout 180 sh -c "until curl -ks -o /dev/null --connect-timeout 2 https://127.0.0.1:8443/; do sleep 2; done" || true'
EOF

systemctl daemon-reload

echo "✅ Deployment completed successfully"
echo "📊 Backups: $DB_BACKUP_DIR"
echo "🗄️  DB: $DB_LIVE_DIR/$DB_FILE"
echo "🟢 PM2 status:"
$PM2_BIN status
