<?php

declare(strict_types=1);

namespace App\Services;

require_once __DIR__ . '/../../vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xls;
use PhpOffice\PhpSpreadsheet\Writer\Csv;
use PDO;
use Database;
use Session;
use App\Services\LogService;
use App\Services\ApiService;

require_once __DIR__ . '/../Services/FileService.php';


class ExportService {
    private PDO $db;
    private FileService $fileService;

    public function __construct() {
        $this->db = Database::getInstance();
        $this->fileService = new FileService();
    }

    /**
     * Génère un export Excel complet d'une opération
     *
     * @param int $operationId ID de l'opération
     * @param int $entiteId ID de l'entité
     * @param int|null $userId Filtrer par utilisateur (optionnel)
     * @return array Informations du fichier généré
     */
    public function generateExcelExport(int $operationId, int $entiteId, ?int $userId = null): array {
        try {
            // Récupérer les données de l'opération
            $operationData = $this->getOperationData($operationId, $entiteId);
            if (!$operationData) {
                throw new Exception('Opération non trouvée');
            }

            // Créer le dossier de destination
            $exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}");

            LogService::log('exportDir', [
                'level' => 'warning',
                'exportDir' => $exportDir,
            ]);

            // Générer le nom du fichier
            $timestamp = date('Ymd-His');
            $userSuffix = $userId ? "-user{$userId}" : '';
            $filename = "geosector-export-{$operationId}{$userSuffix}-{$timestamp}.xlsx";
            $filepath = $exportDir . '/' . $filename;

            // Créer le spreadsheet
            $spreadsheet = new Spreadsheet();

            // Insérer les données
            $this->createPassagesSheet($spreadsheet, $operationId, $userId);
            $this->createUsersSheet($spreadsheet, $operationId);
            $this->createSectorsSheet($spreadsheet, $operationId);
            $this->createUserSectorsSheet($spreadsheet, $operationId);

            // Supprimer la feuille par défaut (Worksheet) qui est créée automatiquement
            $defaultSheet = $spreadsheet->getSheetByName('Worksheet');
            if ($defaultSheet) {
                $spreadsheet->removeSheetByIndex($spreadsheet->getIndex($defaultSheet));
            }

            // Essayer d'abord le writer XLSX, sinon utiliser CSV
            try {
                $writer = new Xls($spreadsheet);
                $writer->save($filepath);
            } catch (Exception $e) {
                // Si XLSX échoue, utiliser CSV comme fallback
                $csvPath = str_replace('.xlsx', '.csv', $filepath);
                $csvWriter = new Csv($spreadsheet);
                $csvWriter->setDelimiter(';');
                $csvWriter->setEnclosure('"');
                $csvWriter->save($csvPath);

                // Mettre à jour les variables pour le CSV
                $filepath = $csvPath;
                $filename = str_replace('.xlsx', '.csv', $filename);

                LogService::log('Fallback vers CSV car XLSX a échoué', [
                    'level' => 'warning',
                    'error' => $e->getMessage(),
                    'operationId' => $operationId
                ]);
            }

            // Appliquer les permissions sur le fichier
            $this->fileService->setFilePermissions($filepath);

            // Déterminer le type de fichier réellement généré
            $fileType = str_ends_with($filename, '.csv') ? 'csv' : 'xlsx';

            // Enregistrer en base de données
            $mediaId = $this->fileService->saveToMediasTable($entiteId, $operationId, $filename, $filepath, $fileType, 'Export Excel opération - ' . $operationData['libelle']);

            LogService::log('Export Excel généré', [
                'level' => 'info',
                'operationId' => $operationId,
                'entiteId' => $entiteId,
                'path' => $exportDir,
                'filename' => $filename,
                'mediaId' => $mediaId
            ]);

            return [
                'id' => $mediaId,
                'filename' => $filename,
                'path' => str_replace(getcwd() . '/', '', $filepath),
                'size' => filesize($filepath),
                'type' => 'excel'
            ];
        } catch (Exception $e) {
            LogService::log('Erreur lors de la génération de l\'export Excel', [
                'level' => 'error',
                'error' => $e->getMessage(),
                'operationId' => $operationId,
                'entiteId' => $entiteId
            ]);
            throw $e;
        }
    }

    /**
     * Génère un export JSON complet d'une opération (chiffré et compressé)
     *
     * @param int $operationId ID de l'opération
     * @param int $entiteId ID de l'entité
     * @param string $type Type d'export (auto, manual)
     * @return array Informations du fichier généré
     */
    public function generateJsonExport(int $operationId, int $entiteId, string $type = 'manual'): array {
        try {
            // Récupérer toutes les données de l'opération
            $exportData = $this->collectOperationData($operationId, $entiteId);

            // Créer le dossier de destination
            $exportDir = $this->fileService->createDirectory($entiteId, "/{$entiteId}/operations/{$operationId}");

            // Initialiser le service de chiffrement
            $backupService = new BackupEncryptionService();

            // Générer le JSON original
            $jsonData = json_encode($exportData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

            // Chiffrer et compresser les données
            $encryptedData = $backupService->encryptBackup($jsonData);

            // Générer le nom du fichier avec extension appropriée
            $timestamp = date('Ymd-His');
            $filename = $backupService->generateBackupFilename($operationId, $timestamp, $type);
            $filepath = $exportDir . '/' . $filename;

            // Sauvegarder le fichier chiffré
            file_put_contents($filepath, $encryptedData);

            // Appliquer les permissions sur le fichier
            $this->fileService->setFilePermissions($filepath);

            // Obtenir les statistiques de compression
            $stats = $backupService->getCompressionStats($jsonData, $encryptedData);

            // Enregistrer en base de données avec le bon type MIME
            $mediaId = $this->fileService->saveToMediasTable(
                $entiteId,
                $operationId,
                $filename,
                $filepath,
                'enc',
                "Sauvegarde chiffrée opération - {$type} - " . $exportData['operation']['libelle'],
                'backup'
            );

            LogService::log('Export JSON chiffré généré', [
                'level' => 'info',
                'operationId' => $operationId,
                'entiteId' => $entiteId,
                'filename' => $filename,
                'type' => $type,
                'mediaId' => $mediaId,
                'original_size' => $stats['original_size'],
                'final_size' => $stats['final_size'],
                'compression_ratio' => $stats['compression_ratio'] . '%',
                'is_compressed' => $stats['is_compressed'],
                'cipher' => $stats['cipher']
            ]);

            return [
                'id' => $mediaId,
                'filename' => $filename,
                'path' => str_replace(getcwd() . '/', '', $filepath),
                'size' => filesize($filepath),
                'type' => 'encrypted_json',
                'compression_stats' => $stats
            ];
        } catch (Exception $e) {
            LogService::log('Erreur lors de la génération de l\'export JSON chiffré', [
                'level' => 'error',
                'error' => $e->getMessage(),
                'operationId' => $operationId,
                'entiteId' => $entiteId
            ]);
            throw $e;
        }
    }

    /**
     * Crée la feuille des passages
     */
    private function createPassagesSheet(Spreadsheet $spreadsheet, int $operationId, ?int $userId = null): void {
        $sheet = $spreadsheet->createSheet();
        $sheet->setTitle('Passages');

        // En-têtes
        $headers = [
            'ID_Passage',
            'Date',
            'Heure',
            'Prénom',
            'Nom',
            'Tournée',
            'Type',
            'N°',
            'Bis',
            'Rue',
            'Ville',
            'Habitat',
            'Donateur',
            'Email',
            'Tél',
            'Montant',
            'Règlement',
            'Remarque',
            'FK_User',
            'FK_Sector',
            'FK_Operation'
        ];

        // Écrire les en-têtes
        $sheet->fromArray([$headers], null, 'A1');

        // Récupérer les données des passages
        $sql = '
            SELECT
                p.id, p.passed_at, p.fk_type, p.numero, p.rue_bis, p.rue, p.ville,
                p.fk_habitat, p.appt, p.niveau, p.encrypted_name, p.encrypted_email,
                p.encrypted_phone, p.montant, p.fk_type_reglement, p.remarque,
                p.fk_user, p.fk_sector, p.fk_operation,
                u.encrypted_name as user_name, ou.first_name as user_first_name, u.sect_name,
                xtr.libelle as reglement_libelle
            FROM ope_pass p
            LEFT JOIN ope_users ou ON ou.id = p.fk_user
            LEFT JOIN users u ON u.id = ou.fk_user
            LEFT JOIN x_types_reglements xtr ON xtr.id = p.fk_type_reglement
            WHERE p.fk_operation = ? AND p.chk_active = 1
        ';

        $params = [$operationId];
        if ($userId) {
            $sql .= ' AND p.fk_user = ?';
            $params[] = $userId;
        }

        $sql .= ' ORDER BY p.passed_at DESC';

        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        $passages = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Remplir les données
        $row = 2;
        foreach ($passages as $passage) {
            $dateEve = $passage['passed_at'] ? date('d/m/Y', strtotime($passage['passed_at'])) : '';
            $heureEve = $passage['passed_at'] ? date('H:i', strtotime($passage['passed_at'])) : '';

            // Déchiffrer les données (avec vérification null)
            $donateur = !empty($passage['encrypted_name']) ? ApiService::decryptData($passage['encrypted_name']) : '';
            $email = !empty($passage['encrypted_email']) ? ApiService::decryptSearchableData($passage['encrypted_email']) : '';
            $phone = !empty($passage['encrypted_phone']) ? ApiService::decryptData($passage['encrypted_phone']) : '';
            $userName = !empty($passage['user_name']) ? ApiService::decryptData($passage['user_name']) : '';

            // Type de passage
            $typeLabels = [
                1 => 'Effectué',
                2 => 'A finaliser',
                3 => 'Refusé',
                4 => 'Don',
                9 => 'Habitat vide'
            ];
            $typeLabel = $typeLabels[$passage['fk_type']] ?? $passage['fk_type'];

            // Habitat
            $habitat = $passage['fk_habitat'] == 1 ? 'Individuel' :
                "Etage {$passage['niveau']} - Appt {$passage['appt']}";

            $rowData = [
                $passage['id'],
                $dateEve,
                $heureEve,
                $passage['user_first_name'],
                $userName,
                $passage['sect_name'],
                $typeLabel,
                $passage['numero'],
                $passage['rue_bis'],
                $passage['rue'],
                $passage['ville'],
                $habitat,
                $donateur,
                $email,
                $phone,
                $passage['montant'],
                $passage['reglement_libelle'],
                $passage['remarque'],
                $passage['fk_user'],
                $passage['fk_sector'],
                $passage['fk_operation']
            ];

            $sheet->fromArray([$rowData], null, "A{$row}");
            $row++;
        }

        // Auto-ajuster les colonnes
        foreach (range('A', 'T') as $col) {
            $sheet->getColumnDimension($col)->setAutoSize(true);
        }
    }

    /**
     * Crée la feuille des utilisateurs
     */
    private function createUsersSheet(Spreadsheet $spreadsheet, int $operationId): void {
        $sheet = $spreadsheet->createSheet();
        $sheet->setTitle('Utilisateurs');

        // En-têtes
        $headers = [
            'ID_User',
            'Nom',
            'Prénom',
            'Email',
            'Téléphone',
            'Mobile',
            'Rôle',
            'Date_création',
            'Actif',
            'FK_Entite'
        ];

        $sheet->fromArray([$headers], null, 'A1');

        // Récupérer les utilisateurs de l'opération
        $sql = '
            SELECT DISTINCT
                u.id, u.encrypted_name, u.first_name, u.encrypted_email,
                u.encrypted_phone, u.encrypted_mobile, u.fk_role, u.created_at,
                u.chk_active, u.fk_entite,
                r.libelle as role_libelle
            FROM users u
            INNER JOIN ope_users ou ON ou.fk_user = u.id
            LEFT JOIN x_users_roles r ON r.id = u.fk_role
            WHERE ou.fk_operation = ? AND ou.chk_active = 1
            ORDER BY u.encrypted_name
        ';

        $stmt = $this->db->prepare($sql);
        $stmt->execute([$operationId]);
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $row = 2;
        foreach ($users as $user) {
            $rowData = [
                $user['id'],
                !empty($user['encrypted_name']) ? ApiService::decryptData($user['encrypted_name']) : '',
                $user['first_name'],
                !empty($user['encrypted_email']) ? ApiService::decryptSearchableData($user['encrypted_email']) : '',
                !empty($user['encrypted_phone']) ? ApiService::decryptData($user['encrypted_phone']) : '',
                !empty($user['encrypted_mobile']) ? ApiService::decryptData($user['encrypted_mobile']) : '',
                $user['role_libelle'],
                date('d/m/Y H:i', strtotime($user['created_at'])),
                $user['chk_active'] ? 'Oui' : 'Non',
                $user['fk_entite']
            ];

            $sheet->fromArray([$rowData], null, "A{$row}");
            $row++;
        }

        foreach (range('A', 'J') as $col) {
            $sheet->getColumnDimension($col)->setAutoSize(true);
        }
    }

    /**
     * Crée la feuille des secteurs
     */
    private function createSectorsSheet(Spreadsheet $spreadsheet, int $operationId): void {
        $sheet = $spreadsheet->createSheet();
        $sheet->setTitle('Secteurs');

        $headers = ['ID_Sector', 'Libellé', 'Couleur', 'Date_création', 'Actif', 'FK_Operation'];
        $sheet->fromArray([$headers], null, 'A1');

        $sql = '
            SELECT id, libelle, color, created_at, chk_active, fk_operation
            FROM ope_sectors
            WHERE fk_operation = ? AND chk_active = 1
            ORDER BY libelle
        ';

        $stmt = $this->db->prepare($sql);
        $stmt->execute([$operationId]);
        $sectors = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $row = 2;
        foreach ($sectors as $sector) {
            $rowData = [
                $sector['id'],
                $sector['libelle'],
                $sector['color'],
                date('d/m/Y H:i', strtotime($sector['created_at'])),
                $sector['chk_active'] ? 'Oui' : 'Non',
                $sector['fk_operation']
            ];

            $sheet->fromArray([$rowData], null, "A{$row}");
            $row++;
        }

        foreach (range('A', 'F') as $col) {
            $sheet->getColumnDimension($col)->setAutoSize(true);
        }
    }

    /**
     * Crée la feuille des relations secteurs-utilisateurs
     */
    private function createUserSectorsSheet(Spreadsheet $spreadsheet, int $operationId): void {
        $sheet = $spreadsheet->createSheet();
        $sheet->setTitle('Secteurs-Utilisateurs');

        $headers = [
            'ID_Relation',
            'FK_Sector',
            'Nom_Secteur',
            'FK_User',
            'Nom_Utilisateur',
            'Date_assignation',
            'FK_Operation'
        ];
        $sheet->fromArray([$headers], null, 'A1');

        $sql = '
            SELECT
                ous.id, ous.fk_sector, ous.fk_user, ous.created_at, ous.fk_operation,
                s.libelle as sector_name,
                u.encrypted_name as user_name, ou.first_name
            FROM ope_users_sectors ous
            INNER JOIN ope_sectors s ON s.id = ous.fk_sector
            INNER JOIN ope_users ou ON ou.id = ous.fk_user
            INNER JOIN users u ON u.id = ou.fk_user
            WHERE ous.fk_operation = ? AND ous.chk_active = 1
            ORDER BY s.libelle, u.encrypted_name
        ';

        $stmt = $this->db->prepare($sql);
        $stmt->execute([$operationId]);
        $userSectors = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $row = 2;
        foreach ($userSectors as $us) {
            $userName = !empty($us['user_name']) ? ApiService::decryptData($us['user_name']) : '';
            $fullUserName = $us['first_name'] ? $us['first_name'] . ' ' . $userName : $userName;

            $rowData = [
                $us['id'],
                $us['fk_sector'],
                $us['sector_name'],
                $us['fk_user'],
                $fullUserName,
                date('d/m/Y H:i', strtotime($us['created_at'])),
                $us['fk_operation']
            ];

            $sheet->fromArray([$rowData], null, "A{$row}");
            $row++;
        }

        foreach (range('A', 'G') as $col) {
            $sheet->getColumnDimension($col)->setAutoSize(true);
        }
    }

    /**
     * Collecte toutes les données d'une opération pour l'export JSON
     */
    private function collectOperationData(int $operationId, int $entiteId): array {
        // Métadonnées de l'export
        $exportData = [
            'export_metadata' => [
                'version' => '1.0',
                'export_date' => date('c'),
                'source_entite_id' => $entiteId,
                'export_type' => 'full_operation'
            ]
        ];

        // Données de l'opération
        $exportData['operation'] = $this->getOperationData($operationId, $entiteId);

        // Utilisateurs de l'opération
        $exportData['users'] = $this->getOperationUsers($operationId);

        // Secteurs de l'opération
        $exportData['sectors'] = $this->getOperationSectors($operationId);

        // Passages de l'opération
        $exportData['passages'] = $this->getOperationPassages($operationId);

        // Relations utilisateurs-secteurs
        $exportData['user_sectors'] = $this->getOperationUserSectors($operationId);

        return $exportData;
    }

    /**
     * Récupère les données de l'opération
     */
    private function getOperationData(int $operationId, int $entiteId): ?array {
        $stmt = $this->db->prepare('
            SELECT * FROM operations
            WHERE id = ? AND fk_entite = ?
        ');
        $stmt->execute([$operationId, $entiteId]);
        return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
    }

    /**
     * Récupère les utilisateurs de l'opération
     */
    private function getOperationUsers(int $operationId): array {
        $stmt = $this->db->prepare('
            SELECT DISTINCT u.*
            FROM users u
            INNER JOIN ope_users ou ON ou.fk_user = u.id
            WHERE ou.fk_operation = ? AND ou.chk_active = 1
        ');
        $stmt->execute([$operationId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Récupère les secteurs de l'opération
     */
    private function getOperationSectors(int $operationId): array {
        $stmt = $this->db->prepare('
            SELECT * FROM ope_sectors
            WHERE fk_operation = ? AND chk_active = 1
        ');
        $stmt->execute([$operationId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Récupère les passages de l'opération
     */
    private function getOperationPassages(int $operationId): array {
        $stmt = $this->db->prepare('
            SELECT * FROM ope_pass
            WHERE fk_operation = ? AND chk_active = 1
        ');
        $stmt->execute([$operationId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Récupère les relations utilisateurs-secteurs
     */
    private function getOperationUserSectors(int $operationId): array {
        $stmt = $this->db->prepare('
            SELECT * FROM ope_users_sectors
            WHERE fk_operation = ? AND chk_active = 1
        ');
        $stmt->execute([$operationId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    /**
     * Récupère les données des passages dans un format simple pour l'export Excel
     * (inspiré de l'ancienne version qui fonctionne)
     */
    private function getSimplePassagesData(int $operationId, ?int $userId = null): array {
        // En-têtes (comme dans l'ancienne version)
        $aData = [];
        $aData[] = [
            'Date',
            'Heure',
            'Prenom',
            'Nom',
            'Tournee',
            'Type',
            'N°',
            'Rue',
            'Ville',
            'Habitat',
            'Donateur',
            'Email',
            'Tel',
            'Montant',
            'Reglement',
            'Remarque'
        ];

        // Récupérer les données des passages
        $sql = '
            SELECT
                p.passed_at, p.fk_type, p.numero, p.rue_bis, p.rue, p.ville,
                p.fk_habitat, p.appt, p.niveau, p.encrypted_name, p.encrypted_email,
                p.encrypted_phone, p.montant, p.fk_type_reglement, p.remarque,
                u.encrypted_name as user_name, ou.first_name as user_first_name, u.sect_name,
                xtr.libelle as reglement_libelle
            FROM ope_pass p
            LEFT JOIN ope_users ou ON ou.id = p.fk_user
            LEFT JOIN users u ON u.id = ou.fk_user
            LEFT JOIN x_types_reglements xtr ON xtr.id = p.fk_type_reglement
            WHERE p.fk_operation = ? AND p.chk_active = 1
        ';

        $params = [$operationId];
        if ($userId) {
            $sql .= ' AND p.fk_user = ?';
            $params[] = $userId;
        }

        $sql .= ' ORDER BY p.passed_at DESC';

        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        $passages = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Traiter les données comme dans l'ancienne version
        foreach ($passages as $p) {
            // Type de passage
            switch ($p["fk_type"]) {
                case 1:
                    $ptype = "Effectué";
                    $preglement = $p["reglement_libelle"];
                    break;
                case 2:
                    $ptype = "A finaliser";
                    $preglement = "";
                    break;
                case 3:
                    $ptype = "Refusé";
                    $preglement = "";
                    break;
                case 4:
                    $ptype = "Don";
                    $preglement = "";
                    break;
                case 9:
                    $ptype = "Habitat vide";
                    $preglement = "";
                    break;
                default:
                    $ptype = $p["fk_type"];
                    $preglement = "";
                    break;
            }

            // Habitat
            if ($p["fk_habitat"] == 1) {
                $phabitat = "Individuel";
            } else {
                $phabitat = "Etage " . $p["niveau"] . " - Appt " . $p["appt"];
            }

            // Dates
            $dateEve = $p["passed_at"] ? date("d/m/Y", strtotime($p["passed_at"])) : "";
            $heureEve = $p["passed_at"] ? date("H:i", strtotime($p["passed_at"])) : "";

            // Déchiffrer les données (avec vérification null)
            $donateur = !empty($p["encrypted_name"]) ? ApiService::decryptData($p["encrypted_name"]) : "";
            $email = !empty($p["encrypted_email"]) ? ApiService::decryptSearchableData($p["encrypted_email"]) : "";
            $phone = !empty($p["encrypted_phone"]) ? ApiService::decryptData($p["encrypted_phone"]) : "";
            $userName = !empty($p["user_name"]) ? ApiService::decryptData($p["user_name"]) : "";

            // Nettoyer les données (comme dans l'ancienne version)
            $nom = str_replace("/", "-", $userName);
            $tournee = str_replace("/", "-", $p["sect_name"]);

            $aData[] = [
                $dateEve,
                $heureEve,
                $p["user_first_name"],
                $nom,
                $tournee,
                $ptype,
                $p["numero"] . $p["rue_bis"],
                $p["rue"],
                $p["ville"],
                $phabitat,
                $donateur,
                $email,
                $phone,
                $p["montant"],
                $preglement,
                $p["remarque"]
            ];
        }

        return $aData;
    }

    /**
     * Restaure une opération à partir d'un backup chiffré
     *
     * @param string $backupFilePath Chemin vers le fichier de backup
     * @param int $targetEntiteId ID de l'entité cible (pour restauration cross-entité)
     * @return array Résultat de la restauration
     * @throws Exception En cas d'erreur de restauration
     */
    public function restoreFromBackup(string $backupFilePath, int $targetEntiteId): array {
        try {
            // Initialiser le service de chiffrement
            $backupService = new BackupEncryptionService();

            // Lire et déchiffrer le backup
            $backupData = $backupService->readBackupFile($backupFilePath);

            // Valider la structure du backup
            if (!isset($backupData['operation']) || !isset($backupData['export_metadata'])) {
                throw new Exception('Structure de backup invalide');
            }

            $operationData = $backupData['operation'];
            $originalEntiteId = $backupData['export_metadata']['source_entite_id'];

            // Commencer la transaction
            $this->db->beginTransaction();

            // Créer la nouvelle opération
            $newOperationId = $this->restoreOperation($operationData, $targetEntiteId);

            // Restaurer les utilisateurs (si même entité)
            if ($targetEntiteId === $originalEntiteId && isset($backupData['users'])) {
                $this->restoreUsers($backupData['users'], $newOperationId);
            }

            // Restaurer les secteurs
            if (isset($backupData['sectors'])) {
                $this->restoreSectors($backupData['sectors'], $newOperationId);
            }

            // Restaurer les relations utilisateurs-secteurs
            if (isset($backupData['user_sectors'])) {
                $this->restoreUserSectors($backupData['user_sectors'], $newOperationId);
            }

            // Restaurer les passages
            if (isset($backupData['passages'])) {
                $this->restorePassages($backupData['passages'], $newOperationId);
            }

            $this->db->commit();

            LogService::log('Restauration de backup réussie', [
                'level' => 'info',
                'backup_file' => $backupFilePath,
                'original_operation_id' => $operationData['id'],
                'new_operation_id' => $newOperationId,
                'target_entite_id' => $targetEntiteId,
                'original_entite_id' => $originalEntiteId
            ]);

            return [
                'success' => true,
                'new_operation_id' => $newOperationId,
                'original_operation_id' => $operationData['id'],
                'restored_data' => [
                    'operation' => true,
                    'users' => isset($backupData['users']) && $targetEntiteId === $originalEntiteId,
                    'sectors' => isset($backupData['sectors']),
                    'user_sectors' => isset($backupData['user_sectors']),
                    'passages' => isset($backupData['passages'])
                ]
            ];
        } catch (Exception $e) {
            $this->db->rollBack();

            LogService::log('Erreur lors de la restauration du backup', [
                'level' => 'error',
                'backup_file' => $backupFilePath,
                'target_entite_id' => $targetEntiteId,
                'error' => $e->getMessage()
            ]);

            throw $e;
        }
    }

    /**
     * Restaure les données de l'opération
     */
    private function restoreOperation(array $operationData, int $targetEntiteId): int {
        $stmt = $this->db->prepare('
            INSERT INTO operations (
                fk_entite, libelle, date_deb, date_fin, chk_distinct_sectors,
                fk_user_creat, chk_active, created_at
            ) VALUES (?, ?, ?, ?, ?, ?, 0, NOW())
        ');

        $userId = Session::getUserId() ?? 1;

        $stmt->execute([
            $targetEntiteId,
            $operationData['libelle'] . ' (Restaurée)',
            $operationData['date_deb'],
            $operationData['date_fin'],
            $operationData['chk_distinct_sectors'] ?? 0,
            $userId
        ]);

        return (int)$this->db->lastInsertId();
    }

    /**
     * Restaure les utilisateurs (uniquement si même entité)
     */
    private function restoreUsers(array $users, int $newOperationId): void {
        foreach ($users as $user) {
            // Vérifier si l'utilisateur existe déjà
            $stmt = $this->db->prepare('SELECT id FROM users WHERE id = ?');
            $stmt->execute([$user['id']]);

            if ($stmt->fetch()) {
                // Associer l'utilisateur existant à la nouvelle opération
                $stmt = $this->db->prepare('
                    INSERT IGNORE INTO ope_users (fk_operation, fk_user, chk_active, created_at)
                    VALUES (?, ?, 1, NOW())
                ');
                $stmt->execute([$newOperationId, $user['id']]);
            }
        }
    }

    /**
     * Restaure les secteurs
     */
    private function restoreSectors(array $sectors, int $newOperationId): void {
        foreach ($sectors as $sector) {
            $stmt = $this->db->prepare('
                INSERT INTO ope_sectors (
                    fk_operation, libelle, color, chk_active, created_at
                ) VALUES (?, ?, ?, 1, NOW())
            ');

            $stmt->execute([
                $newOperationId,
                $sector['libelle'],
                $sector['color']
            ]);
        }
    }

    /**
     * Restaure les relations utilisateurs-secteurs
     */
    private function restoreUserSectors(array $userSectors, int $newOperationId): void {
        foreach ($userSectors as $us) {
            // Trouver le nouveau secteur par son libellé
            $stmt = $this->db->prepare('
                SELECT id FROM ope_sectors
                WHERE fk_operation = ? AND libelle = ?
                LIMIT 1
            ');
            $stmt->execute([$newOperationId, $us['libelle'] ?? '']);
            $newSector = $stmt->fetch();

            if ($newSector) {
                $stmt = $this->db->prepare('
                    INSERT IGNORE INTO ope_users_sectors (
                        fk_operation, fk_sector, fk_user, chk_active, created_at
                    ) VALUES (?, ?, ?, 1, NOW())
                ');

                $stmt->execute([
                    $newOperationId,
                    $newSector['id'],
                    $us['fk_user']
                ]);
            }
        }
    }

    /**
     * Restaure les passages
     */
    private function restorePassages(array $passages, int $newOperationId): void {
        foreach ($passages as $passage) {
            $stmt = $this->db->prepare('
                INSERT INTO ope_pass (
                    fk_operation, fk_user, fk_sector, fk_type, passed_at,
                    numero, rue_bis, rue, ville, fk_habitat, appt, niveau,
                    encrypted_name, encrypted_email, encrypted_phone,
                    montant, fk_type_reglement, remarque, chk_active, created_at
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, NOW())
            ');

            $stmt->execute([
                $newOperationId,
                $passage['fk_user'],
                $passage['fk_sector'],
                $passage['fk_type'],
                $passage['passed_at'],
                $passage['numero'],
                $passage['rue_bis'],
                $passage['rue'],
                $passage['ville'],
                $passage['fk_habitat'],
                $passage['appt'],
                $passage['niveau'],
                $passage['encrypted_name'],
                $passage['encrypted_email'],
                $passage['encrypted_phone'],
                $passage['montant'],
                $passage['fk_type_reglement'],
                $passage['remarque']
            ]);
        }
    }
}
