#!/bin/bash
set -euo pipefail

# Immer im Repo-Verzeichnis arbeiten (wichtig für Backup/Restore mit relativen Pfaden)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"

# Deployment Script für Harheimer TC Website
# Sichert Produktivdaten vor dem Build und stellt sie danach wieder her

echo "=== Harheimer TC Deployment ==="
echo ""
echo "Working directory: $(pwd)"
echo ""

if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  echo "ERROR: Dieses Script muss im Git-Repository ausgeführt werden (kein .git gefunden)."
  exit 1
fi

# Optional (empfohlen): Persistente Daten außerhalb des Git-Repos halten und per Symlink einbinden.
# Das verhindert zuverlässig, dass Git jemals Produktivdaten überschreibt.
DEPLOY_HOME="${DEPLOY_HOME:-${HOME:-/tmp}}"
DATA_ROOT="${DATA_ROOT:-$DEPLOY_HOME/harheimertc-data}"
BACKUP_ROOT="${BACKUP_ROOT:-$DEPLOY_HOME/harheimertc-backups}"

mkdir -p "$DATA_ROOT" "$BACKUP_ROOT"

ensure_symlink_dir() {
  local src="$1"      # z.B. server/data
  local target="$2"   # z.B. /var/lib/harheimertc/server-data

  mkdir -p "$(dirname "$src")"
  mkdir -p "$target"

  if [ -L "$src" ]; then
    return 0
  fi

  if [ -d "$src" ]; then
    echo "   Moving $src -> $target (first-time migration)"
    # Merge existing content into target
    cp -a "$src/." "$target/" || true
    rm -rf "$src"
  fi

  ln -s "$target" "$src"
  echo "   Linked $src -> $target"
}

has_tracked_files_under() {
  local prefix="$1" # e.g. public/data
  # If any file is tracked under this path, symlinking the directory will break git operations
  git ls-files "$prefix" | head -n 1 | grep -q .
}

install_dependencies() {
  if [ -f "package-lock.json" ]; then
    echo "   Running: npm ci"
    npm ci
  else
    echo "   WARNING: package-lock.json fehlt. Führe npm install aus..."
    npm install
  fi
}

install_dependencies_if_needed() {
  local cache_dir=".deploy-cache"
  local lock_hash_file="$cache_dir/package-lock.sha256"
  local current_lock_hash=""
  local previous_lock_hash=""

  if [ ! -f "package-lock.json" ]; then
    echo "   package-lock.json fehlt, führe npm install aus..."
    install_dependencies
    return 0
  fi

  mkdir -p "$cache_dir"
  current_lock_hash="$(sha256sum package-lock.json | awk '{print $1}')"
  if [ -f "$lock_hash_file" ]; then
    previous_lock_hash="$(cat "$lock_hash_file" 2>/dev/null || true)"
  fi

  if [ ! -d "node_modules" ]; then
    echo "   node_modules fehlt, installiere Dependencies..."
    install_dependencies
  elif [ "$current_lock_hash" != "$previous_lock_hash" ]; then
    echo "   package-lock.json geändert, führe npm ci aus..."
    install_dependencies
  else
    echo "   package-lock.json unverändert, überspringe npm ci"
  fi

  printf '%s\n' "$current_lock_hash" > "$lock_hash_file"
}

use_project_node() {
  export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
  if [ -s "$NVM_DIR/nvm.sh" ]; then
    # shellcheck disable=SC1090
    . "$NVM_DIR/nvm.sh"
    if [ -f ".nvmrc" ]; then
      echo "   Using Node version from .nvmrc..."
      nvm use
    fi
  fi
}

ensure_node_version() {
  if ! command -v node >/dev/null 2>&1; then
    echo "ERROR: Node.js ist nicht im PATH."
    exit 1
  fi

  local node_version
  node_version="$(node -p 'process.versions.node')"
  if ! node -e 'const [major, minor] = process.versions.node.split(".").map(Number); process.exit(major > 22 || (major === 22 && minor >= 12) ? 0 : 1)' >/dev/null 2>&1; then
    echo "ERROR: Node.js >= 22.12.0 wird benötigt, aktuell ist $node_version aktiv."
    echo "Bitte Node 22 installieren/aktivieren, z.B.:"
    echo "  nvm install 22"
    echo "  nvm alias default 22"
    exit 1
  fi

  echo "   Node.js $node_version"
}

sync_public_documents_to_build() {
  if [ ! -d "public/documents" ]; then
    echo "   No public/documents directory to sync"
    return 0
  fi

  if [ ! -d ".output/public" ]; then
    echo "ERROR: .output/public fehlt, kann public/documents nicht synchronisieren."
    exit 1
  fi

  mkdir -p ".output/public/documents"
  cp -a "public/documents/." ".output/public/documents/"
  echo "   ✓ public/documents -> .output/public/documents synchronisiert"

  local template_pdf="beitrittserklärung_template.pdf"
  if [ -f "public/documents/$template_pdf" ]; then
    local source_size output_size
    source_size=$(stat -f%z "public/documents/$template_pdf" 2>/dev/null || stat -c%s "public/documents/$template_pdf" 2>/dev/null || echo "0")
    output_size=$(stat -f%z ".output/public/documents/$template_pdf" 2>/dev/null || stat -c%s ".output/public/documents/$template_pdf" 2>/dev/null || echo "0")

    if [ "$source_size" != "$output_size" ] || [ "$source_size" = "0" ]; then
      echo "ERROR: .output/public/documents/$template_pdf stimmt nicht mit public/documents überein (Source: $source_size, Output: $output_size)."
      exit 1
    fi

    echo "   ✓ $template_pdf im Build verifiziert ($output_size bytes)"
  fi
}

echo "0. Ensuring persistent data directories (recommended)..."
# IMPORTANT: Only symlink server/data if it's not tracked by git.
if has_tracked_files_under "server/data"; then
  echo "   Skipping symlink for server/data (tracked files detected in git)."
  echo "   Recommendation: remove server/data/** from git history and keep them only as production data."
else
  ensure_symlink_dir "server/data" "$DATA_ROOT/server-data"
fi

# IMPORTANT: Only symlink public/data if it's not tracked by git.
# Otherwise git will error with "path is beyond a symbolic link".
if has_tracked_files_under "public/data"; then
  echo "   Skipping symlink for public/data (tracked files detected in git)."
  echo "   Recommendation: remove public/data/*.csv from git history and keep them only as production data."
else
  ensure_symlink_dir "public/data" "$DATA_ROOT/public-data"
fi

ensure_symlink_dir "public/uploads" "$DATA_ROOT/public-uploads"
echo ""

# 1. BACKUP: Laufende Produktivdaten VOR allen Git-Operationen sichern
echo "1. Backing up current production data (pre-git)..."

# Human readable timestamp (lokal)
BACKUP_TS="$(date +"%Y-%m-%d_%H-%M-%S")"
BACKUP_DIR="$BACKUP_ROOT/backup_$BACKUP_TS"
mkdir -p "$BACKUP_DIR"
echo "   Backup directory: $BACKUP_DIR"

# Backup server data (JSON) und CSVs immer vom Dateisystem, nicht aus 'stash'
if [ -d server/data ]; then
  cp -a server/data "$BACKUP_DIR/server-data"
  echo "   Backed up server/data -> $BACKUP_DIR/server-data"
else
  echo "ERROR: server/data existiert nicht. Abbruch, damit wir keine Repo-Defaults ausrollen."
  exit 1
fi

if ls public/data/*.csv >/dev/null 2>&1; then
  mkdir -p "$BACKUP_DIR/public-data"
  cp -a public/data/*.csv "$BACKUP_DIR/public-data/"
  echo "   Backed up public/data/*.csv -> $BACKUP_DIR/public-data/"
else
  echo "   No public CSVs to backup (public/data/*.csv not found)"
fi
# Prefer internal public-data under server/data/public-data for backups; fallback to legacy public/data
if ls server/data/public-data/*.csv >/dev/null 2>&1; then
  mkdir -p "$BACKUP_DIR/public-data"
  cp -a server/data/public-data/*.csv "$BACKUP_DIR/public-data/"
  echo "   Backed up server/data/public-data/*.csv -> $BACKUP_DIR/public-data/"
elif ls public/data/*.csv >/dev/null 2>&1; then
  mkdir -p "$BACKUP_DIR/public-data"
  cp -a public/data/*.csv "$BACKUP_DIR/public-data/"
  echo "   Backed up public/data/*.csv -> $BACKUP_DIR/public-data/"
else
  echo "   No public CSVs to backup (server/data/public-data or public/data not found)"
fi

# 2. Handle local changes and Git Pull
echo "2. Handling local changes and pulling latest from git..."

# Check if there are merge conflicts first
if [ -n "$(git status --porcelain | grep '^UU\|^AA\|^DD')" ]; then
  echo "   Resolving existing merge conflicts..."
  git reset --hard HEAD
fi

# Ensure git operations can run even if we have untracked local artifacts (e.g. backups/)
# We avoid `git stash` (breaks with symlinked tracked paths). Instead, hard-reset and clean safely.
echo "   Resetting working tree to HEAD (production data will be restored from backup)..."
git reset --hard HEAD

echo "   Cleaning untracked files (excluding data dirs/backups/.env)..."
git clean -fd \
  -e server/data \
  -e public/data \
  -e public/uploads \
  -e backups \
  -e .env || true

# Pull latest changes
echo "   Pulling latest changes..."
git fetch origin main
git checkout -B main origin/main
if ! git reset --hard origin/main; then
  echo "ERROR: git pull fehlgeschlagen."
  echo ""
  echo "Häufige Ursache: SSH-Key für den aktuellen User fehlt."
  echo "Prüfen:"
  echo "  ssh -T git@tsschulz.de"
  echo ""
  echo "Optional auf HTTPS wechseln:"
  echo "  git remote set-url origin https://tsschulz.de/<owner>/<repo>.git"
  echo "Oder SSH-Key für User $(id -un) hinterlegen."
  exit 1
fi

# Reset any accidental changes from stash restore (should be none now)
git reset --hard HEAD >/dev/null 2>&1

# WICHTIG: Entferne public/data Dateien aus Git-Index, falls sie getrackt sind
# (Sie sollten in .gitignore sein, aber falls sie historisch getrackt wurden)
if git ls-files --error-unmatch public/data/*.csv >/dev/null 2>&1; then
  echo "   WARNING: public/data/*.csv Dateien sind im Git getrackt!"
  echo "   Entferne sie aus dem Git-Index (Dateien bleiben erhalten)..."
  git rm --cached public/data/*.csv 2>/dev/null || true
fi

# 3. Install dependencies
echo ""
echo "3. Installing dependencies..."
use_project_node
ensure_node_version
install_dependencies_if_needed

# 4. Remove old build (but keep data!)
echo ""
echo "4. Cleaning build artifacts..."
# Sicherstellen, dass .output vollständig gelöscht wird
if [ -d ".output" ]; then
  echo "   Removing .output directory..."
  rm -rf .output
  # Prüfen, ob wirklich gelöscht wurde
  if [ -d ".output" ]; then
    echo "WARNING: .output konnte nicht vollständig gelöscht werden. Versuche erneut..."
    sleep 2
    rm -rf .output
    if [ -d ".output" ]; then
      echo "ERROR: .output konnte auch nach erneutem Versuch nicht gelöscht werden!"
      echo "Bitte manuell prüfen und löschen: rm -rf .output"
      exit 1
    fi
  fi
  echo "   ✓ .output gelöscht"
fi

# .nuxt standardmäßig behalten (beschleunigt Folge-Builds deutlich).
# Für erzwungenen Clean-Build: CLEAN_NUXT_CACHE=1 ./deploy-production.sh
if [ "${CLEAN_NUXT_CACHE:-0}" = "1" ]; then
  if [ -d ".nuxt" ]; then
    echo "   CLEAN_NUXT_CACHE=1 gesetzt: entferne .nuxt cache..."
    rm -rf .nuxt
    echo "   ✓ .nuxt gelöscht"
  fi
else
  echo "   Behalte .nuxt cache für schnelleren Build (CLEAN_NUXT_CACHE=1 für Clean-Build)"
fi

# Prüfe, ob node_modules vorhanden ist (für npm run build)
if [ ! -d "node_modules" ]; then
  echo ""
  echo "WARNING: node_modules fehlt. Installiere Dependencies..."
  install_dependencies
fi

# 5. Build
echo ""
echo "5. Building application..."
echo "   Running: npm run build"
echo "   (This may take a few minutes...)"

# Clean-Build: Stelle sicher, dass node_modules aktuell ist
echo "   Checking dependencies..."
if [ ! -f "node_modules/.package-lock.json" ] && [ ! -f "package-lock.json" ]; then
  echo "   WARNING: package-lock.json fehlt. Führe npm install aus..."
  install_dependencies
fi

# Build mit expliziter Fehlerbehandlung und gleichzeitiger Log-Datei
BUILD_LOG_FILE=".deploy-cache/build-$(date +%Y%m%d-%H%M%S).log"
mkdir -p ".deploy-cache"
if npm run build 2>&1 | tee "$BUILD_LOG_FILE"; then
  BUILD_EXIT_CODE=0
else
  BUILD_EXIT_CODE=$?
fi

if [ "$BUILD_EXIT_CODE" -ne 0 ]; then
  echo ""
  echo "ERROR: Build fehlgeschlagen mit Exit-Code $BUILD_EXIT_CODE"
  echo "Bitte prüfen Sie die Build-Ausgabe oben auf Fehler."
  echo "Build-Log: $BUILD_LOG_FILE"
  exit 1
fi

echo ""
echo "   Synchronizing public documents into build output..."
sync_public_documents_to_build

# Prüfe auf Warnungen im Build-Output, die auf Probleme hinweisen
if rg -i "error|failed|missing" "$BUILD_LOG_FILE" >/dev/null 2>&1; then
  echo ""
  echo "WARNING: Build-Output enthält möglicherweise Fehler oder Warnungen."
  echo "Bitte prüfen Sie die Ausgabe oben."
  echo "Build-Log: $BUILD_LOG_FILE"
fi

# Prüfe, ob der Build erfolgreich war - mehrere Checks
echo ""
echo "   Verifying build output..."

BUILD_FAILED=0

# Check 1: _nuxt Verzeichnis
if [ ! -d ".output/public/_nuxt" ]; then
  echo "ERROR: .output/public/_nuxt Verzeichnis fehlt!"
  BUILD_FAILED=1
else
  NUXT_FILES=$(find .output/public/_nuxt -type f 2>/dev/null | wc -l)
  echo "   ✓ .output/public/_nuxt vorhanden ($NUXT_FILES Dateien)"
  if [ "$NUXT_FILES" -eq 0 ]; then
    echo "ERROR: .output/public/_nuxt ist leer!"
    BUILD_FAILED=1
  else
    # Prüfe, ob wichtige Dateien vorhanden sind
    JS_FILES=$(find .output/public/_nuxt -name "*.js" 2>/dev/null | wc -l)
    CSS_FILES=$(find .output/public/_nuxt -name "*.css" 2>/dev/null | wc -l)
    echo "   ✓ JS-Dateien: $JS_FILES, CSS-Dateien: $CSS_FILES"
    if [ "$JS_FILES" -eq 0 ]; then
      echo "ERROR: Keine JS-Dateien in .output/public/_nuxt gefunden!"
      BUILD_FAILED=1
    fi
  fi
fi

# Check 1b: _nuxt/builds Verzeichnis (für Meta-Dateien)
if [ -d ".output/public/_nuxt/builds" ]; then
  BUILD_META_FILES=$(find .output/public/_nuxt/builds -type f 2>/dev/null | wc -l)
  echo "   ✓ .output/public/_nuxt/builds vorhanden ($BUILD_META_FILES Meta-Dateien)"
else
  echo "WARNING: .output/public/_nuxt/builds fehlt (kann in manchen Nuxt-Versionen normal sein)"
fi

# Check 2: Server index.mjs
if [ ! -f ".output/server/index.mjs" ]; then
  echo "ERROR: .output/server/index.mjs fehlt!"
  BUILD_FAILED=1
else
  echo "   ✓ .output/server/index.mjs vorhanden"
fi

# Check 3: Public Verzeichnis
if [ ! -d ".output/public" ]; then
  echo "ERROR: .output/public Verzeichnis fehlt!"
  BUILD_FAILED=1
else
  echo "   ✓ .output/public vorhanden"
fi

# Check 4: Server Verzeichnis
if [ ! -d ".output/server" ]; then
  echo "ERROR: .output/server Verzeichnis fehlt!"
  BUILD_FAILED=1
else
  echo "   ✓ .output/server vorhanden"
fi

if [ "$BUILD_FAILED" -eq 1 ]; then
  echo ""
  echo "ERROR: Build-Verifikation fehlgeschlagen!"
  echo "Bitte führen Sie manuell aus:"
  echo "  rm -rf .output .nuxt"
  echo "  npm run build"
  exit 1
fi

echo "   ✓ Build erfolgreich verifiziert"

# 6. Restore Production Data (überschreibe Repo-Defaults mit Backup)
echo ""
echo "6. Restoring production data..."

# Stelle server/data vollständig wieder her (inkl. config.json, users.json, news.json, sessions.json, members.json, membership-applications)
if [ ! -d "$BACKUP_DIR/server-data" ]; then
  echo "ERROR: Backup-Verzeichnis $BACKUP_DIR/server-data fehlt. Abbruch."
  exit 1
fi

# WICHTIG: Prüfe, ob server/data ein Symlink ist (z.B. auf Backup-Verzeichnis)
# Falls ja, entferne den Symlink, damit wir in das echte Verzeichnis kopieren können
if [ -L "server/data" ]; then
  echo "   WARNING: server/data ist ein Symlink. Entferne Symlink..."
  rm "server/data"
fi

# Stelle sicher, dass server/data ein echtes Verzeichnis ist
if [ ! -d "server/data" ]; then
  mkdir -p server/data
fi

# Kopiere Daten vom Backup (verwende -L, um Symlinks zu folgen, falls nötig)
cp -aL "$BACKUP_DIR/server-data/." server/data/
echo "   Restored server/data from backup ($BACKUP_DIR/server-data)."

# Stelle alle CSVs wieder her
if ls "$BACKUP_DIR/public-data"/*.csv >/dev/null 2>&1; then
  mkdir -p public/data
  
  # WICHTIG: Überschreibe auch Dateien, die aus dem Git-Repository kommen
  # Verwende cp mit -f (force) um sicherzustellen, dass Backup-Dateien Vorrang haben
  for csv_file in "$BACKUP_DIR/public-data"/*.csv; do
    filename=$(basename "$csv_file")
    # Überschreibe explizit, auch wenn Datei bereits existiert
    cp -f "$csv_file" "public/data/$filename"
    # Stelle sicher, dass die Datei wirklich überschrieben wurde
    if [ -f "public/data/$filename" ]; then
      # Prüfe, ob die Datei wirklich vom Backup kommt (Größenvergleich)
      backup_size=$(stat -f%z "$csv_file" 2>/dev/null || stat -c%s "$csv_file" 2>/dev/null || echo "0")
      restored_size=$(stat -f%z "public/data/$filename" 2>/dev/null || stat -c%s "public/data/$filename" 2>/dev/null || echo "0")
      if [ "$backup_size" = "$restored_size" ] && [ "$backup_size" != "0" ]; then
        echo "   ✓ Restored public/data/$filename from backup ($backup_size bytes)"
      else
        echo "   ⚠ WARNING: public/data/$filename Größe stimmt nicht überein (Backup: $backup_size, Restored: $restored_size)"
      fi
    else
      echo "   ❌ ERROR: Konnte public/data/$filename nicht wiederherstellen!"
    fi
  done
  
  echo "   ✓ All public/data/*.csv files restored from backup ($BACKUP_DIR/public-data)."
  
  # Zusätzliche Sicherheit: Entferne public/data Dateien aus Git-Index, falls sie getrackt sind
  # (nach dem Restore, damit sie nicht beim nächsten git reset überschrieben werden)
  if git ls-files --error-unmatch public/data/*.csv >/dev/null 2>&1; then
    echo "   WARNING: public/data/*.csv Dateien sind noch im Git getrackt!"
    echo "   Entferne sie aus dem Git-Index (Dateien bleiben erhalten)..."
    git rm --cached public/data/*.csv 2>/dev/null || true
    echo "   ✓ public/data/*.csv aus Git-Index entfernt"
  fi
else
  echo "   No public CSVs to restore"
fi

# Sanity Check: users.json muss existieren und darf nicht leer sein
if [ ! -s server/data/users.json ]; then
  echo "ERROR: server/data/users.json fehlt oder ist leer nach Restore. Abbruch."
  exit 1
fi

# 7. Cleanup (Backups werden bewusst behalten)
echo ""
echo "7. Keeping backups in $BACKUP_ROOT (no git stash used)."

# 8. Restart PM2
echo ""
echo "8. Restarting PM2..."

# Prüfe, ob PM2 installiert ist
if ! command -v pm2 &> /dev/null; then
  echo "ERROR: PM2 ist nicht installiert oder nicht im PATH!"
  echo "Bitte installieren Sie PM2: npm install -g pm2"
  exit 1
fi

# Funktion zum Starten/Neustarten einer PM2-Instanz
restart_pm2_instance() {
  local instance_name=$1
  if ! pm2 describe "$instance_name" &> /dev/null; then
    echo "   WARNING: PM2-Prozess '$instance_name' existiert nicht."
    echo "   Versuche, den Prozess zu starten..."
    if pm2 start harheimertc.config.cjs --only "$instance_name" --update-env; then
      echo "   ✓ PM2-Prozess '$instance_name' gestartet"
      return 0
    else
      echo "   ERROR: Konnte PM2-Prozess '$instance_name' nicht starten."
      return 1
    fi
  else
    echo "   Restarting $instance_name with --update-env..."
    if pm2 restart "$instance_name" --update-env; then
      echo "   ✓ PM2-Prozess '$instance_name' neu gestartet"
      return 0
    else
      echo "   ERROR: PM2-Restart für '$instance_name' fehlgeschlagen!"
      return 1
    fi
  fi
}

# Starte/Neustarte beide Instanzen
INSTANCE_ERRORS=0

if ! restart_pm2_instance "harheimertc"; then
  INSTANCE_ERRORS=$((INSTANCE_ERRORS + 1))
fi

if ! restart_pm2_instance "harheimertc-3102"; then
  INSTANCE_ERRORS=$((INSTANCE_ERRORS + 1))
fi

# Prüfe, ob beide Prozesse laufen
sleep 2
echo ""
echo "   Checking PM2 instances status..."

if pm2 describe harheimertc | grep -q "online"; then
  echo "   ✓ PM2-Prozess 'harheimertc' läuft (online)"
else
  echo "   WARNING: PM2-Prozess 'harheimertc' ist nicht online. Prüfe Logs: pm2 logs harheimertc"
  INSTANCE_ERRORS=$((INSTANCE_ERRORS + 1))
fi

if pm2 describe harheimertc-3102 | grep -q "online"; then
  echo "   ✓ PM2-Prozess 'harheimertc-3102' läuft (online)"
else
  echo "   WARNING: PM2-Prozess 'harheimertc-3102' ist nicht online. Prüfe Logs: pm2 logs harheimertc-3102"
  INSTANCE_ERRORS=$((INSTANCE_ERRORS + 1))
fi

if [ "$INSTANCE_ERRORS" -gt 0 ]; then
  echo ""
  echo "WARNING: Einige PM2-Instanzen haben Probleme. Bitte manuell prüfen:"
  echo "  pm2 status"
  echo "  pm2 logs harheimertc"
  echo "  pm2 logs harheimertc-3102"
fi

echo ""
echo "=== Deployment completed successfully! ==="
echo "The application is now running with the latest code and your production data preserved."
echo ""
echo "Useful commands:"
echo "  pm2 logs harheimertc          # View logs (Port 3100)"
echo "  pm2 logs harheimertc-3102     # View logs (Port 3102)"
echo "  pm2 status                     # View status"
echo "  pm2 restart harheimertc        # Restart instance on port 3100"
echo "  pm2 restart harheimertc-3102   # Restart instance on port 3102"
echo "  pm2 restart all                # Restart all instances"
