#!/usr/bin/env bash
#
# Déploiement du frontend ESTAIR Connect (Nuxt / Nitro) — staging.
# Script UNIQUE : appelé par deploy-all-staging.sh (via variables d'env) ou à la
# main (options CLI). Procédure : pull -> deps (si besoin) -> build propre ->
# restart systemd (sans sudo) -> vérifs PID + HTTP.
#
# Usage :
#   bash deploy.sh                    # branche dev, npm ci auto (si deps changées)
#   bash deploy.sh [branche]          # autre branche
#   bash deploy.sh --deps             # forcer npm ci
#   bash deploy.sh --no-deps          # sauter npm ci
#   BRANCH=xxx PORT=3000 SERVICE_NAME=frontend-staging bash deploy.sh
#                                     # overrides env (deploy-all-staging.sh)
#
# ⚠️ Ce script ne déploie JAMAIS le .env : il est posé à la main sur le serveur.
#
# ─── LES 3 PIÈGES DE CE DÉPLOIEMENT ───────────────────────────────────────────
# 1. Le .env doit exister AVANT le build : les NUXT_PUBLIC_* sont FIGÉS AU BUILD
#    via vite.define. Modifier le .env puis redémarrer Node NE SUFFIT PAS.
# 2. JAMAIS `npm ci --omit=dev` : le postinstall lance `nuxt prepare` +
#    `build:icons`, et tsx / @iconify/tools / vite-plugin-vuetify sont en
#    devDependencies mais REQUIS au build.
# 3. Le build exige ≥ 8 Go de RAM (--max-old-space-size=8192). Prévoir du swap
#    sur un petit VPS, sinon OOM silencieux.
# ──────────────────────────────────────────────────────────────────────────────

set -euo pipefail

APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# La branche livrée est `dev` (décision 07/2026) — aligné sur estair/chaps.
BRANCH="${BRANCH:-dev}"
SERVICE_NAME="${SERVICE_NAME:-frontend-staging}"
PORT="${PORT:-3000}"
# Dépendances : auto (npm ci seulement si package*.json a changé) | force | skip.
# SKIP_DEPS=1 (ancien contrat env) reste accepté.
DEPS="auto"
[ "${SKIP_DEPS:-0}" = "1" ] && DEPS="skip"

# --- Options CLI (héritées de deploy-frontend-staging.sh) ---------------------
for a in "$@"; do
    case "$a" in
        --deps)    DEPS="force" ;;
        --no-deps) DEPS="skip"  ;;
        -h|--help) sed -n '3,15p' "$0"; exit 0 ;;
        -*)        echo "Option inconnue : $a" >&2; exit 2 ;;
        *)         BRANCH="$a" ;;
    esac
done

cd "$APP_DIR"

log()  { echo -e "\n\033[1;36m==> $*\033[0m"; }
warn() { echo -e "\033[1;33m  ! $*\033[0m"; }
die()  { echo -e "\n\033[1;31m✘ $*\033[0m" >&2; exit 1; }

# Utilisateur courant (contrôles de permissions).
ME="$(id -un)"; MEGRP="$(id -gn)"

# Garde-fou : refuse d'aller plus loin si un chemin contient des fichiers
# appartenant à un AUTRE utilisateur (ex. root, suite à un `sudo npm install`).
# Sinon `npm ci` (qui efface node_modules d'abord) ou `rm -rf` échouerait à
# mi-chemin et laisserait le dossier cassé. Tente un chown si on en a le droit,
# sinon stoppe net.
assert_owned() {
    local path="$1" foreign
    [ -e "$path" ] || return 0
    foreign="$(find "$path" ! -user "$ME" -print -quit 2>/dev/null || true)"
    if [ -n "$foreign" ]; then
        chown -R "$ME":"$MEGRP" "$path" 2>/dev/null || true
        foreign="$(find "$path" ! -user "$ME" -print -quit 2>/dev/null || true)"
    fi
    [ -z "$foreign" ] || die "Permissions : '$path' contient des fichiers d'un autre utilisateur (ex. $foreign).
   npm ci / rm ne pourrait pas les supprimer → dossier cassé à moitié.
   Corrige UNE fois (admin) :  sudo chown -R $ME:$MEGRP \"$APP_DIR\"
   puis relance ce script."
}

[ -d .git ] || die "Pas un dépôt git : $APP_DIR"
# Piège n°1 : sans .env, les NUXT_PUBLIC_* figés au build seraient vides/faux.
[ -f .env ] || die ".env absent — il doit être posé à la main AVANT le build (NUXT_PUBLIC_* figés au build)."

CURRENT_SHA=$(git rev-parse HEAD 2>/dev/null || echo none)
log "Révision actuelle : $CURRENT_SHA  (rollback : git reset --hard $CURRENT_SHA && bash deploy.sh)"

log "Récupération du code (origin/$BRANCH)"
git fetch origin
git rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1 \
    || die "La branche '$BRANCH' n'existe pas sur origin."
git reset --hard "origin/$BRANCH"
NEW_SHA=$(git rev-parse HEAD)
echo "   → HEAD : $(git log -1 --oneline)"

# --- Dépendances (npm ci conditionnel) -----------------------------------------
NEED_DEPS=0
if [ "$DEPS" = "force" ]; then
    NEED_DEPS=1
elif [ "$DEPS" = "skip" ]; then
    NEED_DEPS=0
elif [ "$CURRENT_SHA" = "none" ]; then
    NEED_DEPS=1
elif ! git diff --quiet "$CURRENT_SHA" "$NEW_SHA" -- package.json package-lock.json; then
    NEED_DEPS=1
fi
if [ "$NEED_DEPS" = "1" ]; then
    log "Dépendances (npm ci — surtout PAS --omit=dev)"
    assert_owned node_modules      # évite un node_modules à moitié effacé (EACCES)
    npm ci
else
    log "Dépendances inchangées → npm ci sauté (forcer : --deps)"
fi

# Obligatoire : sans ça, on mélange les artefacts de deux builds.
log "Build propre (rm .nuxt .output + npm run build, ≥ 8 Go de RAM)"
assert_owned .nuxt
assert_owned .output
rm -rf .nuxt .output
npm run build

# Contrôle de sanité : c'est CE fichier que systemd lance.
[ -f .output/server/index.mjs ] || die "Build KO : .output/server/index.mjs absent."

log "Redémarrage du service $SERVICE_NAME"
# PID exact du service via systemd (lecture seule, sans sudo) — pas de pgrep/pattern.
OLD_PID=$(systemctl show -p MainPID --value "$SERVICE_NAME" 2>/dev/null || echo 0)
echo "   → ancien PID : ${OLD_PID:-0}"
# Deux chemins : sudo systemctl si permis, sinon SIGTERM du process et systemd
# (Restart=always, RestartSec=5) relance avec le nouveau build — indispensable
# quand l'utilisateur n'est pas sudoer (staging).
if sudo -n systemctl restart "$SERVICE_NAME" 2>/dev/null; then
    echo "   → systemctl restart $SERVICE_NAME"
elif [ "${OLD_PID:-0}" != "0" ]; then
    echo "   → pas de sudo : SIGTERM PID $OLD_PID (systemd relance)"
    kill -TERM "$OLD_PID" 2>/dev/null || true
    for i in $(seq 1 10); do kill -0 "$OLD_PID" 2>/dev/null || break; sleep 1; done
    if kill -0 "$OLD_PID" 2>/dev/null; then
        warn "SIGTERM insuffisant après 10s → SIGKILL"
        kill -9 "$OLD_PID" 2>/dev/null || true
        sleep 2
    fi
else
    warn "Service non démarré (MainPID=0). Restart=always ne relance qu'après kill/crash."
    warn "S'il reste arrêté : sudo systemctl start $SERVICE_NAME"
fi

# Vérifier que systemd a bien relancé un NOUVEAU process : un ancien node qui a
# survécu servirait l'ANCIEN build en répondant 200 — le health check HTTP seul
# ne le détecterait pas.
NEW_PID="0"
for i in $(seq 1 20); do
    NEW_PID=$(systemctl show -p MainPID --value "$SERVICE_NAME" 2>/dev/null || echo 0)
    if [ "${NEW_PID:-0}" != "0" ] && [ "$NEW_PID" != "$OLD_PID" ]; then break; fi
    sleep 1
done
echo "   → nouveau PID : ${NEW_PID:-0}"
[ "${NEW_PID:-0}" != "0" ] || die "Le service $SERVICE_NAME n'a pas redémarré — journalctl -u $SERVICE_NAME -n 50 --no-pager"
if [ "${OLD_PID:-0}" != "0" ] && [ "$NEW_PID" = "$OLD_PID" ]; then
    die "PID inchangé ($NEW_PID) : l'ancien process sert toujours l'ANCIEN build — systemctl status $SERVICE_NAME"
fi
systemctl status "$SERVICE_NAME" --no-pager 2>/dev/null | head -5 || true

log "Health check"
CODE="000"
for i in $(seq 1 10); do
    CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "http://127.0.0.1:${PORT}" || echo "000")
    case "$CODE" in 200|302) break ;; esac
    sleep 3
done
case "$CODE" in
    200|302) : ;;
    *) die "Health check KO (HTTP $CODE sur :$PORT) — journalctl -u $SERVICE_NAME -n 50 --no-pager" ;;
esac

log "OK (HTTP $CODE) — déploiement terminé : $(git log -1 --oneline)"
echo -e "\n\033[1;33m! RAPPEL NAVIGATEUR (PWA) : le service worker sert encore l'ancien SPA depuis le cache.\033[0m"
echo -e "\033[1;33m  Pour voir le nouveau build : navigation privée, OU\033[0m"
echo -e "\033[1;33m  F12 > Application > Service Workers > Unregister, puis Clear storage > Clear site data, puis Ctrl+Shift+R.\033[0m"
