#!/bin/bash

#############################################################################
# Script de mise à jour production - Formation Manager Itinova
# Version: 2.0
# 
# Ce script gère:
# - Sauvegarde automatique de la base de données
# - Sauvegarde des fichiers
# - Extraction du package
# - Application des migrations SQL versionnées
# - Redémarrage du service
# - Vérification post-déploiement
#############################################################################

set -e  # Arrêter en cas d'erreur
set -u  # Arrêter si variable non définie

# Couleurs pour les messages
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Configuration
APP_DIR="/var/www/formation-manager-itinova"
BACKUP_DIR="$APP_DIR/backups"
MIGRATIONS_DIR="$APP_DIR/migrations"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
LOG_FILE="$APP_DIR/logs/update-$TIMESTAMP.log"

# Fonction pour afficher les messages
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE"
}

log_success() {
    echo -e "${GREEN}[✓]${NC} $1" | tee -a "$LOG_FILE"
}

log_warning() {
    echo -e "${YELLOW}[⚠]${NC} $1" | tee -a "$LOG_FILE"
}

log_error() {
    echo -e "${RED}[✗]${NC} $1" | tee -a "$LOG_FILE"
}

# Fonction pour vérifier les prérequis
check_prerequisites() {
    log_info "Vérification des prérequis..."
    
    # Vérifier que nous sommes dans le bon répertoire
    if [ ! -f "$APP_DIR/package.json" ]; then
        log_error "Erreur: package.json non trouvé dans $APP_DIR"
        exit 1
    fi
    
    # Vérifier que le fichier .env existe
    if [ ! -f "$APP_DIR/.env" ]; then
        log_error "Erreur: fichier .env non trouvé"
        exit 1
    fi
    
    # Créer les répertoires nécessaires
    mkdir -p "$BACKUP_DIR" "$MIGRATIONS_DIR" "$(dirname "$LOG_FILE")"
    
    log_success "Prérequis vérifiés"
}

# Fonction pour charger les variables d'environnement
load_env() {
    log_info "Chargement des variables d'environnement..."
    
    # Charger le .env
    set -a
    source "$APP_DIR/.env"
    set +a
    
    # Extraire les informations de connexion MySQL depuis DATABASE_URL
    # Format: mysql://user:password@host:port/database
    if [ -z "${DATABASE_URL:-}" ]; then
        log_error "DATABASE_URL non définie dans .env"
        exit 1
    fi
    
    # Parser DATABASE_URL
    DB_USER=$(echo "$DATABASE_URL" | sed -n 's/.*:\/\/\([^:]*\):.*/\1/p')
    DB_PASS=$(echo "$DATABASE_URL" | sed -n 's/.*:\/\/[^:]*:\([^@]*\)@.*/\1/p')
    DB_HOST=$(echo "$DATABASE_URL" | sed -n 's/.*@\([^:]*\):.*/\1/p')
    DB_PORT=$(echo "$DATABASE_URL" | sed -n 's/.*:\([0-9]*\)\/.*/\1/p')
    DB_NAME=$(echo "$DATABASE_URL" | sed -n 's/.*\/\([^?]*\).*/\1/p')
    
    if [ -z "$DB_USER" ] || [ -z "$DB_NAME" ]; then
        log_error "Impossible de parser DATABASE_URL"
        exit 1
    fi
    
    log_success "Variables d'environnement chargées"
}

# Fonction pour sauvegarder la base de données
backup_database() {
    log_info "Sauvegarde de la base de données..."
    
    BACKUP_FILE="$BACKUP_DIR/db-backup-$TIMESTAMP.sql"
    
    # Créer un fichier de configuration MySQL temporaire pour éviter le warning
    MYSQL_CONFIG=$(mktemp)
    cat > "$MYSQL_CONFIG" << EOF
[client]
user=$DB_USER
password=$DB_PASS
host=$DB_HOST
port=$DB_PORT
EOF
    
    # Sauvegarder
    if mysqldump --defaults-extra-file="$MYSQL_CONFIG" \
        --single-transaction \
        --routines \
        --triggers \
        "$DB_NAME" > "$BACKUP_FILE" 2>&1; then
        log_success "Sauvegarde créée: $BACKUP_FILE"
    else
        log_warning "Sauvegarde partielle (certains privilèges manquants)"
        # Ne pas arrêter le script, la sauvegarde partielle est acceptable
    fi
    
    # Nettoyer
    rm -f "$MYSQL_CONFIG"
    
    # Compresser la sauvegarde
    gzip "$BACKUP_FILE"
    log_success "Sauvegarde compressée: $BACKUP_FILE.gz"
    
    # Garder seulement les 10 dernières sauvegardes
    ls -t "$BACKUP_DIR"/db-backup-*.sql.gz | tail -n +11 | xargs -r rm
}

# Fonction pour sauvegarder les fichiers
backup_files() {
    log_info "Sauvegarde des fichiers..."
    
    BACKUP_FILE="$BACKUP_DIR/files-backup-$TIMESTAMP.tar.gz"
    
    # Sauvegarder les fichiers importants (exclure node_modules et dist)
    tar -czf "$BACKUP_FILE" \
        --exclude='node_modules' \
        --exclude='dist' \
        --exclude='backups' \
        --exclude='logs' \
        -C "$APP_DIR" \
        . 2>/dev/null || true
    
    log_success "Fichiers sauvegardés: $BACKUP_FILE"
    
    # Garder seulement les 5 dernières sauvegardes de fichiers
    ls -t "$BACKUP_DIR"/files-backup-*.tar.gz | tail -n +6 | xargs -r rm
}

# Fonction pour détecter le gestionnaire de processus
detect_process_manager() {
    if systemctl is-active --quiet formation-manager 2>/dev/null; then
        echo "systemd"
    elif pm2 list | grep -q "formation-manager"; then
        echo "pm2"
    else
        echo "unknown"
    fi
}

# Fonction pour arrêter le service
stop_service() {
    log_info "Arrêt du service..."
    
    PROCESS_MANAGER=$(detect_process_manager)
    
    case "$PROCESS_MANAGER" in
        systemd)
            sudo systemctl stop formation-manager
            log_success "Service arrêté (systemd)"
            ;;
        pm2)
            pm2 stop formation-manager 2>/dev/null || true
            log_success "Service arrêté (PM2)"
            ;;
        *)
            log_warning "Gestionnaire de processus non détecté, le service n'a pas été arrêté"
            ;;
    esac
}

# Fonction pour extraire le package
extract_package() {
    local PACKAGE_PATH="$1"
    
    log_info "Extraction du package..."
    
    if [ ! -f "$PACKAGE_PATH" ]; then
        log_error "Package non trouvé: $PACKAGE_PATH"
        exit 1
    fi
    
    # Créer un répertoire temporaire
    TEMP_DIR=$(mktemp -d)
    
    # Extraire dans le répertoire temporaire
    tar -xzf "$PACKAGE_PATH" -C "$TEMP_DIR"
    
    # Copier les nouveaux fichiers (préserver .env)
    rsync -av --exclude='.env' --exclude='backups' --exclude='logs' "$TEMP_DIR/" "$APP_DIR/"
    
    # Nettoyer
    rm -rf "$TEMP_DIR"
    
    log_success "Package extrait"
}

# Fonction pour obtenir la version actuelle de la base de données
get_current_db_version() {
    MYSQL_CONFIG=$(mktemp)
    cat > "$MYSQL_CONFIG" << EOF
[client]
user=$DB_USER
password=$DB_PASS
host=$DB_HOST
port=$DB_PORT
EOF
    
    # Créer la table de versions si elle n'existe pas
    mysql --defaults-extra-file="$MYSQL_CONFIG" "$DB_NAME" << 'EOF' 2>/dev/null
CREATE TABLE IF NOT EXISTS schema_migrations (
    version VARCHAR(50) PRIMARY KEY,
    applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    description TEXT
);
EOF
    
    # Obtenir la dernière version
    VERSION=$(mysql --defaults-extra-file="$MYSQL_CONFIG" "$DB_NAME" -sN << 'EOF' 2>/dev/null
SELECT version FROM schema_migrations ORDER BY version DESC LIMIT 1;
EOF
)
    
    rm -f "$MYSQL_CONFIG"
    
    echo "${VERSION:-0}"
}

# Fonction pour appliquer les migrations
apply_migrations() {
    log_info "Application des migrations..."
    
    CURRENT_VERSION=$(get_current_db_version)
    log_info "Version actuelle de la base de données: $CURRENT_VERSION"
    
    # Créer un fichier de configuration MySQL
    MYSQL_CONFIG=$(mktemp)
    cat > "$MYSQL_CONFIG" << EOF
[client]
user=$DB_USER
password=$DB_PASS
host=$DB_HOST
port=$DB_PORT
EOF
    
    # Appliquer chaque migration non appliquée
    MIGRATIONS_APPLIED=0
    
    for MIGRATION_FILE in "$MIGRATIONS_DIR"/*.sql; do
        if [ ! -f "$MIGRATION_FILE" ]; then
            continue
        fi
        
        MIGRATION_VERSION=$(basename "$MIGRATION_FILE" .sql)
        
        # Vérifier si la migration a déjà été appliquée
        ALREADY_APPLIED=$(mysql --defaults-extra-file="$MYSQL_CONFIG" "$DB_NAME" -sN << EOF
SELECT COUNT(*) FROM schema_migrations WHERE version = '$MIGRATION_VERSION';
EOF
)
        
        if [ "$ALREADY_APPLIED" -eq 0 ]; then
            log_info "Application de la migration: $MIGRATION_VERSION"
            
            # Appliquer la migration
            if mysql --defaults-extra-file="$MYSQL_CONFIG" "$DB_NAME" < "$MIGRATION_FILE" 2>&1 | tee -a "$LOG_FILE"; then
                # Enregistrer la migration
                mysql --defaults-extra-file="$MYSQL_CONFIG" "$DB_NAME" << EOF
INSERT INTO schema_migrations (version, description) 
VALUES ('$MIGRATION_VERSION', 'Migration appliquée automatiquement');
EOF
                log_success "Migration $MIGRATION_VERSION appliquée avec succès"
                MIGRATIONS_APPLIED=$((MIGRATIONS_APPLIED + 1))
            else
                log_error "Échec de la migration $MIGRATION_VERSION"
                rm -f "$MYSQL_CONFIG"
                exit 1
            fi
        else
            log_info "Migration $MIGRATION_VERSION déjà appliquée (ignorée)"
        fi
    done
    
    rm -f "$MYSQL_CONFIG"
    
    if [ $MIGRATIONS_APPLIED -eq 0 ]; then
        log_info "Aucune nouvelle migration à appliquer"
    else
        log_success "$MIGRATIONS_APPLIED migration(s) appliquée(s)"
    fi
}

# Fonction pour installer les dépendances
install_dependencies() {
    log_info "Installation des dépendances..."
    
    cd "$APP_DIR"
    
    if command -v pnpm &> /dev/null; then
        pnpm install --prod 2>&1 | tee -a "$LOG_FILE"
    else
        npm install --production 2>&1 | tee -a "$LOG_FILE"
    fi
    
    log_success "Dépendances installées"
}

# Fonction pour démarrer le service
start_service() {
    log_info "Démarrage du service..."
    
    PROCESS_MANAGER=$(detect_process_manager)
    
    case "$PROCESS_MANAGER" in
        systemd)
            sudo systemctl start formation-manager
            sleep 3
            if systemctl is-active --quiet formation-manager; then
                log_success "Service démarré (systemd)"
            else
                log_error "Échec du démarrage du service"
                exit 1
            fi
            ;;
        pm2)
            pm2 restart formation-manager 2>&1 | tee -a "$LOG_FILE"
            sleep 3
            if pm2 list | grep -q "formation-manager.*online"; then
                log_success "Service démarré (PM2)"
            else
                log_error "Échec du démarrage du service"
                exit 1
            fi
            ;;
        *)
            log_warning "Gestionnaire de processus non détecté, démarrage manuel requis"
            ;;
    esac
}

# Fonction pour vérifier le service
verify_service() {
    log_info "Vérification du service..."
    
    # Attendre que le service démarre
    sleep 5
    
    # Vérifier que le service répond
    if curl -f http://localhost:3000/ &>/dev/null; then
        log_success "Service opérationnel"
    else
        log_warning "Le service ne répond pas sur le port 3000"
    fi
    
    # Afficher les derniers logs
    PROCESS_MANAGER=$(detect_process_manager)
    
    case "$PROCESS_MANAGER" in
        systemd)
            log_info "Derniers logs:"
            sudo journalctl -u formation-manager -n 20 --no-pager | tee -a "$LOG_FILE"
            ;;
        pm2)
            log_info "Derniers logs:"
            pm2 logs formation-manager --lines 20 --nostream | tee -a "$LOG_FILE"
            ;;
    esac
}

# Fonction principale
main() {
    echo ""
    echo "========================================="
    echo "  Mise à jour Formation Manager Itinova"
    echo "========================================="
    echo ""
    
    # Demander le chemin du package
    if [ $# -eq 0 ]; then
        read -p "Chemin du package tar.gz: " PACKAGE_PATH
    else
        PACKAGE_PATH="$1"
    fi
    
    # Vérifier les prérequis
    check_prerequisites
    
    # Charger les variables d'environnement
    load_env
    
    # Sauvegardes
    backup_database
    backup_files
    
    # Arrêter le service
    stop_service
    
    # Extraire le package
    extract_package "$PACKAGE_PATH"
    
    # Appliquer les migrations
    apply_migrations
    
    # Installer les dépendances
    install_dependencies
    
    # Démarrer le service
    start_service
    
    # Vérifier le service
    verify_service
    
    echo ""
    log_success "Mise à jour terminée avec succès!"
    echo ""
    log_info "Logs complets: $LOG_FILE"
    log_info "Sauvegarde DB: $BACKUP_DIR/db-backup-$TIMESTAMP.sql.gz"
    echo ""
}

# Exécuter
main "$@"
