#!/usr/bin/env php
<?php

/**
 * Script de migration v2 - Architecture modulaire
 *
 * Utilise les migrators spécialisés pour une migration hiérarchique par opération.
 * Source fixe: geosector (synchronisée 2x/jour par PM7 depuis nx4)
 * Cible: dva_geo (développement), rca_geo (recette) ou pra_geo (production)
 *
 * Usage:
 *   Migration d'une entité:
 *     php migrate_from_backup.php --mode=entity --entity-id=2
 *
 *   Migration globale (toutes les entités):
 *     php migrate_from_backup.php --mode=global
 *
 *   Avec environnement explicite:
 *     php migrate_from_backup.php --env=dva --mode=entity --entity-id=2
 */

// Inclure ApiService pour le chiffrement
require_once dirname(__DIR__, 3) . '/src/Services/ApiService.php';

// Inclure les classes v2
require_once __DIR__ . '/lib/DatabaseConfig.php';
require_once __DIR__ . '/lib/MigrationLogger.php';
require_once __DIR__ . '/lib/DatabaseConnection.php';
require_once __DIR__ . '/lib/UserMigrator.php';
require_once __DIR__ . '/lib/PassageMigrator.php';
require_once __DIR__ . '/lib/SectorMigrator.php';
require_once __DIR__ . '/lib/OperationMigrator.php';

// Configuration PHP pour les grosses migrations
ini_set('memory_limit', '512M');
ini_set('max_execution_time', '3600'); // 1 heure max

class DataMigration
{
    private PDO $sourceDb;
    private PDO $targetDb;
    private MigrationLogger $logger;
    private DatabaseConfig $config;
    private OperationMigrator $operationMigrator;

    // Options
    private string $mode;
    private ?int $entityId;
    private bool $deleteBefore;

    // Statistiques
    private array $migrationStats = [];

    public function __construct(string $env, string $mode = 'global', ?int $entityId = null, ?string $logFile = null, bool $deleteBefore = true)
    {
        // Initialisation config et logger
        $this->config = new DatabaseConfig($env);
        $this->mode = $mode;
        $this->entityId = $entityId;
        $this->deleteBefore = $deleteBefore;

        // Générer le nom du fichier log selon le mode si non spécifié
        if (!$logFile) {
            $logDir = dirname(__DIR__, 2) . '/logs';
            $timestamp = date('Ymd_His');

            if ($mode === 'entity' && $entityId) {
                $logFile = "{$logDir}/migration_entite_{$entityId}_{$timestamp}.log";
            } else {
                $logFile = "{$logDir}/migration_global_{$timestamp}.log";
            }
        }

        $this->logger = new MigrationLogger($logFile);

        // Log header
        $this->logHeader();

        // Connexions
        $dbConnection = new DatabaseConnection($this->config, $this->logger);
        $dbConnection->connect();
        $this->sourceDb = $dbConnection->getSourceDb();
        $this->targetDb = $dbConnection->getTargetDb();

        // Initialiser les migrators
        $this->initializeMigrators();
    }

    private function initializeMigrators(): void
    {
        // Créer les migrators dans l'ordre de dépendance
        $passageMigrator = new PassageMigrator($this->sourceDb, $this->targetDb, $this->logger);
        $sectorMigrator = new SectorMigrator($this->sourceDb, $this->targetDb, $this->logger, $passageMigrator);
        $userMigrator = new UserMigrator($this->sourceDb, $this->targetDb, $this->logger);

        $this->operationMigrator = new OperationMigrator(
            $this->sourceDb,
            $this->targetDb,
            $this->logger,
            $userMigrator,
            $sectorMigrator
        );
    }

    public function run(): void
    {
        if ($this->mode === 'entity') {
            if (!$this->entityId) {
                throw new Exception("entity-id requis en mode entity");
            }
            $this->migrateEntity($this->entityId);
        } else {
            $this->migrateAllEntities();
        }

        // Afficher le récapitulatif
        if (!empty($this->migrationStats)) {
            $this->logger->logMigrationSummary($this->migrationStats);
        }

        $this->logger->separator();
        $this->logger->success("🎉 Migration terminée !");
        $this->logger->info("📄 Log: " . $this->logger->getLogFile());
    }

    private function migrateEntity(int $entityId): void
    {
        $this->logger->separator();
        $this->logger->info("🏢 Migration de l'entité ID: {$entityId}");

        // Supprimer les données existantes si demandé
        if ($this->deleteBefore) {
            $this->deleteEntityData($entityId);
        }

        // Migrer l'entité elle-même
        $this->migrateEntityRecord($entityId);

        // Migrer les users de l'entité (table centrale users)
        $this->migrateEntityUsers($entityId);

        // Récupérer le nom de l'entité pour les stats
        $stmt = $this->sourceDb->prepare("SELECT libelle FROM users_entites WHERE rowid = :id");
        $stmt->execute([':id' => $entityId]);
        $entityName = $stmt->fetchColumn();

        // Récupérer et migrer les opérations
        $operationIds = $this->operationMigrator->getOperationsToMigrate($entityId);

        $operations = [];
        foreach ($operationIds as $oldOperationId) {
            $operationStats = $this->operationMigrator->migrateOperation($oldOperationId);
            if ($operationStats) {
                $operations[] = $operationStats;
            }
        }

        // Stocker les stats pour cette entité
        $this->migrationStats = [
            'entity' => [
                'id' => $entityId,
                'name' => $entityName ?: "Entité #{$entityId}"
            ],
            'operations' => $operations
        ];
    }

    private function migrateAllEntities(): void
    {
        // Récupérer toutes les entités actives
        $stmt = $this->sourceDb->query("SELECT rowid FROM users_entites WHERE active = 1 ORDER BY rowid");
        $entities = $stmt->fetchAll(PDO::FETCH_COLUMN);

        $this->logger->info("📊 " . count($entities) . " entité(s) à migrer");

        $allOperations = [];
        foreach ($entities as $entityId) {
            // Sauvegarder les stats actuelles avant de migrer
            $previousStats = $this->migrationStats;

            $this->migrateEntity($entityId);

            // Agréger les opérations de toutes les entités
            if (!empty($this->migrationStats['operations'])) {
                $allOperations = array_merge($allOperations, $this->migrationStats['operations']);
            }
        }

        // Stocker les stats globales
        $this->migrationStats = [
            'operations' => $allOperations
        ];
    }

    private function deleteEntityData(int $entityId): void
    {
        $this->logger->separator();
        $this->logger->warning("🗑️  Suppression des données de l'entité {$entityId}...");

        // Ordre inverse des contraintes FK
        $tables = [
            'medias' => "fk_entite = {$entityId} OR fk_operation IN (SELECT id FROM operations WHERE fk_entite = {$entityId})",
            'ope_pass_histo' => "fk_pass IN (SELECT id FROM ope_pass WHERE fk_operation IN (SELECT id FROM operations WHERE fk_entite = {$entityId}))",
            'ope_pass' => "fk_operation IN (SELECT id FROM operations WHERE fk_entite = {$entityId})",
            'ope_users_sectors' => "fk_operation IN (SELECT id FROM operations WHERE fk_entite = {$entityId})",
            'ope_users' => "fk_operation IN (SELECT id FROM operations WHERE fk_entite = {$entityId})",
            'sectors_adresses' => "fk_sector IN (SELECT id FROM ope_sectors WHERE fk_operation IN (SELECT id FROM operations WHERE fk_entite = {$entityId}))",
            'ope_sectors' => "fk_operation IN (SELECT id FROM operations WHERE fk_entite = {$entityId})",
            'operations' => "fk_entite = {$entityId}",
            'users' => "fk_entite = {$entityId}"
        ];

        foreach ($tables as $table => $condition) {
            $stmt = $this->targetDb->query("DELETE FROM {$table} WHERE {$condition}");
            $count = $stmt->rowCount();
            if ($count > 0) {
                $this->logger->info("  ✓ {$table}: {$count} ligne(s) supprimée(s)");
            }
        }

        $this->logger->success("✓ Suppression terminée");
    }

    private function migrateEntityRecord(int $entityId): void
    {
        // Vérifier si existe déjà
        $stmt = $this->targetDb->prepare("SELECT COUNT(*) FROM entites WHERE id = :id");
        $stmt->execute([':id' => $entityId]);

        if ($stmt->fetchColumn() > 0) {
            $this->logger->info("Entité {$entityId} existe déjà, skip");
            return;
        }

        // Récupérer depuis source
        $stmt = $this->sourceDb->prepare("SELECT * FROM users_entites WHERE rowid = :id");
        $stmt->execute([':id' => $entityId]);
        $entity = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$entity) {
            throw new Exception("Entité {$entityId} non trouvée");
        }

        // Insérer dans cible (schéma geo_app)
        $stmt = $this->targetDb->prepare("
            INSERT INTO entites (
                id, encrypted_name, adresse1, adresse2, code_postal, ville,
                fk_region, fk_type, encrypted_phone, encrypted_mobile, encrypted_email,
                gps_lat, gps_lng, chk_stripe, encrypted_stripe_id, encrypted_iban, encrypted_bic,
                chk_demo, chk_mdp_manuel, chk_username_manuel, chk_user_delete_pass,
                chk_copie_mail_recu, chk_accept_sms, chk_lot_actif,
                created_at, fk_user_creat, updated_at, fk_user_modif, chk_active
            ) VALUES (
                :id, :encrypted_name, :adresse1, :adresse2, :code_postal, :ville,
                :fk_region, :fk_type, :encrypted_phone, :encrypted_mobile, :encrypted_email,
                :gps_lat, :gps_lng, :chk_stripe, :encrypted_stripe_id, :encrypted_iban, :encrypted_bic,
                :chk_demo, :chk_mdp_manuel, :chk_username_manuel, :chk_user_delete_pass,
                :chk_copie_mail_recu, :chk_accept_sms, :chk_lot_actif,
                :created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active
            )
        ");

        $stmt->execute([
            ':id' => $entityId,
            ':encrypted_name' => $entity['libelle'] ? ApiService::encryptData($entity['libelle']) : '',
            ':adresse1' => $entity['adresse1'] ?? '',
            ':adresse2' => $entity['adresse2'] ?? '',
            ':code_postal' => $entity['cp'] ?? '',
            ':ville' => $entity['ville'] ?? '',
            ':fk_region' => $entity['fk_region'],
            ':fk_type' => $entity['fk_type'] ?? 1,
            ':encrypted_phone' => $entity['tel1'] ? ApiService::encryptData($entity['tel1']) : '',
            ':encrypted_mobile' => $entity['tel2'] ? ApiService::encryptData($entity['tel2']) : '',
            ':encrypted_email' => $entity['email'] ? ApiService::encryptSearchableData($entity['email']) : '',
            ':gps_lat' => $entity['gps_lat'] ?? '',
            ':gps_lng' => $entity['gps_lng'] ?? '',
            ':chk_stripe' => 0,
            ':encrypted_stripe_id' => '',
            ':encrypted_iban' => $entity['iban'] ? ApiService::encryptData($entity['iban']) : '',
            ':encrypted_bic' => $entity['bic'] ? ApiService::encryptData($entity['bic']) : '',
            ':chk_demo' => $entity['demo'] ?? 1,
            ':chk_mdp_manuel' => $entity['chk_mdp_manuel'] ?? 0,
            ':chk_username_manuel' => 0,
            ':chk_user_delete_pass' => 0,
            ':chk_copie_mail_recu' => $entity['chk_copie_mail_recu'] ?? 0,
            ':chk_accept_sms' => $entity['chk_accept_sms'] ?? 0,
            ':chk_lot_actif' => 0,
            ':created_at' => date('Y-m-d H:i:s'),
            ':fk_user_creat' => 0,
            ':updated_at' => $entity['date_modif'],
            ':fk_user_modif' => $entity['fk_user_modif'] ?? 0,
            ':chk_active' => $entity['active'] ?? 1
        ]);

        $this->logger->success("✓ Entité {$entityId} migrée");
    }

    private function migrateEntityUsers(int $entityId): void
    {
        $stmt = $this->sourceDb->prepare("SELECT * FROM users WHERE fk_entite = :entity_id AND active = 1");
        $stmt->execute([':entity_id' => $entityId]);
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $count = 0;
        foreach ($users as $user) {
            // Vérifier si existe déjà
            $stmt = $this->targetDb->prepare("SELECT COUNT(*) FROM users WHERE id = :id");
            $stmt->execute([':id' => $user['rowid']]);

            if ($stmt->fetchColumn() > 0) {
                continue; // Skip si existe
            }

            // Insérer l'utilisateur
            $stmt = $this->targetDb->prepare("
                INSERT INTO users (
                    id, fk_entite, fk_role, first_name, encrypted_name,
                    encrypted_user_name, user_pass_hash, encrypted_email, encrypted_phone, encrypted_mobile,
                    created_at, fk_user_creat, updated_at, fk_user_modif, chk_active
                ) VALUES (
                    :id, :fk_entite, :fk_role, :first_name, :encrypted_name,
                    :encrypted_user_name, :user_pass_hash, :encrypted_email, :encrypted_phone, :encrypted_mobile,
                    :created_at, :fk_user_creat, :updated_at, :fk_user_modif, :chk_active
                )
            ");

            $stmt->execute([
                ':id' => $user['rowid'],
                ':fk_entite' => $user['fk_entite'],
                ':fk_role' => $user['fk_role'],
                ':first_name' => $user['prenom'],
                ':encrypted_name' => ApiService::encryptData($user['libelle']), // Chiffrer avec IV aléatoire
                ':encrypted_user_name' => ApiService::encryptSearchableData($user['username']),
                ':user_pass_hash' => $user['userpswd'], // Hash bcrypt du mot de passe
                ':encrypted_email' => $user['email'] ? ApiService::encryptSearchableData($user['email']) : null,
                ':encrypted_phone' => $user['telephone'] ? ApiService::encryptData($user['telephone']) : null,
                ':encrypted_mobile' => $user['mobile'] ? ApiService::encryptData($user['mobile']) : null,
                ':created_at' => $user['date_creat'],
                ':fk_user_creat' => $user['fk_user_creat'],
                ':updated_at' => $user['date_modif'],
                ':fk_user_modif' => $user['fk_user_modif'],
                ':chk_active' => $user['active']
            ]);

            $count++;
        }

        $this->logger->success("✓ {$count} utilisateur(s) de l'entité migré(s)");
    }

    private function logHeader(): void
    {
        $this->logger->separator();
        $this->logger->info("🚀 Migration v2 - Architecture modulaire");
        $this->logger->info("📅 Date: " . date('Y-m-d H:i:s'));
        $this->logger->info("🌍 Environnement: " . $this->config->getEnvName());
        $this->logger->info("🔧 Mode: " . $this->mode);
        if ($this->entityId) {
            $this->logger->info("🏢 Entité: " . $this->entityId);
        }
        $this->logger->info("🗑️  Suppression avant: " . ($this->deleteBefore ? 'OUI' : 'NON'));
        $this->logger->separator();
    }
}

// === GESTION DES ARGUMENTS CLI ===

function parseArguments(array $argv): array
{
    $options = [
        'env' => DatabaseConfig::autoDetect(),
        'mode' => 'global',
        'entity-id' => null,
        'log' => null,
        'delete-before' => true,
        'help' => false
    ];

    foreach ($argv as $arg) {
        if ($arg === '--help') {
            $options['help'] = true;
        } elseif (preg_match('/^--env=(.+)$/', $arg, $matches)) {
            $options['env'] = $matches[1];
        } elseif (preg_match('/^--mode=(.+)$/', $arg, $matches)) {
            $options['mode'] = $matches[1];
        } elseif (preg_match('/^--entity-id=(\d+)$/', $arg, $matches)) {
            $options['entity-id'] = (int)$matches[1];
        } elseif (preg_match('/^--log=(.+)$/', $arg, $matches)) {
            $options['log'] = $matches[1];
        } elseif ($arg === '--delete-before=false') {
            $options['delete-before'] = false;
        }
    }

    return $options;
}

function showHelp(): void
{
    echo <<<HELP

🚀 Migration v2 - Architecture modulaire

USAGE:
  php migrate_from_backup.php [OPTIONS]

OPTIONS:
  --env=ENV              Environnement: 'dva' (développement), 'rca' (recette) ou 'pra' (production)
                         Par défaut: auto-détection selon hostname

  --mode=MODE            Mode de migration: 'global' ou 'entity'
                         Par défaut: global

  --entity-id=ID         ID de l'entité à migrer (requis si mode=entity)

  --log=PATH             Fichier de log personnalisé
                         Par défaut: logs/migration_YYYYMMDD_HHMMSS.log

  --delete-before        Supprimer les données existantes avant migration
                         Par défaut: true
                         Utiliser --delete-before=false pour désactiver

  --help                 Afficher cette aide

EXEMPLES:
  # Migration d'une entité avec suppression (recommandé)
  php migrate_from_backup.php --mode=entity --entity-id=2

  # Migration sans suppression (risque de doublons)
  php migrate_from_backup.php --mode=entity --entity-id=2 --delete-before=false

  # Migration globale de toutes les entités
  php migrate_from_backup.php --mode=global

  # Spécifier l'environnement manuellement (DVA, RCA ou PRA)
  php migrate_from_backup.php --env=dva --mode=entity --entity-id=2


HELP;
}

// === POINT D'ENTRÉE ===

try {
    $options = parseArguments($argv);

    if ($options['help']) {
        showHelp();
        exit(0);
    }

    // Valider l'environnement
    if (!DatabaseConfig::exists($options['env'])) {
        throw new Exception("Invalid environment: {$options['env']}. Use 'dva', 'rca' or 'pra'");
    }

    // Créer et exécuter la migration
    $migration = new DataMigration(
        $options['env'],
        $options['mode'],
        $options['entity-id'],
        $options['log'],
        $options['delete-before']
    );

    $migration->run();

} catch (Exception $e) {
    echo "❌ ERREUR: " . $e->getMessage() . "\n";
    exit(1);
}
