<?php
// WordPress Management AJAX Handler

// Set error reporting for debugging
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);

// Start output buffering to catch any unwanted output
ob_start();

require_once('../auto-prepend.php');

// Check if user is authenticated
if (!defined('AUTH_USER')) {
    ob_clean();
    http_response_code(401);
    header('Content-Type: application/json');
    error_log("WordPress AJAX: AUTH_USER not defined");
    echo json_encode(['error' => 'Not authenticated']);
    exit();
}

require_once('../libs/WordPressManager.php');
require_once('../libs/mysqlmgmt.php');
require_once('../libs/BackupEngine.php');
require_once('../libs/BackupHistory.php');
require_once('../libs/BackupTarget.php');
require_once('../libs/BackupStorage.php');

use WHP\WordPressManager;
use WHPBackup\BackupHistory;
use WHPBackup\BackupTarget;
use WHPBackup\BackupStorage;

// Helper function for permission checking
function check_permission($permission) {
    // For now, return true for basic permissions, root for admin permissions
    $adminPermissions = ['wordpress_manage_all', 'wordpress_recommendations'];
    if (in_array($permission, $adminPermissions)) {
        return AUTH_USER === 'root';
    }
    return true; // Basic permissions allowed for all users
}

// Clean any output that might have been generated
ob_clean();

// Set JSON header
header('Content-Type: application/json');

try {
    $wpManager = new WordPressManager();
    $isRoot = AUTH_USER === 'root';
    $username = AUTH_USER;
    $action = $_POST['action'] ?? $_GET['action'] ?? '';

    // Get database connection for backup queries
    $mysql = new mysqlmgmt();
    $db = $mysql->getMySQLConnection();
    $db->exec("USE whp");

    error_log("WordPress AJAX: User=" . AUTH_USER . ", Action=" . $action . ", POST data: " . print_r($_POST, true));

    switch ($action) {
        case 'update_wp_cli_support':
            if (!$isRoot) {
                throw new Exception('Only root can manage container support');
            }
            $result = $wpManager->updateWpCliSupport($_POST['container_name'], $_POST['enabled'] === 'true');
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'check_wordpress':
            $result = $wpManager->checkWordPressInstallation($_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'install':
            if (!check_permission('wordpress_install')) {
                throw new Exception('Permission denied');
            }
            $result = $wpManager->installWordPress($_POST);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'import':
            if (!check_permission('wordpress_install')) {
                throw new Exception('Permission denied');
            }
            $result = $wpManager->importWordPress($_POST);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'update_core':
            // WP core update + theme/plugin downloads can easily exceed php.ini's
            // 30s max_execution_time (especially with commercial plugins like
            // Beaver Builder that fetch from external license servers). Without
            // these two lines, PHP kills the process mid-update and the
            // wp_update_history row stays stuck at status='in_progress' with no
            // completion or error message. ignore_user_abort lets the script
            // finish writing to the DB even if the HTTP request times out at
            // some upstream layer (Apache/HAProxy/browser).
            @set_time_limit(0);
            @ignore_user_abort(true);
            if (!check_permission('wordpress_update')) {
                throw new Exception('Permission denied');
            }
            $createBackup = isset($_POST['create_backup']) ? (bool)$_POST['create_backup'] : null;
            $result = $wpManager->updateCore($_POST['site_id'], $createBackup);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'update_all':
            // See update_core above — same reasoning, more so since this hits
            // core + every plugin + every theme.
            @set_time_limit(0);
            @ignore_user_abort(true);
            if (!check_permission('wordpress_update')) {
                throw new Exception('Permission denied');
            }
            $createBackup = isset($_POST['create_backup']) ? (bool)$_POST['create_backup'] : null;
            $result = $wpManager->updateAll($_POST['site_id'], $createBackup);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'reset_password':
            $result = $wpManager->resetAdminPassword($_POST['site_id'], $_POST['new_password'] ?? null);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
            
        case 'apply_security':
            if (!check_permission('wordpress_security')) {
                throw new Exception('Permission denied');
            }
            $result = $wpManager->applySecurityHardening($_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'clone_staging':
            if (!check_permission('wordpress_staging')) {
                throw new Exception('Permission denied');
            }
            $result = $wpManager->cloneToStaging(
                $_POST['site_id'],
                $_POST['staging_domain'],
                $_POST['staging_container']
            );
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;

        case 'clone_site':
            if (!check_permission('wordpress_install')) {
                throw new Exception('Permission denied');
            }

            // Validate and sanitize input parameters
            $sourceSiteId = filter_var($_POST['source_site_id'] ?? '', FILTER_VALIDATE_INT);
            $targetSiteId = filter_var($_POST['target_site_id'] ?? '', FILTER_VALIDATE_INT);

            if (!$sourceSiteId || !$targetSiteId) {
                throw new Exception('Invalid site ID parameters');
            }

            // Additional security validation will be performed in cloneSite method
            $result = $wpManager->cloneSite($sourceSiteId, $targetSiteId);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'search_replace':
            $result = $wpManager->searchReplace(
                $_POST['container'],
                $_POST['user'],
                $_POST['search'],
                $_POST['replace'],
                $_POST['path'] ?? null
            );
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'install_plugin':
            $result = $wpManager->installRecommendedPlugin(
                $_POST['site_id'],
                $_POST['plugin_slug']
            );
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'update_backup_settings':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->updateBackupSettings(
                $_POST['site_id'],
                $_POST['backup_target_id'] ?? null,
                isset($_POST['auto_backup_before_update'])
            );
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'check_update_status':
            if (empty($_POST['update_id'])) {
                throw new Exception('Update ID required');
            }
            $result = $wpManager->getUpdateStatus($_POST['update_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'create_backup_now':
            // Ad-hoc backup trigger from the WP-management page. Async — the
            // backup worker picks up the row and processes it in the
            // background, and the existing per-site notification system fires
            // when it completes (or fails).
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->createImmediateBackup($_POST['site_id']);
            ob_clean();
            echo json_encode([
                'success'     => true,
                'backup_id'   => $result['backup_id'] ?? null,
                'backup_name' => $result['backup_name'] ?? null,
                'status'      => $result['status'] ?? 'pending',
                'message'     => 'Backup queued. The worker will process it shortly; you\'ll get an email when it finishes if Notifications are enabled.',
            ]);
            exit;

        case 'get_notification_settings':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->getNotificationSettings($_POST['site_id']);
            ob_clean();
            echo json_encode(['success' => true, 'settings' => $result]);
            exit;

        case 'update_notification_settings':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $settings = [
                'notification_email'     => $_POST['notification_email'] ?? '',
                'notify_backup_complete' => isset($_POST['notify_backup_complete']) && $_POST['notify_backup_complete'] === '1',
                'notify_backup_failed'   => isset($_POST['notify_backup_failed']) && $_POST['notify_backup_failed'] === '1',
                'notify_update_complete' => isset($_POST['notify_update_complete']) && $_POST['notify_update_complete'] === '1',
                'notify_update_failed'   => isset($_POST['notify_update_failed']) && $_POST['notify_update_failed'] === '1',
            ];
            $result = $wpManager->updateNotificationSettings($_POST['site_id'], $settings);
            ob_clean();
            echo json_encode($result);
            exit;

        case 'update_auto_update_settings':
            if (empty($_POST['site_id']) || empty($_POST['update_type']) || !isset($_POST['enabled'])) {
                throw new Exception('Site ID, update type, and enabled status required');
            }
            $result = $wpManager->updateAutoUpdateSettings(
                $_POST['site_id'],
                $_POST['update_type'], 
                $_POST['enabled'] === '1'
            );
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'get_security_settings':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->getSecuritySettings($_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'update_security_settings':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->updateSecuritySettings($_POST['site_id'], $_POST);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'shuffle_salts':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->shuffleSalts($_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'update_htaccess_rules':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->updateHtaccessRules($_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;

        case 'check_force_https_status':
            if (empty($_POST['site_id']) || !is_numeric($_POST['site_id'])) {
                throw new Exception('Valid numeric site ID required');
            }
            $result = $wpManager->checkForceHttpsStatus((int)$_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;

        case 'force_https':
            if (empty($_POST['site_id']) || !is_numeric($_POST['site_id'])) {
                throw new Exception('Valid numeric site ID required');
            }
            $result = $wpManager->forceHttps((int)$_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;

        case 'disable_force_https':
            if (empty($_POST['site_id']) || !is_numeric($_POST['site_id'])) {
                throw new Exception('Valid numeric site ID required');
            }
            $result = $wpManager->disableForceHttps((int)$_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;

        case 'security_scan':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->performSecurityScan($_POST['site_id']);
            ob_clean(); // Clear buffer before output
            echo json_encode($result);
            exit;
            
        case 'get_recommended_plugins':
            if (!check_permission('wordpress_recommendations')) {
                throw new Exception('Insufficient permissions');
            }
            
            $plugins = $wpManager->getRecommendedPluginsForManagement();
            ob_clean();
            echo json_encode([
                'success' => true,
                'plugins' => $plugins
            ]);
            exit;
            
        case 'get_recommended_plugin':
            if (!check_permission('wordpress_recommendations')) {
                throw new Exception('Insufficient permissions');
            }
            
            if (empty($_POST['plugin_id'])) {
                throw new Exception('Plugin ID is required');
            }
            
            $plugin = $wpManager->getRecommendedPlugin($_POST['plugin_id']);
            ob_clean();
            echo json_encode([
                'success' => true,
                'plugin' => $plugin
            ]);
            exit;
            
        case 'add_recommended_plugin':
            if (!check_permission('wordpress_recommendations')) {
                throw new Exception('Insufficient permissions');
            }
            
            if (empty($_POST['name']) || empty($_POST['slug'])) {
                throw new Exception('Plugin name and slug are required');
            }
            
            $pluginData = [
                'name' => $_POST['name'],
                'slug' => $_POST['slug'],
                'description' => $_POST['description'] ?? '',
                'category' => $_POST['category'] ?? '',
                'install_url' => $_POST['install_url'] ?? '',
                'sort_order' => intval($_POST['sort_order'] ?? 0),
                'is_active' => ($_POST['is_active'] ?? '0') === '1'
            ];
            
            $result = $wpManager->addRecommendedPlugin($pluginData);
            ob_clean();
            echo json_encode([
                'success' => true,
                'plugin_id' => $result,
                'message' => 'Plugin added successfully'
            ]);
            exit;
            
        case 'update_recommended_plugin':
            if (!check_permission('wordpress_recommendations')) {
                throw new Exception('Insufficient permissions');
            }
            
            if (empty($_POST['plugin_id']) || empty($_POST['name']) || empty($_POST['slug'])) {
                throw new Exception('Plugin ID, name, and slug are required');
            }
            
            $pluginData = [
                'name' => $_POST['name'],
                'slug' => $_POST['slug'],
                'description' => $_POST['description'] ?? '',
                'category' => $_POST['category'] ?? '',
                'install_url' => $_POST['install_url'] ?? '',
                'sort_order' => intval($_POST['sort_order'] ?? 0),
                'is_active' => ($_POST['is_active'] ?? '0') === '1'
            ];
            
            $wpManager->updateRecommendedPlugin($_POST['plugin_id'], $pluginData);
            ob_clean();
            echo json_encode([
                'success' => true,
                'message' => 'Plugin updated successfully'
            ]);
            exit;
            
        case 'delete_recommended_plugin':
            if (!check_permission('wordpress_recommendations')) {
                throw new Exception('Insufficient permissions');
            }
            
            if (empty($_POST['plugin_id'])) {
                throw new Exception('Plugin ID is required');
            }
            
            $wpManager->deleteRecommendedPlugin($_POST['plugin_id']);
            ob_clean();
            echo json_encode([
                'success' => true,
                'message' => 'Plugin deleted successfully'
            ]);
            exit;
            
        case 'create_login':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID is required');
            }
            
            $result = $wpManager->createLoginToken($_POST['site_id']);
            ob_clean();
            echo json_encode($result);
            exit;
            
        case 'remove_from_management':
            if (empty($_POST['site_id'])) {
                throw new Exception('Site ID is required');
            }
            
            $result = $wpManager->removeFromManagement($_POST['site_id']);
            ob_clean();
            echo json_encode($result);
            exit;
            
        case 'get_wordpress_versions':
            // Read cached versions from the DB. Refreshes are handled by
            // the hourly refresh-wp-versions cron and inline writes from
            // installWordPress / importWordPress / core-update flows.
            // This used to fetch live wp-cli per site, which serialized
            // and held the PHP session lock for ~40s on a 27-site fleet.
            $siteIds = $_POST['site_ids'] ?? [];
            $versions = [];
            $checkedAt = [];

            foreach ($siteIds as $siteId) {
                $site = $wpManager->getSite($siteId);
                if ($site) {
                    $versions[$siteId] = !empty($site['wp_version'])
                        ? $site['wp_version']
                        : 'Unknown';
                    $checkedAt[$siteId] = $site['wp_version_checked_at'] ?? null;
                }
            }

            ob_clean();
            echo json_encode([
                'success'    => true,
                'versions'   => $versions,
                'checked_at' => $checkedAt,
            ]);
            exit;

        case 'refresh_wp_version':
            // On-demand refresh for a single site — UI's per-row refresh button.
            $siteId = $_POST['site_id'] ?? '';
            if (!$siteId) {
                throw new Exception('Site ID required');
            }
            $result = $wpManager->refreshCachedVersion($siteId);
            ob_clean();
            echo json_encode([
                'success'    => true,
                'version'    => $result['version'] ?: 'Unknown',
                'checked_at' => $result['checked_at'],
            ]);
            exit;

        case 'get_site_backups':
            // Get backups for a specific WordPress site
            $siteId = $_POST['site_id'] ?? '';
            if (!$siteId) {
                throw new Exception('Site ID required');
            }

            // Get site information
            $site = $wpManager->getSite($siteId);
            if (!$site) {
                throw new Exception('Site not found');
            }

            // Check permissions
            if (!$isRoot && $site['user'] !== $username) {
                throw new Exception('Permission denied');
            }

            // Get domain and container for backup filtering
            $domain = $site['domain'];
            $containerName = $site['container_name'];

            // Escape LIKE wildcards to prevent SQL injection
            $escapedDomain = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $domain);
            $escapedContainer = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $containerName);

            // Create sanitized domain pattern (periods replaced with underscores)
            // Database backups sanitize domain names: dev.example.com → dev_example_com
            $sanitizedDomain = str_replace('.', '_', $domain);
            $escapedSanitizedDomain = str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $sanitizedDomain);

            // Query backups for this domain - include all relevant backup types
            // wordpress: auto WordPress backups
            // site: full site backups (may contain WordPress)
            // database: database-only backups
            // userfiles: files-only backups
            $stmt = $db->prepare("
                SELECT
                    bh.id,
                    bh.backup_name,
                    bh.backup_path,
                    bh.backup_size,
                    bh.backup_type,
                    bh.status,
                    bh.upload_status,
                    bh.started_at,
                    bh.completed_at,
                    bh.local_path,
                    bh.local_deleted_at,
                    bh.metadata
                FROM backup_history bh
                WHERE bh.user = ?
                AND (
                    bh.backup_name LIKE ?
                    OR bh.backup_name LIKE ?
                    OR bh.backup_name LIKE ?
                )
                AND bh.backup_type IN ('wordpress', 'site', 'database', 'userfiles')
                AND bh.status = 'completed'
                ORDER BY bh.started_at DESC
                LIMIT 100
            ");
            $stmt->execute([
                $site['user'],
                '%' . $escapedDomain . '%',
                '%' . $escapedContainer . '%',
                '%' . $escapedSanitizedDomain . '%'
            ]);
            $backups = $stmt->fetchAll(PDO::FETCH_ASSOC);

            // Decode metadata for each backup
            foreach ($backups as &$backup) {
                if (!empty($backup['metadata']) && is_string($backup['metadata'])) {
                    $backup['metadata'] = json_decode($backup['metadata'], true);
                }
            }

            ob_clean();
            echo json_encode(['success' => true, 'backups' => $backups]);
            exit;

        case 'restore_backup':
            // Restore WordPress from backup
            // Supports multiple backup types: wordpress, site, database, userfiles
            $siteId = $_POST['site_id'] ?? '';
            $backupId = $_POST['backup_id'] ?? '';

            if (!$siteId || !$backupId) {
                throw new Exception('Site ID and Backup ID required');
            }

            // Get site information
            $site = $wpManager->getSite($siteId);
            if (!$site) {
                throw new Exception('Site not found');
            }

            // Check permissions
            if (!$isRoot && $site['user'] !== $username) {
                throw new Exception('Permission denied');
            }

            // Get backup information
            $backupHistory = new BackupHistory($db, $backupId);
            $backupData = $backupHistory->getData();

            if (!$backupData) {
                throw new Exception('Backup not found');
            }

            // Verify backup belongs to this user
            if (!$isRoot && $backupData['user'] !== $username) {
                throw new Exception('Permission denied to access this backup');
            }

            // Verify backup is completed
            if ($backupData['status'] !== 'completed') {
                throw new Exception('Backup is not completed');
            }

            // Log backup type for debugging
            error_log("WordPress Restore: Restoring backup ID {$backupId}, type: {$backupData['backup_type']}");

            // Restore the backup (method will route based on backup_type)
            $result = $wpManager->restoreWordPressBackup(
                $site['container_name'],
                $site['user'],
                $site['domain'],
                $backupData,
                $db
            );

            if ($result['success']) {
                ob_clean();
                echo json_encode(['success' => true, 'message' => $result['message']]);
            } else {
                throw new Exception($result['error'] ?? 'Restore failed');
            }
            exit;

        default:
            throw new Exception('Invalid action');
    }
} catch (Exception $e) {
    ob_clean();
    http_response_code(400);
    error_log("WordPress AJAX Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
    echo json_encode(['error' => $e->getMessage()]);
    exit();
} catch (Error $e) {
    ob_clean();
    http_response_code(500);
    error_log("WordPress AJAX Fatal Error: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
    echo json_encode(['error' => 'Fatal error: ' . $e->getMessage()]);
    exit();
} catch (Throwable $e) {
    ob_clean();
    http_response_code(500);
    error_log("WordPress AJAX Throwable: " . $e->getMessage() . " in " . $e->getFile() . " on line " . $e->getLine());
    echo json_encode(['error' => 'Unexpected error: ' . $e->getMessage()]);
    exit();
}

// End output buffering
ob_end_clean();
?>