#!/usr/bin/env bash
# Déploiement / mise à jour sur cPanel, à lancer en SSH APRÈS avoir envoyé et décompressé les zip dans le dossier de l'application.
#
#   ./deploy.sh              contrôles → sauvegarde de la base → migrations → dossier d'images → redémarrage → test de santé
#   ./deploy.sh --plan       contrôles + liste des migrations en attente, sans rien modifier
#   ./deploy.sh --restore F  restaure une sauvegarde (F = fichier .sql.gz de ~/flanord-backups), après confirmation
#   Options : --no-restart   ne pas redémarrer l'application      --skip-backup   déconseillé : pas de sauvegarde (confirmation demandée)
#
# Les réglages sont lus dans ~/.flanord-deploy.env (créé au premier lancement, droits 600, jamais dans public_html) :
#   DATABASE_URL=mysql://UTILISATEUR:MOT_DE_PASSE@localhost:3306/BASE      (obligatoire)
#   APP_URL=https://www.flanord-nziengui.com                               (pour le test de santé)
#   UPLOAD_DIR=/home/UTILISATEUR/flanord-uploads                           (dossier créé s'il manque)
# Le script n'affiche jamais le mot de passe et ne le passe jamais en argument de commande.
set -euo pipefail
umask 077

APP="$(cd "$(dirname "$0")" && pwd)"
ENV_FILE="${FLANORD_DEPLOY_ENV:-$HOME/.flanord-deploy.env}"
BACKUP_DIR="$HOME/flanord-backups"
MODE=deploy RESTART=1 BACKUP=1 RESTORE_FILE=""
while [ $# -gt 0 ]; do
  case "$1" in
    --plan) MODE=plan ;;
    --restore) MODE=restore; RESTORE_FILE="${2:-}"; shift ;;
    --no-restart) RESTART=0 ;;
    --skip-backup) BACKUP=0 ;;
    -h|--help) sed -n '2,13p' "$0"; exit 0 ;;
    *) echo "Option inconnue : $1 (voir --help)" >&2; exit 1 ;;
  esac
  shift
done

ok()   { printf '  ✔ %s\n' "$*"; }
warn() { printf '  ⚠ %s\n' "$*" >&2; }
die()  { printf '\n✖ %s\n' "$*" >&2; exit 1; }
step() { printf '\n== %s\n' "$*"; }

TMP="$(mktemp -d)"
LOCK="$APP/.deploy.lock"
cleanup() { rm -rf "$TMP"; rmdir "$LOCK" 2>/dev/null || true; }
mkdir "$LOCK" 2>/dev/null || die "Un autre déploiement est en cours (ou a été interrompu) : supprimez $LOCK si vous en êtes sûr."
trap cleanup EXIT

# ---------- 1. Node ----------
step "1/7 Node.js"
node_ok() { command -v node >/dev/null 2>&1 && node -e 'const [a,b]=process.versions.node.split(".").map(Number);process.exit(a>20||(a===20&&b>=19)?0:1)'; }
if ! node_ok; then
  # cPanel installe Node dans ~/nodevenv/<dossier>/<version>/bin : on prend la plus récente trouvée pour cette application.
  cand="$(ls -d "$HOME/nodevenv/$(basename "$APP")"/*/bin 2>/dev/null | sort -V | tail -1 || true)"
  [ -n "$cand" ] && PATH="$cand:$PATH"
fi
node_ok || die "Node 20.19 ou plus requis (trouvé : $(node -v 2>/dev/null || echo aucun)). Activez l'environnement : source ~/nodevenv/$(basename "$APP")/20/bin/activate  — puis relancez. Voir docs/CPANEL.md."
ok "Node $(node -v)"

# ---------- 2. Contenu du zip ----------
step "2/7 Fichiers de l'application"
for f in server.js start.js migrate.cjs .next/BUILD_ID .next/static public migrations/0_init/migration.sql node_modules/mariadb/package.json node_modules/next/package.json; do
  [ -e "$APP/$f" ] || die "Fichier manquant : $f — décompressez flanord-next-app.zip ET flanord-next-modules.zip dans $APP."
done
[ -d "$APP/.next/server" ] || die ".next/server manquant : zip incomplet."
case "$APP" in */public_html|*/public_html/*) die "L'application ne doit pas être dans public_html (ses fichiers seraient publics).";; esac
ok "application et dépendances présentes"

# ---------- 3. Réglages ----------
step "3/7 Réglages"
get_var() { sed -n "s/^$1=//p" "$ENV_FILE" 2>/dev/null | tail -1 | tr -d '\r' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/^"\(.*\)"$/\1/' -e "s/^'\(.*\)'\$/\1/"; }
if [ ! -f "$ENV_FILE" ]; then
  [ -t 0 ] || die "$ENV_FILE introuvable et pas de terminal pour le créer. Créez-le (voir l'en-tête de deploy.sh)."
  echo "  Premier lancement : création de $ENV_FILE (lisible par vous seul)."
  printf '  DATABASE_URL (mysql://UTILISATEUR:MOT_DE_PASSE@localhost:3306/BASE — @ → %%40, # → %%23 dans le mot de passe) : '
  read -rs DB_IN; echo
  printf '  APP_URL (https://www.flanord-nziengui.com) : '
  read -r URL_IN
  printf '  UPLOAD_DIR (/home/%s/flanord-uploads) : ' "$(id -un)"
  read -r UP_IN
  { printf 'DATABASE_URL=%s\n' "$DB_IN"; [ -n "$URL_IN" ] && printf 'APP_URL=%s\n' "$URL_IN"; printf 'UPLOAD_DIR=%s\n' "${UP_IN:-$HOME/flanord-uploads}"; } > "$ENV_FILE"
fi
chmod 600 "$ENV_FILE"
DATABASE_URL="$(get_var DATABASE_URL)"; APP_URL="$(get_var APP_URL)"; UPLOAD_DIR="$(get_var UPLOAD_DIR)"
[ -n "$DATABASE_URL" ] || die "DATABASE_URL absente de $ENV_FILE."
case "$DATABASE_URL" in *[[:space:]]*) die "DATABASE_URL contient une espace (souvent avant le « : » ou après le nom d'utilisateur) : corrigez $ENV_FILE.";; esac
export DATABASE_URL
ok "réglages lus dans $ENV_FILE"

# ---------- 4. Base joignable + plan ----------
step "4/7 Base de données"
node "$APP/migrate.cjs" --plan || die "Contrôle de la base impossible (voir ci-dessus). Rien n'a été modifié."
DB_NAME="$(node "$APP/migrate.cjs" --db-name)"
cnf="$TMP/client.cnf"
node "$APP/migrate.cjs" --write-cnf "$cnf"

if [ "$MODE" = plan ]; then echo; echo "Mode --plan : rien n'a été modifié."; exit 0; fi

if [ "$MODE" = restore ]; then
  [ -f "$RESTORE_FILE" ] || die "Sauvegarde introuvable : '$RESTORE_FILE' (voir $BACKUP_DIR)."
  command -v mysql >/dev/null 2>&1 || die "Commande mysql introuvable."
  gzip -t "$RESTORE_FILE" || die "Archive corrompue : $RESTORE_FILE"
  echo "  Cette opération REMPLACE le contenu de la base « $DB_NAME » par celui de la sauvegarde :"
  echo "  les demandes de contact / devis, e-mails et statistiques reçus depuis seront perdus."
  printf '  Tapez le nom de la base pour confirmer : '
  read -r conf
  [ "$conf" = "$DB_NAME" ] || die "Confirmation différente : restauration annulée."
  gunzip -c "$RESTORE_FILE" | mysql --defaults-extra-file="$cnf" "$DB_NAME"
  node "$APP/migrate.cjs" --reset-tracker
  ok "base restaurée. Remettez aussi l'ancienne version du code si nécessaire, puis redémarrez l'application."
  exit 0
fi

# ---------- 5. Sauvegarde ----------
step "5/7 Sauvegarde de la base"
out=""
if [ "$BACKUP" = 1 ] && [ "$(node "$APP/migrate.cjs" --table-count)" = 0 ]; then
  ok "base sans aucune table : rien à sauvegarder (première migration)"
elif [ "$BACKUP" = 1 ]; then
  command -v mysqldump >/dev/null 2>&1 || die "mysqldump introuvable : pas de sauvegarde possible. Faites un export phpMyAdmin puis relancez avec --skip-backup."
  mkdir -p "$BACKUP_DIR"; chmod 700 "$BACKUP_DIR"
  out="$BACKUP_DIR/${DB_NAME}-$(date +%Y%m%d-%H%M%S).sql.gz"
  if ! mysqldump --defaults-extra-file="$cnf" --single-transaction --routines --no-tablespaces "$DB_NAME" | gzip > "$out"; then
    rm -f "$out"; die "Sauvegarde échouée : déploiement arrêté, rien n'a été modifié."
  fi
  [ "$(wc -c < "$out")" -gt 500 ] || { rm -f "$out"; die "Sauvegarde vide : déploiement arrêté, rien n'a été modifié."; }
  gzip -t "$out" || die "Sauvegarde corrompue : $out"
  ls -1t "$BACKUP_DIR"/*.sql.gz 2>/dev/null | tail -n +11 | while read -r old; do rm -f "$old"; done # on garde les 10 plus récentes
  ok "sauvegarde : $out ($(du -h "$out" | cut -f1))"
else
  printf '  --skip-backup : AUCUNE sauvegarde. Tapez « oui » pour continuer : '
  read -r a; [ "$a" = oui ] || die "Annulé."
fi

# ---------- 6. Migrations + dossier d'images ----------
step "6/7 Migrations"
if ! node "$APP/migrate.cjs" --apply; then
  [ -n "$out" ] && echo "  Retour arrière de la base : $APP/deploy.sh --restore $out" >&2
  die "Migration en échec. L'application n'a PAS été redémarrée (l'ancienne version continue de tourner)."
fi
if [ -n "$UPLOAD_DIR" ]; then
  if mkdir -p "$UPLOAD_DIR" && chmod 755 "$UPLOAD_DIR"; then ok "dossier d'images : $UPLOAD_DIR"; else warn "Dossier d'images non créé : $UPLOAD_DIR"; fi
else
  warn "UPLOAD_DIR absent de $ENV_FILE : pensez à le déclarer (variable de l'application aussi)."
fi

# ---------- 7. Redémarrage + santé ----------
step "7/7 Redémarrage"
if [ "$RESTART" = 1 ]; then
  mkdir -p "$APP/tmp" && touch "$APP/tmp/restart.txt" && ok "redémarrage demandé (Passenger : tmp/restart.txt)"
  warn "Si les variables d'environnement ont changé dans « Setup Node.js App », cliquez aussi sur Restart dans cPanel."
else
  warn "--no-restart : redémarrez l'application dans cPanel."
fi
if [ -n "$APP_URL" ] && [ "$RESTART" = 1 ] && command -v curl >/dev/null 2>&1; then
  healthy=0
  for _ in 1 2 3 4 5 6; do
    sleep 5
    if curl -fsS --max-time 15 -o /dev/null "${APP_URL%/}/api/health" 2>/dev/null; then healthy=1; break; fi
  done
  if [ "$healthy" = 1 ]; then ok "${APP_URL%/}/api/health répond 200"
  else warn "${APP_URL%/}/api/health ne répond pas encore (DNS / Cloudflare pas encore basculés ? application en démarrage ?). Consultez le journal de l'application dans cPanel."; fi
fi

echo
echo "Terminé. Sauvegarde : ${out:-aucune}. Retour arrière de la base : $APP/deploy.sh --restore <fichier>"
