<?php
/**
 * SearchShifter™ Job Runner
 * Executes queued background jobs (≤3 concurrent)
 */

if ( ! defined( 'ABSPATH' ) ) exit;

class SS_JobRunner {

    const MAX_CONCURRENT = 3;
    const MAX_ATTEMPTS = 3;
    const MEMORY_LIMIT_MB = 128;
    const TIME_LIMIT_SEC = 25;

    public static function init() {
        // Schedule recurring cron job
        add_action('ss_run_jobs_event', [__CLASS__, 'process_queue']);
        if (!wp_next_scheduled('ss_run_jobs_event')) {
            wp_schedule_event(time() + 60, 'five_minutes', 'ss_run_jobs_event');
        }

        // Add custom interval (5 minutes)
        add_filter('cron_schedules', function($schedules){
            $schedules['five_minutes'] = [
                'interval' => 300, // 5 minutes
                'display'  => __('Every 5 Minutes')
            ];
            return $schedules;
        });
    }

    /**
     * Process queued jobs
     */
    public static function process_queue() {
    global $wpdb;
    $start_time = microtime(true);
    $table = "{$wpdb->prefix}ss_jobs";

    $jobs = $wpdb->get_results("
        SELECT * FROM $table
        WHERE status='queued'
        ORDER BY id ASC
        LIMIT " . self::MAX_CONCURRENT
    );

    if (empty($jobs)) return;

    foreach ($jobs as $job) {
        if (self::near_limits($start_time)) break;

        $wpdb->update($table, ['status' => 'running'], ['id' => $job->id]);

        try {
            // 🧠 Handle special Smart Sync job type
            if ($job->type === 'smart_sync') {
                $payload = maybe_unserialize($job->payload);
                $post_id = intval($payload['post_id'] ?? 0);

                if (class_exists('SS_AI_Protocol')) {
                    SS_AI_Protocol::on_activation(); // regenerate llms.txt / ai.txt
                }
                if (class_exists('SS_Schema')) {
                    SS_Schema::generate_all(); // regenerate schema
                }

                $wpdb->update($table, [
                    'status' => 'done',
                    'log'    => '✅ Smart Sync completed for Post ID ' . $post_id,
                    'last_error' => null,
                ], ['id' => $job->id]);

                continue; // move to next job
            }

            // 🔄 For all other job payloads
            $success = self::execute_job($job);

            if ($success) {
                $wpdb->update($table, [
                    'status' => 'done',
                    'log'    => '✅ Job completed successfully',
                ], ['id' => $job->id]);
            } else {
                throw new Exception('Unknown or failed job action');
            }

        } catch (Exception $e) {
            $attempts = $job->attempts + 1;
            $status = ($attempts >= self::MAX_ATTEMPTS) ? 'failed' : 'queued';
            $wpdb->update($table, [
                'status'     => $status,
                'attempts'   => $attempts,
                'last_error' => $e->getMessage(),
            ], ['id' => $job->id]);

            if ($status === 'queued') {
                $delay = pow(2, $attempts) * 60;
                wp_schedule_single_event(time() + $delay, 'ss_run_jobs_event');
            }
        }
    }
}

    // public static function process_queue() {
    //     global $wpdb;
    //     $start_time = microtime(true);

    //     $jobs = $wpdb->get_results("
    //         SELECT * FROM {$wpdb->prefix}ss_jobs
    //         WHERE status='queued'
    //         ORDER BY id ASC
    //         LIMIT " . self::MAX_CONCURRENT
    //     );

    //     if (empty($jobs)) return;

    //     foreach ($jobs as $job) {
    //         if (self::near_limits($start_time)) break;

    //         $wpdb->update(
    //             "{$wpdb->prefix}ss_jobs",
    //             ['status' => 'running'],
    //             ['id' => $job->id]
    //         );

    //         $success = self::execute_job($job);

    //         if ($success) {
    //             $wpdb->update(
    //                 "{$wpdb->prefix}ss_jobs",
    //                 ['status' => 'done'],
    //                 ['id' => $job->id]
    //             );
    //         } else {
    //             $attempts = $job->attempts + 1;
    //             $status = ($attempts >= self::MAX_ATTEMPTS) ? 'failed' : 'queued';

    //             $wpdb->update(
    //                 "{$wpdb->prefix}ss_jobs",
    //                 [
    //                     'status' => $status,
    //                     'attempts' => $attempts,
    //                     'last_error' => 'Job failed, will retry if under limit'
    //                 ],
    //                 ['id' => $job->id]
    //             );

    //             if ($status === 'queued') {
    //                 // Apply exponential backoff (next run after +minutes)
    //                 $delay = pow(2, $attempts) * 60; // 2, 4, 8 mins
    //                 wp_schedule_single_event(time() + $delay, 'ss_run_jobs_event');
    //             }
    //         }
    //     }

        
    // }

    /**
     * Execute individual job
     */
    private static function execute_job($job) {
        try {
            $payload = json_decode($job->payload, true);
            if (empty($payload['action'])) return false;

            switch ($payload['action']) {

                case 'sync_llms':
                    if (class_exists('SS_SyncEngine')) {
                        SS_SyncEngine::sync_llms($payload);
                    }
                    break;

                case 'crawl_url':
                    if (class_exists('SS_Scanner')) {
                        SS_Scanner::scan_single($payload['url']);
                    }
                    break;

                case 'analyze_backlink':
                    if (class_exists('SS_Analytics')) {
                        SS_Analytics::record_backlink($payload);
                    }
                    break;

                default:
                    error_log("[SS_JobRunner] Unknown job type: {$payload['action']}");
                    return false;
            }

            return true;

        } catch (\Throwable $e) {
            error_log("[SS_JobRunner] Job {$job->id} failed: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Prevent runaway memory or time usage
     */
    private static function near_limits($start_time) {
        $elapsed = microtime(true) - $start_time;
        $used_mb = memory_get_usage(true) / 1024 / 1024;

        return ($elapsed > self::TIME_LIMIT_SEC || $used_mb > self::MEMORY_LIMIT_MB);
    }

    /**
     * Manual test trigger (optional admin button)
     */
    public static function test_enqueue_sample() {
        global $wpdb;
        $wpdb->insert("{$wpdb->prefix}ss_jobs", [
            'type' => 'test',
            'payload' => json_encode(['action' => 'sync_llms']),
            'status' => 'queued'
        ]);
    }
}
