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

class AIIO_Queue {

    const CRON_HOOK = 'aiio_process_queue';

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

    public static function option_key() {
        return 'aiio_active_job';
    }

    /**
     * @return array|WP_Error
     */
    public static function create_job($attachment_ids, $args = []) {

        $existing = self::get_job();
        if (!empty($existing) && ($existing['status'] ?? '') === 'running') {
            return new WP_Error('aiio_job_running', __('A background job is already running.', 'pewit-ai-image-optimizer'));
        }

        $ids = [];
        foreach ((array) $attachment_ids as $id) {
            $id = intval($id);
            if ($id && !in_array($id, $ids, true)) {
                $ids[] = $id;
            }
        }

        if (empty($ids)) {
            return new WP_Error('aiio_job_empty', __('No images selected for bulk optimization.', 'pewit-ai-image-optimizer'));
        }

        $create_webp = !empty($args['webp']) && !empty(aiio_get_settings()['webp_enabled']);
        $create_avif = !empty($args['avif']) && !empty(aiio_get_settings()['avif_enabled']);

        $job = [
            'id' => 'aiio_job_' . time() . '_' . wp_rand(1000, 9999),
            'status' => 'running',
            'type' => 'bulk_optimize',
            'total' => count($ids),
            'remaining' => array_values($ids),
            'processed' => [],
            'failed' => [],
            'skipped' => [],
            'create_webp' => $create_webp ? 1 : 0,
            'create_avif' => $create_avif ? 1 : 0,
            'current' => null,
            'started_at' => current_time('mysql'),
            'updated_at' => current_time('mysql'),
            'message' => __('Job started', 'pewit-ai-image-optimizer'),
            'log' => [],
        ];

        self::add_log($job, 'info', __('Bulk optimization started', 'pewit-ai-image-optimizer'), ['total' => count($ids)]);
        self::save_job($job);

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

        return $job;
    }

    public static function process() {
        $job = self::get_job();
        if (empty($job) || ($job['status'] ?? '') !== 'running') {
            return;
        }

        if (empty($job['remaining'])) {
            $job['status'] = 'completed';
            $job['message'] = __('Job completed', 'pewit-ai-image-optimizer');
            $job['updated_at'] = current_time('mysql');
            self::add_log($job, 'info', __('Job completed', 'pewit-ai-image-optimizer'));
            self::save_job($job);
            AIIO_Job_Notify::maybe_send($job);
            return;
        }

        $attachment_id = intval(array_shift($job['remaining']));
        $job['current'] = $attachment_id;
        $job['updated_at'] = current_time('mysql');
        self::save_job($job);

        $reason = '';
        if (!AIIO_Media_Apply::is_optimizable($attachment_id, $reason)) {
            $job['skipped'][] = [
                'id' => $attachment_id,
                'reason' => $reason,
            ];
            self::add_log($job, 'warn', sprintf(/* translators: 1: attachment ID, 2: skip reason */ __('Skipped #%1$d: %2$s', 'pewit-ai-image-optimizer'), $attachment_id, $reason));
            self::save_job($job);
            wp_schedule_single_event(time() + 2, self::CRON_HOOK);
            return;
        }

        $result = AIIO_Media_Apply::apply($attachment_id, [
            'webp' => !empty($job['create_webp']),
            'avif' => !empty($job['create_avif']),
        ]);

        if (is_wp_error($result)) {
            $job['failed'][] = [
                'id' => $attachment_id,
                'error' => $result->get_error_message(),
            ];
            self::add_log($job, 'error', sprintf(/* translators: 1: attachment ID, 2: error message */ __('Failed #%1$d: %2$s', 'pewit-ai-image-optimizer'), $attachment_id, $result->get_error_message()));
        } else {
            $job['processed'][] = [
                'id' => $attachment_id,
                'saved_bytes' => intval($result['saved_bytes'] ?? 0),
                'after_bytes' => intval($result['after_bytes'] ?? 0),
            ];
            self::add_log(
                $job,
                'info',
                sprintf(
                    /* translators: 1: attachment ID, 2: bytes saved */ __('Optimized #%1$d — saved %2$s', 'pewit-ai-image-optimizer'),
                    $attachment_id,
                    AIIO_Optimizer::format_bytes(intval($result['saved_bytes'] ?? 0))
                )
            );
        }

        $job['current'] = null;
        self::save_job($job);

        if (!empty($job['remaining'])) {
            wp_schedule_single_event(time() + 2, self::CRON_HOOK);
        } else {
            $job['status'] = 'completed';
            $job['message'] = __('Job completed', 'pewit-ai-image-optimizer');
            $job['updated_at'] = current_time('mysql');
            self::add_log($job, 'info', __('Job completed', 'pewit-ai-image-optimizer'));
            self::save_job($job);
            AIIO_Job_Notify::maybe_send($job);
        }
    }

    public static function cancel_job() {
        $job = self::get_job();
        if (empty($job)) {
            return false;
        }
        $job['status'] = 'cancelled';
        $job['message'] = __('Job cancelled', 'pewit-ai-image-optimizer');
        $job['updated_at'] = current_time('mysql');
        self::add_log($job, 'warn', __('Job cancelled by user', 'pewit-ai-image-optimizer'));
        self::save_job($job);
        wp_clear_scheduled_hook(self::CRON_HOOK);
        return true;
    }

    public static function get_job() {
        $job = get_option(self::option_key(), []);
        return is_array($job) ? $job : [];
    }

    public static function clear_job() {
        delete_option(self::option_key());
        wp_clear_scheduled_hook(self::CRON_HOOK);
    }

    private static function save_job($job) {
        update_option(self::option_key(), $job, false);
    }

    private static function add_log(&$job, $level, $message, $data = []) {
        if (empty($job['log']) || !is_array($job['log'])) {
            $job['log'] = [];
        }
        $job['log'][] = [
            'ts' => time(),
            'time' => current_time('mysql'),
            'level' => sanitize_key($level),
            'message' => wp_strip_all_tags((string) $message),
            'data' => is_array($data) ? $data : [],
        ];
        if (count($job['log']) > 200) {
            $job['log'] = array_slice($job['log'], -200);
        }
    }
}
