<?php
if (!defined('ABSPATH')) exit;

/**
 * Background queue (Pro) — bulk GEO analysis of published posts via WP-Cron,
 * in small batches. Pause / resume / stop supported.
 */
class AIVT_Queue {

    public static function init() {
        add_action('aivt_process_queue', [__CLASS__, 'process']);
    }

    public static function get_job() {
        $job = get_option(AIVT_JOB_OPTION, null);
        return is_array($job) ? $job : null;
    }

    private static function save_job($job) {
        update_option(AIVT_JOB_OPTION, $job, false);
        return $job;
    }

    /** Job types and the meta key that marks a post as already processed. */
    public static function job_types() {
        return [
            'geo'    => AIVT_Store::META_GEO,
            'faq'    => AIVT_Store::META_FAQ,
            'qa'     => AIVT_Store::META_QA,
            'schema' => AIVT_Store::META_SCHEMA,
        ];
    }

    public static function type_label($type) {
        $labels = [
            'geo'    => __('GEO Score', 'pewit-geo-analysis-tool'),
            'faq'    => __('FAQ generation', 'pewit-geo-analysis-tool'),
            'qa'     => __('Q&A generation', 'pewit-geo-analysis-tool'),
            'schema' => __('Schema generation', 'pewit-geo-analysis-tool'),
        ];
        return $labels[$type] ?? $type;
    }

    /** Backward-compatible GEO job creator. */
    public static function create_geo_job() {
        return self::create_job('geo');
    }

    /** Create a bulk job for any supported type over posts missing that output. */
    public static function create_job($type = 'geo') {
        $types = self::job_types();
        if (!isset($types[$type])) {
            return new WP_Error('aivt_bad_type', __('Unknown job type.', 'pewit-geo-analysis-tool'));
        }
        if (!aivt_api_ready()) {
            return new WP_Error('aivt_no_key', __('Connect your API key first.', 'pewit-geo-analysis-tool'));
        }
        $existing = self::get_job();
        if ($existing && in_array($existing['status'] ?? '', ['running', 'paused'], true)) {
            return new WP_Error('aivt_busy', __('Another job is already running. Stop it first.', 'pewit-geo-analysis-tool'));
        }
        $ids = AIVT_Store::ids_missing_meta($types[$type], 1000);
        if (empty($ids)) {
            return new WP_Error('aivt_nothing', __('Every published post is already processed for this job.', 'pewit-geo-analysis-tool'));
        }
        $job = [
            'type'    => $type,
            'status'  => 'running',
            'ids'     => array_values($ids),
            'total'   => count($ids),
            'done'    => 0,
            'current' => null,
            'log'     => [],
            'started' => time(),
        ];
        return self::save_job($job);
    }

    public static function pause() {
        $job = self::get_job();
        if ($job && $job['status'] === 'running') {
            $job['status'] = 'paused';
            self::save_job($job);
        }
        return self::get_job();
    }

    public static function resume() {
        $job = self::get_job();
        if ($job && $job['status'] === 'paused') {
            $job['status'] = 'running';
            self::save_job($job);
        }
        return self::get_job();
    }

    public static function stop() {
        $job = self::get_job();
        if ($job) {
            $job['status'] = 'stopped';
            self::save_job($job);
        }
        return self::get_job();
    }

    /** Cron worker: process one batch. */
    public static function process() {
        $job = self::get_job();
        if (!$job || $job['status'] !== 'running') {
            return;
        }
        $s = aivt_get_settings();
        $batch = max(1, min(10, (int) ($s['batch_size'] ?? 3)));
        $processed = 0;
        $type = $job['type'] ?? 'geo';

        while ($processed < $batch && !empty($job['ids'])) {
            $post_id = (int) array_shift($job['ids']);
            $job['current'] = ['id' => $post_id, 'title' => get_the_title($post_id)];
            $result = self::run_one($type, $post_id);
            if (is_wp_error($result)) {
                $job['log'][] = [
                    'time'    => gmdate('H:i:s'),
                    'level'   => 'error',
                    'message' => sprintf('#%d %s', $post_id, $result->get_error_message()),
                ];
                // Stop early on auth/credit errors to avoid burning the key.
                if (in_array($result->get_error_code(), ['pewit_llm_api', 'aivt_no_key'], true)) {
                    $job['status'] = 'paused';
                    self::save_job($job);
                    return;
                }
            } else {
                $job['done']++;
                $job['log'][] = [
                    'time'    => gmdate('H:i:s'),
                    'level'   => 'info',
                    'message' => sprintf('#%d → %s', $post_id, self::result_summary($type, $result)),
                ];
            }
            $processed++;
        }

        $job['log'] = array_slice($job['log'], -40);
        if (empty($job['ids'])) {
            $job['status'] = 'done';
            $job['current'] = null;
            if ($type === 'geo') {
                AIVT_Store::maybe_snapshot_site();
            }
            self::maybe_notify($job);
        }
        self::save_job($job);
    }

    /** Run a single item for the given job type. Returns array result or WP_Error. */
    private static function run_one($type, $post_id) {
        switch ($type) {
            case 'faq':
                $r = AIVT_FAQ::generate($post_id);
                if (!is_wp_error($r) && !empty($r['pairs'])) {
                    // Queue for review instead of touching content automatically.
                    AIVT_Store::add_approval($post_id, 'faq', AIVT_FAQ::render_blocks($r['pairs'], __('Frequently Asked Questions', 'pewit-geo-analysis-tool')), count($r['pairs']));
                }
                return $r;
            case 'qa':
                $r = AIVT_QA::generate($post_id);
                if (!is_wp_error($r) && !empty($r['items'])) {
                    AIVT_Store::add_approval($post_id, 'qa', AIVT_QA::render_blocks($r['items'], __('Q&A', 'pewit-geo-analysis-tool')), count($r['items']));
                }
                return $r;
            case 'schema': return AIVT_Schema::generate($post_id);
            case 'geo':
            default:       return AIVT_GEO_Score::analyze($post_id);
        }
    }

    private static function result_summary($type, $result) {
        if ($type === 'geo' && isset($result['score'])) {
            return sprintf('%d/100', (int) $result['score']);
        }
        if ($type === 'faq' && isset($result['pairs'])) {
            /* translators: %d: number of FAQ pairs */
            return sprintf(_n('%d FAQ', '%d FAQs', count($result['pairs']), 'pewit-geo-analysis-tool'), count($result['pairs']));
        }
        if ($type === 'qa' && isset($result['items'])) {
            /* translators: %d: number of Q&A items */
            return sprintf(_n('%d Q&A', '%d Q&As', count($result['items']), 'pewit-geo-analysis-tool'), count($result['items']));
        }
        if ($type === 'schema') {
            return __('schema saved', 'pewit-geo-analysis-tool');
        }
        return __('done', 'pewit-geo-analysis-tool');
    }

    private static function maybe_notify($job) {
        $s = aivt_get_settings();
        if (empty($s['notify_email_enabled']) || empty($s['notify_email_to'])) {
            return;
        }
        $subject = sprintf(
            /* translators: %s: site name */
            __('[%s] AI Visibility bulk job complete', 'pewit-geo-analysis-tool'),
            get_bloginfo('name')
        );
        $body = sprintf(
            /* translators: 1: job type label, 2: number of processed posts */
            __('%1$s finished for %2$d posts.', 'pewit-geo-analysis-tool'),
            self::type_label($job['type'] ?? 'geo'),
            (int) $job['done']
        );
        wp_mail(sanitize_email($s['notify_email_to']), $subject, $body);
    }
}
