<?php

namespace App\Core;

/**
 * Backup Manager - إدارة النسخ الاحتياطي للقاعدة
 * يدعم: compression, cloud upload, notifications, scheduling
 */
class BackupManager
{
    private \PDO $db;
    private array $config;
    private Logger $logger;
    private string $backupDir;
    
    public function __construct(\PDO $db, array $config, Logger $logger)
    {
        $this->db = $db;
        $this->config = $config;
        $this->logger = $logger;
        $this->backupDir = $config['backup']['directory'] ?? __DIR__ . '/../../backups';
        
        // إنشاء مجلد النسخ الاحتياطي إذا لم يكن موجوداً
        if (!is_dir($this->backupDir)) {
            mkdir($this->backupDir, 0755, true);
        }
    }
    
    /**
     * إنشاء نسخة احتياطية كاملة
     */
    public function createBackup(bool $compress = true, bool $notify = true): ?string
    {
        try {
            $dbConfig = $this->config['db'];
            $timestamp = date('Y-m-d_His');
            $filename = "backup_{$timestamp}.sql";
            $filepath = $this->backupDir . '/' . $filename;
            
            // استخدام mysqldump
            $command = sprintf(
                'mysqldump --host=%s --user=%s --password=%s %s > %s',
                escapeshellarg($dbConfig['host']),
                escapeshellarg($dbConfig['user']),
                escapeshellarg($dbConfig['password']),
                escapeshellarg($dbConfig['name']),
                escapeshellarg($filepath)
            );
            
            exec($command, $output, $returnCode);
            
            if ($returnCode !== 0 || !file_exists($filepath)) {
                throw new \Exception("Failed to create backup. Return code: {$returnCode}");
            }
            
            $finalPath = $filepath;
            
            // ضغط الملف
            if ($compress) {
                $finalPath = $this->compressBackup($filepath);
                if ($finalPath && file_exists($filepath)) {
                    unlink($filepath); // حذف الملف غير المضغوط
                }
            }
            
            // حفظ معلومات النسخة الاحتياطية
            $this->saveBackupInfo($finalPath, $compress);
            
            // تنظيف النسخ القديمة
            $this->cleanupOldBackups();
            
            // إرسال إشعار
            if ($notify) {
                $this->notifyBackupCreated($finalPath);
            }
            
            $this->logger->info("Backup created successfully: {$finalPath}");
            
            return $finalPath;
        } catch (\Exception $e) {
            $this->logger->error("Backup failed: " . $e->getMessage());
            return null;
        }
    }
    
    /**
     * ضغط النسخة الاحتياطية
     */
    private function compressBackup(string $filepath): ?string
    {
        if (!extension_loaded('zlib')) {
            return null;
        }
        
        $compressedPath = $filepath . '.gz';
        $fp_in = fopen($filepath, 'rb');
        $fp_out = gzopen($compressedPath, 'wb9');
        
        if (!$fp_in || !$fp_out) {
            return null;
        }
        
        while (!feof($fp_in)) {
            gzwrite($fp_out, fread($fp_in, 8192));
        }
        
        fclose($fp_in);
        gzclose($fp_out);
        
        return $compressedPath;
    }
    
    /**
     * حفظ معلومات النسخة الاحتياطية في قاعدة البيانات
     */
    private function saveBackupInfo(string $filepath, bool $compressed): void
    {
        try {
            $stmt = $this->db->prepare('
                INSERT INTO backup_logs (filename, filepath, file_size, compressed, created_at)
                VALUES (?, ?, ?, ?, NOW())
            ');
            $stmt->execute([
                basename($filepath),
                $filepath,
                filesize($filepath),
                $compressed ? 1 : 0
            ]);
        } catch (\PDOException $e) {
            // تجاهل الأخطاء
        }
    }
    
    /**
     * تنظيف النسخ القديمة
     */
    private function cleanupOldBackups(): void
    {
        $maxBackups = $this->config['backup']['max_backups'] ?? 10;
        $maxAge = $this->config['backup']['max_age_days'] ?? 30;
        
        try {
            // جلب جميع النسخ
            $stmt = $this->db->prepare('
                SELECT id, filepath, created_at 
                FROM backup_logs 
                ORDER BY created_at DESC
            ');
            $stmt->execute();
            $backups = $stmt->fetchAll();
            
            $deleted = 0;
            foreach ($backups as $index => $backup) {
                // حذف إذا تجاوز العدد المسموح
                if ($index >= $maxBackups) {
                    if (file_exists($backup['filepath'])) {
                        unlink($backup['filepath']);
                    }
                    $stmt = $this->db->prepare('DELETE FROM backup_logs WHERE id = ?');
                    $stmt->execute([$backup['id']]);
                    $deleted++;
                    continue;
                }
                
                // حذف إذا تجاوز العمر المسموح
                $createdAt = strtotime($backup['created_at']);
                if (time() - $createdAt > ($maxAge * 24 * 60 * 60)) {
                    if (file_exists($backup['filepath'])) {
                        unlink($backup['filepath']);
                    }
                    $stmt = $this->db->prepare('DELETE FROM backup_logs WHERE id = ?');
                    $stmt->execute([$backup['id']]);
                    $deleted++;
                }
            }
            
            if ($deleted > 0) {
                $this->logger->info("Cleaned up {$deleted} old backup(s)");
            }
        } catch (\PDOException $e) {
            // تجاهل الأخطاء
        }
    }
    
    /**
     * إرسال إشعار بإنشاء النسخة الاحتياطية
     */
    private function notifyBackupCreated(string $filepath): void
    {
        $backupConfig = $this->config['backup'] ?? [];
        
        // إرسال بريد إلكتروني
        if (!empty($backupConfig['email_notifications'])) {
            $this->sendEmailNotification($filepath);
        }
        
        // إرسال WhatsApp
        if (!empty($backupConfig['whatsapp_notifications'])) {
            $this->sendWhatsAppNotification($filepath);
        }
    }
    
    /**
     * إرسال إشعار بريد إلكتروني
     */
    private function sendEmailNotification(string $filepath): void
    {
        // TODO: تنفيذ إرسال البريد الإلكتروني
    }
    
    /**
     * إرسال إشعار WhatsApp
     */
    private function sendWhatsAppNotification(string $filepath): void
    {
        try {
            $whatsapp = new WhatsApp($this->db, $this->config);
            $message = "✅ تم إنشاء نسخة احتياطية بنجاح\n";
            $message .= "الملف: " . basename($filepath) . "\n";
            $message .= "الحجم: " . $this->formatBytes(filesize($filepath)) . "\n";
            $message .= "التاريخ: " . date('Y-m-d H:i:s');
            
            $adminPhone = $this->config['backup']['admin_phone'] ?? '';
            if ($adminPhone) {
                $whatsapp->send($adminPhone, $message);
            }
        } catch (\Exception $e) {
            $this->logger->error("Failed to send WhatsApp notification: " . $e->getMessage());
        }
    }
    
    /**
     * تنسيق حجم الملف
     */
    private function formatBytes(int $bytes, int $precision = 2): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];
        
        for ($i = 0; $bytes > 1024 && $i < count($units) - 1; $i++) {
            $bytes /= 1024;
        }
        
        return round($bytes, $precision) . ' ' . $units[$i];
    }
    
    /**
     * استعادة نسخة احتياطية
     */
    public function restoreBackup(string $filepath): bool
    {
        try {
            $dbConfig = $this->config['db'];
            
            // فك الضغط إذا كان مضغوطاً
            if (substr($filepath, -3) === '.gz') {
                $filepath = $this->decompressBackup($filepath);
            }
            
            if (!file_exists($filepath)) {
                throw new \Exception("Backup file not found: {$filepath}");
            }
            
            // استعادة النسخة الاحتياطية
            $command = sprintf(
                'mysql --host=%s --user=%s --password=%s %s < %s',
                escapeshellarg($dbConfig['host']),
                escapeshellarg($dbConfig['user']),
                escapeshellarg($dbConfig['password']),
                escapeshellarg($dbConfig['name']),
                escapeshellarg($filepath)
            );
            
            exec($command, $output, $returnCode);
            
            if ($returnCode !== 0) {
                throw new \Exception("Failed to restore backup. Return code: {$returnCode}");
            }
            
            $this->logger->info("Backup restored successfully: {$filepath}");
            
            return true;
        } catch (\Exception $e) {
            $this->logger->error("Backup restore failed: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * فك ضغط النسخة الاحتياطية
     */
    private function decompressBackup(string $filepath): string
    {
        $outputPath = substr($filepath, 0, -3);
        
        $fp_in = gzopen($filepath, 'rb');
        $fp_out = fopen($outputPath, 'wb');
        
        if (!$fp_in || !$fp_out) {
            throw new \Exception("Failed to decompress backup");
        }
        
        while (!gzeof($fp_in)) {
            fwrite($fp_out, gzread($fp_in, 8192));
        }
        
        gzclose($fp_in);
        fclose($fp_out);
        
        return $outputPath;
    }
    
    /**
     * جلب قائمة النسخ الاحتياطية
     */
    public function listBackups(): array
    {
        try {
            $stmt = $this->db->prepare('
                SELECT id, filename, filepath, file_size, compressed, created_at
                FROM backup_logs
                ORDER BY created_at DESC
            ');
            $stmt->execute();
            return $stmt->fetchAll();
        } catch (\PDOException $e) {
            return [];
        }
    }
}
