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

class VMO_Website_Media_Manifest {
    private static $instance = null;

    public static function get_instance() {
        if (!self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function build_from_payload($website_payload, array $context = array()) {
        return $this->build_from_html($this->payload_to_html($website_payload), $context);
    }

    public function build_from_html($html, array $context = array()) {
        $html = is_string($html) ? $html : '';
        $html_lower = strtolower($html);
        $required_assets = $this->build_required_assets($context, $html_lower);
        $required_assets = $this->apply_queue_state_to_assets($required_assets, $context);
        $unresolved_images = (int) preg_match_all('/data-vmo-generate\s*=|\[(generated_image):/i', $html);
        $unresolved_videos = (int) preg_match_all('/data-vmo-sora\s*=|\[(generated_video):/i', $html);
        $queueable_placeholders = (int) preg_match_all('/vmo-media-placeholder|data-vmo-generate|data-vmo-sora/i', $html);
        $image_tags = (int) preg_match_all('/<img\b/i', $html);
        $video_tags = (int) preg_match_all('/<video\b|<iframe\b/i', $html);
        $images_with_alt = (int) preg_match_all('/<img\b[^>]*\balt\s*=\s*["\'][^"\']+["\']/i', $html);
        $resolved_visual_assets = $image_tags + $video_tags;
        $minimum_assets = max(1, min(4, count($required_assets)));
        $media_floor_met = $resolved_visual_assets >= $minimum_assets;
        $uploaded_media_contract = $this->uploaded_media_contract($context);
        $media_complete = ($unresolved_images + $unresolved_videos + $queueable_placeholders) === 0 && $media_floor_met && empty($uploaded_media_contract['blocking_issues']);

        return array(
            'manifest_version' => 'v2.0-2026-04-30',
            'must_generate_before_preview' => true,
            'media_complete' => $media_complete,
            'media_floor_met' => $media_floor_met,
            'unresolved_image_markers' => $unresolved_images,
            'unresolved_video_markers' => $unresolved_videos,
            'queueable_placeholders' => $queueable_placeholders,
            'resolved_image_tags' => $image_tags,
            'resolved_video_tags' => $video_tags,
            'resolved_visual_assets' => $resolved_visual_assets,
            'images_with_alt_text' => $images_with_alt,
            'alt_text_complete' => $image_tags === 0 || $images_with_alt >= $image_tags,
            'uploaded_media_count' => $uploaded_media_contract['uploaded_media_count'],
            'unassigned_uploaded_media_count' => $uploaded_media_contract['unassigned_uploaded_media_count'],
            'quality_issues' => $uploaded_media_contract['quality_issues'],
            'strict_media_completion_contract' => array(
                'logo_ready' => $uploaded_media_contract['logo_ready'],
                'hero_media_ready' => $uploaded_media_contract['hero_media_ready'],
                'mobile_fallbacks_ready' => $uploaded_media_contract['mobile_fallbacks_ready'],
                'service_media_ready' => $uploaded_media_contract['service_media_ready'],
                'product_media_ready' => $uploaded_media_contract['product_media_ready'],
                'video_posters_ready' => $uploaded_media_contract['video_posters_ready'],
                'missing_media_count' => $unresolved_images + $unresolved_videos + $queueable_placeholders,
                'unassigned_uploaded_media_count' => $uploaded_media_contract['unassigned_uploaded_media_count'],
                'placeholder_count' => $queueable_placeholders,
                'quality_issues' => $uploaded_media_contract['quality_issues'],
            ),
            'desktop_mobile_variants_required' => true,
            'poster_frames_required' => $video_tags > 0 || $this->context_wants_video($context),
            'placement_map_required' => true,
            'required_assets' => $required_assets,
            'placement_map' => $this->build_placement_map($required_assets),
            'readiness' => array(
                'preview_blocked' => !$media_complete,
                'reason' => $media_complete ? 'All required media checks passed.' : 'Required media is incomplete or unresolved generation markers remain.',
            ),
        );
    }

    private function uploaded_media_contract(array $context) {
        $media_assets = is_array($context['media_assets'] ?? null) ? $context['media_assets'] : array();
        $contract = array(
            'uploaded_media_count' => 0,
            'unassigned_uploaded_media_count' => 0,
            'quality_issues' => array(),
            'blocking_issues' => array(),
            'logo_ready' => true,
            'hero_media_ready' => true,
            'mobile_fallbacks_ready' => true,
            'service_media_ready' => true,
            'product_media_ready' => true,
            'video_posters_ready' => true,
        );

        if (!$media_assets) {
            return $contract;
        }

        $role_counts = array();
        $blocked_roles = array();
        foreach ($media_assets as $asset) {
            if (!is_array($asset)) {
                continue;
            }

            $media_type = sanitize_key((string) ($asset['type'] ?? $asset['media_type'] ?? ''));
            if (!in_array($media_type, array('image', 'video'), true)) {
                continue;
            }

            $contract['uploaded_media_count']++;
            $roles = is_array($asset['roles'] ?? null) ? $asset['roles'] : array($asset['usage_context'] ?? '', $asset['business_role'] ?? '', $asset['placement_role'] ?? '');
            $roles = array_values(array_unique(array_filter(array_map('sanitize_key', array_map('strval', $roles)))));
            foreach ($roles as $role) {
                $role_counts[$role] = ($role_counts[$role] ?? 0) + 1;
            }

            $unassigned = !empty($asset['unassigned']) || in_array('unassigned_media', $roles, true) || (($asset['classification_confidence'] ?? '') === 'low');
            if ($unassigned) {
                $contract['unassigned_uploaded_media_count']++;
                foreach ($roles as $role) {
                    $blocked_roles[$role] = true;
                }
                $contract['blocking_issues'][] = array(
                    'type' => 'unassigned_uploaded_media',
                    'media_id' => intval($asset['id'] ?? 0),
                    'title' => sanitize_text_field((string) ($asset['title'] ?? 'Uploaded media')),
                );
            }

            $quality_status = sanitize_key((string) ($asset['quality_status'] ?? ''));
            if (in_array($quality_status, array('rejected', 'failed', 'needs_replacement', 'blocked'), true)) {
                foreach ($roles as $role) {
                    $blocked_roles[$role] = true;
                }
                $issue = array(
                    'type' => 'quality_status',
                    'status' => $quality_status,
                    'media_id' => intval($asset['id'] ?? 0),
                    'title' => sanitize_text_field((string) ($asset['title'] ?? 'Uploaded media')),
                );
                $contract['quality_issues'][] = $issue;
                $contract['blocking_issues'][] = $issue;
            }
        }

        $contract['logo_ready'] = empty($blocked_roles['logo']);
        $contract['hero_media_ready'] = empty($blocked_roles['hero_image']) && empty($blocked_roles['hero_video']) && empty($blocked_roles['page_hero_image']);
        $contract['mobile_fallbacks_ready'] = empty($blocked_roles['mobile_fallback_image']) && empty($blocked_roles['mobile_variant']);
        $contract['service_media_ready'] = empty($blocked_roles['service_media']) && empty($blocked_roles['service_image']);
        $contract['product_media_ready'] = $contract['unassigned_uploaded_media_count'] === 0 && empty($blocked_roles['product_media']) && empty($blocked_roles['product_card_image']) && empty($blocked_roles['product_hero_image']);
        $contract['video_posters_ready'] = empty($role_counts['product_video']) || !empty($role_counts['video_poster']);
        if (!$contract['video_posters_ready']) {
            $contract['blocking_issues'][] = array(
                'type' => 'missing_video_poster',
                'title' => 'Product video poster image is required before preview release.',
            );
        }

        return $contract;
    }

    private function payload_to_html($website_payload) {
        if (is_string($website_payload)) {
            return $website_payload;
        }
        if (!is_array($website_payload)) {
            return '';
        }

        $html = '';
        foreach (array('content', 'homepage_html', 'website_code') as $key) {
            if (!empty($website_payload[$key]) && is_string($website_payload[$key])) {
                $html .= "\n" . $website_payload[$key];
            }
        }
        foreach (array('pages_map', 'pages', 'pages_generated') as $key) {
            if (!is_array($website_payload[$key] ?? null)) {
                continue;
            }
            foreach ($website_payload[$key] as $page) {
                if (is_string($page)) {
                    $html .= "\n" . $page;
                } elseif (is_array($page)) {
                    $html .= "\n" . (string) ($page['html'] ?? $page['content'] ?? '');
                }
            }
        }
        return $html;
    }

    private function build_required_assets(array $context, $html_lower) {
        $preset = sanitize_key((string) ($context['selected_visual_preset'] ?? $context['visual_preset'] ?? $context['canonical_generation_context']['selected_visual_preset'] ?? ''));
        $serialized = strtolower(wp_json_encode($context) . ' ' . $html_lower . ' ' . $preset);
        $assets = array(
            $this->asset('hero_primary_visual', 'image_or_video', 'hero', 'Hero focal media that makes the business immediately inspectable.', 'desktop_hero'),
            $this->asset('mobile_hero_fallback', 'image', 'hero', 'Mobile-specific hero crop or poster fallback.', 'mobile_hero'),
        );
        if (preg_match('/video|sora|motion|cinematic|scroll_synced|transparent_subject|multi_layer/', $serialized)) {
            $assets[] = $this->asset('hero_video_loop_or_poster', 'video_or_poster', 'hero', 'Short loop or poster frame for cinematic hero treatment.', 'desktop_hero_background');
        }
        if (preg_match('/ecommerce|product|shop|store|cart|checkout|wine|fashion|food_order|buy/', $serialized)) {
            $assets[] = $this->asset('product_story_visuals', 'image_set', 'product', 'Inspectable product/detail images for ecommerce storytelling.', 'product_sections');
        }
        $assets = array_merge($assets, $this->product_media_packet_assets($context));
        if (preg_match('/restaurant|food|cafe|bakery|bar|catering|menu|reservation/', $serialized)) {
            $assets[] = $this->asset('appetite_food_visuals', 'image_set', 'food', 'Appetite-focused food/menu visuals for order or reservation flow.', 'menu_sections');
        }
        if (preg_match('/glass|overlay|parallax|atmospheric|steam|smoke|fog|particles|light leaks/', $serialized)) {
            $assets[] = $this->asset('atmospheric_overlay_layer', 'image_or_video', 'overlay', 'Transparent or subtle atmosphere layer for premium depth.', 'hero_overlay');
        }
        return $assets;
    }

    private function product_media_packet_assets(array $context) {
        $packet_summary = $this->product_packet_summary_from_context($context);
        $products = is_array($packet_summary['products'] ?? null) ? $packet_summary['products'] : array();
        $assets = array();

        foreach ($products as $product_packet) {
            if (!is_array($product_packet)) {
                continue;
            }
            $media_packet = is_array($product_packet['media_packet'] ?? null) ? $product_packet['media_packet'] : array();
            $packet_assets = is_array($media_packet['assets'] ?? null) ? $media_packet['assets'] : array();
            foreach ($packet_assets as $role => $packet_asset) {
                if (!is_array($packet_asset) || empty($packet_asset['required_before_preview'])) {
                    continue;
                }
                if (!empty($packet_asset['url']) && filter_var($packet_asset['url'], FILTER_VALIDATE_URL)) {
                    continue;
                }
                $asset_id = sanitize_key((string) ($packet_asset['manifest_asset_id'] ?? ''));
                if ($asset_id === '') {
                    $asset_id = sanitize_key('product_' . ($product_packet['slug'] ?? md5(wp_json_encode($packet_asset))) . '_' . $role);
                }
                $asset = $this->asset(
                    $asset_id,
                    'image',
                    'product_media_packet',
                    sanitize_text_field((string) ($packet_asset['alt_text'] ?? $product_packet['title'] ?? 'Required product media')),
                    sanitize_key((string) ($packet_asset['placement'] ?? $role))
                );
                $asset['prompt'] = sanitize_textarea_field((string) ($packet_asset['prompt'] ?? $asset['purpose']));
                $asset['alt_text'] = sanitize_text_field((string) ($packet_asset['alt_text'] ?? $asset['purpose']));
                $asset['product_title'] = sanitize_text_field((string) ($packet_asset['product_title'] ?? $product_packet['title'] ?? 'Product'));
                $asset['product_slug'] = sanitize_key((string) ($packet_asset['product_slug'] ?? $product_packet['slug'] ?? 'product'));
                $asset['role'] = sanitize_key((string) ($packet_asset['role'] ?? $role));
                $asset['desktop_variant_required'] = !empty($packet_asset['desktop_variant_required']);
                $asset['mobile_variant_required'] = !empty($packet_asset['mobile_variant_required']);
                $asset['poster_required'] = !empty($packet_asset['poster_required']);
                $asset['status'] = 'needs_generation';
                $assets[] = $asset;
            }
        }

        return $assets;
    }

    private function product_packet_summary_from_context(array $context) {
        $candidates = array(
            $context['product_generation_packets'] ?? null,
            $context['business_data']['ecommerce']['product_generation_packets'] ?? null,
            $context['business_package']['product_generation_packets'] ?? null,
            $context['business_package']['ecommerce']['product_generation_packets'] ?? null,
        );
        foreach ($candidates as $candidate) {
            if (is_array($candidate) && !empty($candidate['products'])) {
                return $candidate;
            }
        }
        return array();
    }

    private function asset($id, $type, $group, $purpose, $placement) {
        return array(
            'id' => $id,
            'type' => $type,
            'group' => $group,
            'purpose' => $purpose,
            'placement' => $placement,
            'required_before_preview' => true,
            'desktop_variant_required' => true,
            'mobile_variant_required' => true,
            'poster_required' => strpos($type, 'video') !== false,
            'alt_text_required' => true,
            'attachment_id' => 0,
            'status' => 'planned_or_resolved_by_queue',
        );
    }

    private function build_placement_map(array $assets) {
        $map = array();
        foreach ($assets as $asset) {
            $map[$asset['id']] = array(
                'placement' => $asset['placement'],
                'group' => $asset['group'],
                'required_before_preview' => !empty($asset['required_before_preview']),
            );
        }
        return $map;
    }

    private function apply_queue_state_to_assets(array $assets, array $context) {
        $queue = is_array($context['queue'] ?? null) ? $context['queue'] : array();
        $items = is_array($queue['items'] ?? null) ? $queue['items'] : array();
        if (!$items) {
            return $assets;
        }

        $items_by_asset = array();
        foreach ($items as $item) {
            if (!is_array($item)) {
                continue;
            }
            $asset_id = sanitize_key((string) ($item['manifest_asset_id'] ?? ''));
            if ($asset_id === '') {
                continue;
            }
            $items_by_asset[$asset_id] = $item;
        }

        foreach ($assets as $index => $asset) {
            $asset_id = sanitize_key((string) ($asset['id'] ?? ''));
            if ($asset_id === '' || empty($items_by_asset[$asset_id])) {
                continue;
            }

            $item = $items_by_asset[$asset_id];
            $assets[$index]['status'] = sanitize_key((string) ($item['status'] ?? 'pending'));
            $assets[$index]['queue_key'] = sanitize_text_field((string) ($item['key'] ?? ''));
            $assets[$index]['attachment_id'] = intval($item['attachment_id'] ?? 0);
            $assets[$index]['url'] = esc_url_raw((string) ($item['url'] ?? ''));
            $assets[$index]['generated_at'] = sanitize_text_field((string) ($item['completed_at'] ?? ''));
        }

        return $assets;
    }

    private function context_wants_video(array $context) {
        return (bool) preg_match('/video|sora|loop|cinematic|motion/i', wp_json_encode($context));
    }
}

if (!function_exists('vmo_get_website_media_manifest_service')) {
    function vmo_get_website_media_manifest_service() {
        return VMO_Website_Media_Manifest::get_instance();
    }
}
