<?php
/**
 * Script de migration générique pour transférer des données entre les bases geosector et geosector_app
 * 
 * Usage: 
 *   php migrate.php                  - Exécute toutes les migrations dans l'ordre
 *   php migrate.php <table_name>     - Exécute la migration pour une table spécifique
 * 
 * Options:
 *   --truncate      Vide la table cible avant la migration
 *   --create-table  Crée la table cible si elle n'existe pas
 *   --help          Affiche l'aide
 */

require_once dirname(__DIR__) . '/config.php';

// Définition des mappages de colonnes pour chaque table
$tableMappings = [
    'x_devises' => [
        'source_to_target' => [
            'rowid' => 'id',
            'active' => 'chk_active'
        ],
        'primary_key' => 'rowid',  // Clé primaire dans la table source
        'target_primary_key' => 'id'  // Clé primaire dans la table cible
    ],
    'users' => [
        'source_to_target' => [
            'id' => 'id',
            'user_pass_hash' => 'password_hash',
            'encrypted_user_name' => 'encrypted_last_name',
            'lang' => 'preferred_language',
            'chk_active' => 'is_active'
        ],
        'primary_key' => 'id',
        'target_primary_key' => 'id',
        'encrypted_fields' => [
            'email' => ['field' => 'encrypted_email', 'searchable' => true],
            'user_name' => ['field' => 'encrypted_last_name', 'searchable' => false],
            'phone' => ['field' => 'encrypted_phone', 'searchable' => false],
            'mobile' => ['field' => 'encrypted_mobile', 'searchable' => false]
        ]
    ],
    // Ajoutez d'autres tables selon les besoins
];

// Fonction pour afficher l'aide
function showHelp() {
    echo "Usage: php migrate.php <table_name> [--truncate] [--create-table]\n";
    echo "\nOptions disponibles:\n";
    echo "  --truncate      Vide la table cible avant la migration\n";
    echo "  --create-table  Crée la table cible si elle n'existe pas\n";
    echo "  --help          Affiche cette aide\n";
    echo "\nTables disponibles:\n";
    
    global $tableMappings;
    foreach (array_keys($tableMappings) as $table) {
        echo "  - $table\n";
    }
    
    exit(0);
}

// Définition des scripts de migration disponibles dans l'ordre d'exécution
$migrationScripts = [
    'x_devises' => __DIR__ . '/migrate_x_devises.php',
    'x_entites_types' => __DIR__ . '/migrate_x_entites_types.php',
    'x_types_passages' => __DIR__ . '/migrate_x_types_passages.php',
    'x_types_reglements' => __DIR__ . '/migrate_x_types_reglements.php',
    'x_users_roles' => __DIR__ . '/migrate_x_users_roles.php',
    'x_pays' => __DIR__ . '/migrate_x_pays.php',
    'x_regions' => __DIR__ . '/migrate_x_regions.php',
    'x_departements' => __DIR__ . '/migrate_x_departements.php',
    'x_villes' => __DIR__ . '/migrate_x_villes.php',
    'entites' => __DIR__ . '/migrate_entites.php',
    'users' => __DIR__ . '/migrate_users.php',
    'operations' => __DIR__ . '/migrate_operations.php',
    'ope_sectors' => __DIR__ . '/migrate_ope_sectors.php',
    'sectors_adresses' => __DIR__ . '/migrate_sectors_adresses.php',
    'ope_users' => __DIR__ . '/migrate_ope_users.php',
    'ope_users_sectors' => __DIR__ . '/migrate_ope_users_sectors.php',
    'ope_pass' => __DIR__ . '/migrate_ope_pass.php',
    'ope_pass_histo' => __DIR__ . '/migrate_ope_pass_histo.php',
    'medias' => __DIR__ . '/migrate_medias.php'
    // Ajoutez d'autres scripts de migration au fur et à mesure
];

// Fonction pour exécuter un script de migration spécifique
function executeMigrationScript($scriptPath) {
    echo "\nExécution du script: " . basename($scriptPath) . "\n";
    echo "------------------------------------------------\n";
    
    // Exécuter le script PHP
    include $scriptPath;
    
    echo "\n";
    return true;
}

// Traitement des arguments de ligne de commande
$tableName = null;
$truncateTable = false;
$createTable = false;
$runAllScripts = true;

for ($i = 1; $i < $_SERVER['argc']; $i++) {
    $arg = $_SERVER['argv'][$i];
    
    if ($arg === '--help') {
        showHelp();
    } elseif ($arg === '--truncate') {
        $truncateTable = true;
    } elseif ($arg === '--create-table') {
        $createTable = true;
    } elseif (substr($arg, 0, 2) !== '--') {
        $tableName = $arg;
        $runAllScripts = false;
    }
}

// Si aucune table n'est spécifiée, exécuter tous les scripts de migration dans l'ordre
if ($runAllScripts) {
    echo "\nDémarrage de la migration complète de la base de données\n";
    echo "=======================================================\n";
    
    $startTime = microtime(true);
    $successCount = 0;
    $failCount = 0;
    
    foreach ($migrationScripts as $table => $scriptPath) {
        if (file_exists($scriptPath)) {
            try {
                executeMigrationScript($scriptPath);
                $successCount++;
            } catch (Exception $e) {
                echo "\nErreur lors de la migration de la table $table: " . $e->getMessage() . "\n";
                $failCount++;
            }
        } else {
            echo "\nScript de migration introuvable pour la table $table: $scriptPath\n";
            $failCount++;
        }
    }
    
    $endTime = microtime(true);
    $executionTime = round($endTime - $startTime, 2);
    
    echo "\n=======================================================\n";
    echo "Migration terminée en $executionTime secondes\n";
    echo "Tables migrées avec succès: $successCount\n";
    echo "Tables en échec: $failCount\n";
    
    exit(0);
}

// Si une table spécifique est demandée, vérifier si un script dédié existe
if (isset($migrationScripts[$tableName])) {
    $scriptPath = $migrationScripts[$tableName];
    if (file_exists($scriptPath)) {
        executeMigrationScript($scriptPath);
        exit(0);
    }
}

// Sinon, utiliser la méthode générique de migration (code existant)
if (!isset($tableMappings[$tableName])) {
    echo "Erreur: La table '$tableName' n'est pas configurée pour la migration.\n";
    echo "Tables disponibles: " . implode(', ', array_keys($tableMappings)) . "\n";
    exit(1);
}

// Création du dossier de logs si nécessaire
if (!is_dir(dirname(__DIR__) . '/logs')) {
    mkdir(dirname(__DIR__) . '/logs', 0755, true);
}

logOperation("Démarrage de la migration de la table $tableName");

try {
    // Connexion aux bases de données
    $sourceDb = getSourceConnection();
    $targetDb = getTargetConnection();
    
    // Obtenir le service API pour le chiffrement si nécessaire
    $apiService = null;
    if (isset($tableMappings[$tableName]['encrypted_fields'])) {
        $container = $GLOBALS['container'];
        $apiService = $container->get('ApiService');
    }
    
    // Récupération des données de la source
    $stmt = $sourceDb->query("SELECT * FROM $tableName");
    $records = $stmt->fetchAll();
    
    logOperation("Nombre d'enregistrements à migrer: " . count($records));
    
    // Vérifier si la table existe dans la cible
    try {
        $targetDb->query("SELECT 1 FROM $tableName LIMIT 1");
        $tableExists = true;
    } catch (PDOException $e) {
        $tableExists = false;
    }
    
    // Créer la table si elle n'existe pas et si l'option est activée
    if (!$tableExists && $createTable) {
        logOperation("La table $tableName n'existe pas dans la base cible. Création de la table...");
        
        // Récupérer la structure de la table source
        $stmt = $sourceDb->query("SHOW CREATE TABLE $tableName");
        $tableStructure = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (isset($tableStructure['Create Table'])) {
            $createTableSql = $tableStructure['Create Table'];
            
            // Adapter les noms de colonnes selon le mapping
            $mapping = $tableMappings[$tableName]['source_to_target'];
            foreach ($mapping as $sourceCol => $targetCol) {
                $createTableSql = str_replace("`$sourceCol`", "`$targetCol`", $createTableSql);
            }
            
            // Remplacer le nom de la clé primaire si nécessaire
            $sourcePk = $tableMappings[$tableName]['primary_key'];
            $targetPk = $tableMappings[$tableName]['target_primary_key'];
            if ($sourcePk !== $targetPk) {
                $createTableSql = str_replace("PRIMARY KEY (`$sourcePk`)", "PRIMARY KEY (`$targetPk`)", $createTableSql);
            }
            
            // Créer la table
            $targetDb->exec($createTableSql);
            logOperation("Table $tableName créée avec succès");
        } else {
            throw new Exception("Impossible de récupérer la structure de la table source");
        }
    }
    
    // Vider la table cible si l'option est activée
    if ($truncateTable && $tableExists) {
        logOperation("Vidage de la table cible $tableName...");
        $targetDb->exec("TRUNCATE TABLE $tableName");
    }
    
    // Construire la requête d'insertion dynamiquement
    $mapping = $tableMappings[$tableName]['source_to_target'];
    
    // Récupérer les colonnes de la table cible
    $stmt = $targetDb->query("DESCRIBE $tableName");
    $targetColumns = $stmt->fetchAll(PDO::FETCH_COLUMN);
    
    // Construire les listes de colonnes pour l'insertion
    $insertColumns = [];
    $insertPlaceholders = [];
    $updateClauses = [];
    
    foreach ($targetColumns as $column) {
        $insertColumns[] = "`$column`";
        $insertPlaceholders[] = ":$column";
        $updateClauses[] = "`$column` = VALUES(`$column`)";
    }
    
    $insertColumnsSql = implode(", ", $insertColumns);
    $insertPlaceholdersSql = implode(", ", $insertPlaceholders);
    $updateClausesSql = implode(", ", $updateClauses);
    
    $insertQuery = "INSERT INTO $tableName ($insertColumnsSql) "
                . "VALUES ($insertPlaceholdersSql) "
                . "ON DUPLICATE KEY UPDATE $updateClausesSql";
    
    $insertStmt = $targetDb->prepare($insertQuery);
    
    // Compteurs
    $successCount = 0;
    $errorCount = 0;
    
    // Traitement de chaque enregistrement
    foreach ($records as $record) {
        try {
            $data = [];
            
            // Mappage des colonnes selon la configuration
            foreach ($targetColumns as $targetCol) {
                // Trouver la colonne source correspondante
                $sourceCol = array_search($targetCol, $mapping);
                
                if ($sourceCol !== false) {
                    // La colonne existe dans le mapping
                    $data[$targetCol] = $record[$sourceCol];
                } elseif (isset($record[$targetCol])) {
                    // La colonne a le même nom dans les deux tables
                    $data[$targetCol] = $record[$targetCol];
                } else {
                    // Colonne non trouvée, utiliser NULL ou une valeur par défaut
                    $data[$targetCol] = null;
                }
            }
            
            // Traitement des champs chiffrés si nécessaire
            if (isset($tableMappings[$tableName]['encrypted_fields']) && $apiService) {
                foreach ($tableMappings[$tableName]['encrypted_fields'] as $sourceField => $config) {
                    $targetField = $config['field'];
                    $isSearchable = $config['searchable'];
                    
                    if (isset($record[$sourceField]) && !empty($record[$sourceField])) {
                        // Vérifier si le champ est déjà chiffré
                        if (isset($record["encrypted_$sourceField"])) {
                            $data[$targetField] = $record["encrypted_$sourceField"];
                        } else {
                            // Chiffrer la donnée selon qu'elle est recherchable ou non
                            if ($isSearchable) {
                                $data[$targetField] = $apiService->encryptSearchableData($record[$sourceField]);
                            } else {
                                $data[$targetField] = $apiService->encryptData($record[$sourceField]);
                            }
                        }
                    }
                }
            }
            
            // Gestion spécifique pour certaines tables
            if ($tableName === 'users') {
                // Conversion de chk_active (0,1,2) vers is_active (booléen)
                if (isset($record['chk_active'])) {
                    $data['is_active'] = ($record['chk_active'] > 0) ? 1 : 0;
                }
            }
            
            // Insertion dans la base cible
            $insertStmt->execute($data);
            $successCount++;
            
            // Identifiant pour le log
            $pkField = $tableMappings[$tableName]['primary_key'];
            $recordId = $record[$pkField] ?? 'inconnu';
            
            logOperation("Enregistrement ID $recordId migré avec succès", "INFO");
        } catch (Exception $e) {
            $errorCount++;
            $pkField = $tableMappings[$tableName]['primary_key'];
            $recordId = $record[$pkField] ?? 'inconnu';
            
            logOperation("Erreur lors de la migration de l'enregistrement ID $recordId: " . $e->getMessage(), "ERROR");
        }
    }
    
    logOperation("Migration terminée. Succès: $successCount, Erreurs: $errorCount");
    
    // Fermer le tunnel SSH
    closeSshTunnel();
    
} catch (Exception $e) {
    logOperation("Erreur critique: " . $e->getMessage(), "ERROR");
    
    // Fermer le tunnel SSH en cas d'erreur
    closeSshTunnel();
    
    exit(1);
}
