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

if (!class_exists('VMO_Project_Media_Queue')) {
    class VMO_Project_Media_Queue {
        const META_QUEUE = '_vmo_project_media_queue';
        const META_TOKEN = '_vmo_project_media_queue_token';
        const PROCESS_HOOK = 'vmo_process_project_media_queue_event';
        const LOCK_PREFIX = 'vmo_project_media_queue_lock_';

        public function __construct() {
            add_action('wp_ajax_vmo_queue_project_media', array($this, 'ajax_queue_project_media'));
            add_action('wp_ajax_vmo_get_project_media_queue', array($this, 'ajax_get_project_media_queue'));
            add_action('wp_ajax_vmo_process_project_media_queue', array($this, 'ajax_process_project_media_queue'));
            add_action('wp_ajax_nopriv_vmo_process_project_media_queue', array($this, 'ajax_process_project_media_queue'));
            add_action(self::PROCESS_HOOK, array($this, 'process_project_media_queue_event'));
        }

        public function ajax_queue_project_media() {
            check_ajax_referer('vmo_builder_nonce', 'security');

            if (!is_user_logged_in()) {
                wp_send_json_error(array('message' => 'Not logged in.'), 403);
            }

            $post_id = $this->resolve_post_id($_POST);
            $post = $this->get_editable_post($post_id, get_current_user_id());
            if (!$post) {
                wp_send_json_error(array('message' => 'A saved project or draft is required before queueing media.'), 404);
            }

            $targets = $this->decode_targets($_POST['targets'] ?? '');
            $queue = $this->merge_targets_into_queue($post, $targets);
            $this->save_queue($post->ID, $queue);

            if (!empty($queue['items'])) {
                $this->dispatch_async($post->ID);
                $this->schedule_fallback($post->ID);
            }

            wp_send_json_success($this->prepare_queue_response($queue));
        }

        public function ajax_get_project_media_queue() {
            check_ajax_referer('vmo_builder_nonce', 'security');

            if (!is_user_logged_in()) {
                wp_send_json_error(array('message' => 'Not logged in.'), 403);
            }

            $post_id = $this->resolve_post_id($_POST);
            $post = $this->get_editable_post($post_id, get_current_user_id());
            if (!$post) {
                wp_send_json_error(array('message' => 'Project not found.'), 404);
            }

            $queue = $this->get_queue($post->ID);
            if ($queue && $this->queue_has_pending_work($queue)) {
                $this->dispatch_async($post->ID);
                $this->schedule_fallback($post->ID);
            }

            wp_send_json_success($this->prepare_queue_response($queue ?: $this->empty_queue($post->ID, $post->post_author)));
        }

        public function ajax_process_project_media_queue() {
            $post_id = $this->resolve_post_id($_REQUEST);
            if (!$post_id) {
                wp_send_json_error(array('message' => 'Project ID required.'), 400);
            }

            if (!$this->authorize_process_request($post_id, $_REQUEST['token'] ?? '')) {
                wp_send_json_error(array('message' => 'Unauthorized queue request.'), 403);
            }

            $queue = $this->process_queue($post_id);
            if (is_wp_error($queue)) {
                wp_send_json_error(array('message' => $queue->get_error_message()), 500);
            }

            wp_send_json_success($this->prepare_queue_response($queue));
        }

        public function process_project_media_queue_event($post_id) {
            $this->process_queue(intval($post_id));
        }

        protected function process_queue($post_id) {
            $post_id = intval($post_id);
            if (!$post_id) {
                return new WP_Error('missing_post', 'Project ID is required.');
            }

            if (!$this->acquire_lock($post_id)) {
                return $this->get_queue($post_id) ?: $this->empty_queue($post_id, 0);
            }

            try {
                $post = get_post($post_id);
                if (!$post) {
                    return new WP_Error('missing_post', 'Project not found.');
                }

                $queue = $this->get_queue($post_id);
                if (!$queue) {
                    return $this->empty_queue($post_id, intval($post->post_author));
                }

                $item_index = $this->find_next_item_index($queue);
                if ($item_index === -1) {
                    $this->refresh_queue($queue);
                    $this->save_queue($post_id, $queue);
                    if (!$this->queue_has_pending_work($queue) && !empty($queue['counts']['total'])) {
                        $this->refresh_publish_readiness($post);
                    }
                    return $queue;
                }

                $item = $queue['items'][$item_index];
                $processed_item = $this->process_item($post, $item);
                $queue['items'][$item_index] = $processed_item;

                if (!empty($processed_item['status']) && $processed_item['status'] === 'complete' && !empty($processed_item['url'])) {
                    $this->apply_item_to_post($post, $processed_item);
                }

                $this->refresh_queue($queue);
                $this->save_queue($post_id, $queue);

                if ($this->queue_has_pending_work($queue)) {
                    $this->dispatch_async($post_id);
                    $this->schedule_fallback($post_id);
                } else {
                    $this->refresh_publish_readiness($post);
                }

                return $queue;
            } finally {
                $this->release_lock($post_id);
            }
        }

        protected function process_item($post, $item) {
            $item['updated_at'] = current_time('mysql');
            $item['attempts'] = intval($item['attempts'] ?? 0) + 1;
            $item['error'] = '';

            if (($item['type'] ?? '') === 'video') {
                return $this->process_video_item($post, $item);
            }

            return $this->process_image_item($post, $item);
        }

        protected function process_image_item($post, $item) {
            $item['status'] = 'processing';

            $result = function_exists('vmo_generate_image_asset')
                ? vmo_generate_image_asset(array(
                    'user_id' => intval($post->post_author),
                    'desc' => $item['prompt'] ?? '',
                    'position' => 'auto',
                    'size' => '1024x1024',
                    'section' => 'website-content',
                    'project_id' => intval($post->ID),
                    'charge_tokens' => empty($item['tokens_charged']),
                    'require_consultation' => true,
                ))
                : array('error' => 'Image helper is unavailable.');

            if (!empty($result['error'])) {
                $item['status'] = 'failed';
                $item['error'] = $result['error'];
                return $item;
            }

            $item['status'] = 'complete';
            $item['url'] = esc_url_raw($result['url'] ?? '');
            $item['attachment_id'] = intval($result['attachment_id'] ?? 0);
            $item['tokens_charged'] = true;
            $item['completed_at'] = current_time('mysql');

            return $item;
        }

        protected function process_video_item($post, $item) {
            $generator = $this->get_video_generator();
            if (!$generator) {
                $item['status'] = 'failed';
                $item['error'] = 'Video generator is unavailable.';
                return $item;
            }

            $model = sanitize_text_field($item['model'] ?? 'sora-2');
            $seconds = sanitize_text_field($item['seconds'] ?? '4');
            $size = sanitize_text_field($item['size'] ?? '1280x720');
            $user_id = intval($post->post_author);

            if (empty($item['remote_job_id'])) {
                $token_cost = class_exists('VMO_Sora_Video_Generator')
                    ? VMO_Sora_Video_Generator::get_token_cost($model, $seconds)
                    : 25200;

                if (empty($item['tokens_charged']) && function_exists('vmo_deduct_tokens')) {
                    if (!vmo_deduct_tokens($user_id, $token_cost, 'sora_video', 'Queued Sora video generation')) {
                        $item['status'] = 'failed';
                        $item['error'] = 'Insufficient tokens for video generation.';
                        return $item;
                    }
                    $item['tokens_charged'] = true;
                    $item['token_cost'] = $token_cost;
                }

                $result = $generator->generate_video($item['prompt'] ?? '', array(
                    'model' => $model,
                    'seconds' => $seconds,
                    'size' => $size,
                ));

                if (!empty($result['error'])) {
                    $this->refund_video_tokens($user_id, $item);
                    $item['status'] = 'failed';
                    $item['error'] = $result['error'];
                    return $item;
                }

                $item['status'] = 'processing';
                $item['remote_job_id'] = sanitize_text_field($result['video_id'] ?? '');
                $item['progress'] = intval($result['progress'] ?? 0);
                $item['started_at'] = current_time('mysql');
                return $item;
            }

            $status = $generator->get_video_status($item['remote_job_id']);
            if (!empty($status['error'])) {
                $item['status'] = 'processing';
                $item['error'] = '';
                return $item;
            }

            $normalized = strtolower($status['status'] ?? '');
            $item['progress'] = intval($status['progress'] ?? 0);
            $item['status_text'] = $normalized;

            if ($normalized === 'completed' || $normalized === 'succeeded') {
                $download = $generator->download_and_save_video(
                    $item['remote_job_id'],
                    $user_id,
                    'VMO Website Video',
                    array(
                        'video_type' => 'website_background',
                        'prompt' => $item['prompt'] ?? '',
                        'project_id' => intval($post->ID),
                    )
                );

                if (!empty($download['error'])) {
                    $item['status'] = 'failed';
                    $item['error'] = $download['error'];
                    return $item;
                }

                $item['status'] = 'complete';
                $item['url'] = esc_url_raw($download['url'] ?? '');
                $item['attachment_id'] = intval($download['attachment_id'] ?? 0);
                $item['completed_at'] = current_time('mysql');
                return $item;
            }

            if ($normalized === 'failed' || $normalized === 'error') {
                $this->refund_video_tokens($user_id, $item);
                $item['status'] = 'failed';
                $item['error'] = is_array($status['error'] ?? null)
                    ? sanitize_text_field($status['error']['message'] ?? 'Video generation failed.')
                    : sanitize_text_field($status['error'] ?? 'Video generation failed.');
                return $item;
            }

            $item['status'] = 'processing';
            return $item;
        }

        protected function refund_video_tokens($user_id, &$item) {
            if (empty($item['tokens_charged']) || !empty($item['tokens_refunded']) || !function_exists('vmo_add_tokens')) {
                return;
            }

            $amount = intval($item['token_cost'] ?? 0);
            if ($amount > 0) {
                vmo_add_tokens($user_id, $amount, 'sora_refund', 'Queued video generation failed - refund');
                $item['tokens_refunded'] = true;
            }
        }

        protected function apply_item_to_post($post, $item) {
            $updated_post_html = $this->apply_media_to_markup((string) $post->post_content, $item);
            if ($updated_post_html !== (string) $post->post_content) {
                wp_update_post(array(
                    'ID' => intval($post->ID),
                    'post_content' => $updated_post_html,
                ));
                $post->post_content = $updated_post_html;
            }

            $updated_state = null;
            $state_json = get_post_meta($post->ID, 'vmo_state', true);
            if ($state_json) {
                $state = json_decode($state_json, true);
                if (is_array($state)) {
                    $updated_state = $this->apply_item_to_state($state, $item);
                    update_post_meta($post->ID, 'vmo_state', wp_json_encode($updated_state));
                }
            }

            $updated_pages_map = null;
            $pages_map = json_decode((string) get_post_meta($post->ID, 'vmo_pages_map', true), true);
            if (is_array($pages_map)) {
                $updated_pages_map = $this->apply_item_to_pages_map($pages_map, $item);
                update_post_meta($post->ID, 'vmo_pages_map', wp_json_encode($updated_pages_map));
            }

            update_post_meta($post->ID, 'vmo_last_updated', current_time('mysql'));

            if ($post->post_type === 'vmo_project') {
                $this->sync_project_row($post, $updated_post_html);
            }

            $this->sync_consultation_website_data($post, $updated_post_html, $updated_state, $updated_pages_map);
        }

        protected function sync_project_row($post, $html) {
            global $wpdb;

            $table_name = $wpdb->prefix . 'vmo_projects';
            $state_json = get_post_meta($post->ID, 'vmo_state', true);
            $chat = get_post_meta($post->ID, 'vmo_chat', true);
            $images = get_post_meta($post->ID, 'vmo_images', true);

            $data = array(
                'html' => $html,
                'state_json' => $state_json,
                'chat' => $chat,
                'images' => maybe_serialize($images),
                'updated_at' => current_time('mysql'),
            );

            $wpdb->update(
                $table_name,
                $data,
                array(
                    'user_id' => intval($post->post_author),
                    'project_title' => $post->post_title,
                )
            );
        }

        protected function apply_item_to_state($state, $item) {
            if (empty($state['blocks']) || !is_array($state['blocks'])) {
                return $state;
            }

            foreach ($state['blocks'] as $index => $block) {
                if (empty($block['html'])) {
                    continue;
                }

                $state['blocks'][$index]['html'] = $this->apply_media_to_markup($block['html'], $item);
            }

            return $state;
        }

        protected function apply_item_to_pages_map($pages_map, $item) {
            foreach ($pages_map as $page_key => $page_value) {
                if (is_string($page_value)) {
                    $pages_map[$page_key] = $this->apply_media_to_markup($page_value, $item);
                    continue;
                }

                if (!is_array($page_value)) {
                    continue;
                }

                if (!empty($page_value['html']) && is_string($page_value['html'])) {
                    $page_value['html'] = $this->apply_media_to_markup($page_value['html'], $item);
                }

                if (!empty($page_value['content']) && is_string($page_value['content'])) {
                    $page_value['content'] = $this->apply_media_to_markup($page_value['content'], $item);
                }

                $pages_map[$page_key] = $page_value;
            }

            return $pages_map;
        }

        protected function sync_consultation_website_data($post, $homepage_html, $builder_state = null, $pages_map = null, $qa_report = null) {
            $session_id = (string) get_post_meta($post->ID, 'vmo_session_id', true);
            if ($session_id === '') {
                return;
            }

            if (!class_exists('VMO_Consultation_Database')) {
                $db_file = plugin_dir_path(__FILE__) . 'class-vmo-consultation-database.php';
                if (file_exists($db_file)) {
                    require_once $db_file;
                }
            }

            if (!class_exists('VMO_Consultation_Database')) {
                return;
            }

            $db = new VMO_Consultation_Database();
            $existing = $db->get_consultation_by_session($session_id);
            if (!$existing) {
                return;
            }

            $website_data = json_decode((string) ($existing->website_data ?? '{}'), true);
            if (!is_array($website_data)) {
                $website_data = array();
            }

            $website_data['draft_post_id'] = intval($post->ID);
            $website_data['preview_url'] = get_preview_post_link($post->ID);
            $website_data['homepage_html'] = is_string($homepage_html) ? $homepage_html : (string) $post->post_content;

            if (is_array($builder_state)) {
                $website_data['builder_state'] = $builder_state;
            }

            if (is_array($pages_map)) {
                $website_data['pages_map'] = $pages_map;
            }

            if (is_array($qa_report)) {
                $website_data['qa_report'] = $qa_report;
                $website_data['publish_ready'] = !empty($qa_report['publish_ready']);
            }

            $db->save_consultation((int) $post->post_author, $session_id, array(
                'website_data' => wp_json_encode($website_data),
            ));
        }

        protected function refresh_publish_readiness($post) {
            if (!$post || intval($post->ID) <= 0 || $post->post_type !== 'vmo_project') {
                return;
            }

            $session_id = (string) get_post_meta($post->ID, 'vmo_session_id', true);
            $user_id = intval($post->post_author);
            if ($session_id === '' || $user_id <= 0) {
                return;
            }

            $pages_map = json_decode((string) get_post_meta($post->ID, 'vmo_pages_map', true), true);
            $business_package = json_decode((string) get_post_meta($post->ID, 'vmo_business_package', true), true);
            if (!is_array($pages_map)) {
                $pages_map = array();
            }
            if (!is_array($business_package)) {
                $business_package = array();
            }

            $website_payload = array(
                'content' => (string) $post->post_content,
                'homepage_html' => (string) $post->post_content,
                'pages_map' => $pages_map,
            );

            $qa_context = array(
                'related_post_id' => intval($post->ID),
                'draft_key' => (string) $post->ID,
            );

            $qa_report = array();
            if (function_exists('vmo_get_agent_orchestrator')) {
                $qa_report = vmo_get_agent_orchestrator()->run_website_qa($user_id, $session_id, $website_payload, $business_package, $qa_context);
            } elseif (function_exists('vmo_get_website_qa_service')) {
                $qa_report = vmo_get_website_qa_service()->run_qa($user_id, $session_id, $website_payload, $business_package, $qa_context);
            }

            if (!is_array($qa_report) || empty($qa_report)) {
                return;
            }

            $publish_ready = !empty($qa_report['publish_ready']);
            update_post_meta($post->ID, 'vmo_publish_ready', $publish_ready ? 'yes' : 'no');
            update_post_meta($post->ID, 'vmo_ready_to_publish', $publish_ready ? 'yes' : 'no');
            update_post_meta($post->ID, 'vmo_publish_checklist', wp_json_encode($qa_report['checklist'] ?? array()));
            update_post_meta($post->ID, 'vmo_website_qa_report', wp_json_encode($qa_report));

            $state = json_decode((string) get_post_meta($post->ID, 'vmo_state', true), true);
            if (!is_array($state)) {
                $state = null;
            }

            $this->sync_consultation_website_data($post, (string) $post->post_content, $state, $pages_map, $qa_report);
        }

        protected function apply_media_to_markup($html, $item) {
            $markup = is_string($html) ? $html : '';
            if ($markup === '') {
                return $markup;
            }

            libxml_use_internal_errors(true);

            $doc = new DOMDocument('1.0', 'UTF-8');
            $wrapped_html = '<!DOCTYPE html><html><body><div id="vmo-queue-root">' . $markup . '</div></body></html>';
            $load_result = $doc->loadHTML(mb_convert_encoding($wrapped_html, 'HTML-ENTITIES', 'UTF-8'));

            if (!$load_result) {
                libxml_clear_errors();
                return $markup;
            }

            $xpath = new DOMXPath($doc);
            $root_nodes = $xpath->query('//*[@id="vmo-queue-root"]');
            if (!$root_nodes || !$root_nodes->length) {
                libxml_clear_errors();
                return $markup;
            }

            $nodes = $this->find_target_nodes($xpath, $item);
            if (!$nodes || !$nodes->length) {
                libxml_clear_errors();
                return $markup;
            }

            foreach ($nodes as $node) {
                $this->apply_to_dom_node($doc, $node, $item);
            }

            $result = $this->inner_html($root_nodes->item(0));
            libxml_clear_errors();
            return $result ?: $markup;
        }

        protected function find_target_nodes($xpath, $item) {
            $media_id = sanitize_text_field($item['media_id'] ?? '');
            if ($media_id !== '') {
                return $xpath->query('//*[@data-media-id=' . $this->xpath_literal($media_id) . ']');
            }

            $type = sanitize_text_field($item['type'] ?? 'image');
            if ($type === 'video') {
                return $xpath->query('//*[@data-vmo-sora or @data-type="video" or self::video]');
            }

            return $xpath->query('//*[@data-vmo-generate or @data-type="image" or self::img]');
        }

        protected function apply_to_dom_node($doc, $node, $item) {
            $type = sanitize_text_field($item['type'] ?? 'image');
            $url = esc_url_raw($item['url'] ?? '');
            if ($url === '') {
                return;
            }

            $tag_name = strtolower($node->nodeName);
            $this->strip_generation_markers($node);

            if ($type === 'image') {
                if ($tag_name === 'img') {
                    $node->setAttribute('src', $url);
                    $node->setAttribute('loading', 'lazy');
                    return;
                }

                $node->setAttribute('data-vmo-generated', 'image');
                $style = trim($node->getAttribute('style'));
                $style .= ($style !== '' ? ';' : '') . 'background-image:url(' . $url . ');background-size:cover;background-position:center;background-repeat:no-repeat;';
                $node->setAttribute('style', $style);
                $this->clear_node_children($node);
                return;
            }

            if ($tag_name === 'video') {
                $node->setAttribute('src', $url);
                $node->setAttribute('autoplay', 'autoplay');
                $node->setAttribute('muted', 'muted');
                $node->setAttribute('loop', 'loop');
                $node->setAttribute('playsinline', 'playsinline');
                $this->clear_node_children($node);
                return;
            }

            $replacement = $doc->createElement('video');
            $replacement->setAttribute('src', $url);
            $replacement->setAttribute('autoplay', 'autoplay');
            $replacement->setAttribute('muted', 'muted');
            $replacement->setAttribute('loop', 'loop');
            $replacement->setAttribute('playsinline', 'playsinline');
            $replacement->setAttribute('data-type', 'video');

            if ($node->attributes) {
                foreach ($node->attributes as $attribute) {
                    if (!$attribute) continue;
                    if (strpos($attribute->nodeName, 'data-vmo-') === 0) continue;
                    if ($attribute->nodeName === 'data-type') continue;
                    $replacement->setAttribute($attribute->nodeName, $attribute->nodeValue);
                }
            }

            $style = trim($replacement->getAttribute('style'));
            $style .= ($style !== '' ? ';' : '') . 'width:100%;height:100%;object-fit:cover;display:block;';
            $replacement->setAttribute('style', $style);
            $node->parentNode->replaceChild($replacement, $node);
        }

        protected function strip_generation_markers($node) {
            $attributes = array('data-vmo-generate', 'data-vmo-prompt', 'data-vmo-sora', 'data-vmo-sora-prompt');
            foreach ($attributes as $attribute) {
                if ($node->hasAttribute($attribute)) {
                    $node->removeAttribute($attribute);
                }
            }
        }

        protected function clear_node_children($node) {
            while ($node->firstChild) {
                $node->removeChild($node->firstChild);
            }
        }

        protected function inner_html($node) {
            $html = '';
            foreach ($node->childNodes as $child) {
                $html .= $node->ownerDocument->saveHTML($child);
            }
            return $html;
        }

        protected function xpath_literal($value) {
            if (strpos($value, "'") === false) {
                return "'" . $value . "'";
            }

            if (strpos($value, '"') === false) {
                return '"' . $value . '"';
            }

            $parts = explode("'", $value);
            return "concat('" . implode("', \"'\", '", $parts) . "')";
        }

        protected function decode_targets($raw_targets) {
            if (is_array($raw_targets)) {
                return $raw_targets;
            }

            if (!is_string($raw_targets) || $raw_targets === '') {
                return array();
            }

            $decoded = json_decode(wp_unslash($raw_targets), true);
            return is_array($decoded) ? $decoded : array();
        }

        protected function merge_targets_into_queue($post, $targets) {
            $queue = $this->get_queue($post->ID);
            if (!$queue) {
                $queue = $this->empty_queue($post->ID, intval($post->post_author));
            }

            $normalized_targets = $this->normalize_targets($targets);
            $existing_by_key = array();
            foreach ($queue['items'] as $existing_item) {
                if (!empty($existing_item['key'])) {
                    $existing_by_key[$existing_item['key']] = $existing_item;
                }
            }

            $active_keys = array();
            $merged = array();

            foreach ($normalized_targets as $target) {
                $key = $target['key'];
                $active_keys[$key] = true;
                if (isset($existing_by_key[$key])) {
                    $merged[] = array_merge($existing_by_key[$key], $target, array('active' => true));
                    continue;
                }

                $merged[] = $target;
            }

            foreach ($queue['items'] as $existing_item) {
                $key = $existing_item['key'] ?? '';
                if ($key === '' || isset($active_keys[$key])) {
                    continue;
                }

                if (($existing_item['status'] ?? '') === 'processing') {
                    $existing_item['active'] = false;
                    $merged[] = $existing_item;
                    continue;
                }

                $existing_item['status'] = 'superseded';
                $existing_item['active'] = false;
                $merged[] = $existing_item;
            }

            $queue['items'] = $merged;
            $queue['post_id'] = intval($post->ID);
            $queue['user_id'] = intval($post->post_author);
            $queue['post_type'] = sanitize_key($post->post_type);
            $queue['token'] = $this->get_or_create_queue_token($post->ID);
            $queue['last_dispatch_at'] = current_time('mysql');

            $this->refresh_queue($queue);
            return $queue;
        }

        protected function normalize_targets($targets) {
            $normalized = array();

            foreach ((array) $targets as $index => $target) {
                if (!is_array($target)) {
                    continue;
                }

                $type = sanitize_text_field($target['type'] ?? 'image');
                if ($type !== 'video') {
                    $type = 'image';
                }

                $prompt = sanitize_textarea_field($target['prompt'] ?? '');
                if ($prompt === '') {
                    continue;
                }

                $media_id = sanitize_text_field($target['mediaId'] ?? ($target['media_id'] ?? ''));
                $key = $media_id !== ''
                    ? 'media:' . $media_id
                    : 'hash:' . md5($type . '|' . $prompt . '|' . intval($target['blockIndex'] ?? -1) . '|' . $index);

                $normalized[] = array(
                    'key' => $key,
                    'media_id' => $media_id,
                    'type' => $type,
                    'prompt' => $prompt,
                    'label' => sanitize_text_field($target['label'] ?? ucfirst($type)),
                    'block_index' => isset($target['blockIndex']) ? intval($target['blockIndex']) : -1,
                    'source' => sanitize_text_field($target['source'] ?? 'builder'),
                    'model' => sanitize_text_field($target['model'] ?? ($type === 'video' && $index === 0 ? 'sora-2-pro' : 'sora-2')),
                    'seconds' => sanitize_text_field($target['seconds'] ?? '4'),
                    'size' => sanitize_text_field($target['size'] ?? '1280x720'),
                    'queue_position' => isset($target['queuePosition']) ? intval($target['queuePosition']) : $index,
                    'status' => 'pending',
                    'active' => true,
                    'attempts' => 0,
                    'progress' => 0,
                    'remote_job_id' => '',
                    'url' => '',
                    'attachment_id' => 0,
                    'error' => '',
                    'tokens_charged' => false,
                    'tokens_refunded' => false,
                    'created_at' => current_time('mysql'),
                    'updated_at' => current_time('mysql'),
                );
            }

            return $normalized;
        }

        protected function find_next_item_index($queue) {
            $items = isset($queue['items']) && is_array($queue['items']) ? $queue['items'] : array();
            if (!$items) {
                return -1;
            }

            $processing_video_index = -1;
            $pending_index = -1;

            foreach ($items as $index => $item) {
                if (empty($item['active']) && ($item['status'] ?? '') !== 'processing') {
                    continue;
                }

                if (($item['status'] ?? '') === 'processing' && ($item['type'] ?? '') === 'video') {
                    $processing_video_index = $index;
                    break;
                }

                if (($item['status'] ?? '') === 'pending' && $pending_index === -1) {
                    $pending_index = $index;
                }
            }

            if ($processing_video_index !== -1) {
                return $processing_video_index;
            }

            return $pending_index;
        }

        protected function refresh_queue(&$queue) {
            $items = isset($queue['items']) && is_array($queue['items']) ? $queue['items'] : array();
            $active_items = array_filter($items, function($item) {
                return !empty($item['active']);
            });

            $counts = array(
                'total' => count($active_items),
                'pending' => 0,
                'processing' => 0,
                'complete' => 0,
                'failed' => 0,
            );

            foreach ($active_items as $item) {
                $status = $item['status'] ?? 'pending';
                if (isset($counts[$status])) {
                    $counts[$status] += 1;
                }
            }

            if ($counts['pending'] > 0 || $counts['processing'] > 0) {
                $queue['status'] = 'processing';
            } elseif ($counts['failed'] > 0 && $counts['complete'] > 0) {
                $queue['status'] = 'partial';
            } elseif ($counts['failed'] > 0) {
                $queue['status'] = 'failed';
            } else {
                $queue['status'] = 'complete';
            }

            $queue['counts'] = $counts;
            $queue['updated_at'] = current_time('mysql');
        }

        protected function queue_has_pending_work($queue) {
            $counts = $queue['counts'] ?? array();
            return !empty($counts['pending']) || !empty($counts['processing']);
        }

        protected function get_queue($post_id) {
            $queue = get_post_meta($post_id, self::META_QUEUE, true);
            return is_array($queue) ? $queue : null;
        }

        protected function save_queue($post_id, $queue) {
            update_post_meta($post_id, self::META_QUEUE, $queue);
        }

        protected function empty_queue($post_id, $user_id) {
            return array(
                'post_id' => intval($post_id),
                'user_id' => intval($user_id),
                'status' => 'complete',
                'counts' => array(
                    'total' => 0,
                    'pending' => 0,
                    'processing' => 0,
                    'complete' => 0,
                    'failed' => 0,
                ),
                'items' => array(),
                'updated_at' => current_time('mysql'),
            );
        }

        protected function prepare_queue_response($queue) {
            $queue = is_array($queue) ? $queue : $this->empty_queue(0, 0);
            $items = array();
            $post_id = intval($queue['post_id'] ?? 0);
            $qa_report = $post_id ? json_decode((string) get_post_meta($post_id, 'vmo_website_qa_report', true), true) : array();
            if (!is_array($qa_report)) {
                $qa_report = array();
            }

            foreach (($queue['items'] ?? array()) as $item) {
                $items[] = array(
                    'key' => $item['key'] ?? '',
                    'media_id' => $item['media_id'] ?? '',
                    'type' => $item['type'] ?? 'image',
                    'label' => $item['label'] ?? '',
                    'status' => $item['status'] ?? 'pending',
                    'url' => $item['url'] ?? '',
                    'attachment_id' => intval($item['attachment_id'] ?? 0),
                    'error' => $item['error'] ?? '',
                    'progress' => intval($item['progress'] ?? 0),
                    'active' => !empty($item['active']),
                );
            }

            return array(
                'post_id' => $post_id,
                'status' => $queue['status'] ?? 'complete',
                'counts' => $queue['counts'] ?? array(),
                'updated_at' => $queue['updated_at'] ?? '',
                'items' => $items,
                'publish_ready' => $post_id ? get_post_meta($post_id, 'vmo_publish_ready', true) === 'yes' : false,
                'qa_report' => $qa_report,
            );
        }

        protected function resolve_post_id($payload) {
            return intval($payload['project_id'] ?? ($payload['post_id'] ?? 0));
        }

        protected function get_editable_post($post_id, $user_id) {
            $post_id = intval($post_id);
            if (!$post_id || !$user_id) {
                return null;
            }

            $post = get_post($post_id);
            if (!$post) {
                return null;
            }

            if (intval($post->post_author) !== intval($user_id) && !current_user_can('edit_post', $post_id)) {
                return null;
            }

            return $post;
        }

        protected function authorize_process_request($post_id, $token) {
            $post_id = intval($post_id);
            if ($post_id && is_user_logged_in() && current_user_can('edit_post', $post_id)) {
                return true;
            }

            $stored = get_post_meta($post_id, self::META_TOKEN, true);
            $token = sanitize_text_field(wp_unslash($token));

            return $stored && $token && hash_equals($stored, $token);
        }

        protected function get_or_create_queue_token($post_id) {
            $token = get_post_meta($post_id, self::META_TOKEN, true);
            if ($token) {
                return $token;
            }

            $token = wp_generate_password(40, false, false);
            update_post_meta($post_id, self::META_TOKEN, $token);
            return $token;
        }

        protected function dispatch_async($post_id) {
            $token = $this->get_or_create_queue_token($post_id);
            wp_remote_post(admin_url('admin-ajax.php'), array(
                'timeout' => 1,
                'blocking' => false,
                'body' => array(
                    'action' => 'vmo_process_project_media_queue',
                    'post_id' => intval($post_id),
                    'token' => $token,
                ),
            ));
        }

        protected function schedule_fallback($post_id) {
            if (!wp_next_scheduled(self::PROCESS_HOOK, array(intval($post_id)))) {
                wp_schedule_single_event(time() + 60, self::PROCESS_HOOK, array(intval($post_id)));
            }
        }

        protected function acquire_lock($post_id) {
            $key = self::LOCK_PREFIX . intval($post_id);
            if (get_transient($key)) {
                return false;
            }

            set_transient($key, 1, 5 * MINUTE_IN_SECONDS);
            return true;
        }

        protected function release_lock($post_id) {
            delete_transient(self::LOCK_PREFIX . intval($post_id));
        }

        protected function get_video_generator() {
            if (!empty($GLOBALS['vmo_sora_video_generator']) && $GLOBALS['vmo_sora_video_generator'] instanceof VMO_Sora_Video_Generator) {
                return $GLOBALS['vmo_sora_video_generator'];
            }

            return null;
        }
    }
}

if (class_exists('VMO_Project_Media_Queue')) {
    new VMO_Project_Media_Queue();
}