<?php
/**
 * Background Queue Manager
 *
 * Handles asynchronous bulk processing using WP Cron to prevent timeouts.
 *
 * @package PackshotPhotoAI
 */

namespace PackshotPhotoAI\Core;

defined('ABSPATH') || exit;

/**
 * Manages the background processing queue
 */
class QueueManager {

    /**
     * Option key for storing queue state
     */
    private const QUEUE_OPTION = 'packshotphoto_bulk_queue';

    /**
     * Cron hook name
     */
    public const CRON_HOOK = 'packshotphoto_bulk_worker';

    /**
     * Items to process per batch
     */
    private const BATCH_SIZE = 3;

    /**
     * Register cron hook
     */
    public function register_hooks(): void {
        add_action(self::CRON_HOOK, [$this, 'process_batch']);
    }

    /**
     * Add items to the background queue
     *
     * @param array  $post_ids List of attachment IDs
     * @param string $action   Action type (ai, webp, resize)
     * @param mixed  $args     Optional extra arguments
     * @return bool Success
     */
    public function push(array $post_ids, string $action, $args = null): bool {
        if (empty($post_ids)) {
            return false;
        }

        $queue = get_option(self::QUEUE_OPTION, []);

        // If queue exists, append items or overwrite?
        // Let's support appending for robustness.
        $existing_items = $queue['items'] ?? [];
        $new_items      = array_values(array_unique(array_merge($existing_items, $post_ids)));

        $state = [
            'status'    => 'processing',
            'action'    => $action,
            'items'     => $new_items,
            'total'     => count($new_items),
            'processed' => isset($queue['processed']) ? $queue['processed'] : 0,
            'errors'    => isset($queue['errors']) ? $queue['errors'] : 0,
            'args'      => $args,
            'updated'   => time(),
        ];

        update_option(self::QUEUE_OPTION, $state, false);
        Logger::info('Queue: Pushed items', ['count' => count($post_ids), 'action' => $action]);

        // Schedule worker if not already running
        if (!\wp_next_scheduled(self::CRON_HOOK)) {
            \wp_schedule_single_event(time(), self::CRON_HOOK);
        }

        return true;
    }

    /**
     * Process a batch of items from the queue
     */
    public function process_batch(): void {
        $queue = get_option(self::QUEUE_OPTION, []);

        if (empty($queue) || 'processing' !== $queue['status']) {
            return;
        }

        $items     = $queue['items'];
        $processed = (int) $queue['processed'];
        $error_count = (int) $queue['errors'];
        $action    = $queue['action'];
        $args      = $queue['args'];

        // Ensure resources for batch processing
        MemoryManager::ensure_memory_limit(true);
        MemoryManager::ensure_time_limit(600);

        // Get next batch
        $batch = array_slice($items, $processed, self::BATCH_SIZE);

        if (empty($batch)) {
            $this->complete_queue();
            return;
        }

        Logger::debug('Queue: Processing batch', ['batch' => $batch, 'action' => $action]);

        foreach ($batch as $post_id) {
            $success = $this->execute_action($post_id, $action, $args);
            
            if ($success) {
                $processed++;
            } else {
                $error_count++;
                // We still count it as "processed" (attempted) to move the pointer
                $processed++;
            }
        }

        // Update state
        $queue['processed'] = $processed;
        $queue['errors']    = $error_count;
        $queue['updated']   = time();

        if ($processed >= count($items)) {
            $this->complete_queue();
        } else {
             update_option(self::QUEUE_OPTION, $queue, false);
             // Re-schedule next batch immediately
             \wp_schedule_single_event(time(), self::CRON_HOOK);
        }
    }

    /**
     * Execute specific action for an item
     */
    private function execute_action(int $post_id, string $action, $args): bool {
        // Validate attachment
        if ('attachment' !== \get_post_type($post_id)) {
            return false;
        }

        try {
            switch ($action) {
                case 'ai':
                    $result = AIProcessor::generate($post_id);
                    return $result['success'];

                case 'eu_ai':
                    $labeller = new EuAiActLabeller();
                    $result = $labeller->apply_label($post_id);
                    return $result['success'];

                case 'webp':
                    $converter = new WebPConverter();
                    $result = $converter->convert($post_id, true);
                    return $result['success'];

                case 'avif':
                    $converter = new AvifConverter();
                    $result = $converter->convert($post_id, true);
                    return $result['success'];

                case 'resize':
                    $processor = new ImageProcessor();
                    $width = $args ? (int)$args : (int)get_option('packshotphoto_max_image_size', 2000);
                    $result = $processor->resize($post_id, $width);
                    return $result['success'];

                default:
                    return false;
            }
        } catch (\Exception $e) {
            Logger::error('Queue: Execution error', ['id' => $post_id, 'msg' => $e->getMessage()]);
            return false;
        }
    }

private function complete_queue(): void {
        $queue = get_option(self::QUEUE_OPTION, []);
        if (empty($queue)) return;

        $queue['status']    = 'completed';
        $queue['completed'] = time();
        update_option(self::QUEUE_OPTION, $queue, false);
        
        Logger::info('Queue: Batch completed', ['total' => $queue['total'], 'errors' => $queue['errors']]);
    }

    /**
     * Get current status
     *
     * @return array
     */
    public static function get_status(): array {
        $queue = get_option(self::QUEUE_OPTION, [
            'status'    => 'idle',
            'total'     => 0,
            'processed' => 0,
            'errors'    => 0
        ]);

        // If completed more than 1 minute ago, return idle
        if ('completed' === $queue['status'] && time() - ($queue['completed'] ?? 0) > 60) {
            return ['status' => 'idle', 'total' => 0, 'processed' => 0, 'errors' => 0];
        }

        return $queue;
    }

    /**
     * Clear queue
     */
    public function clear(): void {
        delete_option(self::QUEUE_OPTION);
        \wp_clear_scheduled_hook(self::CRON_HOOK);
    }
}
