<?php

namespace HaoZiTeam\AIPost\Service\Features;

defined('ABSPATH') || exit;

class PriorityQueue
{
    const OPTION_QUEUE = 'aipost_priority_queue';
    const CRON_HOOK = 'aipost_priority_queue_process';

    const PRIORITY_HIGH = 1;
    const PRIORITY_NORMAL = 5;

    const TYPE_EDITOR_GENERATE = 'editor_generate';
    const TYPE_TASK_CRON = 'task_cron';

    private static function queue_lock_key(): string
    {
        return 'aipost_priority_queue_lock';
    }

    public static function register(): void
    {
        add_action(self::CRON_HOOK, [__CLASS__, 'process'], 10, 0);
    }

    public static function enqueue_editor_generate(string $job_id): bool
    {
        return self::enqueue(self::TYPE_EDITOR_GENERATE, ['job_id' => $job_id], self::PRIORITY_HIGH);
    }

    public static function enqueue_task_cron($task_key): bool
    {
        return self::enqueue(self::TYPE_TASK_CRON, ['task_key' => $task_key], self::PRIORITY_NORMAL);
    }

    public static function enqueue(string $type, array $payload, int $priority): bool
    {
        $priority = max(1, (int)$priority);

        $queue = get_option(self::OPTION_QUEUE, []);
        if (!is_array($queue)) {
            $queue = [];
        }

        $id = wp_generate_password(16, false, false) . '_' . time();
        $queue[] = [
            'id' => $id,
            'type' => (string)$type,
            'priority' => $priority,
            'payload' => $payload,
            'created_at' => time(),
        ];

        $ok = update_option(self::OPTION_QUEUE, $queue, false);
        if (!$ok) {
            return false;
        }

        if (!wp_next_scheduled(self::CRON_HOOK)) {
            wp_schedule_single_event(time() + 1, self::CRON_HOOK);
        }

        try {
            $spawn_guard = 'aipost_priority_queue_spawn_guard';
            if (!function_exists('get_transient') || !get_transient($spawn_guard)) {
                if (function_exists('set_transient')) {
                    set_transient($spawn_guard, 1, 15);
                }
                if (function_exists('spawn_cron')) {
                    @spawn_cron(time() + 1);
                }
            }
        } catch (\Throwable $e) {
        }

        return true;
    }

    public static function process(): void
    {
        $lock_key = self::queue_lock_key();
        if (get_transient($lock_key)) {
            return;
        }
        set_transient($lock_key, 1, 60);

        try {
            $queue = get_option(self::OPTION_QUEUE, []);
            if (!is_array($queue) || empty($queue)) {
                return;
            }

            $ran = 0;
            $max = 3;

            while ($ran < $max) {
                $queue = get_option(self::OPTION_QUEUE, []);
                if (!is_array($queue) || empty($queue)) {
                    break;
                }

                $best_index = -1;
                $best_pri = null;
                $best_ts = null;

                foreach ($queue as $i => $item) {
                    if (!is_array($item)) {
                        continue;
                    }
                    $pri = isset($item['priority']) ? (int)$item['priority'] : self::PRIORITY_NORMAL;
                    $ts = isset($item['created_at']) ? (int)$item['created_at'] : 0;

                    if ($best_index < 0 || $pri < $best_pri || ($pri === $best_pri && $ts < $best_ts)) {
                        $best_index = (int)$i;
                        $best_pri = $pri;
                        $best_ts = $ts;
                    }
                }

                if ($best_index < 0 || !isset($queue[$best_index])) {
                    break;
                }

                $job = $queue[$best_index];
                array_splice($queue, $best_index, 1);
                update_option(self::OPTION_QUEUE, $queue, false);

                $GLOBALS['aipost_queue_processing'] = true;
                try {
                    self::execute_item($job);
                } catch (\Throwable $e) {
                }
                unset($GLOBALS['aipost_queue_processing']);

                $ran++;
            }

            if (!empty(get_option(self::OPTION_QUEUE, [])) && !wp_next_scheduled(self::CRON_HOOK)) {
                wp_schedule_single_event(time() + 5, self::CRON_HOOK);
            }
        } finally {
            delete_transient($lock_key);
        }
    }

    private static function execute_item(array $item): void
    {
        $type = (string)($item['type'] ?? '');
        $payload = isset($item['payload']) && is_array($item['payload']) ? $item['payload'] : [];

        if ($type === self::TYPE_EDITOR_GENERATE) {
            $job_id = (string)($payload['job_id'] ?? '');
            if ($job_id !== '' && class_exists('HaoZiTeam\\AIPost\\Service\\Features\\EditorGenerateEndpoint')) {
                EditorGenerateEndpoint::run_job($job_id);
            }
            return;
        }

        if ($type === self::TYPE_TASK_CRON) {
            $task_key = $payload['task_key'] ?? null;
            do_action('ai_post_cron', $task_key);
            return;
        }
    }
}

PriorityQueue::register();
