<?php

/**
 * Lead Connector Migrator
 * Copyright (C) 2025 Lead Connector
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

namespace Lcmigrator\LcMigrator\Admin;

use Exception;
use Lcm_Database_Exception;
use Lcm_Not_Valid_Secret_Key_Exception;
use Lcm_Status;
use Lcmigrator\LcMigrator\Constants\Constants;
use Lcmigrator\LcMigrator\Backend\LMRequest;
use Lcmigrator\LcMigrator\Encryption\Data_Encryption;
use Lcmigrator\LcMigrator\FileUpload\GCP;
use Lcmigrator\LcMigrator\Logger\Logger;
use Lcmigrator\LcMigrator\Migrator\BackupInProgress\BackupInProgress;
use Lcmigrator\LcMigrator\Migrator\Migrator;
use Lcmigrator\LcMigrator\OptionManager\OptionManager;
use Lcmigrator\LcMigrator\Event\EventUpdater;
use Lcmigrator\LcMigrator\StageInfo\StageInfo;
use Lcmigrator\LcMigrator\Migrator\MigrationManager;
use Lcmigrator\LcMigrator\SecureAccess\SecureAccessManager;

class LcMigrator_Admin
{
    private $plugin_name;
    private $version;
    private $optionManager;

    /**
     * Initialize the class and set its properties.
     */
    public function __construct($plugin_name, $version)
    {
        $this->plugin_name = $plugin_name;
        $this->version = $version;
        $this->optionManager = OptionManager::getInstance();

        // Add action for admin menu
        add_action('admin_menu', array($this, 'add_plugin_admin_menu'));


        // Register background processing hooks
        add_action('lc_migrator_background_export', array($this, 'handle_background_export'));
        add_action('lc_migrator_background_upload', array($this, 'handle_background_upload'));
        add_action('lc_migrator_background_cleanup', array($this, 'handle_background_cleanup'));
        add_action('lc_migrator_background_start_migration', array($this, 'handle_background_start_migration'));

        // Add a test cron job for debugging
        add_action('lc_migrator_test_cron', array($this, 'handle_test_cron'));

        // Schedule the test cron job if it's not already scheduled
        if (!wp_next_scheduled('lc_migrator_test_cron')) {
            wp_schedule_event(time(), 'hourly', 'lc_migrator_test_cron');
        }

        // Secure-access link: one-shot cron tears down an expired link; login_init
        // and init intercept ?lc_sal= on the resolved login URL (incl. custom slugs).
        add_action('lc_migrator_secure_access_expire', [SecureAccessManager::class, 'handleExpireStatic'], 10, 1);
        add_action('login_init', [SecureAccessManager::class, 'handleLoginInterceptStatic']);
        add_action('init', [SecureAccessManager::class, 'handleLoginInterceptStaticEarly'], 1);
        SecureAccessManager::registerPublicRouteCacheBypassHooks();
    }

    /**
     * Add menu item and its sub menu
     */
    public function add_plugin_admin_menu()
    {
        // Add main menu item
        add_menu_page(
            'LC Migrator', // Page title
            'LC Migrator', // Menu title
            'manage_options', // Capability
            'lc-migrator', // Menu slug
            array($this, 'display_plugin_admin_page'), // Callback function
            'dashicons-migrate', // Icon URL
            100 // Position
        );
    }

    /**
     * Display the main admin page
     */
    public function display_plugin_admin_page()
    {
        // Root element for Vue.js
        echo '<div id="app"></div>';
    }

    /**
     * Register the JavaScript for the admin area.
     */
    public function enqueue_scripts($hook)
    {
        // Only load on our plugin pages
        if (strpos($hook, 'lc-migrator') === false) {
            return;
        }

        wp_enqueue_script($this->plugin_name, plugin_dir_url(__FILE__) . 'js/lc-admin.js', array('jquery'), $this->version, false);
        $css_to_load = plugin_dir_url(__FILE__) . 'app.css';
        $vendor_css_to_load = plugin_dir_url(__FILE__) . 'app2.css';

        wp_enqueue_style('vue_lead_connector_app', $css_to_load, array(), $this->version, 'all');

        // Load Vue app
        $js_to_load = plugin_dir_url(__FILE__) . 'app.js';

        wp_localize_script(
            $this->plugin_name,
            'lc_admin_settings',
            array(
                'proxy_url' => rest_url('lem_public_api/v1/proxy'),
                'nonce' => wp_create_nonce('wp_rest'),
                'background_processing' => true, // Indicate that background processing is enabled
            )
        );

        wp_enqueue_script('vue_lead_connector_js', $js_to_load, '', wp_rand(10, 1000), array(
            'type' => 'module',
        ));

        add_filter('script_loader_tag', array($this, 'add_type_attribute'), 10, 3);

        // Ensure WP Cron is working
        $this->ensure_cron_is_working();

        wp_localize_script(
            $this->plugin_name,
            'leadMigratorConfig',
            array(
                'LC_MIGRATOR_VERSION' => LC_MIGRATOR_VERSION,
                'LC_MIGRATOR_PLUGIN_NAME' => LC_MIGRATOR_PLUGIN_NAME,
                'LC_MIGRATOR_SERVICES_BASE_URL' => LC_MIGRATOR_SERVICES_BASE_URL,
                'LC_MIGRATOR_OPTION_NAME' => LC_MIGRATOR_OPTION_NAME,
                'LC_MIGRATOR_CDN_BASE_URL' => '',
                'LC_MIGRATOR_OAUTH_CLIENT_ID' => LC_MIGRATOR_OAUTH_CLIENT_ID,
                'LC_MIGRATOR_BASE_URL' => LEAD_CONNECTOR_BASE_URL,
                'LC_MIGRATOR_DISPLAY_NAME' => LC_MIGRATOR_PLUGIN_NAME,
                'LC_MIGRATOR_ROOT_DOMAIN' => LC_MIGRATOR_ROOT_DOMAIN,
                'LEAD_CONNECTOR_BASE_URL' => LEAD_CONNECTOR_BASE_URL
            )
        );
    }

    /**
     * Ensure WordPress cron is working properly
     */
    private function ensure_cron_is_working()
    {
        // Check if cron is disabled
        if (defined('DISABLE_WP_CRON') && constant('DISABLE_WP_CRON')) {
            // Log warning
            $logger = Logger::getInstance();
            $logger->warning("WP-Cron is disabled. Background processing may not work properly.");

            // Alternative: Use our own cron mechanism if WP-Cron is disabled
            // This is just a placeholder - you might want to implement a custom solution
            // or use a library like Action Scheduler for more reliable background processing
        }
    }

    /**
     * Add module type attribute to script tag
     */
    public function add_type_attribute($tag, $handle, $src)
    {
        if ('vue_lead_connector_js' !== $handle) {
            return $tag;
        }
        $tag = '<script type="module" src="' . esc_url($src) . '"></script>';
        return $tag;
    }

    /**
     * Create and verify backup directories
     *
     * @return array Success status and message or error details
     */
    private function _initializeBackupDirectories()
    {
        try {
            // Get WordPress uploads directory
            $upload_dir = wp_upload_dir();
            if (isset($upload_dir['error']) && $upload_dir['error']) {
                throw new Exception('WordPress uploads directory is not writable: ' . $upload_dir['error']);
            }

            // Create backup directory paths
            $backup_dir = $upload_dir['basedir'] . '/wp-site-backups/';
            $temp_dir = $upload_dir['basedir'] . '/wp-site-temp/';

            // Create directories if they don't exist
            if (!file_exists($backup_dir)) {
                wp_mkdir_p($backup_dir);
            }
            if (!file_exists($temp_dir)) {
                wp_mkdir_p($temp_dir);
            }

            // Set proper permissions (0755 for directories)
            $this->_setProperPermissions($backup_dir);
            $this->_setProperPermissions($temp_dir);

            // Verify directories are writable
            if (!is_writable($backup_dir)) {
                throw new Exception("Backup directory is not writable: $backup_dir");
            }
            if (!is_writable($temp_dir)) {
                throw new Exception("Temporary directory is not writable: $temp_dir");
            }

            return [
                'success' => true,
                'backup_dir' => $backup_dir,
                'temp_dir' => $temp_dir
            ];
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Set proper permissions for directories and files
     *
     * @param string $path Path to set permissions for
     * @return void
     */
    private function _setProperPermissions($path)
    {
        // Set directory permissions to 0755
        @chmod($path, 0755);

        // If it's a directory, recursively set permissions on contents
        if (is_dir($path)) {
            $objects = scandir($path);
            foreach ($objects as $object) {
                if ($object != "." && $object != "..") {
                    $full_path = $path . '/' . $object;
                    if (is_dir($full_path)) {
                        @chmod($full_path, 0755); // Directory permissions
                    } else {
                        @chmod($full_path, 0644); // File permissions
                    }
                }
            }
        }
    }

    /**
     * Register REST API routes
     */
    public function admin_rest_api_init()
    {
        register_rest_route('lem_public_api/v1', '/proxy', array(
            'methods' => 'GET',
            'callback' => array($this, 'lc_public_api_proxy'),
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ));

        register_rest_route('lem_public_api/v1', 'proxy', array(
            'methods' => 'POST',
            'callback' => array($this, 'lc_public_api_proxy'),
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ));

        // Register a heartbeat endpoint to check background process status
        register_rest_route('lem_public_api/v1', '/background_heartbeat', array(
            'methods' => 'GET',
            'callback' => array($this, 'background_heartbeat'),
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ));

        // Register a debug endpoint to manually trigger the background export process
        register_rest_route('lem_public_api/v1', '/debug_trigger_export', array(
            'methods' => 'GET',
            'callback' => array($this, 'debug_trigger_export'),
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ));

        // Register the try_new_module endpoint for new export functionality
        register_rest_route('lem_public_api/v1', '/try_new_module', array(
            'methods' => 'POST',
            'callback' => array($this, 'handle_try_new_module'),
            'permission_callback' => function () {
                return current_user_can('manage_options');
            },
        ));

        // Public secure-access resolver: short URL → plain-text encrypted token.
        add_filter(
            'rest_allowed_cors_headers',
            static function ($allow_headers) {
                $allow_headers[] = 'X-LC-Secure-Link';
                return $allow_headers;
            }
        );

        add_filter(
            'rest_pre_serve_request',
            array(SecureAccessManager::class, 'servePlainTextSecureToken'),
            10,
            4
        );

        add_filter(
            'rest_pre_dispatch',
            array($this, 'nocache_public_secure_access_routes'),
            10,
            3
        );

        $secureAccessTokenArgs = array(
            'token' => array(
                'required' => true,
                'validate_callback' => function ($param) {
                    return is_string($param) && preg_match('/^[a-zA-Z0-9_-]{8,64}$/', $param);
                },
            ),
        );

        register_rest_route('leadconnector-token', '/secure/(?P<token>[a-zA-Z0-9_-]+)', array(
            'methods' => 'GET',
            'callback' => array(SecureAccessManager::class, 'restResolveEncryptedToken'),
            'permission_callback' => '__return_true',
            'args' => $secureAccessTokenArgs,
        ));

        // Open metadata sibling — same access key, JSON body (timestamps exceed RSA payload).
        register_rest_route('leadconnector-token', '/meta/(?P<token>[a-zA-Z0-9_-]+)', array(
            'methods' => 'GET',
            'callback' => array(SecureAccessManager::class, 'restResolvePublicMeta'),
            'permission_callback' => '__return_true',
            'args' => $secureAccessTokenArgs,
        ));
    }

    /**
     * Prevent LiteSpeed/CDN from caching the browser HTML response and serving
     * it to expert backends that send X-LC-Secure-Link.
     *
     * @param mixed             $result
     * @param \WP_REST_Server   $server
     * @param \WP_REST_Request  $request
     * @return mixed
     */
    public function nocache_public_secure_access_routes($result, $server, $request)
    {
        if (!($request instanceof \WP_REST_Request)) {
            return $result;
        }

        $route = $request->get_route();
        if (!is_string($route) || strpos($route, '/leadconnector-token/') === false) {
            return $result;
        }

        SecureAccessManager::disableExternalPageCache();

        return $result;
    }

    /**
     * Heartbeat endpoint to check if background processes are running
     */
    public function background_heartbeat()
    {
        // Check if any cron jobs are due but not running
        $cron_jobs = _get_cron_array();
        $lc_migrator_jobs = array();

        if (is_array($cron_jobs)) {
            foreach ($cron_jobs as $timestamp => $jobs) {
                foreach ($jobs as $hook => $events) {
                    if (strpos($hook, 'lc_migrator_background') === 0) {
                        foreach ($events as $key => $event) {
                            $lc_migrator_jobs[] = array(
                                'hook' => $hook,
                                'timestamp' => $timestamp,
                                'args' => $event['args'],
                                'due' => ($timestamp <= time())
                            );
                        }
                    }
                }
            }
        }

        return array(
            'success' => true,
            'cron_jobs' => $lc_migrator_jobs,
            'time_now' => time(),
            'cron_disabled' => defined('DISABLE_WP_CRON') && constant('DISABLE_WP_CRON')
        );
    }

    /**
     * Debug endpoint to manually trigger the background export process
     */
    public function debug_trigger_export($request)
    {
        $params = $request->get_query_params();
        $site_id = isset($params['site_id']) ? $params['site_id'] : 'test_site_id';

        $logger = Logger::getInstance();
        $logger->info("Manual trigger of background export for site: " . $site_id);

        // Write to debug log
        $debug_log_file = dirname(__DIR__) . '/src/logs/manual_trigger.log';
        file_put_contents($debug_log_file, date('Y-m-d H:i:s') . " - Manual trigger of background export for site: $site_id\n", FILE_APPEND);

        // Execute the background export directly
        $this->handle_background_export($site_id);

        return array(
            'success' => true,
            'message' => 'Background export process triggered manually',
            'site_id' => $site_id
        );
    }

    /**
     * Set appropriate PHP limits for long-running processes
     * 
     * @param int $time_limit Time limit in seconds (0 for unlimited)
     * @param string $memory_limit Memory limit (e.g., '512M', '1G')
     * @return bool Success status
     */
    private function set_system_limits($time_limit = 0, $memory_limit = '512M')
    {
        $logger = Logger::getInstance();
        $success = true;

        // Set time limit
        if (@set_time_limit($time_limit) === false) {
            $logger->warning("Failed to set time limit to {$time_limit}");
            $success = false;
        }

        // Set memory limit
        if (@ini_set('memory_limit', $memory_limit) === false) {
            $logger->warning("Failed to set memory limit to {$memory_limit}");
            $success = false;
        }

        // Disable output buffering
        @ini_set('output_buffering', 'off');
        @ini_set('zlib.output_compression', 'off');

        // Disable max execution time for CLI
        if (php_sapi_name() === 'cli') {
            @ini_set('max_execution_time', '0');
        }

        return $success;
    }



    public function lc_wp_get($endpoint, $params = array())
    {
        $params = (object) $params;
        $httpMethod = "GET";

        $lcOptions = $this->optionManager->all();

        $api_key = $this->optionManager->get(Constants::api_key) ?? null;
        $lcAccessToken = $this->optionManager->get(Constants::oauth_access_token) ?? null;
        $dataEncryption = new Data_Encryption();
        $lcAccessToken = $dataEncryption->decrypt($lcAccessToken);
        $lcLocationId = $this->optionManager->get(Constants::location_id) ?? null;
        $logger = Logger::getInstance();
        $finalEndpoint = "";
        $authMethod = 'api_key';

        if ($lcAccessToken != '') {
            $authMethod = 'oauth';
        }

        $baseHost = LEAD_CONNECTOR_BASE_URL;

        $baseHost = LC_MIGRATOR_SERVICES_BASE_URL;

        if ($endpoint == 'gcp_upload_file') {
            $finalEndpoint = "wordpress/lc-plugin/migrator/get-temp-link/{$lcLocationId}/site/{$params->site_id}/{$params->file_name}";
            $logger = Logger::getInstance();
            $logger->info("Final Endpoint: " . $finalEndpoint);
            $logger->info("Site ID: " . json_encode($params->site_id));
        }
        if ($endpoint == 'get_site_list')
            $finalEndpoint = "wordpress/lc-plugin/migrator/list-sites/{$lcLocationId}";
        if ($endpoint == 'health_check')
            $finalEndpoint = "wordpress/lc-plugin/migrator/health/{$lcLocationId}";
        if ($endpoint == 'process_migration') {
            $backup_url = rawurlencode($params->backup_url);
            $finalEndpoint = sprintf(
                "wordpress/lc-plugin/migrator/process-migration/%s/site/%s?backup_url=%s",
                $lcLocationId,
                $params->siteId,
                $backup_url
            );
        }
        if ($endpoint == "check_offering_status") {
            $finalEndpoint = "wordpress/lc-plugin/migrator/wordpress-config/{$lcLocationId}";
        }

        if ($endpoint == "check_if_latest_version_installed") {
            $finalEndpoint = "wordpress/lc-plugin/migrator/get-latest-version/{$lcLocationId}";
            $lmRequest = new LMRequest();
            $response = $lmRequest->request($finalEndpoint, 'GET');
            return $response;
        }

        if ($endpoint == "get_status_new") {
            return get_option(LC_MIGRATOR_STATUS);
        }


        // Step 1: Check if the user is connected or not
        if ($endpoint == "is_connected") {
            // Absolute Entry Point For Migration
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_ABSOLUTE_ENTRY_POINT', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'location_id' => $lcLocationId,
                'step' => 1
            ]);
            $event->send();
            // Make A Call To Health Check
            $request = new LMRequest();
            $response = $request->request("wordpress/lc-plugin/migrator/health/{$lcLocationId}", "GET");
            $logger = Logger::getInstance();
            $logger->info("Response: " . json_encode($response));
            if (!isset($response->error)) {
                return array(
                    "success" => true,
                );
            } else {
                return array(
                    "success" => false,
                );
            }
        }

        if ($endpoint == "get_backup_progress") {
            $body = json_decode($params->data);
            $backupId = $body->backupId;
            $progress = StageInfo::getProgressAsJson($backupId);
            return $progress;
        }

        // Secure-access link endpoints. All three ride the existing
        // `manage_options` permission check on the proxy route, so only the
        // WP admin can hit them.
        if ($endpoint == 'secure_access_get') {
            return (new SecureAccessManager())->getCurrent();
        }

        if ($endpoint == 'secure_access_generate') {
            $hours = 72;
            if (!empty($params->data)) {
                $body = json_decode($params->data);
                if (is_object($body) && isset($body->hours)) {
                    $hours = (int) $body->hours;
                }
            } elseif (!empty($params->hours)) {
                $hours = (int) $params->hours;
            }
            return (new SecureAccessManager())->generate($hours);
        }

        if ($endpoint == 'secure_access_revoke') {
            return (new SecureAccessManager())->revoke();
        }

        if ($endpoint == "get_rocket_import_status") {
            $body = json_decode($params->data);
            $siteId = $body->siteId;
            $finalEndpoint = "wordpress/lc-plugin/migrator/import-status/{$lcLocationId}/site/{$siteId}";

            $lmRequest = new LMRequest();
            $response = $lmRequest->request($finalEndpoint, 'GET');
            if ($response->data->migrationStatus == "DONE") {
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_SUCCESS', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $siteId,
                    'error_message' => "Migration Successfully Completed",
                    'step' => 7
                ]);
                $event->send();
            } else if ($response->data->migrationStatus == "FAILED") {
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FAILED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $siteId,
                    'error_message' => "Migration Failed",
                ]);
                $event->send();
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_ABSOLUTE_FINISH_FAILED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $siteId,
                    'location_id' => $lcLocationId,
                ]);
                $event->send();
            }
            return $response;
        }

        if ($endpoint == "clear_backup_progress") {
            $body = json_decode($params->data);
            $backupId = $body->siteId;
            StageInfo::reset($backupId);
            $backupInProgress = new BackupInProgress($backupId);
            $migrator = new Migrator($backupId, $backupInProgress);
            $migrator->perform_cleanup();
            $backupInProgress->clearMetadata();
            // Clear all scheduled cron events
            $cron_jobs = array(
                'lc_migrator_background_export',
                'lc_migrator_background_upload',
                'lc_migrator_background_cleanup',
                'lc_migrator_background_start_migration',
                'lc_migrator_test_cron'
            );

            foreach ($cron_jobs as $cron_job) {
                wp_clear_scheduled_hook($cron_job);
            }
            return array(
                "success" => true,
                "message" => "Backup Progress Cleared",
            );
        }

        if ($endpoint == 'start_migration') {
            $requestBody = json_decode($params->data);
            $siteId = $requestBody->siteId;
            $stage = $requestBody->stage;
            $backupInProgress = new BackupInProgress($siteId);

            $backupId = StageInfo::initialize($siteId);

            // Use our class method instead of global function
            $this->set_system_limits(0, '5G');

            // Create an Exportable Zip Here
            if ($stage < 3) {
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_STARTED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $siteId,
                    'step' => 1
                ]);
                $event->send();
                $backupInProgress->clearMetadata();
                // Schedule the export task as a background process
                wp_schedule_single_event(time(), 'lc_migrator_background_export', array(
                    'site_id' => $siteId
                ));

                // Trigger the cron event immediately
                spawn_cron();

                return array(
                    'success' => true,
                    'status' => 'core_migration_scheduled',
                    'message' => 'Export process has been scheduled in the background',
                    'background' => true,
                );
            }

            // Check if force closed
            if ($backupInProgress->getMetadata('force_closed') === true) {
                return array(
                    'success' => false,
                    'status' => 'backup_stopped',
                    'backup_id' => $siteId,
                    'closed_at_stage' => 'Final Stages',
                    'stage' => $stage + 1
                );
            }

            // Handle stage 4 - GCS upload
            if ($stage == 4) {
                $logger = Logger::getInstance();
                $logger->info("Stage 4 - GCS upload");
                $logger->info("Backup In Progress: " . json_encode($backupInProgress->getAllMetadata()));
                // Check if the export is complete
                $backup_path = $backupInProgress->getMetadata('wp-zip-path');
                if (empty($backup_path)) {
                    return array(
                        'success' => false,
                        'status' => 'export_failed',
                        'message' => 'Export failed',
                        'stage' => 4,
                    );
                }


                // Schedule the GCS upload task
                $backupInProgress->setMetadata('message', 'Transferring website files to Hosting servers...');
                $backupInProgress->setMetadata('stage', 4);
                $backupInProgress->setMetadata('status', 'running');
                $backupInProgress->setMetadata('action', 'Uploading To Cloud Storage');


                wp_schedule_single_event(time(), 'lc_migrator_background_upload', array(
                    'site_id' => $siteId
                ));

                // Trigger the cron event immediately
                spawn_cron();

                return array(
                    'success' => true,
                    'status' => 'gcs_upload_scheduled',
                    'message' => 'Upload process has been scheduled in the background',
                    'stage' => 4,
                    'background' => true,
                );
            }

            // Handle stage 5 - Cleanup
            if ($stage == 5 || $backupInProgress->getMetadata('force_closed') === true) {
                // Check if upload is complete
                $gcs_public_url = $backupInProgress->getMetadata('gcs_public_url');
                if (empty($gcs_public_url)) {
                    $backupInProgress->setMetadata('status', 'failed');
                    $backupInProgress->setMetadata('error', 'Upload failed');
                    return array(
                        'success' => false,
                        'status' => 'upload_failed',
                        'message' => 'Upload failed',
                        'stage' => 5,
                    );
                }

                // Set cleanup process message
                StageInfo::updateProgress("lc_migrator_backup_backup_" . $siteId, 5, Constants::total_steps, 'Updating URLs and configuring settings for your new site...', 'running');
                $backupInProgress->setMetadata('message', 'Updating URLs and configuring settings for your new site...');
                $backupInProgress->setMetadata('stage', 5);
                $backupInProgress->setMetadata('status', 'running');
                $backupInProgress->setMetadata('action', 'cleanup process');

                // Execute the cleanup process directly instead of scheduling it
                $logger = Logger::getInstance();
                $logger->info("Starting direct cleanup for site: " . $siteId);

                try {
                    // Set appropriate system limits for the cleanup process
                    $this->set_system_limits(300, '512M'); // Set reasonable limits for a direct request

                    $migrator = new Migrator($siteId, $backupInProgress);
                    $migrator->perform_cleanup();

                    $backupInProgress->setMetadata('status', 'completed');
                    $backupInProgress->setMetadata('move_to_next', true);
                    $logger->info("Direct cleanup completed successfully for site: " . $siteId);

                    return array(
                        'success' => true,
                        'status' => 'cleanup_completed',
                        'message' => 'Cleanup process completed successfully',
                        'stage' => 6,
                        'background' => false, // Indicate this was not a background process
                    );
                } catch (Exception $e) {
                    $backupInProgress->setMetadata('status', 'failed');
                    $backupInProgress->setMetadata('error', $e->getMessage());
                    $logger->error("Direct cleanup failed for site: " . $siteId . " - " . $e->getMessage());

                    $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FAILED', [
                        'user_id' => get_current_user_id(),
                        'source_website_url' => get_site_url(),
                        'target_website' => $siteId,
                        'error_message' => "Error during cleanup: " . $e->getMessage(),
                        'step' => 5
                    ]);
                    $event->send();

                    return array(
                        'success' => false,
                        'status' => 'cleanup_failed',
                        'message' => 'Cleanup process failed: ' . $e->getMessage(),
                        'stage' => 5,
                    );
                }
            }

            // Handle stage 6 - Start migration
            if ($stage == 6) {

                // Check if cleanup is complete
                $action = $backupInProgress->getMetadata('action');
                $cleanup_status = $backupInProgress->getMetadata('status');

                // If cleanup was done with direct processing (not background), we don't need to check status
                // because it would have returned an error directly if it failed

                // Schedule the migration start task
                $backupInProgress->setMetadata('message', 'Finalizing your migration and verifying site integrity...');
                $backupInProgress->setMetadata('stage', 6);
                $backupInProgress->setMetadata('status', 'running');
                $backupInProgress->setMetadata('action', 'Starting Migration - Hosting Servers');

                wp_schedule_single_event(time(), 'lc_migrator_background_start_migration', array(
                    'site_id' => $siteId
                ));

                // Trigger the cron event immediately
                spawn_cron();

                return array(
                    'success' => true,
                    'status' => 'migration_scheduled',
                    'message' => 'Migration process has been scheduled in the background',
                    'stage' => 6,
                    'background' => true,
                );
            }
        }

        if ($endpoint == 'get_background_status') {
            $body = json_decode($params->data);
            $siteId = $body->siteId;
            $stage = $body->stage;
            $backupInProgress = new BackupInProgress($siteId);

            $message = $backupInProgress->getMetadata('message');
            $currentAction = $backupInProgress->getMetadata('status');
            $moveToNext = $backupInProgress->getMetadata('move_to_next');
            if ($moveToNext) {
                $backupInProgress->setMetadata('move_to_next', false);
            }
            $stage = $backupInProgress->getMetadata('stage');
            $error = $backupInProgress->getMetadata('error');
            $rocketPool = $backupInProgress->getMetadata('rocketPool');

            // For cleanup that was processed directly (not as background), we don't need special handling
            // as the status is already set in the metadata

            return array(
                'success' => $error ? false : true,
                'action' => $currentAction,
                'message' => $message,
                'moveToNext' => $moveToNext ?? false,
                'stage' => $stage,
                'rocketPool' => $rocketPool ?? false,
                'data' => $backupInProgress->getAllMetadata()
            );
        }

        if ($endpoint == "force_close_migration") {
            $body = json_decode($params->data);
            $backupId = $body->siteId;
            $logger = Logger::getInstance();
            //Force Close Migration
            $logger->info("Force Close Migration: " . $backupId);
            $backupInProgress = new BackupInProgress($backupId);
            $backupInProgress->setMetadata('force_closed', true);
            return array(
                'success' => true,
                'message' => 'Migration force closed',
                'backupId' => $backupId,
            );
        }

        if ($finalEndpoint == '') {
            return array(
                'error' => true,
                'message' => 'Invalid Endpoint received',
                'endpoint' => $endpoint,
                'finalEndpoint' => $finalEndpoint,
                'auth' => $authMethod,
                'lcAccessToken' => $lcAccessToken
            );
        }

        if ($authMethod == 'oauth') {
            return $this->lc_oauth_wp_remote_get($finalEndpoint, $lcAccessToken, $baseHost);
        }

        return $this->lc_wp_remote_get($finalEndpoint, $api_key, $baseHost);
    }
    private function lc_oauth_wp_remote_get($endpoint, $lcAccessToken, $baseHost = LC_MIGRATOR_SERVICES_BASE_URL)
    {
        $lmRequest = new LMRequest();
        $response = $lmRequest->request($endpoint, 'GET');

        if (isset($response->error)) {
            return (object) array(
                'error' => true,
                'http_code' => $response->http_code ?? 500,
                'body' => $response->body ?? 'Unknown error occurred',
                'from' => 'oauth_wp_remote_get'
            );
        }

        return $response;
    }

    private function lc_wp_remote_get($endpoint, $api_key, $baseHost = LEAD_CONNECTOR_BASE_URL)
    {
        //else call Remote API here
        $args = array(
            'timeout' => 60,
            'headers' => array(
                'Authorization' => 'Bearer ' . $api_key,
            ),
        );
        $response = wp_remote_get(LEAD_CONNECTOR_BASE_URL . $endpoint, $args);
        $http_code = wp_remote_retrieve_response_code($response);
        if ($http_code === 200) {
            $body = wp_remote_retrieve_body($response);
            $obj = json_decode($body, false);
            return $obj;
        } else {
            return (array(
                'error' => true,
                'http_code' => $http_code,
                'from' => 'wp_remote_get_api'
            ));
        }
    }

    public function lc_public_api_proxy($request)
    {
        $params = $request->get_query_params();
        $endpoint = $params[Constants::rest_api_endpoint_param];
        $directEndpoint = $params[Constants::rest_api_direct_endpoint_param];

        $authorized_location_id = trim($this->optionManager->get(Constants::location_id) ?? '');
        $api_key = trim($this->optionManager->get(Constants::api_key) ?? '');
        $lc_access_token = trim($this->optionManager->get(Constants::oauth_access_token) ?? '');

        // Endpoint Handling
        if ($endpoint == 'wp_regenerate_token') {
            $lmRequest = new LMRequest();
            return $lmRequest->regenerateAccessToken();
        }

        // Basically checks if the user has connected the auth or not
        if ($endpoint == "wp_validate_auth_state") {
            $has_connected_auth = false;
            $connection_method = '';

            $funnelFetchResponse = array('error' => true);

            if ($lc_access_token != '' || $api_key != '') {
                $has_connected_auth = true;
            }

            if ($has_connected_auth) {
                if ($lc_access_token != '') {
                    $connection_method = 'oauth';
                } else {
                    $connection_method = 'api_key';
                }

                $funnelFetchResponse = $this->lc_wp_get('health_check');
            }
            $funnelFetchResponse = (array) $funnelFetchResponse;

            $is_connection_status_active = false;
            if (!array_key_exists("error", $funnelFetchResponse)) {
                $is_connection_status_active = true;
            }
            return array(
                "is_connection_status_active" => $is_connection_status_active,
                "funnelFetchResponse" => $funnelFetchResponse,
                "has_connected_auth" => $has_connected_auth,
                "connection_method" => $connection_method,
                "access_token" => $lc_access_token,
                "api_key" => $api_key,
                "authorized_location_id" => $authorized_location_id,
                "options" => $this->optionManager->all()
            );
        }

        if ($endpoint == 'wp_disconnect') {
            $event = new EventUpdater('LC_MIGRATOR_OAUTH_DISCONNECTED', [
                'authorization_status' => 'disconnected',
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url()
            ]);
            $event->send();
            $this->optionManager->remove(Constants::oauth_access_token);
            $this->optionManager->remove(Constants::oauth_refresh_token);
            $this->optionManager->remove(Constants::location_id);
            return array(
                "-success" => true,
            );
        }

        if ($endpoint == 'wp_validate_oauth') {
            $body = json_decode($params['data']);
            $lmRequest = new LMRequest();
            return $lmRequest->validateAndSaveOauthToken($body->code);
        }

        if ($endpoint == "wp_get_lc_options") {
            return $this->optionManager->all();
        }
        if ($endpoint == "try_new_module") {
            $body = $request->get_body();
            // If the body is a JSON string, decode it to an array/object
            if (is_string($body)) {
                $decoded_body = json_decode($body, true);
                if (json_last_error() === JSON_ERROR_NONE) {
                    $body = $decoded_body;
                }
            }
            return $this->handle_try_new_module($body);
        }

        if ($directEndpoint == "true") {
            $args = array(
                'timeout' => 60,
            );
            $response = wp_remote_get($endpoint, $args);
            $http_code = wp_remote_retrieve_response_code($response);
            if ($http_code === 200) {
                $body = wp_remote_retrieve_body($response);
                return json_decode($body, false);
            } else {
                return array(
                    'error' => true,
                );
            }
        }

        return $this->lc_wp_get($endpoint, $params);
    }

    /**
     * Background handler for site export
     */
    public function handle_background_export($site_id)
    {
        // Set unlimited execution time for background process
        $this->set_system_limits(0, '5G');

        $dirs = $this->_initializeBackupDirectories();
        if (!$dirs['success']) {
            return array(
                'success' => false,
                'status' => 'initialization_failed',
                'message' => $dirs['error']
            );
        }

        $backupInProgress = new BackupInProgress($site_id);
        try {
            // Initialize migration manager with verified directories
            $migration_manager = new MigrationManager(
                $dirs['backup_dir'],
                $dirs['temp_dir'],
                $site_id,
                Logger::getInstance(),
                $backupInProgress,
            );
            $zipDetails = $migration_manager->exportSite();
            $backupInProgress->setMetadata('wp-zip-path', $zipDetails['backup_path']);
        } catch (Exception $e) {
            $backupInProgress->setMetadata('error', $e->getMessage());

            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FAILED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $site_id,
                'error_message' => "Error during site export: " . $e->getMessage(),
                'step' => 3
            ]);
            $event->send();
        }
    }

    /**
     * Background handler for GCS upload
     */
    public function handle_background_upload($site_id)
    {
        // Set unlimited execution time for background process
        $this->set_system_limits(0, '5G');

        $logger = Logger::getInstance();
        $logger->info("Starting background GCS upload for site: " . $site_id);

        $backupInProgress = new BackupInProgress($site_id);


        try {

            $gcsUrl = $this->lc_wp_get("gcp_upload_file", array("site_id" => $site_id));
            if (isset($gcsUrl->error)) {
                $backupInProgress->setMetadata('error', 'Failed To Upload To Hosting Servers');
                throw new Exception("Failed to get GCS upload URL: " . ($gcsUrl->message ?? 'Unknown error'));
            }

            $backup_path = $backupInProgress->getMetadata('wp-zip-path');
            if (empty($backup_path)) {
                $backupInProgress->setMetadata('error', 'Backup Path Not Found');
                throw new Exception("Backup path not found");
            }

            $backupInProgress->setMetadata('gcs_public_url', $gcsUrl->publicUrl);
            // Send Pendo Event for GCS upload started

            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_GCS_UPLOAD_STARTED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $site_id,
                'step' => 4
            ]);
            $event->send();

            // Send Pendo Event for GCS upload completed

            $gcpUpload = new GCP();
            // Backend may return uploadUrl as string or array; normalize to single URL string
            $uploadUrl = isset($gcsUrl->uploadUrl) ? (is_array($gcsUrl->uploadUrl) ? ($gcsUrl->uploadUrl[0] ?? '') : $gcsUrl->uploadUrl) : '';
            $gcpUploadResponse = $gcpUpload->uploadToSignedUrl($uploadUrl, $backup_path, 'application/zip', $site_id, function ($progress) use ($site_id, $backupInProgress) {
                $logger = Logger::getInstance();
                $logger->info("GCP Upload Progress: " . round($progress) . "%");
                $backupInProgress->setMetadata('message', "Transferring website files to Hosting servers (" . round($progress) . "%)...");

            });
            $event = new EventUpdater('LC_MIGATOR_MIGRATION_GCS_UPLOAD_COMPLETED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $site_id,
                'step' => 4
            ]);
            $event->send();
            $logger->info("GCP Upload Response: " . json_encode($gcpUploadResponse));

            if (isset($gcpUploadResponse['success']) && $gcpUploadResponse['success'] === true) {

                $backupInProgress->setMetadata('status', 'completed');
                $logger->info("Background GCS upload completed successfully for site: " . $site_id);
                $backupInProgress->setMetadata('move_to_next', true);
            } else {
                if ($gcpUploadResponse['status'] != 'backup_stopped') {
                    $event = new EventUpdater('LC_MIGATOR_MIGRATION_GCS_UPLOAD_FAILED', [
                        'user_id' => get_current_user_id(),
                        'source_website_url' => get_site_url(),
                        'target_website' => $site_id,
                        'error_message' => "Error While Uploading Website Files to Hosting Servers: " . $gcpUploadResponse['message'],
                        'step' => 4
                    ]);
                    $event->send();
                }

                $backupInProgress->setMetadata('status', 'failed');
                $backupInProgress->setMetadata('error', $gcpUploadResponse['message'] ?? 'Unknown error during upload');
                $logger->error("Background GCS upload failed for site: " . $site_id . " - " . ($gcpUploadResponse['message'] ?? 'Unknown error'));
            }
        } catch (Exception $e) {
            $backupInProgress->setMetadata('status', 'failed');
            $backupInProgress->setMetadata('error', $e->getMessage());
            $logger->error("Background GCS upload failed for site: " . $site_id . " - " . $e->getMessage());
            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_GCS_UPLOAD_FAILED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $site_id,
                'error_message' => "Error While Uploading Website Files to Hosting Servers: " . $e->getMessage(),
                'step' => 4
            ]);
            $event->send();

        }
    }

    /**
     * Background handler for cleanup
     * 
     * Note: This function is still used by other parts of the code and by wp_schedule_single_event.
     * However, for the cleanup stage in start_migration, we now process the cleanup directly
     * in the request/response cycle rather than scheduling it as a background task.
     */
    public function handle_background_cleanup($site_id)
    {
        // Set unlimited execution time for background process
        $this->set_system_limits(0, '5G');

        $logger = Logger::getInstance();
        $logger->info("Starting background cleanup for site: " . $site_id);

        $backupInProgress = new BackupInProgress($site_id);
        $backupInProgress->setMetadata('cleanup_status', 'starting fast');

        try {

            $backupInProgress->setMetadata('message', 'Updating URLs and configuring settings for your new site...');

            $migrator = new Migrator($site_id, $backupInProgress);
            $migrator->perform_cleanup();

            $backupInProgress->setMetadata('status', 'completed');
            $backupInProgress->setMetadata('move_to_next', true);
            $logger->info("Background cleanup completed successfully for site: " . $site_id);
        } catch (Exception $e) {
            $backupInProgress->setMetadata('status', 'failed');
            $backupInProgress->setMetadata('error', $e->getMessage());
            $logger->error("Background cleanup failed for site: " . $site_id . " - " . $e->getMessage());

            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FAILED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $site_id,
                'error_message' => "Error during cleanup: " . $e->getMessage(),
                'step' => 5
            ]);
            $event->send();
        }
    }

    /**
     * Background handler for starting migration
     */
    public function handle_background_start_migration($site_id)
    {
        // Set unlimited execution time for background process
        $this->set_system_limits(0, '5G');

        $logger = Logger::getInstance();
        $logger->info("Starting background migration initiation for site: " . $site_id);

        $backupInProgress = new BackupInProgress($site_id);
        $backupInProgress->setMetadata('migration_status', 'in_progress');

        try {

            $gcsPublicUrl = $backupInProgress->getMetadata('gcs_public_url');
            if (empty($gcsPublicUrl)) {
                throw new Exception("GCS public URL not found");
            }

            $startMigration = $this->lc_wp_get('process_migration', array("siteId" => $site_id, "backup_url" => $gcsPublicUrl));
            $backupInProgress->setMetadata('rocketPool', true);
            if (isset($startMigration->error)) {
                $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FAILED', [
                    'user_id' => get_current_user_id(),
                    'source_website_url' => get_site_url(),
                    'target_website' => $site_id,
                    'error_message' => "Error While Starting Migration Pipeline",
                    'step' => 6
                ]);
                $event->send();
                throw new Exception($startMigration->message ?? "Error starting migration");
            }

            $backupInProgress->setMetadata('migration_status', 'completed');
            $logger->info("Background migration initiation completed successfully for site: " . $site_id);
        } catch (Exception $e) {
            $backupInProgress->setMetadata('migration_status', 'failed');
            $backupInProgress->setMetadata('migration_error', $e->getMessage());
            $logger->error("Background migration initiation failed for site: " . $site_id . " - " . $e->getMessage());

            $event = new EventUpdater('LC_MIGRATOR_MIGRATION_FAILED', [
                'user_id' => get_current_user_id(),
                'source_website_url' => get_site_url(),
                'target_website' => $site_id,
                'error_message' => "Error starting migration: " . $e->getMessage(),
                'step' => 6
            ]);
            $event->send();
        }
    }

    /**
     * Test cron job handler for debugging
     */
    public function handle_test_cron()
    {
        $logger = Logger::getInstance();
        $logger->info("Test cron job executed at " . date('Y-m-d H:i:s'));

        // Write to a specific debug file
        $debug_log_file = dirname(__DIR__) . '/src/logs/cron_debug.log';
        // file_put_contents($debug_log_file, date('Y-m-d H:i:s') . " - Test cron job executed\n", FILE_APPEND);
    }

    /**
     * Handle the try_new_module endpoint for new export functionality
     */
    public function handle_try_new_module($params = array())
    {
        global $lcm_params;

        // Set params
        if (empty($params)) {
            $params = stripslashes_deep(array_merge($_GET, $_POST));
        }

        // Set priority
        if (!isset($params['priority'])) {
            $params['priority'] = 5;
        }

        $lcm_params = $params;
        $this->lcm_setup_environment();
        $this->lcm_setup_errors();

        // Loop over filters
        if (($filters = $this->lcm_get_filters('lcm_export'))) {
            while ($hooks = current($filters)) {
                if (intval($params['priority']) === key($filters)) {
                    foreach ($hooks as $hook) {
                        try {

                            // Run function hook
                            $params = call_user_func_array($hook['function'], array($params));

                        } catch (Lcm_Database_Exception $e) {
                            do_action('lcm_status_export_error', $params, $e);

                            if (defined('WP_CLI')) {
                                /* translators: 1: Error code, 2: Error message. */
                                WP_CLI::error(sprintf(__('Export failed (database error). Code: %1$s. Message: %2$s', 'lc-migrator'), $e->getCode(), $e->getMessage()));
                            }

                            status_header($e->getCode());
                            lcm_json_response(array('errors' => array(array('code' => $e->getCode(), 'message' => $e->getMessage()))));
                            exit;
                        } catch (Exception $e) {
                            do_action('lcm_status_export_error', $params, $e);

                            if (defined('WP_CLI')) {
                                WP_CLI::error(sprintf(__('Export failed: %s', 'lc-migrator'), $e->getMessage()));
                            }

                            Lcm_Status::error(__('Export failed', 'lc-migrator'), $e->getMessage());
                            exit;
                        }
                    }

                    $completed = true;
                    if (isset($params['completed'])) {
                        $completed = (bool) $params['completed'];
                    }

                    // Do request
                    if ($completed === false || ($next = next($filters)) && ($params['priority'] = key($filters))) {
                        if (defined('WP_CLI')) {
                            if (!defined('DOING_CRON')) {
                                continue;
                            }
                        }

                        if (isset($params['lcm_manual_export'])) {
                            lcm_json_response($params);
                            exit;
                        }

                        exit;
                    }
                }
                next($filters);
            }
        }
        return $params;
    }

    /**
     * Set up the environment for export process
     */
    function lcm_setup_environment()
    {
        @ignore_user_abort(true);

        @set_time_limit(0);

        @ini_set('max_input_time', '-1');

        @ini_set('pcre.backtrack_limit', PHP_INT_MAX);

        if (@function_exists('mb_internal_encoding') && (@ini_get('mbstring.func_overload') & 2)) {
            @mb_internal_encoding('ISO-8859-1');
        }

        if (@ob_get_length()) {
            @ob_end_clean();
        }
    }

    function lcm_setup_errors()
    {
        // Set error handler
    }

    /**
     * Get export filters
     */
    function lcm_get_filters($tag)
    {
        global $wp_filter;
        $filters = array();
        if (isset($wp_filter[$tag])) {
            if (($filters = $wp_filter[$tag])) {
                if (isset($filters->callbacks)) {
                    $filters = $filters->callbacks;
                }
            }
            ksort($filters);
        }
        return $filters;
    }
}