<?php

declare(strict_types=1);

namespace MailerPress\Services;

use MailerPress\Core\Enums\Tables;
use MailerPress\Core\Kernel;
use MailerPress\Core\Migrations\CustomTableManager;
use MailerPress\Core\Migrations\Manager;
use MailerPress\Core\Migrations\MigrationTracker;
use MailerPress\Core\Migrations\SchemaBuilder;
use MailerPress\Services\DatabaseRepairLogger;

\defined('ABSPATH') || exit;

/**
 * Service de diagnostic de la base de données
 * Analyse l'état de la base de données et détecte les problèmes
 */
class DatabaseDiagnostic
{
    protected string $migrationPath;
    protected MigrationTracker $tracker;

    public function __construct()
    {
        $this->migrationPath = Kernel::$config['root'] . '/src/Core/Migrations/migrations';
        $this->tracker = new MigrationTracker();
    }

    /**
     * Effectue un diagnostic complet de la base de données
     */
    public function diagnose(): array
    {
        global $wpdb;

        $issues = [];
        $tables = [];
        $migrationStatus = [];

        // 1. Vérifier l'état des migrations
        $migrationStatus = $this->checkMigrationStatus();

        // 2. Analyser toutes les tables attendues
        $expectedTables = $this->getExpectedTables();

        foreach ($expectedTables as $tableName) {
            $fullTableName = Tables::get($tableName);
            $tableInfo = $this->analyzeTable($fullTableName, $tableName);

            if (!empty($tableInfo['issues'])) {
                $issues = array_merge($issues, $tableInfo['issues']);
            }

            $tables[$tableName] = [
                'exists' => $tableInfo['exists'],
                'issues' => $tableInfo['issues'],
                'columns' => $tableInfo['columns'],
                'expected_columns' => $tableInfo['expected_columns'] ?? [],
                'missing_columns' => $tableInfo['missing_columns'] ?? [],
                'indexes' => $tableInfo['indexes'],
                'expected_indexes' => $tableInfo['expected_indexes'] ?? [],
                'missing_indexes' => $tableInfo['missing_indexes'] ?? [],
                'foreign_keys' => $tableInfo['foreign_keys'],
                'expected_foreign_keys' => $tableInfo['expected_foreign_keys'] ?? [],
                'missing_foreign_keys' => $tableInfo['missing_foreign_keys'] ?? [],
            ];
        }

        // 3. Vérifier la table de tracking des migrations
        $trackerTable = $this->tracker->getTableName();
        $trackerExists = $wpdb->get_var(
            $wpdb->prepare("SHOW TABLES LIKE %s", $wpdb->esc_like($trackerTable))
        ) === $trackerTable;

        if (!$trackerExists) {
            $issues[] = [
                'type' => 'critical',
                'table' => 'mailerpress_migrations',
                'issue' => 'missing_table',
                'message' => __('La table de suivi des migrations est manquante', 'mailerpress'),
            ];
        }

        // 4. Vérifier les migrations en échec
        $failedMigrations = $this->tracker->getFailedMigrations();
        if (!empty($failedMigrations)) {
            foreach ($failedMigrations as $migration) {
                $issues[] = [
                    'type' => 'error',
                    'table' => 'migrations',
                    'issue' => 'failed_migration',
                    'message' => sprintf(
                        __('Migration échouée: %s - %s', 'mailerpress'),
                        $migration['migration_name'],
                        $migration['error_message'] ?? __('Erreur inconnue', 'mailerpress')
                    ),
                    'migration_file' => $migration['migration_file'],
                    'error_message' => $migration['error_message'],
                ];
            }
        }

        // 5. Vérifier si les migrations sont verrouillées
        $manager = new Manager($this->migrationPath, []);
        $status = $manager->getStatus();
        if ($status['is_locked']) {
            $issues[] = [
                'type' => 'warning',
                'table' => 'migrations',
                'issue' => 'locked',
                'message' => __('Les migrations sont actuellement verrouillées', 'mailerpress'),
            ];
        }

        return [
            'healthy' => empty($issues),
            'issues' => $issues,
            'tables' => $tables,
            'migration_status' => $migrationStatus,
            'summary' => [
                'total_tables' => count($expectedTables),
                'existing_tables' => count(array_filter($tables, fn($t) => $t['exists'])),
                'missing_tables' => count(array_filter($tables, fn($t) => !$t['exists'])),
                'total_issues' => count($issues),
                'critical_issues' => count(array_filter($issues, fn($i) => $i['type'] === 'critical')),
                'errors' => count(array_filter($issues, fn($i) => $i['type'] === 'error')),
                'warnings' => count(array_filter($issues, fn($i) => $i['type'] === 'warning')),
            ],
        ];
    }

    /**
     * Analyse une table spécifique et compare avec la structure attendue
     */
    protected function analyzeTable(string $fullTableName, string $tableName): array
    {
        global $wpdb;

        $result = [
            'exists' => false,
            'issues' => [],
            'columns' => [],
            'expected_columns' => [],
            'missing_columns' => [],
            'indexes' => [],
            'expected_indexes' => [],
            'missing_indexes' => [],
            'foreign_keys' => [],
            'expected_foreign_keys' => [],
            'missing_foreign_keys' => [],
        ];

        // Vérifier si la table existe
        $tableExists = $wpdb->get_var(
            $wpdb->prepare("SHOW TABLES LIKE %s", $wpdb->esc_like($fullTableName))
        ) === $fullTableName;

        $result['exists'] = $tableExists;

        if (!$tableExists) {
            $result['issues'][] = [
                'type' => 'critical',
                'table' => $tableName,
                'issue' => 'missing_table',
                'message' => sprintf(__('La table %s est manquante', 'mailerpress'), $tableName),
            ];
            return $result;
        }

        // Obtenir la structure attendue depuis les migrations
        $expectedStructure = $this->getExpectedTableStructure($tableName);

        DatabaseRepairLogger::info("Structure attendue pour {$tableName}", [
            'expected_columns_count' => count($expectedStructure['columns'] ?? []),
            'expected_indexes_count' => count($expectedStructure['indexes'] ?? []),
            'expected_foreign_keys_count' => count($expectedStructure['foreign_keys'] ?? []),
        ]);

        // Analyser les colonnes actuelles
        try {
            $columns = $wpdb->get_results("SHOW COLUMNS FROM {$fullTableName}", ARRAY_A);
            $actualColumns = array_map(fn($col) => $col['Field'], $columns);
            $result['columns'] = $actualColumns;

            // Comparer avec les colonnes attendues
            if (!empty($expectedStructure['columns'])) {
                $result['expected_columns'] = $expectedStructure['columns'];
                $missingColumns = array_diff($expectedStructure['columns'], $actualColumns);
                $result['missing_columns'] = array_values($missingColumns);

                DatabaseRepairLogger::info("Comparaison colonnes pour {$tableName}", [
                    'expected' => count($expectedStructure['columns']),
                    'actual' => count($actualColumns),
                    'missing' => count($result['missing_columns']),
                    'missing_list' => $result['missing_columns'],
                ]);

                foreach ($missingColumns as $missingCol) {
                    $result['issues'][] = [
                        'type' => 'critical',
                        'table' => $tableName,
                        'issue' => 'missing_column',
                        'message' => sprintf(__('Colonne manquante dans %s: %s', 'mailerpress'), $tableName, $missingCol),
                        'column' => $missingCol,
                    ];
                }
            }
        } catch (\Throwable $e) {
            $result['issues'][] = [
                'type' => 'error',
                'table' => $tableName,
                'issue' => 'column_check_failed',
                'message' => sprintf(__('Impossible de vérifier les colonnes: %s', 'mailerpress'), $e->getMessage()),
            ];
        }

        // Analyser les index actuels
        try {
            $indexes = $wpdb->get_results("SHOW INDEX FROM {$fullTableName}", ARRAY_A);
            $indexGroups = [];
            foreach ($indexes as $index) {
                $keyName = $index['Key_name'];
                if ($keyName === 'PRIMARY') {
                    continue; // Ignorer la clé primaire
                }
                if (!isset($indexGroups[$keyName])) {
                    $indexGroups[$keyName] = [];
                }
                $indexGroups[$keyName][] = strtolower($index['Column_name']);
            }
            $result['indexes'] = $indexGroups;

            // Comparer avec les index attendus
            if (!empty($expectedStructure['indexes'])) {
                $result['expected_indexes'] = $expectedStructure['indexes'];
                $actualIndexKeys = array_keys($indexGroups);

                DatabaseRepairLogger::info("Comparaison index pour {$tableName}", [
                    'expected' => count($expectedStructure['indexes']),
                    'actual' => count($indexGroups),
                    'expected_details' => $expectedStructure['indexes'],
                    'actual_details' => $indexGroups,
                ]);

                foreach ($expectedStructure['indexes'] as $expectedIndex) {
                    $indexFound = false;
                    $expectedCols = is_array($expectedIndex['columns'])
                        ? array_map('strtolower', $expectedIndex['columns'])
                        : [strtolower($expectedIndex['columns'])];

                    // Trier les colonnes attendues pour la comparaison
                    $expectedColsSorted = $expectedCols;
                    sort($expectedColsSorted);

                    // Vérifier si un index existe avec les mêmes colonnes (même ordre ou ordre différent)
                    foreach ($indexGroups as $indexName => $indexCols) {
                        $normalizedCols = array_map('strtolower', $indexCols);
                        $normalizedColsSorted = $normalizedCols;
                        sort($normalizedColsSorted);

                        // Comparer l'ordre exact d'abord (plus strict)
                        $exactMatch = (
                            count($normalizedCols) === count($expectedCols) &&
                            $normalizedCols === $expectedCols
                        );

                        // Si pas de correspondance exacte, comparer les colonnes triées (ordre différent mais mêmes colonnes)
                        $sortedMatch = (
                            count($normalizedColsSorted) === count($expectedColsSorted) &&
                            $normalizedColsSorted === $expectedColsSorted
                        );

                        if ($exactMatch || $sortedMatch) {
                            $indexFound = true;
                            DatabaseRepairLogger::info("Index trouvé: {$indexName} correspond à l'index attendu", [
                                'table' => $tableName,
                                'existing_index' => $indexName,
                                'existing_columns' => $indexCols,
                                'expected_columns' => $expectedIndex['columns'],
                                'exact_match' => $exactMatch,
                                'sorted_match' => $sortedMatch,
                            ]);
                            break;
                        }
                    }

                    if (!$indexFound) {
                        $result['missing_indexes'][] = $expectedIndex;
                        $indexDesc = is_array($expectedIndex['columns'])
                            ? implode(', ', $expectedIndex['columns'])
                            : $expectedIndex['columns'];
                        $result['issues'][] = [
                            'type' => 'error',
                            'table' => $tableName,
                            'issue' => 'missing_index',
                            'message' => sprintf(
                                __('Index manquant dans %s: %s (%s)', 'mailerpress'),
                                $tableName,
                                $expectedIndex['type'],
                                $indexDesc
                            ),
                            'index' => $expectedIndex,
                        ];
                        DatabaseRepairLogger::warning("Index manquant détecté pour {$tableName}", [
                            'index' => $expectedIndex,
                            'expected_columns' => $expectedCols,
                            'existing_indexes' => $indexGroups,
                            'total_missing' => count($result['missing_indexes']),
                        ]);
                    }
                }
            }
        } catch (\Throwable $e) {
            $result['issues'][] = [
                'type' => 'warning',
                'table' => $tableName,
                'issue' => 'index_check_failed',
                'message' => sprintf(__('Impossible de vérifier les index: %s', 'mailerpress'), $e->getMessage()),
            ];
        }

        // Analyser les clés étrangères actuelles
        try {
            $foreignKeys = $wpdb->get_results(
                $wpdb->prepare(
                    "SELECT CONSTRAINT_NAME, COLUMN_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
                     FROM information_schema.KEY_COLUMN_USAGE
                     WHERE TABLE_SCHEMA = DATABASE()
                     AND TABLE_NAME = %s
                     AND REFERENCED_TABLE_NAME IS NOT NULL",
                    $fullTableName
                ),
                ARRAY_A
            );
            $result['foreign_keys'] = $foreignKeys;

            // Comparer avec les clés étrangères attendues
            if (!empty($expectedStructure['foreign_keys'])) {
                $result['expected_foreign_keys'] = $expectedStructure['foreign_keys'];
                $actualFKs = [];
                foreach ($foreignKeys as $fk) {
                    $actualFKs[] = [
                        'column' => strtolower($fk['COLUMN_NAME']),
                        'referenced_table' => str_replace($wpdb->prefix, '', $fk['REFERENCED_TABLE_NAME']),
                        'referenced_column' => strtolower($fk['REFERENCED_COLUMN_NAME']),
                    ];
                }

                foreach ($expectedStructure['foreign_keys'] as $expectedFK) {
                    $fkFound = false;
                    foreach ($actualFKs as $actualFK) {
                        if (
                            $actualFK['column'] === strtolower($expectedFK['column']) &&
                            $actualFK['referenced_table'] === $expectedFK['referenced_table'] &&
                            $actualFK['referenced_column'] === strtolower($expectedFK['referenced_column'])
                        ) {
                            $fkFound = true;
                            break;
                        }
                    }

                    if (!$fkFound) {
                        $result['missing_foreign_keys'][] = $expectedFK;
                        $result['issues'][] = [
                            'type' => 'error',
                            'table' => $tableName,
                            'issue' => 'missing_foreign_key',
                            'message' => sprintf(
                                __('Clé étrangère manquante dans %s: %s -> %s.%s', 'mailerpress'),
                                $tableName,
                                $expectedFK['column'],
                                $expectedFK['referenced_table'],
                                $expectedFK['referenced_column']
                            ),
                            'foreign_key' => $expectedFK,
                        ];
                    }
                }
            }
        } catch (\Throwable $e) {
            // Ignorer les erreurs de clés étrangères (peut ne pas être supporté)
        }

        return $result;
    }

    /**
     * Obtient la structure attendue d'une table depuis les migrations
     * Agrège toutes les modifications de toutes les migrations
     */
    protected function getExpectedTableStructure(string $tableName): array
    {
        global $wpdb;
        $fullTableName = Tables::get($tableName);

        $structure = [
            'columns' => [],
            'indexes' => [],
            'foreign_keys' => [],
        ];

        $files = glob($this->migrationPath . '/*.php');
        if ($files === false) {
            return $structure;
        }

        sort($files);

        // Utiliser des clés pour éviter les doublons
        $columnsMap = [];
        $indexesMap = [];
        $foreignKeysMap = [];

        foreach ($files as $file) {
            if (!file_exists($file)) {
                continue;
            }

            try {
                $schema = new SchemaBuilder();
                $migration = require $file;

                if (!is_callable($migration)) {
                    continue;
                }

                $migration($schema);

                // Utiliser la réflexion pour accéder aux opérations
                $reflection = new \ReflectionClass($schema);
                $operationsProperty = $reflection->getProperty('operations');
                $operationsProperty->setAccessible(true);
                $operations = $operationsProperty->getValue($schema);

                foreach ($operations as $op) {
                    $manager = $op['manager'];
                    if ($manager->getTableName() !== $fullTableName) {
                        continue;
                    }

                    // Extraire les colonnes
                    $managerReflection = new \ReflectionClass($manager);

                    // Colonnes depuis columnBuilders
                    $columnBuildersProperty = $managerReflection->getProperty('columnBuilders');
                    $columnBuildersProperty->setAccessible(true);
                    $columnBuilders = $columnBuildersProperty->getValue($manager);

                    foreach ($columnBuilders as $builder) {
                        $columnName = $builder->getName();
                        $columnsMap[$columnName] = true;
                    }

                    // Colonnes depuis columns (directement ajoutées via addColumn)
                    $columnsProperty = $managerReflection->getProperty('columns');
                    $columnsProperty->setAccessible(true);
                    $columns = $columnsProperty->getValue($manager);

                    foreach (array_keys($columns) as $columnName) {
                        $columnsMap[$columnName] = true;
                    }

                    // Gérer les colonnes à supprimer (ne pas les inclure dans la structure attendue)
                    $columnsToDropProperty = $managerReflection->getProperty('columnsToDrop');
                    $columnsToDropProperty->setAccessible(true);
                    $columnsToDrop = $columnsToDropProperty->getValue($manager);

                    foreach ($columnsToDrop as $columnToDrop) {
                        unset($columnsMap[$columnToDrop]);
                    }

                    // Extraire les index
                    $indexesProperty = $managerReflection->getProperty('indexes');
                    $indexesProperty->setAccessible(true);
                    $indexes = $indexesProperty->getValue($manager);

                    foreach ($indexes as $indexClause) {
                        // Parser l'index pour extraire les colonnes
                        // Format possible: 
                        // - "INDEX (`col1`, `col2`)"
                        // - "UNIQUE (`col1`, `col2`)"  
                        // - "CONSTRAINT `name_unique` UNIQUE (`col1`, `col2`)"

                        $indexType = 'INDEX';
                        if (stripos($indexClause, 'UNIQUE') !== false) {
                            $indexType = 'UNIQUE';
                        }

                        // Extraire uniquement les colonnes entre parenthèses après UNIQUE ou INDEX
                        // Pattern: chercher UNIQUE ou INDEX suivi de (éventuellement un nom de contrainte) puis des parenthèses avec les colonnes
                        if (preg_match('/\((?:`[^`]+`(?:,\s*`[^`]+`)*)\)/', $indexClause, $parenMatch)) {
                            // Extraire les colonnes de la partie entre parenthèses
                            preg_match_all('/`([^`]+)`/', $parenMatch[0], $matches);
                            $cols = $matches[1] ?? [];
                        } else {
                            // Fallback: extraire toutes les colonnes entre backticks
                            preg_match_all('/`([^`]+)`/', $indexClause, $matches);
                            $cols = $matches[1] ?? [];

                            // Si c'est un index UNIQUE avec CONSTRAINT, le premier élément est le nom de la contrainte
                            // On le supprime si le nom contient "_unique" ou si c'est le seul élément différent
                            if ($indexType === 'UNIQUE' && stripos($indexClause, 'CONSTRAINT') !== false && count($cols) > 1) {
                                // Le premier élément est probablement le nom de la contrainte, on le supprime
                                $firstCol = $cols[0];
                                if (stripos($firstCol, '_unique') !== false || stripos($firstCol, 'unique') !== false) {
                                    array_shift($cols);
                                }
                            }
                        }

                        // Dédupliquer et nettoyer les colonnes
                        $cols = array_unique(array_map('trim', $cols));
                        $cols = array_values(array_filter($cols, function ($col) {
                            // Ignorer les noms qui ressemblent à des noms de contrainte
                            return stripos($col, '_unique') === false &&
                                stripos($col, 'unique') === false &&
                                $col !== 'PRIMARY';
                        }));

                        if (!empty($cols)) {
                            // Créer une clé unique pour l'index (trier les colonnes pour éviter les doublons d'ordre)
                            $colsSorted = $cols;
                            sort($colsSorted);
                            $indexKey = $indexType . '_' . implode('_', $colsSorted);

                            // Ne pas ajouter si un index identique existe déjà (même colonnes, même type)
                            if (!isset($indexesMap[$indexKey])) {
                                $indexesMap[$indexKey] = [
                                    'type' => $indexType,
                                    'columns' => $cols, // Garder l'ordre original
                                ];
                            } else {
                                // Si un index identique existe déjà, on garde celui avec l'ordre original le plus logique
                                DatabaseRepairLogger::info("Index en double détecté (ignoré)", [
                                    'table' => $tableName,
                                    'index_key' => $indexKey,
                                    'columns' => $cols,
                                    'existing' => $indexesMap[$indexKey],
                                ]);
                            }
                        }
                    }

                    // Gérer les index à supprimer
                    $indexesToDropProperty = $managerReflection->getProperty('indexesToDrop');
                    $indexesToDropProperty->setAccessible(true);
                    $indexesToDrop = $indexesToDropProperty->getValue($manager);

                    foreach ($indexesToDrop as $indexToDrop) {
                        // Supprimer tous les index qui contiennent cette colonne
                        foreach (array_keys($indexesMap) as $key) {
                            if (stripos($key, $indexToDrop) !== false) {
                                unset($indexesMap[$key]);
                            }
                        }
                    }

                    // Extraire les clés étrangères
                    $foreignKeysProperty = $managerReflection->getProperty('foreignKeys');
                    $foreignKeysProperty->setAccessible(true);
                    $foreignKeys = $foreignKeysProperty->getValue($manager);

                    foreach ($foreignKeys as $column => $fk) {
                        $fkKey = $column . '_' . $fk['foreignTable'] . '_' . $fk['foreignColumn'];
                        $foreignKeysMap[$fkKey] = [
                            'column' => $column,
                            'referenced_table' => $fk['foreignTable'],
                            'referenced_column' => $fk['foreignColumn'],
                        ];
                    }

                    // Gérer les clés étrangères à supprimer
                    $foreignKeysToDropProperty = $managerReflection->getProperty('foreignKeysToDrop');
                    $foreignKeysToDropProperty->setAccessible(true);
                    $foreignKeysToDrop = $foreignKeysToDropProperty->getValue($manager);

                    foreach ($foreignKeysToDrop as $fkToDrop) {
                        // Supprimer toutes les FK qui utilisent cette colonne
                        foreach (array_keys($foreignKeysMap) as $key) {
                            if (strpos($key, $fkToDrop . '_') === 0) {
                                unset($foreignKeysMap[$key]);
                            }
                        }
                    }
                }
            } catch (\Throwable $e) {
                // Ignorer les erreurs lors de l'analyse des migrations
                continue;
            }
        }

        // Convertir les maps en arrays
        $structure['columns'] = array_keys($columnsMap);
        $structure['indexes'] = array_values($indexesMap);
        $structure['foreign_keys'] = array_values($foreignKeysMap);

        DatabaseRepairLogger::info("Structure finale attendue pour {$tableName}", [
            'columns_count' => count($structure['columns']),
            'indexes_count' => count($structure['indexes']),
            'foreign_keys_count' => count($structure['foreign_keys']),
            'indexes' => $structure['indexes'],
        ]);

        return $structure;
    }

    /**
     * Obtient la liste de toutes les tables attendues depuis les migrations
     */
    protected function getExpectedTables(): array
    {
        // Utiliser les constantes de Tables pour obtenir toutes les tables attendues
        $reflection = new \ReflectionClass(Tables::class);
        $constants = $reflection->getConstants();

        // Tables obsolètes à exclure du diagnostic
        $obsoleteTables = [
            'mailerpress_provider_accounts',
            'mailerpress_provider_contacts',
            'mailerpress_provider_lists',
        ];

        $tables = [];
        foreach ($constants as $name => $value) {
            // Filtrer uniquement les constantes de tables (qui commencent par MAILERPRESS_)
            if (strpos($name, 'MAILERPRESS_') === 0 || strpos($name, 'CONTACT_') === 0) {
                // Exclure les tables obsolètes
                if (!in_array($value, $obsoleteTables, true)) {
                    $tables[] = $value;
                }
            }
        }

        // Ajouter la table de migrations
        $tables[] = 'mailerpress_migrations';

        return array_unique($tables);
    }

    /**
     * Vérifie l'état des migrations
     */
    protected function checkMigrationStatus(): array
    {
        global $wpdb;

        $trackerTable = $this->tracker->getTableName();
        $trackerExists = $wpdb->get_var(
            $wpdb->prepare("SHOW TABLES LIKE %s", $wpdb->esc_like($trackerTable))
        ) === $trackerTable;

        if (!$trackerExists) {
            return [
                'tracker_exists' => false,
                'total_migrations' => 0,
                'completed' => 0,
                'failed' => 0,
                'pending' => 0,
                'running' => 0,
            ];
        }

        $total = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$trackerTable}");
        $completed = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$trackerTable} WHERE status = 'completed'");
        $failed = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$trackerTable} WHERE status = 'failed'");
        $pending = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$trackerTable} WHERE status = 'pending'");
        $running = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$trackerTable} WHERE status = 'running'");

        return [
            'tracker_exists' => true,
            'total_migrations' => $total,
            'completed' => $completed,
            'failed' => $failed,
            'pending' => $pending,
            'running' => $running,
        ];
    }

    /**
     * Répare la base de données en exécutant les migrations manquantes
     */
    public function repair(): array
    {
        DatabaseRepairLogger::init();
        DatabaseRepairLogger::info('Début de la réparation de la base de données');

        $results = [
            'success' => false,
            'message' => '',
            'actions_taken' => [],
            'errors' => [],
            'warnings' => [],
            'fixed_issues' => [],
        ];

        try {
            // 1. Déverrouiller les migrations si nécessaire
            // Créer le manager en mode force pour forcer l'exécution
            $manager = new Manager($this->migrationPath, [], true); // true = force mode
            $status = $manager->getStatus();

            DatabaseRepairLogger::info('État initial des migrations', ['status' => $status]);

            if ($status['is_locked']) {
                $manager->forceReleaseLock();
                $results['actions_taken'][] = __('Verrou des migrations libéré', 'mailerpress');
                DatabaseRepairLogger::info('Verrou des migrations libéré');
            }

            // 2. Réinitialiser les migrations en échec
            if ($status['failed_count'] > 0) {
                $resetCount = $manager->resetFailed();
                $results['actions_taken'][] = sprintf(
                    __('%d migration(s) en échec réinitialisée(s)', 'mailerpress'),
                    $resetCount
                );
                DatabaseRepairLogger::info("{$resetCount} migration(s) en échec réinitialisée(s)");
            }

            // 3. Réinitialiser les migrations en cours (en cas de crash)
            if ($status['running_count'] > 0) {
                $runningCount = $this->tracker->resetAllRunningMigrations();
                $results['actions_taken'][] = sprintf(
                    __('%d migration(s) en cours réinitialisée(s)', 'mailerpress'),
                    $runningCount
                );
                DatabaseRepairLogger::info("{$runningCount} migration(s) en cours réinitialisée(s)");
            }

            // 4. Exécuter les migrations en mode force
            DatabaseRepairLogger::info('Exécution des migrations en mode force');
            $manager->runForce();
            $results['actions_taken'][] = __('Migrations exécutées en mode force', 'mailerpress');
            DatabaseRepairLogger::info('Migrations exécutées en mode force');

            // 5. Réparer les problèmes structurels détectés (index, colonnes, FK manquants)
            DatabaseRepairLogger::info('Vérification et réparation des problèmes structurels');

            // Obtenir le diagnostic actuel pour voir les problèmes
            $currentDiagnostic = $this->diagnose();
            DatabaseRepairLogger::info('Diagnostic avant réparation', [
                'total_issues' => $currentDiagnostic['summary']['total_issues'],
                'missing_tables' => $currentDiagnostic['summary']['missing_tables'],
                'issues_details' => array_map(function ($issue) {
                    return [
                        'type' => $issue['type'],
                        'table' => $issue['table'],
                        'issue' => $issue['issue'],
                    ];
                }, array_slice($currentDiagnostic['issues'], 0, 10)), // Premiers 10 problèmes
            ]);

            // Utiliser les données du diagnostic pour réparer
            $structuralRepairs = $this->repairStructuralIssues($currentDiagnostic);
            DatabaseRepairLogger::info('Résultats de la réparation structurelle', [
                'fixed_count' => count($structuralRepairs['fixed']),
                'warnings_count' => count($structuralRepairs['warnings']),
            ]);

            $results['fixed_issues'] = $structuralRepairs['fixed'];
            $results['warnings'] = array_merge($results['warnings'], $structuralRepairs['warnings']);

            if (!empty($structuralRepairs['fixed'])) {
                DatabaseRepairLogger::info('Problèmes structurels réparés', [
                    'count' => count($structuralRepairs['fixed']),
                    'details' => $structuralRepairs['fixed']
                ]);
            } else {
                DatabaseRepairLogger::info('Aucun problème structurel à réparer', [
                    'total_issues_detected' => $currentDiagnostic['summary']['total_issues'],
                ]);
            }

            $results['success'] = true;
            $results['message'] = __('Base de données réparée avec succès', 'mailerpress');
            DatabaseRepairLogger::info('Réparation terminée avec succès');
        } catch (\Throwable $e) {
            $errorMessage = $e->getMessage();
            $errorTrace = $e->getTraceAsString();

            DatabaseRepairLogger::exception($e, [
                'repair_step' => 'general',
            ]);

            $results['errors'][] = $errorMessage;
            $results['errors'][] = __('Trace:', 'mailerpress') . "\n" . $errorTrace;

            $results['message'] = sprintf(
                __('Erreur lors de la réparation: %s', 'mailerpress'),
                $errorMessage
            );
        }

        return $results;
    }

    /**
     * Répare les problèmes structurels détectés (colonnes, index, FK manquants)
     */
    protected function repairStructuralIssues(?array $diagnostic = null): array
    {
        global $wpdb;

        $fixed = [];
        $warnings = [];

        DatabaseRepairLogger::info('Début de la réparation des problèmes structurels');

        // Obtenir le diagnostic actuel si non fourni
        if ($diagnostic === null) {
            $diagnostic = $this->diagnose();
        }

        DatabaseRepairLogger::info('Diagnostic obtenu', [
            'tables_count' => count($diagnostic['tables']),
            'issues_count' => count($diagnostic['issues']),
            'issues_by_type' => [
                'missing_column' => count(array_filter($diagnostic['issues'], fn($i) => $i['issue'] === 'missing_column')),
                'missing_index' => count(array_filter($diagnostic['issues'], fn($i) => $i['issue'] === 'missing_index')),
                'missing_foreign_key' => count(array_filter($diagnostic['issues'], fn($i) => $i['issue'] === 'missing_foreign_key')),
            ],
        ]);

        // Grouper les problèmes par table pour faciliter le traitement
        $issuesByTable = [];
        foreach ($diagnostic['issues'] as $issue) {
            if (!isset($issuesByTable[$issue['table']])) {
                $issuesByTable[$issue['table']] = [];
            }
            $issuesByTable[$issue['table']][] = $issue;
        }

        DatabaseRepairLogger::info('Problèmes groupés par table', [
            'tables_with_issues' => array_keys($issuesByTable),
            'issues_per_table' => array_map('count', $issuesByTable),
        ]);

        // Traiter les problèmes depuis les issues directement
        foreach ($issuesByTable as $tableName => $tableIssues) {
            $tableInfo = $diagnostic['tables'][$tableName] ?? null;
            if (!$tableInfo || !$tableInfo['exists']) {
                DatabaseRepairLogger::info("Table {$tableName} n'existe pas, sera créée par les migrations");
                continue;
            }

            $fullTableName = Tables::get($tableName);
            DatabaseRepairLogger::info("Traitement des problèmes pour {$tableName}", [
                'issues_count' => count($tableIssues),
            ]);

            foreach ($tableIssues as $issue) {
                try {
                    if ($issue['issue'] === 'missing_index' && isset($issue['index'])) {
                        // Réparer un index manquant
                        $index = $issue['index'];
                        $columns = is_array($index['columns']) ? $index['columns'] : [$index['columns']];
                        $columnsStr = implode('`, `', $columns);

                        $indexType = $index['type'] === 'UNIQUE' ? 'UNIQUE INDEX' : 'INDEX';
                        $indexName = 'idx_' . $tableName . '_' . implode('_', $columns);

                        // Vérifier que toutes les colonnes existent
                        $currentCols = $wpdb->get_col("SHOW COLUMNS FROM {$fullTableName}", 0);
                        $missingCols = [];
                        foreach ($columns as $col) {
                            if (!in_array($col, $currentCols, true)) {
                                $missingCols[] = $col;
                            }
                        }

                        if (!empty($missingCols)) {
                            $missingColsStr = implode(', ', $missingCols);
                            DatabaseRepairLogger::warning("Impossible de créer l'index {$indexName}: colonnes manquantes", [
                                'table' => $tableName,
                                'index' => $indexName,
                                'expected_columns' => $columns,
                                'missing_columns' => $missingCols,
                                'existing_columns' => $currentCols,
                            ]);
                            $warnings[] = sprintf(
                                __('Index manquant: %s (colonnes manquantes: %s)', 'mailerpress'),
                                $indexName,
                                $missingColsStr
                            );
                            continue;
                        }

                        // Vérifier si l'index existe déjà (avec un nom potentiellement différent)
                        $existingIndexes = $wpdb->get_results("SHOW INDEX FROM {$fullTableName}", ARRAY_A);
                        $indexAlreadyExists = false;
                        $normalizedExpectedCols = array_map('strtolower', $columns);

                        foreach ($existingIndexes as $existingIndex) {
                            if ($existingIndex['Key_name'] === 'PRIMARY') {
                                continue;
                            }

                            // Vérifier si un index avec les mêmes colonnes existe déjà
                            $existingCols = [];
                            foreach ($existingIndexes as $idx) {
                                if ($idx['Key_name'] === $existingIndex['Key_name']) {
                                    $existingCols[] = strtolower($idx['Column_name']);
                                }
                            }

                            if (
                                count($existingCols) === count($normalizedExpectedCols) &&
                                empty(array_diff($normalizedExpectedCols, $existingCols))
                            ) {
                                $indexAlreadyExists = true;
                                DatabaseRepairLogger::info("Index existe déjà avec un nom différent: {$existingIndex['Key_name']}", [
                                    'table' => $tableName,
                                    'existing_name' => $existingIndex['Key_name'],
                                    'expected_name' => $indexName,
                                    'columns' => $columns,
                                ]);
                                break;
                            }
                        }

                        if ($indexAlreadyExists) {
                            DatabaseRepairLogger::info("Index déjà présent (nom différent), ignoré: {$indexName}");
                            continue;
                        }

                        // Créer l'index
                        $sql = "ALTER TABLE {$fullTableName} ADD {$indexType} `{$indexName}` (`{$columnsStr}`)";
                        DatabaseRepairLogger::info("Tentative de création de l'index: {$indexName}", [
                            'table' => $tableName,
                            'sql' => $sql,
                            'columns' => $columns,
                        ]);

                        // Réinitialiser les erreurs précédentes
                        $wpdb->last_error = '';
                        $result = $wpdb->query($sql);
                        $lastError = $wpdb->last_error;
                        $lastQuery = $wpdb->last_query;

                        if ($result !== false && empty($lastError)) {
                            // Vérifier que l'index a bien été créé
                            $verifyIndexes = $wpdb->get_results("SHOW INDEX FROM {$fullTableName} WHERE Key_name = '{$indexName}'", ARRAY_A);
                            if (!empty($verifyIndexes)) {
                                $fixed[] = [
                                    'type' => 'index',
                                    'table' => $tableName,
                                    'name' => $indexName,
                                    'columns' => $columns,
                                ];
                                DatabaseRepairLogger::info("Index créé avec succès: {$indexName}", [
                                    'table' => $tableName,
                                    'index' => $indexName,
                                ]);
                            } else {
                                DatabaseRepairLogger::warning("Index créé mais non trouvé lors de la vérification: {$indexName}", [
                                    'table' => $tableName,
                                    'sql' => $sql,
                                ]);
                                $warnings[] = sprintf(
                                    __('Index créé mais non vérifié: %s', 'mailerpress'),
                                    $indexName
                                );
                            }
                        } else {
                            // Vérifier si l'erreur est due à un index déjà existant
                            $errorLower = strtolower($lastError);
                            if (
                                strpos($errorLower, 'duplicate key name') !== false ||
                                strpos($errorLower, 'already exists') !== false ||
                                strpos($errorLower, 'duplicate') !== false
                            ) {
                                DatabaseRepairLogger::info("Index existe déjà (détecté par erreur SQL): {$indexName}", [
                                    'table' => $tableName,
                                    'error' => $lastError,
                                ]);
                                // Ne pas ajouter de warning, l'index existe déjà
                            } else {
                                DatabaseRepairLogger::error("Erreur lors de la création de l'index {$indexName}", [
                                    'table' => $tableName,
                                    'error' => $lastError,
                                    'sql' => $sql,
                                    'result' => $result,
                                    'last_query' => $lastQuery,
                                ]);
                                $warnings[] = sprintf(
                                    __('Erreur lors de la création de l\'index %s: %s', 'mailerpress'),
                                    $indexName,
                                    $lastError ?: __('Erreur inconnue', 'mailerpress')
                                );
                            }
                        }
                    } elseif ($issue['issue'] === 'missing_foreign_key' && isset($issue['foreign_key'])) {
                        // Réparer une clé étrangère manquante
                        $fk = $issue['foreign_key'];
                        $fkName = "fk_{$tableName}_{$fk['column']}";
                        $referencedTable = Tables::get($fk['referenced_table']);

                        // Vérifier que la table référencée existe
                        $refTableExists = $wpdb->get_var(
                            $wpdb->prepare("SHOW TABLES LIKE %s", $wpdb->esc_like($referencedTable))
                        ) === $referencedTable;

                        if (!$refTableExists) {
                            DatabaseRepairLogger::warning("Impossible de créer la FK {$fkName}: table référencée n'existe pas", [
                                'table' => $tableName,
                                'fk' => $fkName,
                                'referenced_table' => $fk['referenced_table'],
                            ]);
                            $warnings[] = sprintf(
                                __('Clé étrangère manquante: %s (table référencée n\'existe pas)', 'mailerpress'),
                                $fkName
                            );
                            continue;
                        }

                        // Créer la clé étrangère
                        $sql = "ALTER TABLE {$fullTableName} 
                                ADD CONSTRAINT `{$fkName}` 
                                FOREIGN KEY (`{$fk['column']}`) 
                                REFERENCES `{$referencedTable}` (`{$fk['referenced_column']}`) 
                                ON DELETE RESTRICT ON UPDATE RESTRICT";

                        DatabaseRepairLogger::info("Tentative de création de la FK: {$fkName}", [
                            'table' => $tableName,
                            'sql' => $sql,
                        ]);

                        $result = $wpdb->query($sql);
                        $lastError = $wpdb->last_error;

                        if ($result !== false && empty($lastError)) {
                            $fixed[] = [
                                'type' => 'foreign_key',
                                'table' => $tableName,
                                'name' => $fkName,
                                'column' => $fk['column'],
                                'referenced_table' => $fk['referenced_table'],
                                'referenced_column' => $fk['referenced_column'],
                            ];
                            DatabaseRepairLogger::info("Clé étrangère créée avec succès: {$fkName}");
                        } else {
                            DatabaseRepairLogger::error("Erreur lors de la création de la FK {$fkName}", [
                                'table' => $tableName,
                                'error' => $lastError,
                                'sql' => $sql,
                                'result' => $result,
                            ]);
                            $warnings[] = sprintf(
                                __('Erreur lors de la création de la clé étrangère %s: %s', 'mailerpress'),
                                $fkName,
                                $lastError ?: __('Erreur inconnue', 'mailerpress')
                            );
                        }
                    } elseif ($issue['issue'] === 'missing_column' && isset($issue['column'])) {
                        // Colonnes manquantes nécessitent une migration, on ne peut pas les créer automatiquement
                        DatabaseRepairLogger::warning("Colonne manquante détectée: {$tableName}.{$issue['column']}", [
                            'table' => $tableName,
                            'column' => $issue['column'],
                        ]);
                        $warnings[] = sprintf(
                            __('Colonne manquante: %s.%s (nécessite une migration)', 'mailerpress'),
                            $tableName,
                            $issue['column']
                        );
                    }
                } catch (\Throwable $e) {
                    DatabaseRepairLogger::exception($e, [
                        'table' => $tableName,
                        'issue' => $issue,
                    ]);
                    $warnings[] = sprintf(
                        __('Erreur lors de la réparation: %s', 'mailerpress'),
                        $e->getMessage()
                    );
                }
            }
        }

        DatabaseRepairLogger::info('Résumé de la réparation structurelle', [
            'total_fixed' => count($fixed),
            'total_warnings' => count($warnings),
            'fixed_details' => $fixed,
        ]);

        return [
            'fixed' => $fixed,
            'warnings' => $warnings,
        ];
    }
}
