<?php

namespace WHPBackup;

require_once('/docker/whp/web/libs/mysqlmgmt.php');
require_once('BackupTarget.php');
require_once('BackupHistory.php');
require_once('BackupStorage.php');

use Exception;

class BackupEngine {
    private $db;
    private $tempDir;
    
    public function __construct() {
        $mysql = new \mysqlmgmt();
        $this->db = $mysql->getMySQLConnection();
        $this->db->exec("USE whp");
        $this->tempDir = '/docker/tmp';
        
        if (!is_dir($this->tempDir)) {
            mkdir($this->tempDir, 0755, true);
        }
    }
    
    public function createSiteBackup($user, $domain, $targetId) {
        try {
            $sitePath = "/docker/users/$user/$domain";

            if (!is_dir($sitePath)) {
                return [
                    'success' => false,
                    'error' => "Site directory not found: $sitePath"
                ];
            }

            $target = new BackupTarget($this->db, $targetId);
            if (!$target->canAccess($user)) {
                return [
                    'success' => false,
                    'error' => "Access denied to backup target"
                ];
            }

            $backupName = "{$user}_{$domain}_site_" . date('Y-m-d_H-i-s');
            $tempFile = $this->tempDir . '/' . $backupName . '.tar.gz';
            $remotePath = "$user/sites/$domain/" . $backupName . '.tar.gz';

            // Create backup history record
            $history = new BackupHistory($this->db);
            $result = $history->create([
                'target_id' => $targetId,
                'user' => $user,
                'backup_type' => 'site',
                'backup_name' => $backupName,
                'backup_path' => $remotePath,
                'status' => 'pending',
                'metadata' => [
                    'domain' => $domain,
                    'source_path' => $sitePath
                ]
            ]);

            if (!$result) {
                return [
                    'success' => false,
                    'error' => "Failed to create backup record"
                ];
            }

            // Trigger background processing
            $this->triggerBackgroundProcessing();

            return [
                'success' => true,
                'backup_id' => $history->getId(),
                'backup_name' => $backupName,
                'status' => 'pending'
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    public function createUserfilesBackup($user, $targetId) {
        try {
            $userfilesPath = "/docker/users/$user/userfiles";

            if (!is_dir($userfilesPath)) {
                return [
                    'success' => false,
                    'error' => "Userfiles directory not found: $userfilesPath"
                ];
            }

            $target = new BackupTarget($this->db, $targetId);
            if (!$target->canAccess($user)) {
                return [
                    'success' => false,
                    'error' => "Access denied to backup target"
                ];
            }

            $backupName = "{$user}_userfiles_" . date('Y-m-d_H-i-s');
            $tempFile = $this->tempDir . '/' . $backupName . '.zip';
            $remotePath = "$user/userfiles/" . $backupName . '.zip';

            // Create backup history record
            $history = new BackupHistory($this->db);
            $result = $history->create([
                'target_id' => $targetId,
                'user' => $user,
                'backup_type' => 'userfiles',
                'backup_name' => $backupName,
                'backup_path' => $remotePath,
                'status' => 'pending',
                'metadata' => [
                    'source_path' => $userfilesPath
                ]
            ]);

            if (!$result) {
                return [
                    'success' => false,
                    'error' => "Failed to create backup record"
                ];
            }

            // Trigger background processing
            $this->triggerBackgroundProcessing();

            return [
                'success' => true,
                'backup_id' => $history->getId(),
                'backup_name' => $backupName,
                'status' => 'pending'
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    public function createDatabaseBackup($user, $database, $targetId) {
        try {
            $target = new BackupTarget($this->db, $targetId);
            if (!$target->canAccess($user)) {
                return [
                    'success' => false,
                    'error' => "Access denied to backup target"
                ];
            }

            // Ensure database name is properly formatted and not empty
            if (empty($database)) {
                return [
                    'success' => false,
                    'error' => "Database name cannot be empty"
                ];
            }

            // Log database backup creation for debugging
            error_log("Creating database backup - User: $user, Database: $database, Target: $targetId");

            $backupName = "{$user}_{$database}_db_" . date('Y-m-d_H-i-s');
            $tempFile = $this->tempDir . '/' . $backupName . '.sql.gz';
            $remotePath = "$user/databases/" . $backupName . '.sql.gz';

            // Create backup history record
            $history = new BackupHistory($this->db);
            $result = $history->create([
                'target_id' => $targetId,
                'user' => $user,
                'backup_type' => 'database',
                'backup_name' => $backupName,
                'backup_path' => $remotePath,
                'status' => 'pending',
                'metadata' => [
                    'database' => $database
                ]
            ]);

            if (!$result) {
                return [
                    'success' => false,
                    'error' => "Failed to create backup record"
                ];
            }

            // Trigger background processing
            $this->triggerBackgroundProcessing();

            return [
                'success' => true,
                'backup_id' => $history->getId(),
                'backup_name' => $backupName,
                'status' => 'pending'
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    /**
     * Schedule a PostgreSQL dump for $user/$database. Mirrors createDatabaseBackup
     * (which targets MySQL) but writes a backup_history row with
     * backup_type='postgres_database' so the worker dispatches to the pg_dump
     * path. The actual dump runs asynchronously via triggerBackgroundProcessing.
     */
    public function createPostgresDatabaseBackup($user, $database, $targetId) {
        try {
            $target = new BackupTarget($this->db, $targetId);
            if (!$target->canAccess($user)) {
                return [
                    'success' => false,
                    'error' => "Access denied to backup target"
                ];
            }

            if (empty($database)) {
                return [
                    'success' => false,
                    'error' => "Database name cannot be empty"
                ];
            }

            error_log("Creating Postgres database backup - User: $user, Database: $database, Target: $targetId");

            $backupName = "{$user}_{$database}_pgdb_" . date('Y-m-d_H-i-s');
            $remotePath = "$user/postgres/" . $backupName . '.sql.gz';

            $history = new BackupHistory($this->db);
            $result = $history->create([
                'target_id' => $targetId,
                'user' => $user,
                'backup_type' => 'postgres_database',
                'backup_name' => $backupName,
                'backup_path' => $remotePath,
                'status' => 'pending',
                'metadata' => [
                    'database' => $database
                ]
            ]);

            if (!$result) {
                return [
                    'success' => false,
                    'error' => "Failed to create backup record"
                ];
            }

            $this->triggerBackgroundProcessing();

            return [
                'success' => true,
                'backup_id' => $history->getId(),
                'backup_name' => $backupName,
                'status' => 'pending'
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Returns the names of PostgreSQL databases owned by (or prefixed with) a
     * given user — the scheduler uses this when a postgres_database schedule
     * has resource_name=NULL to fan out into per-database runs.
     */
    public function getUserPostgresDatabases($user) {
        require_once('/docker/whp/web/libs/pgsqlmgmt.php');
        $pg = new \pgsqlmgmt();
        $result = $pg->listUserDatabases($user);
        if (is_array($result) && ($result['status'] ?? '1') === '0') {
            return $result['databases'] ?? [];
        }
        return [];
    }

    public function downloadBackup($backupId, $user) {
        // Log download initiation
        error_log("AUDIT: Download initiated - User: {$user}, Backup ID: {$backupId}, IP: " . ($_SERVER['REMOTE_ADDR'] ?? 'unknown'));

        $history = new BackupHistory($this->db, $backupId);

        if (!$history->canAccess($user)) {
            error_log("SECURITY: User '{$user}' attempted to access backup {$backupId} (access denied)");
            throw new Exception("Access denied to backup");
        }

        $data = $history->getData();
        if ($data['status'] !== 'completed') {
            error_log("Download failed - Backup not completed - User: {$user}, Backup ID: {$backupId}, Status: {$data['status']}");
            throw new Exception("Backup is not available for download");
        }

        // Secondary validation: verify backup target access
        $target = new BackupTarget($this->db, $data['target_id']);
        if (!$target->canAccess($user)) {
            error_log("SECURITY: User '{$user}' lacks access to backup target {$data['target_id']} for backup {$backupId}");
            throw new Exception("Access denied to backup");
        }

        // Validate upload_status field (whitelist validation)
        $uploadStatus = $data['upload_status'] ?? null;
        $validStatuses = ['pending', 'uploading', 'uploaded', 'failed', 'skipped'];
        if ($uploadStatus !== null && !in_array($uploadStatus, $validStatuses, true)) {
            error_log("SECURITY: Invalid upload_status in database - Backup ID: {$backupId}, Status: {$uploadStatus}");
            throw new Exception("Backup file is not currently available for download");
        }

        // Check if backup is available in remote storage
        $useLocalFallback = false;

        // Use local fallback if:
        // 1. Upload hasn't been attempted yet (pending/null)
        // 2. Upload failed
        // 3. Remote file is not accessible
        if ($uploadStatus === null || $uploadStatus === 'pending' || $uploadStatus === 'uploading' || $uploadStatus === 'failed') {
            $useLocalFallback = true;
        } else if ($uploadStatus === 'uploaded') {
            // Check if remote file actually exists
            $storage = new BackupStorage($target->getCredentials());
            $info = $storage->getFileInfo($data['backup_path']);

            if (!$info['success'] || !$info['exists']) {
                // Remote file not found, try local fallback
                $useLocalFallback = true;
            }
        }

        // Sanitize filename for Content-Disposition header
        $filename = basename($data['backup_path']);
        $filename = preg_replace('/[^\w\.\-]/', '_', $filename);
        if (strlen($filename) > 255) {
            $filename = substr($filename, 0, 255);
        }
        $encodedFilename = rawurlencode($filename);

        // Clean any output buffers to ensure no extra content
        while (ob_get_level()) {
            ob_end_clean();
        }

        if ($useLocalFallback) {
            // Attempt to serve from local storage
            $localPath = $data['local_path'] ?? null;

            // Validate local_path type
            if ($localPath !== null && !is_string($localPath)) {
                error_log("SECURITY: Invalid local_path type - Backup ID: {$backupId}");
                throw new Exception("Backup file is not currently available for download");
            }

            if (!$localPath) {
                error_log("Download failed - No local path - User: {$user}, Backup ID: {$backupId}, Upload status: {$uploadStatus}");
                throw new Exception("Backup file is not currently available for download");
            }

            // CRITICAL: Validate path to prevent directory traversal attacks
            $allowedPaths = [
                '/docker/backups/local/temp/',
                '/docker/backups/local/ready/',
                '/docker/backups/local/failed/'
            ];

            $realPath = realpath($localPath);
            if ($realPath === false) {
                error_log("SECURITY: Invalid backup file path - Backup ID: {$backupId}, Path: {$localPath}");
                throw new Exception("Backup file is not currently available for download");
            }

            $isAllowed = false;
            foreach ($allowedPaths as $allowedPath) {
                $realAllowedPath = realpath($allowedPath);
                if ($realAllowedPath && strpos($realPath, $realAllowedPath) === 0) {
                    $isAllowed = true;
                    break;
                }
            }

            if (!$isAllowed) {
                error_log("SECURITY: Attempted access to unauthorized path - Backup ID: {$backupId}, Path: {$localPath}, Real: {$realPath}");
                throw new Exception("Backup file is not currently available for download");
            }

            // Check if local file was deleted
            if ($data['local_deleted_at'] !== null) {
                error_log("Download failed - Local file deleted - User: {$user}, Backup ID: {$backupId}, Deleted at: {$data['local_deleted_at']}");
                throw new Exception("Backup file is not currently available for download");
            }

            // Open file atomically to avoid race conditions
            $fp = @fopen($realPath, 'rb');
            if (!$fp) {
                error_log("Download failed - Cannot open local file - User: {$user}, Backup ID: {$backupId}, Path: {$realPath}");
                throw new Exception("Backup file is not currently available for download");
            }

            // Get file stats from open handle
            $stats = fstat($fp);
            if ($stats === false) {
                fclose($fp);
                error_log("Download failed - Cannot stat file - User: {$user}, Backup ID: {$backupId}");
                throw new Exception("Backup file is not currently available for download");
            }

            // Verify it's a regular file (not symlink or device)
            if (!($stats['mode'] & 0100000)) { // S_IFREG check
                fclose($fp);
                error_log("SECURITY: Attempted to download non-regular file - Backup ID: {$backupId}, Path: {$realPath}");
                throw new Exception("Backup file is not currently available for download");
            }

            $fileSize = $stats['size'];

            // Log successful local file access
            error_log("AUDIT: Serving backup from local storage - User: {$user}, Backup ID: {$backupId}, Path: {$realPath}, Size: {$fileSize}");

            // Set security headers
            header('Content-Type: application/octet-stream');
            header("Content-Disposition: attachment; filename=\"{$filename}\"; filename*=UTF-8''{$encodedFilename}");
            header('Content-Length: ' . $fileSize);
            header('Cache-Control: no-cache, must-revalidate, no-store, private');
            header('Pragma: no-cache');
            header('X-Content-Type-Options: nosniff');
            header('X-Frame-Options: DENY');
            header('X-XSS-Protection: 1; mode=block');

            // Stream the local file with connection checks
            $bufferSize = ($fileSize > 100 * 1024 * 1024) ? 1024 * 1024 : 8192; // 1MB for large files
            while (!feof($fp) && connection_status() === CONNECTION_NORMAL) {
                $chunk = fread($fp, $bufferSize);
                if ($chunk === false) {
                    break;
                }
                echo $chunk;
                flush();
            }

            fclose($fp);

            // Check if download was interrupted
            if (connection_status() !== CONNECTION_NORMAL) {
                error_log("Download interrupted - User: {$user}, Backup ID: {$backupId}");
            } else {
                error_log("AUDIT: Download completed - User: {$user}, Backup ID: {$backupId}, Method: local");
            }

        } else {
            // Serve from remote storage
            $storage = new BackupStorage($target->getCredentials());

            // Get backup info
            $info = $storage->getFileInfo($data['backup_path']);
            if (!$info['success'] || !$info['exists']) {
                error_log("Download failed - Remote file not found - User: {$user}, Backup ID: {$backupId}");
                throw new Exception("Backup file is not currently available for download");
            }

            // Log successful remote file access
            error_log("AUDIT: Serving backup from remote storage - User: {$user}, Backup ID: {$backupId}, Size: {$info['size']}");

            // Set security headers
            header('Content-Type: application/octet-stream');
            header("Content-Disposition: attachment; filename=\"{$filename}\"; filename*=UTF-8''{$encodedFilename}");
            header('Content-Length: ' . $info['size']);
            header('Cache-Control: no-cache, must-revalidate, no-store, private');
            header('Pragma: no-cache');
            header('X-Content-Type-Options: nosniff');
            header('X-Frame-Options: DENY');
            header('X-XSS-Protection: 1; mode=block');

            // Stream the file directly to output
            $result = $storage->streamFile($data['backup_path']);

            if (!$result['success']) {
                error_log("Download failed - Remote stream error - User: {$user}, Backup ID: {$backupId}, Error: {$result['error']}");
                throw new Exception("Unable to process backup download at this time");
            }

            error_log("AUDIT: Download completed - User: {$user}, Backup ID: {$backupId}, Method: remote");
        }

        return true;
    }
    
    public function retryBackup($backupId, $user) {
        $history = new BackupHistory($this->db, $backupId);

        if (!$history->canAccess($user)) {
            throw new Exception("Access denied to backup");
        }

        $data = $history->getData();
        if ($data['status'] !== 'failed') {
            throw new Exception("Only failed backups can be retried");
        }

        // Reset the backup for retry
        $history->resetForRetry();

        // Clean up any stale upload queue entries
        $stmt = $this->db->prepare("DELETE FROM backup_upload_queue WHERE backup_id = ?");
        $stmt->execute([$backupId]);

        // Trigger background processing
        $this->triggerBackgroundProcessing();

        return [
            'success' => true,
            'backup_id' => $backupId,
            'message' => 'Backup queued for retry'
        ];
    }

    public function deleteBackup($backupId, $user) {
        $history = new BackupHistory($this->db, $backupId);
        
        if (!$history->canAccess($user)) {
            throw new Exception("Access denied to backup");
        }
        
        $data = $history->getData();
        
        // Handle different backup statuses
        if ($data['status'] === 'completed') {
            // Delete completed backups from storage
            $target = new BackupTarget($this->db, $data['target_id']);
            $storage = new BackupStorage($target->getCredentials());
            
            // Delete from storage
            $result = $storage->deleteFile($data['backup_path']);
            
            if (!$result['success']) {
                throw new Exception("Failed to delete backup from storage: " . $result['error']);
            }
        } elseif ($data['status'] === 'failed') {
            // For failed backups, just remove from database
            // No need to delete from storage as upload likely failed
        } elseif ($data['status'] === 'running' || $data['status'] === 'pending') {
            // Allow deletion of stuck running/pending backups
            // These likely failed or got stuck, so clean them up
        }
        
        // Mark as deleted in database
        $history->delete();
        
        return true;
    }
    
    public function getUserSites($user) {
        $userDir = "/docker/users/$user";
        $sites = [];
        
        if (is_dir($userDir)) {
            $directories = glob($userDir . '/*', GLOB_ONLYDIR);
            foreach ($directories as $dir) {
                $dirname = basename($dir);
                // Skip userfiles directory
                if ($dirname !== 'userfiles') {
                    $sites[] = $dirname;
                }
            }
        }
        
        return $sites;
    }
    
    public function getUserDatabases($user) {
        try {
            $stmt = $this->db->prepare("SHOW DATABASES");
            $stmt->execute();
            
            $databases = [];
            while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
                $dbName = $row['Database'];
                // Only include databases that belong to the user
                if (strpos($dbName, $user . '_') === 0) {
                    $databases[] = $dbName;
                }
            }
            
            return $databases;
            
        } catch (Exception $e) {
            throw new Exception("Failed to get user databases: " . $e->getMessage());
        }
    }
    
    public function cleanupOldBackups($targetId = null) {
        $targets = [];
        
        if ($targetId) {
            $targets[] = new BackupTarget($this->db, $targetId);
        } else {
            $targetList = BackupTarget::listTargets($this->db);
            foreach ($targetList as $targetData) {
                $targets[] = new BackupTarget($this->db, $targetData['id']);
            }
        }
        
        foreach ($targets as $target) {
            $targetData = $target->getData();
            $retentionDays = $targetData['retention_days'];
            $maxBackups = $targetData['max_backups'];
            
            // Delete old backups based on retention days
            if ($retentionDays > 0) {
                $oldBackups = BackupHistory::getOldBackups($this->db, $target->getId(), $retentionDays);
                foreach ($oldBackups as $backup) {
                    try {
                        $this->deleteBackup($backup['id'], $backup['user']);
                    } catch (Exception $e) {
                        // Log error but continue
                    }
                }
            }
            
            // Delete excess backups based on max count
            if ($maxBackups > 0) {
                $backupTypes = ['site', 'userfiles', 'database'];
                $users = $this->getAllUsers();
                
                foreach ($users as $user) {
                    foreach ($backupTypes as $type) {
                        $excessBackups = BackupHistory::getExcessBackups($this->db, $target->getId(), $user, $type, $maxBackups);
                        foreach ($excessBackups as $backup) {
                            try {
                                $this->deleteBackup($backup['id'], $backup['user']);
                            } catch (Exception $e) {
                                // Log error but continue
                            }
                        }
                    }
                }
            }
        }
    }
    
    public function cleanupScheduledBackups($targetId, $user, $backupType, $maxRetention) {
        // Get backups for this specific user, target, and type
        $filters = [
            'user' => $user,
            'target_id' => $targetId,
            'backup_type' => $backupType,
            'status' => 'completed'
        ];
        
        $backups = BackupHistory::listBackups($this->db, $filters);
        
        // Sort by creation date (newest first)
        usort($backups, function($a, $b) {
            return strtotime($b['started_at']) - strtotime($a['started_at']);
        });
        
        // Delete excess backups
        for ($i = $maxRetention; $i < count($backups); $i++) {
            try {
                $this->deleteBackup($backups[$i]['id'], $user);
            } catch (Exception $e) {
                // Log error but continue
                error_log("Failed to delete scheduled backup {$backups[$i]['id']}: " . $e->getMessage());
            }
        }
    }
    
    private function getAllUsers() {
        $users = [];
        $userDir = '/docker/users';
        
        if (is_dir($userDir)) {
            $directories = glob($userDir . '/*', GLOB_ONLYDIR);
            foreach ($directories as $dir) {
                $users[] = basename($dir);
            }
        }
        
        return $users;
    }
    
    private function triggerBackgroundProcessing() {
        // Trigger backup creation worker
        $this->triggerBackupWorker();

        // Trigger upload worker (separate process)
        $this->triggerUploadWorker();
    }

    private function triggerBackupWorker() {
        // Use a lock file to prevent multiple backup worker instances
        $lockFile = '/tmp/backup-worker.lock';

        // Check if a worker is already running
        if (file_exists($lockFile)) {
            $pid = trim(file_get_contents($lockFile));
            // Check if the process is actually running
            if ($pid && posix_kill($pid, 0)) {
                // Worker is still running, don't start another
                return;
            } else {
                // Stale lock file, remove it
                unlink($lockFile);
            }
        }

        // Trigger backup creation worker asynchronously
        $scriptPath = dirname(__DIR__) . '/scripts/backup-worker.php';
        if (file_exists($scriptPath)) {
            // Run in background without blocking the response
            exec("php " . escapeshellarg($scriptPath) . " > /dev/null 2>&1 &");
        }
    }

    private function triggerUploadWorker() {
        // Use a lock file to prevent multiple upload worker instances
        $lockFile = '/tmp/backup-upload-worker.lock';

        // Check if a worker is already running
        if (file_exists($lockFile)) {
            $pid = trim(file_get_contents($lockFile));
            // Check if the process is actually running
            if ($pid && posix_kill($pid, 0)) {
                // Worker is still running, don't start another
                return;
            } else {
                // Stale lock file, remove it
                unlink($lockFile);
            }
        }

        // Trigger upload worker asynchronously
        $scriptPath = dirname(__DIR__) . '/scripts/backup-upload-worker.php';
        if (file_exists($scriptPath)) {
            // Run in background without blocking the response
            exec("php " . escapeshellarg($scriptPath) . " > /dev/null 2>&1 &");
        }
    }
    
    /**
     * Create a combined WordPress backup (site files + database)
     */
    public function createWordPressBackup($siteId, $backupName = null, $targetId = null) {
        // Get WordPress site information
        $stmt = $this->db->prepare("SELECT * FROM wordpress_sites WHERE id = ?");
        $stmt->execute([$siteId]);
        $site = $stmt->fetch();
        
        if (!$site) {
            throw new Exception("WordPress site not found");
        }
        
        // Use default backup target if none specified
        if (!$targetId) {
            $targetId = $site['preferred_backup_target_id'];
            if (!$targetId) {
                // Get user's default backup target
                $stmt = $this->db->prepare("SELECT id FROM backup_targets WHERE owner = ? ORDER BY id LIMIT 1");
                $stmt->execute([$site['user']]);
                $target = $stmt->fetch();
                if (!$target) {
                    // Try to get any available backup target (including global ones)
                    $stmt = $this->db->prepare("SELECT id FROM backup_targets WHERE owner = ? OR is_global = 1 ORDER BY id LIMIT 1");
                    $stmt->execute([$site['user']]);
                    $target = $stmt->fetch();
                    if (!$target) {
                        throw new Exception("No backup target available. Please configure a backup target before importing WordPress sites with auto-backup enabled.");
                    }
                }
                $targetId = $target['id'];
            }
        }
        
        $target = new BackupTarget($this->db, $targetId);
        if (!$target->canAccess($site['user'])) {
            return [
                'success' => false,
                'error' => "Access denied to backup target"
            ];
        }

        // Generate backup name if not provided - include domain for clarity
        // Sanitize domain name for filesystem compatibility
        $safeDomain = preg_replace('/[^a-zA-Z0-9.-]/', '_', $site['domain']);
        if (!$backupName) {
            $backupName = "wp_{$safeDomain}_" . date('Y-m-d_H-i-s');
        } else if (strpos($backupName, $safeDomain) === false) {
            // If custom name provided but doesn't include domain, add it
            $backupName = "{$safeDomain}_{$backupName}";
        }

        $remotePath = "{$site['user']}/wordpress/" . $backupName . '.tar.gz';

        try {
            // Create backup history record with pending status
            $history = new BackupHistory($this->db);
            $result = $history->create([
                'target_id' => $targetId,
                'user' => $site['user'],
                'backup_type' => 'wordpress',
                'backup_name' => $backupName,
                'backup_path' => $remotePath,
                'status' => 'pending',
                'metadata' => [
                    'wordpress_site_id' => $siteId,
                    'domain' => $site['domain'],
                    'database' => $site['database_name'] ?? null,
                    'wp_version' => $site['wp_version'] ?? null,
                    'source_path' => "/docker/users/{$site['user']}/{$site['domain']}"
                ]
            ]);

            if (!$result) {
                return [
                    'success' => false,
                    'error' => "Failed to create backup record"
                ];
            }

            // Get the actual backup ID
            $backupId = $history->getId();

            // Trigger background processing
            $this->triggerBackgroundProcessing();

            return [
                'success' => true,
                'backup_id' => $backupId,
                'backup_name' => $backupName,
                'status' => 'pending'
            ];
            
        } catch (Exception $e) {
            error_log("WordPress backup failed for site {$siteId}: " . $e->getMessage());
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
    
    public function __destruct() {
        // Clean up temp directory
        if (is_dir($this->tempDir)) {
            $files = glob($this->tempDir . '/*');
            foreach ($files as $file) {
                if (is_file($file) && (time() - filemtime($file)) > 3600) {
                    unlink($file);
                }
            }
        }
    }
}