<?php
defined('ABSPATH') || exit;

if (!class_exists('Aiomatic_Super_Page_Component_Registry')) {

class Aiomatic_Super_Page_Component_Registry
{
    protected $components = array();
    protected $aliases = array();

    public function __construct()
    {
        $this->register_defaults();

        $this->components = apply_filters('aimogen_super_page_components', $this->components, $this);
        $this->aliases    = apply_filters('aimogen_super_page_component_aliases', $this->aliases, $this);
    }

    public function register($type, $definition)
    {
        $type = sanitize_key($type);

        if (!$type || !is_array($definition)) {
            return false;
        }

        $defaults = array(
            'label'       => $type,
            'category'    => 'content',
            'description' => '',
            'schema'      => array(
                'component' => $type,
                'attrs'    => array(),
            ),
            'renderer'    => '',
            'requires'    => array(),
            'allow_ai'    => true,
            'safe'        => true,
        );

        $this->components[$type] = wp_parse_args($definition, $defaults);

        return true;
    }

    public function alias($alias, $type)
    {
        $alias = sanitize_key($alias);
        $type  = sanitize_key($type);

        if (!$alias || !$type) {
            return false;
        }

        $this->aliases[$alias] = $type;

        return true;
    }

    public function normalize_type($type)
    {
        $type = sanitize_key($type);

        if (isset($this->components[$type])) {
            return $type;
        }

        if (isset($this->aliases[$type])) {
            return $this->aliases[$type];
        }

        return 'text';
    }

    public function has($type)
    {
        return isset($this->components[$this->normalize_type($type)]);
    }

    public function get($type)
    {
        $type = $this->normalize_type($type);

        return isset($this->components[$type]) ? $this->components[$type] : false;
    }

    public function all()
    {
        return $this->components;
    }

    public function ai_components()
    {
        $out = array();

        foreach ($this->components as $type => $component) {
            if (!empty($component['allow_ai'])) {
                $out[$type] = array(
                    'type'        => $type,
                    'label'       => $component['label'],
                    'category'    => $component['category'],
                    'description' => $component['description'],
                    'schema'      => $component['schema'],
                );
            }
        }

        return $out;
    }

    public function schema($type)
    {
        $component = $this->get($type);

        if (!$component || empty($component['schema'])) {
            return array(
                'component' => 'text',
                'attrs'    => array(
                    'title'   => '',
                    'content' => '',
                ),
            );
        }

        return $component['schema'];
    }

    public function render($component)
    {
        if (!is_array($component)) {
            return '';
        }

        $type = isset($component['component'])
            ? sanitize_key($component['component'])
            : (isset($component['block']) ? sanitize_key($component['block']) : 'text');

        $type = $this->normalize_type($type);
        $def  = $this->get($type);

        if (!$def || empty($def['renderer']) || !is_callable($def['renderer'])) {
            return '';
        }

        $attrs = isset($component['attrs']) && is_array($component['attrs'])
            ? $component['attrs']
            : array();

        return call_user_func($def['renderer'], $attrs, $component, $this);
    }

    protected function register_defaults()
    {
        $this->register('hero', array(
            'label'       => 'Hero',
            'category'    => 'conversion',
            'description' => 'Opening hero section with headline, subheadline, CTA buttons and optional media.',
            'renderer'    => 'aiomatic_super_pages_render_component_hero',
            'schema'      => array(
                'component' => 'hero',
                'attrs' => array(
                    'eyebrow' => '',
                    'headline' => '',
                    'subheadline' => '',
                    'primary_cta' => '',
                    'primary_cta_url' => '#get-started',
                    'secondary_cta' => '',
                    'secondary_cta_url' => '#learn-more',
                    'visual' => array(
                        'generate_image' => true,
                        'image_prompt' => '',
                        'image_style' => '',
                        'image_ratio' => '16:9',
                        'layout' => 'split',
                    ),
                ),
            ),
        ));

        $this->register('section_heading', array(
            'label' => 'Section Heading',
            'category' => 'content',
            'description' => 'Section title, eyebrow and subtitle.',
            'renderer' => 'aiomatic_super_pages_render_component_section_heading',
            'schema' => array(
                'component' => 'section_heading',
                'attrs' => array(
                    'eyebrow' => '',
                    'title' => '',
                    'subtitle' => '',
                    'align' => 'center',
                ),
            ),
        ));

        $this->register('text', array(
            'label' => 'Text',
            'category' => 'content',
            'description' => 'Content section with title and formatted text.',
            'renderer' => 'aiomatic_super_pages_render_component_text',
            'schema' => array(
                'component' => 'text',
                'attrs' => array(
                    'title' => '',
                    'content' => '',
                    'layout' => 'single',
                ),
            ),
        ));

        $this->register('feature_grid', array(
            'label' => 'Feature Grid',
            'category' => 'conversion',
            'description' => 'Grid of benefits, features or value points.',
            'renderer' => 'aiomatic_super_pages_render_component_card_grid',
            'schema' => array(
                'component' => 'feature_grid',
                'attrs' => array(
                    'title' => '',
                    'subtitle' => '',
                    'items' => array(
                        array(
                            'title' => '',
                            'content' => '',
                            'icon' => '',
                            'image_prompt' => '',
                        ),
                    ),
                ),
            ),
        ));

        $this->register('card_grid', array(
            'label' => 'Card Grid',
            'category' => 'content',
            'description' => 'Generic card grid.',
            'renderer' => 'aiomatic_super_pages_render_component_card_grid',
            'schema' => array(
                'component' => 'card_grid',
                'attrs' => array(
                    'title' => '',
                    'subtitle' => '',
                    'items' => array(
                        array('title' => '', 'content' => '', 'icon' => ''),
                    ),
                ),
            ),
        ));

        $this->register('icon_list', array(
            'label' => 'Icon List',
            'category' => 'content',
            'description' => 'List of short points with optional icons.',
            'renderer' => 'aiomatic_super_pages_render_component_icon_list',
            'schema' => array(
                'component' => 'icon_list',
                'attrs' => array(
                    'title' => '',
                    'items' => array(
                        array('icon' => '✓', 'text' => ''),
                    ),
                ),
            ),
        ));

        $this->register('steps', array(
            'label' => 'Steps',
            'category' => 'content',
            'description' => 'Ordered process, timeline or how-it-works section.',
            'renderer' => 'aiomatic_super_pages_render_component_steps',
            'schema' => array(
                'component' => 'steps',
                'attrs' => array(
                    'title' => '',
                    'subtitle' => '',
                    'items' => array(
                        array('title' => '', 'content' => ''),
                    ),
                ),
            ),
        ));

        $this->register('timeline', array(
            'label' => 'Timeline',
            'category' => 'content',
            'description' => 'Chronological timeline section.',
            'renderer' => 'aiomatic_super_pages_render_component_timeline',
            'schema' => array(
                'component' => 'timeline',
                'attrs' => array(
                    'title' => '',
                    'items' => array(
                        array('date' => '', 'title' => '', 'content' => ''),
                    ),
                ),
            ),
        ));

        $this->register('stats', array(
            'label' => 'Stats',
            'category' => 'proof',
            'description' => 'Proof or value metrics. Use only believable or user-provided numbers.',
            'renderer' => 'aiomatic_super_pages_render_component_stats',
            'schema' => array(
                'component' => 'stats',
                'attrs' => array(
                    'title' => '',
                    'items' => array(
                        array('value' => '', 'label' => ''),
                    ),
                ),
            ),
        ));

        $this->register('table_of_contents', array(
            'label' => 'Table of Contents',
            'category' => 'content',
            'description' => 'Editorial navigation list for long posts, guides, and resource pages.',
            'renderer' => 'aiomatic_super_pages_render_component_table_of_contents',
            'schema' => array(
                'component' => 'table_of_contents',
                'attrs' => array(
                    'title' => 'In this guide',
                    'items' => array(
                        array('label' => '', 'target' => ''),
                    ),
                ),
            ),
        ));

        $this->register('editorial_summary', array(
            'label' => 'Editorial Summary',
            'category' => 'content',
            'description' => 'Key takeaways or executive summary for professional posts and guides.',
            'renderer' => 'aiomatic_super_pages_render_component_editorial_summary',
            'schema' => array(
                'component' => 'editorial_summary',
                'attrs' => array(
                    'title' => 'Key Takeaways',
                    'items' => array(''),
                ),
            ),
        ));

        $this->register('logo_cloud', array(
            'label' => 'Logo Cloud',
            'category' => 'proof',
            'description' => 'Trust logo cloud or partner/client mark grid. Use text marks when real logo images are not provided.',
            'renderer' => 'aiomatic_super_pages_render_component_logo_cloud',
            'schema' => array(
                'component' => 'logo_cloud',
                'attrs' => array(
                    'title' => '',
                    'subtitle' => '',
                    'items' => array(
                        array('name' => '', 'tagline' => '', 'image_url' => ''),
                    ),
                ),
            ),
        ));

        $this->register('testimonial_grid', array(
            'label' => 'Testimonials',
            'category' => 'proof',
            'description' => 'Testimonials or review-style proof. Do not invent real people.',
            'renderer' => 'aiomatic_super_pages_render_component_testimonials',
            'schema' => array(
                'component' => 'testimonial_grid',
                'attrs' => array(
                    'title' => '',
                    'subtitle' => '',
                    'items' => array(
                        array('quote' => '', 'name' => '', 'role' => ''),
                    ),
                ),
            ),
        ));

        $this->register('highlight_box', array(
            'label' => 'Highlight Box',
            'category' => 'conversion',
            'description' => 'Callout, trust box, warning, guarantee, note or important proof.',
            'renderer' => 'aiomatic_super_pages_render_component_highlight_box',
            'schema' => array(
                'component' => 'highlight_box',
                'attrs' => array(
                    'title' => '',
                    'content' => '',
                    'variant' => 'default',
                ),
            ),
        ));

        $this->register('comparison_table', array(
            'label' => 'Comparison Table',
            'category' => 'conversion',
            'description' => 'Structured comparison table.',
            'renderer' => 'aiomatic_super_pages_render_component_comparison_table',
            'schema' => array(
                'component' => 'comparison_table',
                'attrs' => array(
                    'title' => '',
                    'columns' => array(),
                    'rows' => array(),
                ),
            ),
        ));

        $this->register('pros_cons', array(
            'label' => 'Pros and Cons',
            'category' => 'conversion',
            'description' => 'Pros and cons section.',
            'renderer' => 'aiomatic_super_pages_render_component_pros_cons',
            'schema' => array(
                'component' => 'pros_cons',
                'attrs' => array(
                    'title' => '',
                    'pros_title' => 'Pros',
                    'cons_title' => 'Cons',
                    'pros' => array(),
                    'cons' => array(),
                ),
            ),
        ));

        $this->register('pricing_cards', array(
            'label' => 'Pricing Cards',
            'category' => 'conversion',
            'description' => 'Pricing table or offer cards.',
            'renderer' => 'aiomatic_super_pages_render_component_pricing_cards',
            'schema' => array(
                'component' => 'pricing_cards',
                'attrs' => array(
                    'title' => '',
                    'subtitle' => '',
                    'items' => array(
                        array('name' => '', 'price' => '', 'features' => array(), 'button' => '', 'button_url' => '#get-started'),
                    ),
                ),
            ),
        ));

        $this->register('faq', array(
            'label' => 'FAQ',
            'category' => 'conversion',
            'description' => 'FAQ accordion.',
            'renderer' => 'aiomatic_super_pages_render_component_faq',
            'schema' => array(
                'component' => 'faq',
                'attrs' => array(
                    'title' => '',
                    'items' => array(
                        array('question' => '', 'answer' => ''),
                    ),
                ),
            ),
        ));

        $this->register('cta_banner', array(
            'label' => 'CTA Banner',
            'category' => 'conversion',
            'description' => 'Conversion call-to-action banner.',
            'renderer' => 'aiomatic_super_pages_render_component_cta_banner',
            'schema' => array(
                'component' => 'cta_banner',
                'attrs' => array(
                    'title' => '',
                    'content' => '',
                    'button' => '',
                    'button_url' => '#get-started',
                    'secondary_button' => '',
                    'secondary_button_url' => '#learn-more',
                ),
            ),
        ));

        $this->register('image_banner', array(
            'label' => 'Image Banner',
            'category' => 'media',
            'description' => 'Image section. Can use uploaded/generated image URL or an AI image prompt.',
            'renderer' => 'aiomatic_super_pages_render_component_image_banner',
            'schema' => array(
                'component' => 'image_banner',
                'attrs' => array(
                    'title' => '',
                    'content' => '',
                    'image_url' => '',
                    'image_prompt' => '',
                    'alt' => '',
                    'layout' => 'wide',
                ),
            ),
        ));

        $this->register('video_embed', array(
            'label' => 'Video Embed',
            'category' => 'media',
            'description' => 'Video embed from YouTube, Vimeo, Loom or a direct video URL.',
            'renderer' => 'aiomatic_super_pages_render_component_video_embed',
            'schema' => array(
                'component' => 'video_embed',
                'attrs' => array(
                    'title' => '',
                    'content' => '',
                    'url' => '',
                    'embed_html' => '',
                    'caption' => '',
                    'provider' => 'auto',
                    'search_query' => '',
                ),
            ),
        ));

        $this->register('shortcode_embed', array(
            'label' => 'Shortcode Embed',
            'category' => 'dynamic',
            'description' => 'WordPress shortcode embed. Use only when the user explicitly asks for a shortcode/widget/form.',
            'renderer' => 'aiomatic_super_pages_render_component_shortcode_embed',
            'schema' => array(
                'component' => 'shortcode_embed',
                'attrs' => array(
                    'title' => '',
                    'content' => '',
                    'shortcode' => '',
                ),
            ),
        ));

        $this->register('lead_form', array(
            'label' => 'Lead Form Placeholder',
            'category' => 'dynamic',
            'description' => 'Lead capture form placeholder or shortcode wrapper.',
            'renderer' => 'aiomatic_super_pages_render_component_lead_form',
            'schema' => array(
                'component' => 'lead_form',
                'attrs' => array(
                    'title' => '',
                    'content' => '',
                    'fields' => array('name', 'email'),
                    'button' => '',
                    'shortcode' => '',
                ),
            ),
        ));

        $this->register('map_embed', array(
            'label' => 'Map Embed',
            'category' => 'media',
            'description' => 'Map iframe/embed for location pages.',
            'renderer' => 'aiomatic_super_pages_render_component_map_embed',
            'schema' => array(
                'component' => 'map_embed',
                'attrs' => array(
                    'title' => '',
                    'address' => '',
                    'embed_url' => '',
                    'caption' => '',
                ),
            ),
        ));

        $this->register('code_snippet', array(
            'label' => 'Code Snippet',
            'category' => 'content',
            'description' => 'Code block for developer pages or technical documentation.',
            'renderer' => 'aiomatic_super_pages_render_component_code_snippet',
            'schema' => array(
                'component' => 'code_snippet',
                'attrs' => array(
                    'title' => '',
                    'language' => '',
                    'code' => '',
                    'content' => '',
                ),
            ),
        ));

        $this->register('html_embed', array(
            'label' => 'Safe HTML Embed',
            'category' => 'dynamic',
            'description' => 'Safe HTML block for simple embeds. Scripts are stripped.',
            'renderer' => 'aiomatic_super_pages_render_component_html_embed',
            'schema' => array(
                'component' => 'html_embed',
                'attrs' => array(
                    'title' => '',
                    'html' => '',
                ),
            ),
        ));

        $this->register('product_showcase', array(
            'label' => 'Product Showcase',
            'category' => 'conversion',
            'description' => 'Product/service cards with CTAs.',
            'renderer' => 'aiomatic_super_pages_render_component_product_showcase',
            'schema' => array(
                'component' => 'product_showcase',
                'attrs' => array(
                    'title' => '',
                    'subtitle' => '',
                    'items' => array(
                        array('title' => '', 'content' => '', 'price' => '', 'image_url' => '', 'image_prompt' => '', 'button' => '', 'button_url' => '#get-started'),
                    ),
                ),
            ),
        ));

        $this->register('accordion', array(
            'label' => 'Accordion',
            'category' => 'content',
            'description' => 'Generic accordion section.',
            'renderer' => 'aiomatic_super_pages_render_component_accordion',
            'schema' => array(
                'component' => 'accordion',
                'attrs' => array(
                    'title' => '',
                    'items' => array(
                        array('title' => '', 'content' => ''),
                    ),
                ),
            ),
        ));

        $this->register('separator', array(
            'label' => 'Separator',
            'category' => 'layout',
            'description' => 'Spacing divider.',
            'renderer' => 'aiomatic_super_pages_render_component_separator',
            'schema' => array(
                'component' => 'separator',
                'attrs' => array('height' => '50px'),
            ),
        ));

        $aliases = array(
            'block'            => 'text',
            'paragraph'        => 'text',
            'content'          => 'text',
            'toc'              => 'table_of_contents',
            'table_of_contents'=> 'table_of_contents',
            'key_takeaways'    => 'editorial_summary',
            'summary'          => 'editorial_summary',
            'features'         => 'feature_grid',
            'benefits'         => 'feature_grid',
            'benefit_grid'     => 'feature_grid',
            'feature_cards'    => 'feature_grid',
            'cards'            => 'card_grid',
            'proof'            => 'highlight_box',
            'trust'            => 'highlight_box',
            'testimonials'     => 'testimonial_grid',
            'logos'            => 'logo_cloud',
            'logo_grid'        => 'logo_cloud',
            'partners'         => 'logo_cloud',
            'clients'          => 'logo_cloud',
            'pricing'          => 'pricing_cards',
            'comparison'       => 'comparison_table',
            'faq_schema'       => 'faq',
            'final_cta'        => 'cta_banner',
            'cta'              => 'cta_banner',
            'image'            => 'image_banner',
            'banner'           => 'image_banner',
            'youtube_embed'    => 'video_embed',
            'vimeo_embed'      => 'video_embed',
            'loom_embed'       => 'video_embed',
            'video'            => 'video_embed',
            'form'             => 'lead_form',
            'contact_form'     => 'lead_form',
            'newsletter_form'  => 'lead_form',
            'map'              => 'map_embed',
            'embed'            => 'html_embed',
            'custom_html'      => 'html_embed',
            'process'          => 'steps',
            'how_it_works'     => 'steps',
            'pros_and_cons'    => 'pros_cons',
            'products'         => 'product_showcase',
        );

        foreach ($aliases as $alias => $type) {
            $this->alias($alias, $type);
        }
    }
}

}

if (!class_exists('Aiomatic_Super_Page_Agent')) {

class Aiomatic_Super_Page_Agent extends Aiomatic_Agent
{
    protected $runtime_config = array();
    protected $state = array();
    protected $execution_id = '';
    protected $context_window = array();
    protected $research_data = array();
    protected $component_strategy = array();
    protected $component_tree = array();
    protected $generated_components = array();
    protected $final_page = array();
    protected $quality_audit = array();
    protected $component_registry;
    protected $execution_plan = array();

    const DEFAULT_MODEL = 'gpt-4.1';
    const MAX_COMPETITORS = 5;
    const CACHE_TTL = 21600;
    const MAX_RETRIES = 3;

    public static function create_virtual($args = array())
    {
        $defaults = array(
            'model'            => self::DEFAULT_MODEL,
            'goal'             => 'auto',
            'depth'            => 'comprehensive',
            'language'         => 'English',
            'include_images'   => 'royalty_free',
            'image_source'     => 'royalty_free',
            'research_enabled' => true,
            'content_format'   => 'auto',
            'post_type'        => 'page',
            'max_competitors'  => self::MAX_COMPETITORS,
            'max_components'   => 16,
            'temperature'      => 0.55,
            'status'           => 'draft',
            'allowed_tools' => array(
                'google_results_parser',
                'website_scraper',
                'process_and_transform_data',
                'royalty_free_image_search',
                'youtube_video_search',
                'youtube_video_captions',
                'search_site_posts',
                'get_wp_post_data',
                'get_wp_media_info',
                'wp_taxonomy_discovery',
                'wp_validate_post_state',
                'edit_post_section',
                'get_post_structure',
                'wp_sideload_media',
                'generate_chart'
            ),
        );

        $config = wp_parse_args($args, $defaults);

        if (isset($args['image_source'])) {
            $config['include_images'] = $args['image_source'];
        }

        if (function_exists('aiomatic_super_pages_normalize_image_source')) {
            $image_source = aiomatic_super_pages_normalize_image_source($config['include_images']);
            $config['include_images'] = $image_source;
            $config['image_source'] = $image_source;
        }

        if (
            (!isset($args['allowed_tools']) || !is_array($args['allowed_tools'])) &&
            function_exists('aiomatic_super_pages_allowed_tools_for_image_source')
        ) {
            $config['allowed_tools'] = aiomatic_super_pages_allowed_tools_for_image_source($config['include_images']);
        }

        return new self($config);
    }

    public function __construct($runtime_config = array())
    {
        $this->runtime_config = is_array($runtime_config) ? $runtime_config : array();
        $this->execution_id = 'super-page-' . wp_generate_uuid4();
        $this->component_registry = new Aiomatic_Super_Page_Component_Registry();

        $this->initialize_state();
    }

    protected function initialize_state()
    {
        $this->state = array(
            'prompt'            => '',
            'intent'            => '',
            'audience'          => '',
            'goal'              => isset($this->runtime_config['goal']) ? sanitize_key($this->runtime_config['goal']) : 'auto',
            'style'             => 'modern',
            'language'          => isset($this->runtime_config['language']) ? sanitize_text_field($this->runtime_config['language']) : 'English',
            'offer_type'        => '',
            'tone'              => '',
            'page_type'         => '',
            'primary_goal'      => '',
            'primary_cta'       => '',
            'secondary_cta'     => '',
            'competitors'       => array(),
            'scraped_content'   => array(),
            'semantic_entities' => array(),
            'topics'            => array(),
            'requested_assets'  => array(),
            'warnings'          => array(),
        );

        $this->context_window = array(
            'main_offer'        => '',
            'core_promise'      => '',
            'audience'          => '',
            'tone'              => '',
            'primary_cta'       => '',
            'secondary_cta'     => '',
            'pain_points'       => array(),
            'benefits'          => array(),
            'objections'        => array(),
            'semantic_entities' => array(),
            'cta_patterns'      => array(),
            'headline_style'    => '',
            'proof_strategy'    => '',
            'differentiation'   => '',
            'page_visual_direction' => '',
            'layout_flow'       => array(),
            'visual_memory'     => array(),
            'content_memory'    => array(),
            'design_system'     => array(
                'visual_style'      => '',
                'primary_color'     => '',
                'secondary_color'   => '',
                'accent_color'      => '',
                'background_style'  => '',
                'spacing_style'     => '',
                'border_radius'     => '',
                'shadow_style'      => '',
                'section_density'   => '',
                'typography_style'  => '',
                'button_style'      => '',
                'card_style'        => '',
            ),
        );
    }
    public function generate($args = array())
    {
        $this->state['prompt'] = isset($args['prompt']) ? sanitize_textarea_field(wp_unslash($args['prompt'])) : '';
        $this->state['goal']   = isset($args['goal']) ? sanitize_key(wp_unslash($args['goal'])) : $this->state['goal'];

        if (isset($args['language'])) {
            $this->state['language'] = sanitize_text_field(wp_unslash($args['language']));
            $this->runtime_config['language'] = $this->state['language'];
        }

        if (isset($args['depth'])) {
            $this->runtime_config['depth'] = sanitize_key(wp_unslash($args['depth']));
        }

        if (isset($args['goal'])) {
            $this->runtime_config['goal'] = sanitize_key(wp_unslash($args['goal']));
            $this->state['goal'] = $this->runtime_config['goal'];
        }

        if (isset($args['content_format'])) {
            $this->runtime_config['content_format'] = sanitize_key(wp_unslash($args['content_format']));
        }

        if (isset($args['include_images'])) {
            $this->runtime_config['include_images'] = is_bool($args['include_images'])
                ? $args['include_images']
                : sanitize_key(wp_unslash($args['include_images']));
        }

        if (isset($args['image_source'])) {
            $this->runtime_config['include_images'] = sanitize_key(wp_unslash($args['image_source']));
            $this->runtime_config['image_source'] = $this->runtime_config['include_images'];
        }

        if (isset($args['include_images']) || isset($args['image_source'])) {
            $image_source = $this->get_image_source();
            $this->runtime_config['include_images'] = $image_source;
            $this->runtime_config['image_source'] = $image_source;

            if (
                !isset($args['allowed_tools']) &&
                function_exists('aiomatic_super_pages_allowed_tools_for_image_source')
            ) {
                $this->runtime_config['allowed_tools'] = aiomatic_super_pages_allowed_tools_for_image_source($image_source);
            }
        }

        if (isset($args['research_enabled'])) {
            $this->runtime_config['research_enabled'] = !empty($args['research_enabled']);
        }

        if (isset($args['post_type'])) {
            $this->runtime_config['post_type'] = sanitize_key(wp_unslash($args['post_type']));
        }

        $job_id = !empty($args['job_id']) ? sanitize_text_field($args['job_id']) : '';

        if (empty($this->state['prompt'])) {
            return new WP_Error(
                'missing_prompt',
                esc_html__('Missing generation prompt.', 'aiomatic-automatic-ai-content-writer')
            );
        }

        try {

            $this->log_step('Starting page creation');

            $this->set_job_progress($job_id, 8, 'Analyzing request');

            $this->analyze_intent();

            $this->set_job_progress($job_id, 14, 'Planning generation workflow');

            $this->execution_plan = $this->build_execution_plan();

            $this->log_step(
                'Execution plan: ' . implode(', ', $this->execution_plan)
            );

            $this->run_execution_plan($this->execution_plan, $job_id);

            $this->log_step('Omni Page completed');

            return $this->final_page;

        } catch (Throwable $e) {

            aiomatic_log_to_file(
                'Omni Page Agent Error: ' . $e->getMessage()
            );

            return new WP_Error(
                'super_page_error',
                $e->getMessage()
            );
        }
    }

    protected function get_content_format()
    {
        $format = sanitize_key($this->runtime_config['content_format'] ?? 'auto');

        if ($format !== 'auto') {
            return $format;
        }

        $page_type = sanitize_key($this->state['page_type'] ?? '');
        $post_type = sanitize_key($this->runtime_config['post_type'] ?? 'page');
        $prompt = strtolower((string) $this->state['prompt']);

        foreach (array('article', 'blog post', 'blogpost', 'guide', 'tutorial', 'how to', 'explainer', 'educational', 'news', 'listicle', 'deep dive', 'comprehensive guide', 'buyer\'s guide', 'review page') as $needle) {
            if (strpos($prompt, $needle) !== false) {
                return 'article';
            }
        }

        if ($post_type === 'post') {
            return 'article';
        }

        if (in_array($page_type, array('article', 'blog_post', 'guide', 'tutorial', 'news', 'listicle', 'editorial', 'affiliate_review', 'comparison_page'), true)) {
            return 'article';
        }

        return 'landing_page';
    }

    protected function is_article_format()
    {
        return $this->get_content_format() === 'article';
    }

    protected function get_content_depth()
    {
        $depth = sanitize_key($this->runtime_config['depth'] ?? 'comprehensive');

        return in_array($depth, array('short', 'standard', 'comprehensive'), true)
            ? $depth
            : 'comprehensive';
    }

    protected function get_primary_goal()
    {
        $goal = sanitize_key($this->runtime_config['goal'] ?? 'auto');

        if ($goal !== 'auto') {
            return $goal;
        }

        $primary_goal = strtolower((string) ($this->state['primary_goal'] ?? ''));
        $prompt = strtolower((string) ($this->state['prompt'] ?? ''));
        $page_type = sanitize_key($this->state['page_type'] ?? '');
        $format = $this->get_content_format();
        $goal_text = trim($primary_goal . ' ' . $prompt . ' ' . $page_type);

        foreach (array('lead', 'signup', 'sign up', 'book', 'booking', 'consultation', 'quote', 'contact form', 'capture', 'inquiry', 'enquiry') as $needle) {
            if (strpos($goal_text, $needle) !== false) {
                return 'leads';
            }
        }

        foreach (array('seo', 'rank', 'organic traffic', 'search traffic', 'authority', 'topical authority', 'content hub') as $needle) {
            if (strpos($goal_text, $needle) !== false) {
                return 'seo';
            }
        }

        foreach (array('educate', 'education', 'learn', 'tutorial', 'guide', 'how to', 'explainer', 'knowledge', 'informational') as $needle) {
            if (strpos($goal_text, $needle) !== false) {
                return 'education';
            }
        }

        if ($format === 'article' || in_array($page_type, array('article', 'blog_post', 'guide', 'tutorial', 'news', 'listicle', 'editorial'), true)) {
            return 'education';
        }

        return 'conversions';
    }

    protected function get_builder_persona()
    {
        if ($this->is_article_format()) {
            return 'You are an elite editorial director and senior content strategist who builds premium, publish-ready WordPress articles and long-form guides. You write with authority, specificity, scannability, and editorial polish. Never use generic AI filler, vague claims, or template marketing copy.';
        }

        return 'You are an elite conversion copywriter, UX strategist, and WordPress landing page architect who builds premium, agency-quality marketing pages. You prioritize clarity, proof, hierarchy, persuasive flow, and polished visual rhythm. Never use generic template copy or empty marketing clichés.';
    }

    protected function get_quality_standards_text()
    {
        $goal = $this->get_primary_goal();
        $depth = $this->get_content_depth();
        $standards = array(
            '- Write at a professional, agency-grade level with concrete details from the user request and research.',
            '- Every headline must be specific to the topic, audience, and offer.',
            '- Avoid generic phrases like "Clear Value", "Better Workflow", "Built for Results", or "Ready to get started?" unless the user explicitly requested them.',
            '- Use only source-backed facts. Never invent exact percentages, time savings, uptime, compliance badges, customer counts, ratings, awards, integrations, named customers, or testimonial quotes.',
            '- If proof is needed but no proof was supplied, use careful proof-oriented copy such as evaluation criteria, trust checklist items, implementation notes, or benefits framed without exact fake numbers.',
            '- Do not include a video embed unless the user directly requested video content or supplied a video URL.',
            '- Depth: ' . $depth . '. Primary goal: ' . $goal . '.',
        );

        if ($this->is_article_format()) {
            $standards[] = '- Article format: prioritize informative depth, scannable structure, examples, and natural transitions between sections.';
            $standards[] = '- Text sections must be substantive and editorial, not thin filler paragraphs.';
            $standards[] = '- Professional posts should include a strong editorial opening, table of contents for longer guides, key takeaways, clear H2/H3 structure, and practical examples.';
            $standards[] = '- Do not force aggressive sales CTAs unless the user explicitly requested a landing page or conversion focus.';
        } else {
            $standards[] = '- Landing page format: strong hero promise, differentiated value, proof, objection handling, and a decisive final CTA.';
            $standards[] = '- Benefits must be outcome-focused and specific, not abstract buzzwords.';
            $standards[] = '- Professional landing pages must feel designed: varied section silhouettes, image-led blocks, polished cards, proof/trust, clear CTA flow, and no document-like stacking.';
        }

        return implode("\n", $standards);
    }

    protected function get_min_components()
    {
        $depth = $this->get_content_depth();

        if ($depth === 'short') {
            return $this->is_article_format() ? 4 : 4;
        }

        if ($depth === 'standard') {
            return $this->is_article_format() ? 6 : 6;
        }

        if ($this->is_article_format()) {
            return 8;
        }

        return 8;
    }

    protected function get_component_word_target($type)
    {
        $depth = $this->get_content_depth();

        switch ($type) {
            case 'text':
                if ($depth === 'short') {
                    return '45-90 words of concise, specific copy';
                }

                if ($depth === 'standard') {
                    return '80-150 words of focused, useful copy';
                }

                return '150-280 words of substantive HTML with multiple paragraphs and optional inline subheadings';
            case 'hero':
                return $depth === 'short'
                    ? 'headline 5-10 words; subheadline 14-26 words with a specific promise'
                    : 'headline 6-12 words; subheadline 20-40 words with a specific promise';
            case 'faq':
            case 'accordion':
                if ($depth === 'short') {
                    return '2-3 Q&A pairs with concise answers';
                }

                if ($depth === 'standard') {
                    return '3-4 Q&A pairs with helpful answers';
                }

                return '4-6 Q&A pairs with detailed answers (40-90 words each)';
            case 'feature_grid':
            case 'card_grid':
            case 'icon_list':
                if ($depth === 'short') {
                    return '2-3 concise items with specific titles and descriptions under 30 words';
                }

                if ($depth === 'standard') {
                    return '3-4 items with specific titles and useful descriptions';
                }

                return '3-4 text-heavy items, or 5-6 concise items with titles under 7 words and descriptions under 45 words';
            default:
                return $depth === 'short'
                    ? 'concise, specific, polished copy aligned with the page strategy'
                    : 'specific, polished, non-generic copy aligned with the page strategy';
        }
    }

    protected function get_component_context_for_prompt()
    {
        return wp_json_encode(array(
            'main_offer'            => $this->context_window['main_offer'] ?? '',
            'core_promise'          => $this->context_window['core_promise'] ?? '',
            'audience'              => $this->context_window['audience'] ?? '',
            'tone'                  => $this->context_window['tone'] ?? '',
            'primary_cta'           => $this->context_window['primary_cta'] ?? '',
            'secondary_cta'         => $this->context_window['secondary_cta'] ?? '',
            'differentiation'       => $this->context_window['differentiation'] ?? '',
            'proof_strategy'        => $this->context_window['proof_strategy'] ?? '',
            'page_visual_direction' => $this->context_window['page_visual_direction'] ?? '',
            'design_system'         => $this->context_window['design_system'] ?? array(),
            'content_memory'        => $this->context_window['content_memory'] ?? array(),
        ));
    }

    protected function analyze_intent()
    {
        $prompt = $this->json_prompt(
            'Analyze the page request and decide what type of web experience is needed. Classify whether this should be a conversion landing page, article/guide, comparison/review page, local service page, or other format. Detect if the user asks for videos, forms, maps, embeds, code, pricing, calculators, comparisons, product cards, or other specific components.',
            array(
                'intent'           => '',
                'audience'         => '',
                'offer_type'       => '',
                'tone'             => '',
                'page_type'        => '',
                'primary_goal'     => '',
                'primary_cta'      => '',
                'secondary_cta'    => '',
                'important_topics' => array(),
                'search_queries'   => array(),

                'needs_serp'                 => false,
                'needs_competitor_scraping'  => false,
                'needs_semantic_extraction'  => false,
                'needs_images'               => false,
                'needs_videos'               => false,
                'needs_map'                  => false,
                'needs_forms'                => false,
                'needs_products'             => false,
                'needs_comparison_table'     => false,
                'needs_pricing'              => false,
                'needs_faq'                  => false,
                'needs_schema'               => false,
                'needs_charts'               => false,
                'needs_internal_posts'       => false,
                'needs_existing_media'       => false,
                'complexity'                 => 'low|medium|high',

                'requested_assets' => array(
                    array(
                        'type'        => 'video|image|form|map|code|shortcode|html|product|chart|other',
                        'description' => '',
                        'required'    => false,
                    ),
                ),
            ),
            "Request:\n" . $this->state['prompt'] . "\n\nLanguage:\n" . $this->state['language']
        );

        $result = $this->generate_ai_json_with_retry($prompt, 'intent_analysis');

        if (!$result || !is_array($result)) {
            throw new Exception('Failed intent analysis.');
        }

        $this->state['intent'] = sanitize_text_field($result['intent'] ?? '');
        $this->state['audience'] = sanitize_text_field($result['audience'] ?? '');
        $this->state['offer_type'] = sanitize_text_field($result['offer_type'] ?? '');
        $this->state['tone'] = sanitize_text_field($result['tone'] ?? '');
        $this->state['page_type'] = sanitize_text_field($result['page_type'] ?? '');
        $this->state['primary_goal'] = sanitize_text_field($result['primary_goal'] ?? '');
        $this->state['primary_cta'] = sanitize_text_field($result['primary_cta'] ?? '');
        $this->state['secondary_cta'] = sanitize_text_field($result['secondary_cta'] ?? '');
        $this->state['topics'] = $this->sanitize_string_list($result['important_topics'] ?? array(), 20);
        $this->state['requested_assets'] = isset($result['requested_assets']) && is_array($result['requested_assets'])
            ? $this->sanitize_deep_array($result['requested_assets'])
            : array();

        $boolean_flags = array(
            'needs_serp',
            'needs_competitor_scraping',
            'needs_semantic_extraction',
            'needs_images',
            'needs_videos',
            'needs_map',
            'needs_forms',
            'needs_products',
            'needs_comparison_table',
            'needs_pricing',
            'needs_faq',
            'needs_schema',
            'needs_charts',
            'needs_internal_posts',
            'needs_existing_media',
        );

        foreach ($boolean_flags as $flag) {
            $this->state[$flag] = !empty($result[$flag]);
        }

        $this->state['complexity'] = !empty($result['complexity'])
            ? sanitize_key($result['complexity'])
            : 'medium';

        $this->apply_intent_fallbacks();
        $queries = $this->sanitize_string_list($result['search_queries'] ?? array(), 5);
        if (empty($queries)) {
            $queries[] = $this->state['intent'] ?: $this->state['prompt'];
        }

        $this->research_data['queries'] = $queries;

        $this->log_step('Intent analysis completed');
    }

    protected function apply_intent_fallbacks()
    {
        $prompt = strtolower((string) $this->state['prompt']);
        $page_type = sanitize_key($this->state['page_type']);

        if (empty($this->state['needs_serp'])) {
            foreach (array('best ', 'top ', 'comparison', 'compare', 'review', 'alternatives', 'affiliate', 'buyer', 'buyers guide', 'product recommendations') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_serp'] = true;
                    $this->state['needs_semantic_extraction'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_competitor_scraping'])) {
            foreach (array('competitor', 'alternatives', 'comparison', 'compare', 'review', 'best ', 'top ') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_competitor_scraping'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_images'])) {
            foreach (array('image', 'images', 'imagery', 'photo', 'photos', 'visual', 'spectacular', 'screenshot') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_images'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_videos'])) {
            foreach (array('video', 'videos', 'youtube', 'embed', 'music videos', 'tutorial', 'webinar') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_videos'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_map'])) {
            foreach (array('map', 'address', 'local service', 'near me', 'location') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_map'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_forms'])) {
            foreach (array('lead generation', 'lead capture', 'form', 'contact form', 'opt-in', 'booking', 'quote') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_forms'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_products'])) {
            foreach (array('amazon', 'affiliate', 'product', 'products', 'buy now', 'check price', 'recommendations') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_products'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_comparison_table'])) {
            foreach (array('comparison table', 'compare', 'comparison', 'specifications', 'specs', 'ratings') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_comparison_table'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_pricing'])) {
            foreach (array('pricing', 'plans', 'price table', 'subscription', 'free trial') as $needle) {
                if (strpos($prompt, $needle) !== false) {
                    $this->state['needs_pricing'] = true;
                    break;
                }
            }
        }

        if (empty($this->state['needs_faq'])) {
            if (
                strpos($prompt, 'faq') !== false ||
                in_array($page_type, array('landing_page', 'service_page', 'affiliate_review', 'comparison_page'), true)
            ) {
                $this->state['needs_faq'] = true;
            }
        }

        if ($this->is_article_format()) {
            $this->state['needs_serp'] = true;
            $this->state['needs_semantic_extraction'] = true;
        }

        if (empty($this->runtime_config['research_enabled'])) {
            $this->state['needs_serp'] = false;
            $this->state['needs_competitor_scraping'] = false;
            $this->state['needs_semantic_extraction'] = false;
        }

        if (!$this->images_enabled()) {
            $this->state['needs_images'] = false;
        }

        if (!$this->user_explicitly_requested_video()) {
            $this->state['needs_videos'] = false;

            if (!empty($this->state['requested_assets']) && is_array($this->state['requested_assets'])) {
                $this->state['requested_assets'] = array_values(array_filter(
                    $this->state['requested_assets'],
                    function ($asset) {
                        return empty($asset['type']) || sanitize_key($asset['type']) !== 'video';
                    }
                ));
            }
        }

        if ($this->should_skip_research()) {
            $this->state['needs_competitor_scraping'] = false;

            if (empty($this->state['needs_products']) && empty($this->state['needs_comparison_table'])) {
                $this->state['needs_serp'] = false;
                $this->state['needs_semantic_extraction'] = false;
            }
        }
    }

    protected function user_explicitly_requested_video()
    {
        $prompt = strtolower((string) $this->state['prompt']);

        if (preg_match('#https?://(?:www\.)?(?:youtube\.com|youtu\.be|vimeo\.com|loom\.com)/#i', $prompt)) {
            return true;
        }

        foreach (array('video', 'videos', 'youtube', 'vimeo', 'loom', 'embed a video', 'embed videos', 'music videos', 'video review', 'webinar replay', 'walkthrough video', 'demo video', 'tutorial video') as $needle) {
            if (strpos($prompt, $needle) !== false) {
                return true;
            }
        }

        if (!empty($this->state['requested_assets']) && is_array($this->state['requested_assets'])) {
            foreach ($this->state['requested_assets'] as $asset) {
                if (!empty($asset['type']) && sanitize_key($asset['type']) === 'video') {
                    return true;
                }
            }
        }

        return false;
    }

    protected function user_supplied_testimonial_proof()
    {
        $prompt = strtolower((string) $this->state['prompt']);

        foreach (array('testimonial', 'testimonials', 'customer quote', 'customer quotes', 'review from', 'reviews from', 'case study', 'case studies') as $needle) {
            if (strpos($prompt, $needle) !== false) {
                return true;
            }
        }

        return preg_match('/"[^"]{30,}"\s*(?:-|by|from)?\s*[A-Z][a-z]+/u', (string) $this->state['prompt']) === 1;
    }

    protected function get_source_text_for_fact_check()
    {
        $source = (string) $this->state['prompt'];

        if (!empty($this->state['competitors'])) {
            $source .= "\n" . wp_json_encode($this->state['competitors']);
        }

        if (!empty($this->research_data)) {
            $source .= "\n" . wp_json_encode($this->research_data);
        }

        $source = str_replace('\\/', '/', $source);

        return strtolower(wp_strip_all_tags(html_entity_decode($source, ENT_QUOTES | ENT_HTML5, get_bloginfo('charset') ?: 'UTF-8')));
    }

    protected function source_text_contains($needle)
    {
        $needle = strtolower(trim(wp_strip_all_tags((string) $needle)));

        if ($needle === '') {
            return true;
        }

        return strpos($this->get_source_text_for_fact_check(), $needle) !== false;
    }

    protected function component_has_unsupported_claims($component)
    {
        $text = str_replace('\\/', '/', wp_strip_all_tags(wp_json_encode($component)));

        if ($text === '') {
            return false;
        }

        $patterns = array(
            '/\b\d+(?:[.,]\d+)?\+?\s*(?:%|percent|hours?|hrs?|minutes?|mins?|days?|weeks?|months?|years?|x|times|users?|customers?|clients?|teams?|downloads?|reviews?|stars?|uptime|roi|revenue|sales|leads|conversions)\b/i',
            '/\b(?:soc\s*2|gdpr|hipaa|iso\s*\d+|pci\s*dss|end-to-end encryption|99\.9\s*%?\s*uptime|24\/7)\b/i',
            '/\b(?:thousands|millions|hundreds)\s+of\s+(?:customers|users|professionals|teams|businesses|clients)\b/i',
        );

        foreach ($patterns as $pattern) {
            if (!preg_match_all($pattern, $text, $matches)) {
                continue;
            }

            foreach ($matches[0] as $claim) {
                if (!$this->source_text_contains($claim)) {
                    return true;
                }
            }
        }

        return false;
    }

    protected function component_has_fake_social_proof($component)
    {
        if (($component['component'] ?? '') !== 'testimonial_grid') {
            return false;
        }

        if (!$this->user_supplied_testimonial_proof()) {
            return true;
        }

        $items = $component['attrs']['items'] ?? array();

        if (!is_array($items)) {
            return false;
        }

        foreach ($items as $item) {
            $name = isset($item['name']) ? trim((string) $item['name']) : '';

            if ($name !== '' && !$this->source_text_contains($name)) {
                return true;
            }
        }

        return false;
    }

    protected function component_is_professional_enough($component)
    {
        if (!$component || !is_array($component)) {
            return false;
        }

        if (($component['component'] ?? '') === 'video_embed' && !$this->user_explicitly_requested_video()) {
            return false;
        }

        if ($this->component_has_generic_copy($component)) {
            return false;
        }

        if ($this->component_has_unsupported_claims($component)) {
            return false;
        }

        if ($this->component_has_fake_social_proof($component)) {
            return false;
        }

        return true;
    }

    protected function build_execution_plan()
    {
        $plan = array();

        if (!empty($this->runtime_config['research_enabled']) && !empty($this->state['needs_serp'])) {
            $plan[] = 'perform_serp_research';
        }

        if (!empty($this->runtime_config['research_enabled']) && !empty($this->state['needs_competitor_scraping'])) {
            $plan[] = 'scrape_competitors';
        }

        if (!empty($this->runtime_config['research_enabled']) && !empty($this->state['needs_semantic_extraction'])) {
            $plan[] = 'extract_semantic_entities';
        } else {
            $plan[] = 'ensure_semantic_defaults';
        }

        $plan[] = 'build_context_window';
        $plan[] = 'build_component_strategy';
        $plan[] = 'generate_component_tree';
        $plan[] = 'normalize_component_tree';

        if (
            !empty($this->state['needs_images']) ||
            !empty($this->state['needs_videos']) ||
            !empty($this->state['needs_map']) ||
            !empty($this->state['needs_products']) ||
            !empty($this->state['needs_existing_media'])
        ) {
            $plan[] = 'resolve_component_assets';
        }

        $plan[] = 'generate_components';
        $plan[] = 'assemble_final_page';
        $plan[] = 'run_quality_audit';
        $plan[] = 'repair_final_page_if_needed';
        $plan[] = 'validate_final_page';

        return array_values(array_unique($plan));
    }

    protected function run_execution_plan($plan, $job_id = '')
    {
        $plan = is_array($plan) ? array_values($plan) : array();

        if (empty($plan)) {
            throw new Exception('Execution plan is empty.');
        }

        $allowed_steps = $this->get_allowed_execution_steps();

        $total = count($plan);
        $current = 0;

        foreach ($plan as $step) {

            $step = sanitize_key($step);

            if (empty($allowed_steps[$step])) {
                $this->log_step('Skipped unknown execution step: ' . $step);
                continue;
            }

            $current++;

            $percent = 14 + intval(($current / $total) * 80);
            $percent = max(15, min(94, $percent));

            $this->set_job_progress(
                $job_id,
                $percent,
                $this->get_step_label($step)
            );

            $this->log_step('Running step: ' . $step);

            call_user_func(array($this, $step));
        }
    }

    protected function get_allowed_execution_steps()
    {
        return array(
            'perform_serp_research'      => true,
            'scrape_competitors'         => true,
            'extract_semantic_entities'  => true,
            'ensure_semantic_defaults'   => true,
            'build_context_window'       => true,
            'build_component_strategy'   => true,
            'generate_component_tree'    => true,
            'normalize_component_tree'   => true,
            'resolve_component_assets'   => true,
            'generate_components'        => true,
            'assemble_final_page'        => true,
            'run_quality_audit'          => true,
            'repair_final_page_if_needed'=> true,
            'validate_final_page'        => true,
        );
    }

    protected function get_step_label($step)
    {
        $labels = array(
            'perform_serp_research'       => 'Researching search results',
            'scrape_competitors'          => 'Analyzing competitor pages',
            'extract_semantic_entities'   => 'Extracting SEO and conversion insights',
            'ensure_semantic_defaults'    => 'Preparing page intelligence',
            'build_context_window'        => 'Building content and design strategy',
            'build_component_strategy'    => 'Planning page sections',
            'generate_component_tree'     => 'Designing page structure',
            'normalize_component_tree'    => 'Finalizing section order',
            'resolve_component_assets'    => 'Preparing images, videos and media',
            'generate_components'         => 'Writing page components',
            'assemble_final_page'         => 'Assembling final page',
            'run_quality_audit'           => 'Reviewing page quality',
            'repair_final_page_if_needed' => 'Improving weak sections',
            'validate_final_page'         => 'Validating final output',
        );

        return $labels[$step] ?? 'Processing page';
    }

    protected function set_job_progress($job_id, $percent, $message)
    {
        if (empty($job_id) || !function_exists('aiomatic_super_pages_set_job_progress')) {
            return;
        }

        aiomatic_super_pages_set_job_progress(
            $job_id,
            absint($percent),
            sanitize_text_field($message)
        );
    }

    protected function ensure_semantic_defaults()
    {
        if (!empty($this->state['semantic_entities']) && is_array($this->state['semantic_entities'])) {
            return;
        }

        $this->state['semantic_entities'] = array(
            'entities'        => !empty($this->state['topics']) ? $this->state['topics'] : array(),
            'pain_points'     => array(),
            'benefits'        => array(),
            'objections'      => array(),
            'cta_patterns'    => array(),
            'faq_topics'      => array(),
            'content_angles'  => array(),
            'proof_patterns'  => array(),
            'missing_angles'  => array(),
            'must_cover'      => !empty($this->state['topics']) ? $this->state['topics'] : array(),
            'component_ideas' => array(),
        );

        $this->log_step('Sanitized configuration');
    }

    protected function should_run_repair_pass()
    {
        $complexity = sanitize_key($this->state['complexity'] ?? 'medium');

        if ($complexity === 'high') {
            return true;
        }

        if (!empty($this->state['needs_products'])) {
            return true;
        }

        if (!empty($this->state['needs_comparison_table'])) {
            return true;
        }

        if (!empty($this->state['needs_forms'])) {
            return true;
        }

        return false;
    }

    protected function should_skip_research()
    {
        $page_type = sanitize_key($this->state['page_type']);

        if (!$page_type) {
            return false;
        }

        return in_array(
            $page_type,
            array(
                'thank_you_page',
                'optin_page',
            ),
            true
        );
    }

    protected function detect_required_components()
    {
        $required = array();

        if (!empty($this->state['needs_map'])) {
            $required[] = 'map_embed';
        }

        if (!empty($this->state['needs_videos']) && $this->user_explicitly_requested_video()) {
            $required[] = 'video_embed';
        }

        if (!empty($this->state['needs_forms'])) {
            $required[] = 'lead_form';
        }

        if (!empty($this->state['needs_products'])) {
            $required[] = 'product_showcase';
        }

        if (!empty($this->state['needs_comparison_table'])) {
            $required[] = 'comparison_table';
        }

        if (!empty($this->state['needs_pricing'])) {
            $required[] = 'pricing_cards';
        }

        if (!empty($this->state['needs_faq'])) {
            $required[] = 'faq';
        }

        if (!empty($this->state['needs_charts'])) {
            $required[] = 'html_embed';
        }

        return array_values(array_unique($required));
    }
    protected function perform_serp_research()
    {
        if (empty($this->research_data['queries'])) {
            return;
        }

        $competitors = array();
        $max_competitors = isset($this->runtime_config['max_competitors']) ? absint($this->runtime_config['max_competitors']) : self::MAX_COMPETITORS;
        $max_competitors = max(1, min(self::MAX_COMPETITORS, $max_competitors));

        foreach ($this->research_data['queries'] as $query) {
            $query = trim((string) $query);

            if ($query === '') {
                continue;
            }

            $cache_key = 'aimogen_sp_serp_' . md5(strtolower($query));
            $result = get_transient($cache_key);

            if (false === $result) {
                $result = $this->execute_tool_safe('google_results_parser', array('keywords' => $query));

                if (!empty($result)) {
                    set_transient($cache_key, $result, self::CACHE_TTL);
                }
            }

            foreach ($this->normalize_serp_results($result) as $item) {
                $url = '';

                if (isset($item['url']) && !empty($item['url'])) {
                    $url = $item['url'];
                } elseif (isset($item['link']) && !empty($item['link'])) {
                    $url = $item['link'];
                }

                if (empty($item['title'])) {
                    continue;
                }

                if (!empty($url) && $this->is_duplicate_competitor($competitors, $url)) {
                    continue;
                }

                $competitors[] = array(
                    'title'   => sanitize_text_field($item['title']),
                    'url'     => !empty($url) ? esc_url_raw($url) : '',
                    'snippet' => sanitize_text_field($item['snippet'] ?? ''),
                    'query'   => sanitize_text_field($query),
                );

                if (count($competitors) >= $max_competitors) {
                    break 2;
                }
            }
        }

        $this->state['competitors'] = $competitors;
        $this->log_step('SERP research completed. Found competitors: ' . count($competitors));
    }

    protected function scrape_competitors()
    {
        if (empty($this->state['competitors'])) {
            return;
        }

        $scraped = array();
        foreach ($this->state['competitors'] as $competitor) {
            if (empty($competitor['url'])) {
                continue;
            }

            $url = esc_url_raw($competitor['url']);
            $cache_key = 'aimogen_sp_scrape_' . md5($url);
            $result = get_transient($cache_key);

            if (false === $result) {
                $result = $this->execute_tool_safe('website_scraper', array('url' => $url));

                if (!empty($result)) {
                    set_transient($cache_key, $result, self::CACHE_TTL);
                }
            }

            if (empty($result)) {
                continue;
            }

            $structured = $this->extract_structured_content($result);

            if (empty($structured['text']) && empty($structured['headings'])) {
                continue;
            }

            $scraped[] = array(
                'url'       => $url,
                'title'     => sanitize_text_field($competitor['title'] ?? ''),
                'snippet'   => sanitize_text_field($competitor['snippet'] ?? ''),
                'structure' => $structured,
                'content'   => $this->compress_structured_content($structured),
            );
        }

        $this->state['scraped_content'] = $scraped;
        $this->log_step('Competitor scraping completed. Scraped pages: ' . count($scraped));
    }

    protected function extract_semantic_entities()
    {
        if (empty($this->state['scraped_content'])) {
            $this->state['semantic_entities'] = array(
                'entities'       => $this->state['topics'],
                'pain_points'    => array(),
                'benefits'       => array(),
                'objections'     => array(),
                'cta_patterns'   => array(),
                'faq_topics'     => array(),
                'content_angles' => array(),
                'component_ideas' => array(),
            );
            return;
        }

        $combined = '';

        foreach ($this->state['scraped_content'] as $item) {
            $combined .= "\n\nSOURCE: " . ($item['title'] ?? '') . "\n";
            $combined .= $item['content'] ?? '';
        }

        $combined = aiomatic_substr($combined, 0, 30000);

        $prompt = $this->json_prompt(
            'Extract semantic SEO, conversion intelligence and component opportunities from competitor research. Do not copy competitor text.',
            array(
                'entities'        => array(),
                'pain_points'     => array(),
                'benefits'        => array(),
                'objections'      => array(),
                'cta_patterns'    => array(),
                'faq_topics'      => array(),
                'content_angles'  => array(),
                'proof_patterns'  => array(),
                'missing_angles'  => array(),
                'must_cover'      => array(),
                'component_ideas' => array(
                    array('component' => '', 'reason' => ''),
                ),
            ),
            "User request:\n" . $this->state['prompt'] . "\n\nResearch content:\n" . $combined
        );

        $result = $this->generate_ai_json_with_retry($prompt, 'semantic_extraction');

        if (is_array($result)) {
            $this->state['semantic_entities'] = $this->sanitize_deep_array($result);
        }

        $this->log_step('Semantic extraction completed');
    }

    protected function build_context_window()
    {
        $prompt = $this->json_prompt(
            'Create a stable messaging and design context for the whole page. This context must keep copy, layout, visual style, media, forms and dynamic embeds consistent across all components. Make the strategy feel premium, specific, and non-generic.',
            array(
                'main_offer'        => '',
                'core_promise'      => '',
                'audience'          => '',
                'tone'              => '',
                'primary_cta'       => '',
                'secondary_cta'     => '',
                'pain_points'       => array(),
                'benefits'          => array(),
                'objections'        => array(),
                'semantic_entities' => array(),
                'cta_patterns'      => array(),
                'headline_style'    => '',
                'proof_strategy'    => '',
                'differentiation'   => '',
                'page_visual_direction' => '',
                'layout_flow'       => array(
                    array(
                        'position' => 1,
                        'layout_variant' => 'hero_split|centered|alternating_zigzag|media_left|media_right|dark_band|card_grid|minimal_text',
                        'purpose' => '',
                        'visual_weight' => 'light|medium|heavy',
                        'section_mood' => '',
                    ),
                ),
                'design_system'     => array(
                    'visual_style'      => '',
                    'primary_color'     => '',
                    'secondary_color'   => '',
                    'accent_color'      => '',
                    'background_style'  => '',
                    'spacing_style'     => '',
                    'border_radius'     => '',
                    'shadow_style'      => '',
                    'section_density'   => '',
                    'typography_style'  => '',
                    'button_style'      => '',
                    'card_style'        => '',
                ),
                'visual_memory'     => array(),
                'content_memory'    => array(),
            ),
            "User request:\n" . $this->state['prompt'] .
            "\n\nContent format:\n" . $this->get_content_format() .
            "\n\nGoal:\n" . $this->get_primary_goal() .
            "\n\nDepth:\n" . $this->get_content_depth() .
            "\n\nIntent:\n" . wp_json_encode($this->state) .
            "\n\nSemantic research:\n" . wp_json_encode($this->state['semantic_entities']) .
            "\n\nQuality standards:\n" . $this->get_quality_standards_text() .
            "\n\nDesign instructions:\nCreate a premium, coherent visual language with real color direction (prefer hex colors), strong hierarchy, editorial or conversion-focused rhythm as appropriate, and avoid generic AI-page styling. For landing pages, aim for top-tier agency composition: oversized hero typography, image-led sections, offset cards, strong whitespace, category/icon grids, proof/stat bands, partner/logo clouds when useful, and crisp CTA hierarchy. Use moderate rounded corners for cards and sections; avoid oversized pill, circle, or oval containers around long text."
        );

        $result = $this->generate_ai_json_with_retry($prompt, 'context_window');

        if (is_array($result)) {
            $this->context_window = array_merge($this->context_window, $this->sanitize_deep_array($result));
        }

        if (empty($this->context_window['audience'])) {
            $this->context_window['audience'] = $this->state['audience'];
        }

        if (empty($this->context_window['primary_cta'])) {
            $this->context_window['primary_cta'] = $this->state['primary_cta'] ?: 'Get Started';
        }

        if (empty($this->context_window['page_visual_direction'])) {
            $this->context_window['page_visual_direction'] = 'Premium modern marketing page with clean hierarchy, strong spacing, polished cards, soft depth, consistent visual rhythm and conversion-focused sections.';
        }

        if (empty($this->context_window['design_system']) || !is_array($this->context_window['design_system'])) {
            $this->context_window['design_system'] = array();
        }

        $this->context_window['design_system'] = wp_parse_args(
            $this->context_window['design_system'],
            array(
                'visual_style'     => 'modern premium SaaS',
                'primary_color'    => 'brand primary',
                'secondary_color'  => 'deep neutral',
                'accent_color'     => 'soft accent',
                'background_style' => 'clean with subtle gradients',
                'spacing_style'    => 'generous',
                'border_radius'    => 'large',
                'shadow_style'     => 'soft layered',
                'section_density'  => 'balanced',
                'typography_style' => 'bold headings with readable body copy',
                'button_style'     => 'high-contrast CTA with readable spacing',
                'card_style'       => 'elevated cards with soft border',
            )
        );

        $this->log_step('Context and design system created');
    }

    protected function build_component_strategy()
    {
        $max_components = isset($this->runtime_config['max_components']) ? absint($this->runtime_config['max_components']) : 16;
        $max_components = max($this->get_min_components(), min(24, $max_components));
        $required_components = $this->detect_required_components();
        $format = $this->get_content_format();
        $strategy_task = $format === 'article'
            ? 'Plan a premium editorial article or long-form guide with strong information architecture, scannable sections, useful depth, and polished post UX. Prefer section_heading, table_of_contents, editorial_summary, substantive text blocks, highlight boxes, FAQ, comparisons, stats, or media when they improve the article. Do not force a marketing landing page structure unless the user explicitly asked for one.'
            : 'Plan a top-quality conversion landing page with agency-grade visual composition. Build a page that feels like a designed template, not a document: hero with strong visual direction, category/benefit grid, image-led feature split, project/product cards when relevant, proof/stat band, logo cloud or trust section when useful, FAQ/objection handling, and final CTA. Pick the best components from the registry based on the user request. If the user asks for videos, embeds, forms, maps, product showcases, code snippets or specific media, include the right component.';
        $baseline_rule = $format === 'article'
            ? 'Required baseline for articles: compelling opening section, table of contents for multi-section posts, key takeaways, multiple substantive content sections, at least one proof/summary element, and optional FAQ when useful.'
            : 'Required baseline for landing pages: hero, value/category grid, image-led feature or product/project section, proof/trust section, objection handling, and a final CTA.';
        $prompt = $this->json_prompt(
            $strategy_task,
            array(
                'title' => '',
                'seo_title' => '',
                'meta_description' => '',
                'excerpt' => '',
                'style' => 'modern',
                'page_visual_direction' => '',
                'layout_notes' => '',
                'design_system' => array(
                    'visual_style' => '',
                    'primary_color' => '',
                    'secondary_color' => '',
                    'accent_color' => '',
                    'background_style' => '',
                    'spacing_style' => '',
                    'border_radius' => '',
                    'shadow_style' => '',
                    'section_density' => '',
                    'typography_style' => '',
                    'button_style' => '',
                    'card_style' => '',
                ),
                'layout_flow' => array(
                    array(
                        'position' => 1,
                        'layout_variant' => '',
                        'section_mood' => '',
                        'visual_weight' => 'light|medium|heavy',
                        'reason' => '',
                    ),
                ),
                'components' => array(
                    array(
                        'id' => 'hero',
                        'component' => 'hero',
                        'purpose' => '',
                        'priority' => 1,
                        'layout_variant' => 'hero_split',
                        'section_mood' => '',
                        'visual_weight' => 'heavy',
                        'transition_to_next' => '',
                        'design_notes' => '',
                        'depends_on' => array(),
                        'asset_requests' => array(),
                    ),
                ),
            ),
            "Available components:\n" . wp_json_encode($this->component_registry->ai_components(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) .
            "\n\nRequired components based on intent:\n" . wp_json_encode($required_components) .
            "\n\nContent format:\n" . $format .
            "\n\nGoal:\n" . $this->get_primary_goal() .
            "\n\nDepth:\n" . $this->get_content_depth() .
            "\n\nMinimum components:\n" . $this->get_min_components() .
            "\n\nMaximum components: " . $max_components .
            "\n\n" . $baseline_rule .
            "\n\nDesign system:\n" . wp_json_encode($this->context_window['design_system'] ?? array()) .
            "\n\nPage visual direction:\n" . ($this->context_window['page_visual_direction'] ?? '') .
            "\n\nQuality standards:\n" . $this->get_quality_standards_text() .
            "\n\nRules:\n- Use alternating layout variants where useful.\n- Avoid same-looking consecutive sections.\n- Assign visual_weight to control pacing.\n- Add transition_to_next to create narrative flow.\n- Use dark/light contrast bands only when it helps the page feel premium.\n- Do not overuse images. Use them where they improve clarity, proof, or conversion.\n- Every component must have a distinct strategic purpose." .
            "\n- Avoid crowded multi-column sections. Prefer 3 strong pricing/product cards or 3-4 text-heavy review cards. Use 5-6 feature cards only when each card is concise." .
            "\n- Do not use feature_grid/card_grid for full product reviews, dense pros/cons, or long specifications. Use comparison_table, product_showcase, text, or dedicated pros_cons sections for dense review content." .
            "\n- Do not plan duplicate feature, product, pricing, proof, or comparison sections with the same item themes." .
            "\n- Avoid pill, circle, or oval section/card concepts for long text; use readable rectangular cards with moderate radii." .
            "\n- Do not plan testimonial_grid unless the user or scraped references include real testimonial/source material." .
            "\n- Do not plan stats with exact numbers unless those numbers appear in the user request or scraped reference content." .
            "\n- Do not plan video_embed unless video was explicitly requested or a video URL was provided." .
            "\n- Prefer text, feature_grid, steps, comparison_table, FAQ, lead_form and highlight_box over fake proof when source evidence is limited." .
            "\n- Plan CTA destinations deliberately: use real URLs from the user request or research when available; otherwise use in-page anchors that match real planned sections such as #learn-more, #pricing, #contact, or #get-started." .
            "\n- For landing pages, vary section silhouettes: combine split hero, clean icon/category cards, image/product cards, a horizontal stats or CTA band, and a partner/logo cloud when it strengthens trust." .
            "\n- Use section_heading components before major visual grids when helpful. Strong headings should have short eyebrow text and a confident 3-7 word title." .
            "\n- Logo clouds must use real provided logos when available; otherwise use credible text marks only, never invented real brand names that imply endorsement." .
            "\n- For posts/articles, use table_of_contents when there are 4+ meaningful sections and editorial_summary for key takeaways. TOC targets should match real planned section ids/titles." .
            "\n- For posts/articles, keep the layout editorial and readable: strong intro, logical H2 progression, practical examples, concise summaries, and no fake conversion pressure." .
            "\n\nUser request:\n" . $this->state['prompt'] .
            "\n\nRequested assets:\n" . wp_json_encode($this->state['requested_assets']) .
            "\n\nContext:\n" . wp_json_encode($this->context_window) .
            "\n\nResearch:\n" . wp_json_encode($this->state['semantic_entities'])
        );

        $result = $this->generate_ai_json_with_retry($prompt, 'component_strategy');

        if (empty($result['components']) || !is_array($result['components'])) {
            throw new Exception('Failed component strategy generation.');
        }

        $result['components'] = array_slice($result['components'], 0, $max_components);
        $this->component_strategy = $this->sanitize_deep_array($result);

        if (!empty($this->component_strategy['design_system']) && is_array($this->component_strategy['design_system'])) {
            $this->context_window['design_system'] = array_merge(
                $this->context_window['design_system'] ?? array(),
                $this->component_strategy['design_system']
            );
        }

        if (!empty($this->component_strategy['page_visual_direction'])) {
            $this->context_window['page_visual_direction'] = sanitize_text_field($this->component_strategy['page_visual_direction']);
        }

        if (!empty($this->component_strategy['layout_flow']) && is_array($this->component_strategy['layout_flow'])) {
            $this->context_window['layout_flow'] = $this->component_strategy['layout_flow'];
        }

        $this->log_step('Component strategy done. Components: ' . count($result['components']));
    }

    protected function generate_component_tree()
    {
        $tree = array();

        foreach ($this->component_strategy['components'] as $index => $item) {
            if (!is_array($item)) {
                continue;
            }

            $type = isset($item['component'])
                ? $this->component_registry->normalize_type($item['component'])
                : 'text';

            if ($type === 'video_embed' && !$this->user_explicitly_requested_video()) {
                continue;
            }

            if ($type === 'testimonial_grid' && !$this->user_supplied_testimonial_proof()) {
                $type = 'highlight_box';
                $item['purpose'] = !empty($item['purpose'])
                    ? $item['purpose'] . ' Use source-backed trust signals only; do not invent quotes or names.'
                    : 'Add a grounded trust section without invented testimonials, names or exact metrics.';
            }

            $tree[] = array(
                'id'             => sanitize_key($item['id'] ?? 'component_' . ($index + 1)),
                'component'      => $type,
                'purpose'        => sanitize_text_field($item['purpose'] ?? ''),
                'priority'       => isset($item['priority']) ? (int) $item['priority'] : (($index + 1) * 10),
                'layout_variant' => sanitize_key($item['layout_variant'] ?? $this->get_default_layout_variant($type, $index)),
                'section_mood'   => sanitize_text_field($item['section_mood'] ?? ''),
                'visual_weight'  => sanitize_key($item['visual_weight'] ?? 'medium'),
                'transition_to_next' => sanitize_text_field($item['transition_to_next'] ?? ''),
                'design_notes'   => sanitize_text_field($item['design_notes'] ?? ''),
                'depends_on'     => isset($item['depends_on']) && is_array($item['depends_on']) ? $this->sanitize_string_list($item['depends_on'], 10) : array(),
                'asset_requests' => isset($item['asset_requests']) && is_array($item['asset_requests']) ? $this->sanitize_deep_array($item['asset_requests']) : array(),
            );
        }

        $this->component_tree = $tree;
        $this->log_step('Component tree generated');
    }

    protected function normalize_component_tree()
    {
        if (empty($this->component_tree)) {
            $this->component_tree = array();
        }

        usort($this->component_tree, function ($a, $b) {
            return ((int) ($a['priority'] ?? 50)) <=> ((int) ($b['priority'] ?? 50));
        });

        if ($this->is_article_format()) {
            if (!$this->tree_has_component('section_heading')) {
                array_unshift($this->component_tree, array(
                    'id' => 'article_intro',
                    'component' => 'section_heading',
                    'purpose' => 'Open with a compelling article title and editorial angle.',
                    'priority' => 1,
                    'layout_variant' => 'centered',
                    'section_mood' => 'authoritative and engaging',
                    'visual_weight' => 'heavy',
                    'transition_to_next' => 'Move from the hook into the first substantive section.',
                    'design_notes' => 'Use a strong editorial headline and descriptive subtitle.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                ));
            }

            if (!$this->tree_has_component('editorial_summary')) {
                $this->component_tree[] = array(
                    'id' => 'key_takeaways',
                    'component' => 'editorial_summary',
                    'purpose' => 'Summarize the most useful takeaways before the full article body.',
                    'priority' => 8,
                    'layout_variant' => 'summary_box',
                    'section_mood' => 'concise and useful',
                    'visual_weight' => 'medium',
                    'transition_to_next' => 'Move from summary into the detailed guide.',
                    'design_notes' => 'Use 4-6 concrete takeaways that preview the article value.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }

            if (!$this->tree_has_component('table_of_contents') && $this->get_content_depth() !== 'short') {
                $this->component_tree[] = array(
                    'id' => 'table_of_contents',
                    'component' => 'table_of_contents',
                    'purpose' => 'Give readers a scannable navigation overview of the article sections.',
                    'priority' => 9,
                    'layout_variant' => 'toc_card',
                    'section_mood' => 'organized and helpful',
                    'visual_weight' => 'light',
                    'transition_to_next' => 'Move from navigation into the first body section.',
                    'design_notes' => 'List the major article sections and point to their section anchors.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }

            $text_count = 0;
            foreach ($this->component_tree as $item) {
                if (($item['component'] ?? '') === 'text') {
                    $text_count++;
                }
            }

            while ($text_count < 2) {
                $text_count++;
                $this->component_tree[] = array(
                    'id' => 'article_body_' . $text_count,
                    'component' => 'text',
                    'purpose' => 'Deliver a substantive article section with useful detail and examples.',
                    'priority' => 20 + ($text_count * 10),
                    'layout_variant' => 'minimal_text',
                    'section_mood' => 'informative and clear',
                    'visual_weight' => 'medium',
                    'transition_to_next' => 'Continue the narrative with the next key point.',
                    'design_notes' => 'Use multiple paragraphs and optional inline subheadings.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }

            if (!$this->tree_has_any_component(array('highlight_box', 'stats', 'testimonial_grid', 'comparison_table', 'logo_cloud'))) {
                $this->component_tree[] = array(
                    'id' => 'article_takeaway',
                    'component' => 'highlight_box',
                    'purpose' => 'Summarize the most important takeaway or recommendation.',
                    'priority' => 880,
                    'layout_variant' => 'centered',
                    'section_mood' => 'decisive and helpful',
                    'visual_weight' => 'medium',
                    'transition_to_next' => '',
                    'design_notes' => 'Use a concise editorial summary, not a sales CTA.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }
        } else {
            if (!$this->tree_has_component('hero')) {
                array_unshift($this->component_tree, array(
                    'id' => 'hero',
                    'component' => 'hero',
                    'purpose' => 'Open with a clear promise and primary CTA.',
                    'priority' => 1,
                    'layout_variant' => 'hero_split',
                    'section_mood' => 'confident and premium',
                    'visual_weight' => 'heavy',
                    'transition_to_next' => 'Move from promise to practical value.',
                    'design_notes' => 'Use the strongest visual treatment on the page.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                ));
            }

            if (!$this->tree_has_any_component(array('feature_grid', 'card_grid', 'icon_list', 'product_showcase'))) {
                $this->component_tree[] = array(
                    'id' => 'core_value',
                    'component' => 'feature_grid',
                    'purpose' => 'Explain the strongest benefits and value points.',
                    'priority' => 45,
                    'layout_variant' => 'centered_grid',
                    'section_mood' => 'clear and useful',
                    'visual_weight' => 'medium',
                    'transition_to_next' => 'Move from value to proof.',
                    'design_notes' => 'Use clean elevated cards and consistent icon/visual rhythm.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }

            if ($this->images_enabled() && !$this->tree_has_any_component(array('image_banner', 'product_showcase'))) {
                $this->component_tree[] = array(
                    'id' => 'visual_feature',
                    'component' => 'image_banner',
                    'purpose' => 'Add an image-led feature section that makes the page feel designed and specific.',
                    'priority' => 62,
                    'layout_variant' => 'media_right',
                    'section_mood' => 'polished and explanatory',
                    'visual_weight' => 'heavy',
                    'transition_to_next' => 'Move from visual explanation to proof or next steps.',
                    'design_notes' => 'Use a strong image prompt and concise supporting copy.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }

            if (!$this->tree_has_any_component(array('stats', 'highlight_box', 'comparison_table', 'logo_cloud'))) {
                $this->component_tree[] = array(
                    'id' => 'trust_band',
                    'component' => 'highlight_box',
                    'purpose' => 'Add a grounded proof or trust section using careful, non-fabricated claims.',
                    'priority' => 78,
                    'layout_variant' => 'trust_band',
                    'section_mood' => 'credible and reassuring',
                    'visual_weight' => 'medium',
                    'transition_to_next' => 'Move from proof into the final decision step.',
                    'design_notes' => 'Use evaluation criteria, safeguards, or concrete benefits rather than fake metrics.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }

            if (!$this->tree_has_component('cta_banner')) {
                $this->component_tree[] = array(
                    'id' => 'final_cta',
                    'component' => 'cta_banner',
                    'purpose' => 'End with a strong conversion action.',
                    'priority' => 999,
                    'layout_variant' => 'dark_band',
                    'section_mood' => 'decisive and action-focused',
                    'visual_weight' => 'heavy',
                    'transition_to_next' => '',
                    'design_notes' => 'Strong contrast and very clear CTA.',
                    'depends_on' => array(),
                    'asset_requests' => array(),
                );
            }
        }

        foreach ($this->component_tree as $index => $item) {
            if (empty($this->component_tree[$index]['layout_variant'])) {
                $this->component_tree[$index]['layout_variant'] = $this->get_default_layout_variant($item['component'] ?? 'text', $index);
            }

            if (empty($this->component_tree[$index]['visual_weight'])) {
                $this->component_tree[$index]['visual_weight'] = 'medium';
            }
        }
    }

    protected function resolve_component_assets()
    {
        foreach ($this->component_tree as $index => $item) {

            $type = isset($item['component'])
                ? sanitize_key($item['component'])
                : '';

            if (
                $this->images_enabled() &&
                in_array($type, array('hero', 'image_banner', 'product_showcase', 'feature_grid', 'steps'), true)
            ) {
                $this->component_tree[$index]['asset_requests'][] = array(
                    'type'           => 'image',
                    'description'    => $item['purpose'] ?? '',
                    'required'       => in_array($type, array('hero', 'image_banner'), true),
                    'layout_variant' => $item['layout_variant'] ?? '',
                    'visual_weight'  => $item['visual_weight'] ?? 'medium',
                );
            }

            if ($type === 'video_embed') {
                $this->component_tree[$index]['asset_requests'][] = array(
                    'type'        => 'video',
                    'description' => $item['purpose'] ?? $this->state['prompt'],
                    'required'    => false,
                );
            }
        }

        if ($this->should_force_video_component() && !$this->tree_has_component('video_embed')) {
            $this->component_tree[] = array(
                'id'                 => 'video_demo',
                'component'          => 'video_embed',
                'purpose'            => 'Add a relevant video demonstration or educational video for the page topic.',
                'priority'           => 62,
                'layout_variant'     => 'media_center',
                'section_mood'       => 'helpful and credible',
                'visual_weight'      => 'medium',
                'transition_to_next' => 'Move from demonstration to objection handling.',
                'design_notes'       => 'Use a clean embedded video block with title, description and caption.',
                'depends_on'         => array(),
                'asset_requests'     => array(
                    array(
                        'type'        => 'video',
                        'description' => $this->state['intent'] ?: $this->state['prompt'],
                        'required'    => false,
                    ),
                ),
            );
        }

        usort($this->component_tree, function ($a, $b) {
            return ((int) ($a['priority'] ?? 50)) <=> ((int) ($b['priority'] ?? 50));
        });

        $this->log_step('Component parts resolved');
    }

    protected function should_force_video_component()
    {
        return $this->user_explicitly_requested_video();
    }

    protected function generate_components()
    {
        foreach ($this->component_tree as $item) {
            $type = $item['component'] ?? 'text';
            $generated = false;
            $validated = false;

            for ($attempt = 1; $attempt <= 2; $attempt++) {
                $generated = $this->generate_single_component($item, $type, $attempt > 1);

                if (!$generated || !is_array($generated)) {
                    continue;
                }

                $validated = $this->validate_and_normalize_component($generated, $type);

                if ($validated && $this->component_is_professional_enough($validated)) {
                    break;
                }

                $validated = false;
            }

            if (!$validated) {
                $this->log_step('Skipped component after failed generation: ' . ($item['id'] ?? $type));
                continue;
            }

            $validated['attrs']['layout_variant'] = $validated['attrs']['layout_variant'] ?: ($item['layout_variant'] ?? '');
            $validated['attrs']['section_mood'] = $validated['attrs']['section_mood'] ?: ($item['section_mood'] ?? '');
            $validated['attrs']['visual_weight'] = $validated['attrs']['visual_weight'] ?: ($item['visual_weight'] ?? 'medium');
            $validated['attrs']['transition_to_next'] = $validated['attrs']['transition_to_next'] ?: ($item['transition_to_next'] ?? '');

            $validated = $this->maybe_generate_assets_for_component($validated, $item);
            $this->generated_components[] = $validated;
            $this->update_context_from_generated_component($validated);
        }

        $this->log_step('Component generation completed. Components: ' . count($this->generated_components));
    }
    protected function generate_single_component($item, $type, $retry = false)
    {
        $schema = $this->component_registry->schema($type);

        $rules = array(
            '- Use the requested language: ' . $this->state['language'] . '.',
            '- Keep copy specific, believable, useful, and aligned with the user request and research.',
            '- Format dense explanations professionally: use real HTML headings, paragraphs, ul/ol lists, comparison tables, or structured components. Never put bullet characters or multiple pseudo-sections inside one plain paragraph string.',
            '- Do not invent fake companies, fake certifications, fake testimonials, named customers, awards or fake exact stats.',
            '- Do not use exact numbers, percentages, time savings, uptime, customer counts, ratings, compliance badges, integrations or security claims unless they appear in the user request, scraped reference content, or research context.',
            '- If proof is needed and no source proof exists, write grounded proof-seeking copy: criteria, process evidence, what to verify, implementation safeguards, or qualitative benefits without exact numbers.',
            '- Follow the page design system and visual direction.',
            '- Avoid oversized pill, circle, or oval card/section concepts. Long text must be designed for readable rectangular cards with moderate radius.',
            '- Keep grid item titles concise enough for responsive 2-3 column layouts. Do not split words manually.',
            '- For feature_grid and card_grid, use 3-4 items for review-style or text-heavy content. If using 5-6 items, keep each title under 7 words and each body under 45 words.',
            '- For dense product reviews, buying advice, long pros/cons, specs, or model comparisons, prefer comparison_table, product_showcase, text, FAQ, or pros_cons instead of narrow feature cards.',
            '- For comparison_table, keep tables readable: use 4-6 essential columns, short cell text, no raw HTML in cells, no inline styles, and represent CTA cells as plain labels/URLs or move CTAs into product_showcase cards.',
            '- Do not put raw <button> tags, inline-styled buttons, or multiple CTAs inside text/content paragraphs. Use dedicated button fields on hero/cta/pricing/product components, or plain CTA labels and URLs where supported.',
            '- Button labels should be short, action-oriented, and professional. Avoid full-sentence CTA labels.',
            '- Button URLs must be useful: use real URLs supplied by the user or found in source/research context. If no real URL is available, use an in-page anchor that points to an actual generated section such as #learn-more, #pricing, #contact, or #get-started.',
            '- Do not put fabricated or guessed external URLs in image_url, icon, visual.image_url, or item image_url fields. Use image_prompt fields for new visuals unless the URL was explicitly supplied by the user.',
            '- If royalty-free images are selected, image search terms must be short stock-photo keywords, usually 2-4 words such as "domestic cat", "gaming laptop", or "team meeting"; do not use AI art-direction prompts as stock image search queries.',
            '- Respect layout_variant, visual_weight, section_mood and transition_to_next.',
            '- Avoid repeating benefits, wording, headings or CTAs already used in previous sections.',
            '- Target copy depth: ' . $this->get_component_word_target($type) . '.',
            '- If a text component has several subtopics, use HTML such as <h3>Subtopic</h3><ul><li>Point</li></ul> rather than newline bullets.',
            '- For video_embed, only create the component when the user explicitly requested a video or provided a video URL. Create a useful title, content, caption and search_query. Leave url empty unless the user provided a direct video URL.',
            '- For shortcode_embed or lead_form, only include a shortcode if the user provided or clearly requested one.',
            '- For html_embed, do not include scripts.',
            '- For table_of_contents, create concise labels that match real article sections and use target slugs that correspond to section ids.',
            '- For editorial_summary, create concrete takeaways, not generic motivational bullets.',
            '- For logo_cloud, use only user-provided real brands/logos or neutral descriptive text marks. Do not imply endorsement by real companies unless provided.',
        );

        if ($retry) {
            $rules[] = '- Previous attempt was too generic, shallow, unsupported, or contained fake proof. Rewrite with source-backed specificity, stronger detail, and better editorial/conversion quality.';
        }

        if ($this->is_article_format()) {
            $rules[] = '- This is an article section. Prioritize informative depth, examples, and natural editorial flow over hard selling.';
        } else {
            $rules[] = '- This is a landing page section. Prioritize clarity, differentiation, proof, and conversion momentum.';
        }

        if (
            in_array(
                $type,
                array(
                    'hero',
                    'image_banner',
                    'feature_grid',
                    'product_showcase',
                    'steps'
                ),
                true
            )
        ) {
            $rules[] = '- Create visually descriptive image prompts whenever the schema supports visual, image_prompt, or item image_prompt fields.';
            $rules[] = '- Mention composition, lighting, style, atmosphere, and premium marketing/editorial usage.';
            $rules[] = '- Keep image prompts consistent with the page_visual_direction.';
        }

        $component_task = $this->is_article_format()
            ? 'Generate one premium editorial article component. Return only one component JSON object. Do not generate the whole page.'
            : 'Generate one premium landing page component. Return only one component JSON object. Do not generate the whole page.';

        $prompt = $this->json_prompt(
            $component_task,
            $schema,
            "Component type: " . $type .
            "\n\nComponent purpose:\n" . ($item['purpose'] ?? '') .
            "\n\nLayout variant:\n" . ($item['layout_variant'] ?? '') .
            "\n\nSection mood:\n" . ($item['section_mood'] ?? '') .
            "\n\nVisual weight:\n" . ($item['visual_weight'] ?? 'medium') .
            "\n\nTransition to next:\n" . ($item['transition_to_next'] ?? '') .
            "\n\nDesign notes:\n" . ($item['design_notes'] ?? '') .
            "\n\nAsset requests:\n" . wp_json_encode($item['asset_requests'] ?? array()) .
            "\n\nPage visual direction:\n" . ($this->context_window['page_visual_direction'] ?? '') .
            "\n\nDesign system:\n" . wp_json_encode($this->context_window['design_system'] ?? array()) .
            "\n\nGlobal context:\n" . $this->get_component_context_for_prompt() .
            "\n\nUser request:\n" . $this->state['prompt'] .
            "\n\nResearch intelligence:\n" . wp_json_encode(array(
                'must_cover' => $this->state['semantic_entities']['must_cover'] ?? array(),
                'content_angles' => $this->state['semantic_entities']['content_angles'] ?? array(),
                'pain_points' => $this->state['semantic_entities']['pain_points'] ?? array(),
                'benefits' => $this->state['semantic_entities']['benefits'] ?? array(),
                'faq_topics' => $this->state['semantic_entities']['faq_topics'] ?? array(),
            )) .
            "\n\nPreviously generated components:\n" . $this->summarize_generated_components() .
            "\n\nQuality standards:\n" . $this->get_quality_standards_text() .
            "\n\nRules:\n" . implode("\n", $rules)
        );

        return $this->generate_ai_json_with_retry(
            $prompt,
            'component_' . $type
        );
    }

    protected function component_has_generic_copy($component)
    {
        $haystack = strtolower(wp_json_encode($component));
        $generic_phrases = array(
            'clear value',
            'better workflow',
            'built for results',
            'ready to get started?',
            'take the next step today',
            'ai generated landing page',
            'revolutionize your workflow',
            'transform business efficiency',
            'unlock your team',
            'industry leaders',
            'measurable results',
            'seamless integration',
            'effortless onboarding',
            'enterprise-grade reliability',
            'second to none',
            'starting day one',
        );

        foreach ($generic_phrases as $phrase) {
            if (strpos($haystack, $phrase) !== false) {
                return true;
            }
        }

        return false;
    }

    protected function validate_and_normalize_component($component, $expected_type = '')
    {
        if (!is_array($component)) {
            return false;
        }

        $type = $component['component'] ?? ($component['block'] ?? $expected_type);
        $type = $this->component_registry->normalize_type($type);

        if (!$this->component_registry->has($type)) {
            return false;
        }

        $attrs = isset($component['attrs']) && is_array($component['attrs']) ? $component['attrs'] : array();

        $normalized = array(
            'component' => $type,
            'block'     => $type, // Backward compatibility with old renderer/create functions.
            'attrs'     => $this->sanitize_deep_array($attrs),
        );

        return $this->ensure_component_minimum_attrs($normalized);
    }

    protected function ensure_component_minimum_attrs($component)
    {
        $type = $component['component'];

        if (!isset($component['attrs']) || !is_array($component['attrs'])) {
            $component['attrs'] = array();
        }

        $component['attrs'] = wp_parse_args(
            $component['attrs'],
            array(
                'layout_variant' => '',
                'section_mood' => '',
                'visual_weight' => 'medium',
                'transition_to_next' => '',
            )
        );

        switch ($type) {
            case 'hero':
                $component['attrs'] = wp_parse_args($component['attrs'], array(
                    'eyebrow' => $this->state['offer_type'] ?: $this->state['page_type'],
                    'headline' => $this->context_window['core_promise'] ?: $this->generate_page_title(),
                    'subheadline' => $this->context_window['main_offer'] ?: $this->state['prompt'],
                    'primary_cta' => $this->context_window['primary_cta'] ?: 'Get Started',
                    'primary_cta_url' => '#get-started',
                    'secondary_cta' => $this->context_window['secondary_cta'] ?: 'Learn More',
                    'secondary_cta_url' => '#learn-more',
                    'visual' => array(
                        'generate_image' => true,
                        'image_prompt' => '',
                        'image_style' => '',
                        'image_ratio' => '16:9',
                        'layout' => 'split',
                    ),
                ));

                if (empty($component['attrs']['visual']) || !is_array($component['attrs']['visual'])) {
                    $component['attrs']['visual'] = array();
                }

                $component['attrs']['visual'] = wp_parse_args(
                    $component['attrs']['visual'],
                    array(
                        'generate_image' => true,
                        'image_prompt' => '',
                        'image_style' => '',
                        'image_ratio' => '16:9',
                        'layout' => 'split',
                    )
                );
                break;

            case 'cta_banner':
                $component['attrs'] = wp_parse_args($component['attrs'], array(
                    'title' => $this->context_window['core_promise'] ?: 'Put ' . $this->generate_page_title() . ' into action',
                    'content' => $this->context_window['main_offer'] ?: 'Use the details above to decide the next practical step for this offer.',
                    'button' => $this->context_window['primary_cta'] ?: 'Get Started',
                    'button_url' => '#get-started',
                ));
                break;

            case 'feature_grid':
            case 'card_grid':
                if (empty($component['attrs']['items']) || !is_array($component['attrs']['items'])) {
                    $topics = !empty($this->state['topics']) ? array_slice($this->state['topics'], 0, 3) : array();
                    $items = array();

                    foreach ($topics as $index => $topic) {
                        $items[] = array(
                            'title' => sanitize_text_field($topic),
                            'content' => sanitize_text_field($this->context_window['differentiation'] ?: $this->state['intent']),
                        );
                    }

                    if (empty($items)) {
                        $items = array(
                            array('title' => '', 'content' => ''),
                        );
                    }

                    $component['attrs']['items'] = $items;
                }

                if (!empty($component['attrs']['items']) && is_array($component['attrs']['items']) && count($component['attrs']['items']) > 4) {
                    $word_total = 0;

                    foreach ($component['attrs']['items'] as $item) {
                        if (!is_array($item)) {
                            continue;
                        }

                        $word_total += str_word_count(wp_strip_all_tags(($item['title'] ?? '') . ' ' . ($item['content'] ?? '')));
                    }

                    $average_words = $word_total / max(1, count($component['attrs']['items']));

                    if ($average_words > 22) {
                        $component['attrs']['items'] = array_slice($component['attrs']['items'], 0, 4);
                    }
                }
                break;

            case 'faq':
            case 'accordion':
                if (empty($component['attrs']['items']) || !is_array($component['attrs']['items'])) {
                    $faq_topics = !empty($this->state['semantic_entities']['faq_topics'])
                        ? array_slice($this->state['semantic_entities']['faq_topics'], 0, 3)
                        : array();

                    $items = array();
                    foreach ($faq_topics as $topic) {
                        $items[] = array(
                            'question' => sanitize_text_field($topic),
                            'answer' => '',
                        );
                    }

                    if (empty($items)) {
                        $items = array(
                            array('question' => '', 'answer' => ''),
                        );
                    }

                    $component['attrs']['items'] = $items;
                }
                break;

            case 'logo_cloud':
                if (empty($component['attrs']['items']) || !is_array($component['attrs']['items'])) {
                    $component['attrs']['items'] = array(
                        array('name' => 'Partner Network', 'tagline' => 'Verified Support', 'image_url' => ''),
                        array('name' => 'Growth Fund', 'tagline' => 'Capital Access', 'image_url' => ''),
                        array('name' => 'Founder Circle', 'tagline' => 'Launch Support', 'image_url' => ''),
                        array('name' => 'Impact Network', 'tagline' => 'Community Backing', 'image_url' => ''),
                    );
                }
                break;

            case 'editorial_summary':
                if (empty($component['attrs']['items']) || !is_array($component['attrs']['items'])) {
                    $topics = !empty($this->state['topics']) ? array_slice($this->state['topics'], 0, 5) : array();
                    $items = array();

                    foreach ($topics as $topic) {
                        $items[] = 'Understand ' . sanitize_text_field($topic) . ' and how it affects the decision.';
                    }

                    if (empty($items)) {
                        $items = array(
                            'Start with the main problem, then compare the practical options.',
                            'Use evidence and concrete examples before making a recommendation.',
                            'Focus on what the reader should do next, not generic background.',
                        );
                    }

                    $component['attrs']['items'] = $items;
                }
                break;

            case 'table_of_contents':
                if (empty($component['attrs']['items']) || !is_array($component['attrs']['items'])) {
                    $items = array();

                    foreach ($this->component_tree as $tree_item) {
                        if (($tree_item['component'] ?? '') !== 'text') {
                            continue;
                        }

                        $label = sanitize_text_field($tree_item['purpose'] ?? $tree_item['id'] ?? '');

                        if ($label !== '') {
                            $items[] = array(
                                'label'  => aiomatic_substr($label, 0, 80),
                                'target' => sanitize_key($tree_item['id'] ?? sanitize_title($label)),
                            );
                        }
                    }

                    if (empty($items)) {
                        $items = array(
                            array('label' => 'Main ideas', 'target' => 'article_body_1'),
                            array('label' => 'Practical examples', 'target' => 'article_body_2'),
                            array('label' => 'Final recommendation', 'target' => 'article_takeaway'),
                        );
                    }

                    $component['attrs']['items'] = array_slice($items, 0, 8);
                }
                break;

            case 'video_embed':
                $component['attrs'] = wp_parse_args($component['attrs'], array(
                    'title' => '',
                    'content' => '',
                    'url' => '',
                    'embed_html' => '',
                    'caption' => '',
                    'provider' => 'auto',
                ));
                break;
        }

        return $component;
    }

    protected function import_generated_image($image_url, $title = '')
    {
        if (empty($image_url)) {
            return false;
        }

        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/media.php';
        require_once ABSPATH . 'wp-admin/includes/image.php';

        $tmp = download_url($image_url);

        if (is_wp_error($tmp)) {

            $this->log_step(
                'Failed downloading generated image: ' .
                $tmp->get_error_message()
            );

            return false;
        }

        $filename = sanitize_file_name(
            sanitize_title($title) .
            '-' .
            wp_generate_password(6, false) .
            '.png'
        );

        $file_array = array(
            'name'     => $filename,
            'tmp_name' => $tmp,
        );

        $attachment_id = media_handle_sideload(
            $file_array,
            0,
            $title
        );

        if (is_wp_error($attachment_id)) {

            @unlink($tmp);

            $this->log_step(
                'Failed importing generated image: ' .
                $attachment_id->get_error_message()
            );

            return false;
        }

        $url = wp_get_attachment_url($attachment_id);

        return array(
            'id'  => $attachment_id,
            'url' => $url,
        );
    }

    protected function is_trusted_component_image($url, $attachment_id = 0)
    {
        $url = esc_url_raw((string) $url);
        $attachment_id = absint($attachment_id);

        if ($attachment_id > 0 && get_post($attachment_id) && wp_attachment_is_image($attachment_id)) {
            return true;
        }

        if ($url === '') {
            return false;
        }

        $uploads = wp_upload_dir();

        if (!empty($uploads['baseurl']) && strpos($url, $uploads['baseurl']) === 0) {
            $file = str_replace($uploads['baseurl'], $uploads['basedir'], $url);

            return file_exists($file);
        }

        return (bool) apply_filters('aiomatic_super_pages_allow_external_image_url', false, $url, $attachment_id);
    }

    protected function strip_untrusted_component_images($component)
    {
        if (empty($component['attrs']) || !is_array($component['attrs'])) {
            return $component;
        }

        if (!empty($component['attrs']['image_url']) && !$this->is_trusted_component_image($component['attrs']['image_url'], $component['attrs']['attachment_id'] ?? 0)) {
            $component['attrs']['image_url'] = '';
            $component['attrs']['attachment_id'] = 0;
        }

        if (!empty($component['attrs']['visual']) && is_array($component['attrs']['visual']) && !empty($component['attrs']['visual']['image_url']) && !$this->is_trusted_component_image($component['attrs']['visual']['image_url'], $component['attrs']['visual']['attachment_id'] ?? 0)) {
            $component['attrs']['visual']['image_url'] = '';
            $component['attrs']['visual']['attachment_id'] = 0;
        }

        if (!empty($component['attrs']['items']) && is_array($component['attrs']['items'])) {
            foreach ($component['attrs']['items'] as $index => $item) {
                if (!is_array($item) || empty($item['image_url'])) {
                    continue;
                }

                if (!$this->is_trusted_component_image($item['image_url'], $item['attachment_id'] ?? 0)) {
                    $component['attrs']['items'][$index]['image_url'] = '';
                    $component['attrs']['items'][$index]['attachment_id'] = 0;
                }
            }
        }

        return $component;
    }

    protected function maybe_generate_assets_for_component($component, $tree_item)
    {
        if (!is_array($component) || empty($component['component'])) {
            return $component;
        }

        $component = $this->strip_untrusted_component_images($component);

        $type = sanitize_key($component['component']);

        if ($type === 'video_embed') {
            return $this->maybe_resolve_video_for_component($component, $tree_item);
        }

        if (!$this->images_enabled()) {
            return $component;
        }

        if ($type === 'hero') {
            $visual = isset($component['attrs']['visual']) && is_array($component['attrs']['visual'])
                ? $component['attrs']['visual']
                : array();

            $should_generate = !empty($visual['generate_image']) && empty($visual['image_url']);
            $prompt = $visual['image_prompt'] ?? '';

            if ($should_generate && empty($prompt)) {
                $prompt = $this->build_default_image_prompt($component, $tree_item, 'hero');
            }

            if ($should_generate && $prompt) {
                $attachment = $this->generate_and_import_image(
                    $prompt,
                    $component['attrs']['headline'] ?? $this->state['intent'],
                    $visual['image_ratio'] ?? '16:9',
                    $visual['image_style'] ?? ''
                );

                if (!empty($attachment['url'])) {
                    $component['attrs']['visual']['image_url'] = $attachment['url'];
                    $component['attrs']['visual']['attachment_id'] = $attachment['id'] ?? 0;
                }
            }
        }

        if ($type === 'image_banner' && empty($component['attrs']['image_url'])) {
            $prompt = $component['attrs']['image_prompt'] ?? '';

            if (!$prompt) {
                $prompt = $this->build_default_image_prompt($component, $tree_item, 'image_banner');
            }

            if ($prompt) {
                $attachment = $this->generate_and_import_image(
                    $prompt,
                    $component['attrs']['title'] ?? $this->state['intent'],
                    $component['attrs']['image_ratio'] ?? '16:9',
                    $component['attrs']['image_style'] ?? ''
                );

                if (!empty($attachment['url'])) {
                    $component['attrs']['image_url'] = $attachment['url'];
                    $component['attrs']['attachment_id'] = $attachment['id'] ?? 0;
                }
            }
        }

        foreach (array('product_showcase', 'feature_grid', 'steps') as $item_component) {
            if ($type !== $item_component) {
                continue;
            }

            if (empty($component['attrs']['items']) || !is_array($component['attrs']['items'])) {
                continue;
            }

            foreach ($component['attrs']['items'] as $index => $item) {
                if (empty($item['image_prompt']) || !empty($item['image_url'])) {
                    continue;
                }

                $attachment = $this->generate_and_import_image(
                    $item['image_prompt'],
                    $item['title'] ?? $this->state['intent'],
                    $item_component === 'product_showcase' ? '1:1' : '16:9',
                    ''
                );

                if (!empty($attachment['url'])) {
                    $component['attrs']['items'][$index]['image_url'] = $attachment['url'];
                    $component['attrs']['items'][$index]['attachment_id'] = $attachment['id'] ?? 0;
                }
            }
        }

        return $component;
    }

    protected function maybe_resolve_video_for_component($component, $tree_item)
    {
        if (!$this->user_explicitly_requested_video()) {
            return $component;
        }

        if (empty($component['attrs']) || !is_array($component['attrs'])) {
            $component['attrs'] = array();
        }

        if (!empty($component['attrs']['url']) || !empty($component['attrs']['embed_html'])) {
            return $component;
        }

        if (!$this->tool_is_allowed('youtube_video_search')) {
            $this->log_step('Video search skipped because youtube_video_search is not allowed.');
            return $component;
        }

        $query = $component['attrs']['search_query']
            ?? $component['attrs']['title']
            ?? $tree_item['purpose']
            ?? $this->state['intent']
            ?? $this->state['prompt']
            ?? '';

        $query = trim(wp_strip_all_tags((string) $query));

        if ($query === '') {
            return $component;
        }

        $this->log_step('Searching YouTube video for: ' . $query);

        $result = $this->execute_tool_safe(
            'youtube_video_search',
            array(
                'keyword' => $query,
            )
        );

        $video = $this->extract_video_from_tool_result($result);

        if (!empty($video['url'])) {
            $component['attrs']['url'] = esc_url_raw($video['url']);
            $component['attrs']['provider'] = 'youtube';
        } elseif (!empty($video['embed_html'])) {
            $component['attrs']['embed_html'] = wp_kses(
                $video['embed_html'],
                aiomatic_super_pages_allowed_embed_html()
            );
            $component['attrs']['provider'] = 'youtube';
        } else {
            $this->log_step('No usable YouTube video found.');
            return $component;
        }

        if (empty($component['attrs']['title']) && !empty($video['title'])) {
            $component['attrs']['title'] = sanitize_text_field($video['title']);
        }

        if (empty($component['attrs']['caption']) && !empty($video['description'])) {
            $component['attrs']['caption'] = sanitize_text_field(aiomatic_substr($video['description'], 0, 180));
        }

        $this->log_step(
            'Video resolved: ' .
            (!empty($component['attrs']['url']) ? $component['attrs']['url'] : 'embed_html')
        );

        return $component;
    }

    protected function extract_video_from_tool_result($result)
    {
        if (empty($result)) {
            return array();
        }

        if (is_string($result)) {

            if (preg_match('/https?:\/\/(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)[^\s"\']+/i', $result, $m)) {
                return array(
                    'url' => esc_url_raw($m[0]),
                );
            }

            if (preg_match('/youtube\.com\/embed\/([a-zA-Z0-9_-]+)/i', $result, $m)) {
                return array(
                    'url'        => 'https://www.youtube.com/watch?v=' . sanitize_text_field($m[1]),
                    'embed_html' => $result,
                );
            }

            if (stripos($result, '<iframe') !== false) {
                return array(
                    'embed_html' => $result,
                );
            }

            return array();
        }

        if (is_array($result)) {

            foreach (array('url', 'link', 'video_url', 'watch_url') as $key) {
                if (!empty($result[$key])) {
                    return array(
                        'url' => esc_url_raw($result[$key]),
                        'title' => !empty($result['title']) ? sanitize_text_field($result['title']) : '',
                        'description' => !empty($result['description']) ? sanitize_text_field($result['description']) : '',
                    );
                }
            }

            if (!empty($result['embed_html'])) {
                return array(
                    'embed_html' => $result['embed_html'],
                    'title' => !empty($result['title']) ? sanitize_text_field($result['title']) : '',
                    'description' => !empty($result['description']) ? sanitize_text_field($result['description']) : '',
                );
            }

            foreach ($result as $item) {
                if (is_array($item)) {
                    $video = $this->extract_video_from_tool_result($item);

                    if (!empty($video['url']) || !empty($video['embed_html'])) {
                        return $video;
                    }
                }
            }
        }

        return array();
    }

    protected function assemble_final_page()
    {
        $title = $this->generate_page_title();

        $this->final_page = array(
            'title'            => $title,
            'excerpt'          => !empty($this->component_strategy['excerpt']) ? sanitize_text_field($this->component_strategy['excerpt']) : $this->generate_meta_description(),
            'seo_title'        => !empty($this->component_strategy['seo_title']) ? sanitize_text_field($this->component_strategy['seo_title']) : $title,
            'meta_description' => !empty($this->component_strategy['meta_description']) ? sanitize_text_field($this->component_strategy['meta_description']) : $this->generate_meta_description(),
            'style'            => !empty($this->component_strategy['style']) ? sanitize_key($this->component_strategy['style']) : 'modern',
            'target_audience'  => $this->state['audience'],
            'offer_summary'    => $this->context_window['main_offer'] ?? '',
            'design_system'    => $this->context_window['design_system'] ?? array(),
            'page_visual_direction' => $this->context_window['page_visual_direction'] ?? '',
            'layout_flow'      => $this->context_window['layout_flow'] ?? array(),
            'components'       => array_values($this->generated_components),
            'blocks'           => array_values($this->generated_components),
            'component_tree'    => $this->component_tree,
            'research'         => array(
                'queries' => $this->research_data['queries'] ?? array(),
                'competitors' => $this->state['competitors'],
                'semantic_entities' => $this->state['semantic_entities'],
            ),
            'quality_audit'    => array(),
        );
    }

    protected function run_quality_audit()
    {
        $components = $this->final_page['components'] ?? array();

        $audit = array(
            'has_hero' => false,
            'has_cta' => false,
            'has_value' => false,
            'has_proof' => false,
            'has_objection_handling' => false,
            'has_visuals' => false,
            'has_layout_variation' => false,
            'component_count' => count($components),
            'warnings' => array(),
            'score' => 0,
        );

        $layout_variants = array();
        $visual_count = 0;

        foreach ($components as $component) {
            $type = $component['component'] ?? '';
            $attrs = $component['attrs'] ?? array();

            if ($type === 'hero') {
                $audit['has_hero'] = true;
            }

            if ($type === 'cta_banner' || $type === 'lead_form') {
                $audit['has_cta'] = true;
            }

            if (in_array($type, array('feature_grid', 'card_grid', 'icon_list', 'product_showcase'), true)) {
                $audit['has_value'] = true;
            }

            if (
                in_array($type, array('testimonial_grid', 'stats', 'highlight_box', 'comparison_table', 'logo_cloud'), true) &&
                !$this->component_has_unsupported_claims($component) &&
                !$this->component_has_fake_social_proof($component)
            ) {
                $audit['has_proof'] = true;
            }

            if (in_array($type, array('faq', 'accordion', 'pros_cons', 'comparison_table'), true)) {
                $audit['has_objection_handling'] = true;
            }

            if (!empty($attrs['layout_variant'])) {
                $layout_variants[] = sanitize_key($attrs['layout_variant']);
            }

            if (
                !empty($attrs['image_url']) ||
                !empty($attrs['visual']['image_url']) ||
                !empty($attrs['image_prompt']) ||
                !empty($attrs['visual']['image_prompt'])
            ) {
                $visual_count++;
            }

            if (!empty($attrs['items']) && is_array($attrs['items'])) {
                foreach ($attrs['items'] as $item) {
                    if (!empty($item['image_url']) || !empty($item['image_prompt'])) {
                        $visual_count++;
                    }
                }
            }
        }

        $audit['has_visuals'] = $visual_count > 0;
        $audit['has_layout_variation'] = count(array_unique(array_filter($layout_variants))) >= 2;

        foreach (array(
            'has_hero' => 'Missing hero component.',
            'has_cta' => 'Missing CTA or lead capture component.',
            'has_value' => 'Missing value/benefit component.',
            'has_proof' => 'Missing proof/trust component.',
            'has_objection_handling' => 'Missing objection handling component.',
            'has_visuals' => 'Missing generated or planned visual assets.',
            'has_layout_variation' => 'Page uses too little layout variation.',
        ) as $key => $warning) {
            if ($this->is_article_format() && in_array($key, array('has_hero', 'has_cta', 'has_value', 'has_proof'), true)) {
                continue;
            }

            if (empty($audit[$key])) {
                $audit['warnings'][] = $warning;
            }
        }

        if ($audit['component_count'] < $this->get_min_components()) {
            $audit['warnings'][] = 'Page has too few components for premium quality.';
        }

        if ($this->component_tree_has_generic_copy($components)) {
            $audit['warnings'][] = 'Page contains generic placeholder-style copy.';
        }

        foreach ($components as $component) {
            if ($this->component_has_unsupported_claims($component)) {
                $audit['warnings'][] = 'Page contains unsupported exact claims or proof.';
                break;
            }
        }

        foreach ($components as $component) {
            if ($this->component_has_fake_social_proof($component)) {
                $audit['warnings'][] = 'Page contains testimonial-style proof without source material.';
                break;
            }
        }

        if ($this->is_article_format() && !$this->final_page_has_substantive_text($components)) {
            $audit['warnings'][] = 'Article lacks enough substantive text content.';
        }

        $audit['score'] = max(0, 100 - (count($audit['warnings']) * 12));

        $this->quality_audit = $audit;
        $this->final_page['quality_audit'] = $audit;

        $this->log_step('Quality check completed. Score: ' . $audit['score']);
    }

    protected function repair_final_page_if_needed()
    {
        if (empty($this->quality_audit['warnings'])) {
            return;
        }

        $repairs = array();

        if (!$this->is_article_format()) {
            if (empty($this->quality_audit['has_hero'])) {
                $repairs[] = array('id' => 'repair_hero', 'component' => 'hero', 'purpose' => 'Create a strong opening hero.');
            }

            if (empty($this->quality_audit['has_value'])) {
                $repairs[] = array('id' => 'repair_value', 'component' => 'feature_grid', 'purpose' => 'Explain the strongest benefits.');
            }

            if (empty($this->quality_audit['has_cta'])) {
                $repairs[] = array('id' => 'repair_cta', 'component' => 'cta_banner', 'purpose' => 'Close with a strong CTA.');
            }
        } else {
            if (!$this->final_page_has_substantive_text($this->generated_components)) {
                $repairs[] = array('id' => 'repair_article_text', 'component' => 'text', 'purpose' => 'Add a substantive article section with useful detail and examples.');
            }
        }

        if (empty($this->quality_audit['has_proof'])) {
            $repairs[] = array('id' => 'repair_proof', 'component' => 'highlight_box', 'purpose' => 'Add a grounded trust section using only source-backed proof, implementation safeguards, or evaluation criteria. Do not invent customer names, exact numbers, ratings, certifications, or awards.');
        }

        if (empty($this->quality_audit['has_objection_handling'])) {
            $repairs[] = array('id' => 'repair_faq', 'component' => 'faq', 'purpose' => 'Handle common objections and questions.');
        }

        foreach ($repairs as $repair) {
            $generated = false;
            $validated = false;

            for ($attempt = 1; $attempt <= 2; $attempt++) {
                $generated = $this->generate_single_component($repair, $repair['component'], $attempt > 1);
                $validated = $this->validate_and_normalize_component($generated, $repair['component']);

                if ($validated && $this->component_is_professional_enough($validated)) {
                    break;
                }

                $validated = false;
            }

            if ($validated) {
                $this->generated_components[] = $validated;
            }
        }

        $this->final_page['components'] = array_values($this->generated_components);
        $this->final_page['blocks'] = array_values($this->generated_components);

        $this->run_quality_audit();
        $this->log_step('Repair pass completed');
    }

    protected function component_tree_has_generic_copy($components)
    {
        foreach ((array) $components as $component) {
            if ($this->component_has_generic_copy($component)) {
                return true;
            }
        }

        return false;
    }

    protected function final_page_has_substantive_text($components)
    {
        $word_count = 0;

        foreach ((array) $components as $component) {
            if (($component['component'] ?? '') !== 'text') {
                continue;
            }

            $content = wp_strip_all_tags($component['attrs']['content'] ?? '');
            $word_count += str_word_count($content);
        }

        return $word_count >= 180;
    }

    protected function get_component_signature($component)
    {
        if (!is_array($component)) {
            return '';
        }

        $type = sanitize_key($component['component'] ?? $component['block'] ?? '');

        if (!in_array($type, array('feature_grid', 'card_grid', 'product_showcase', 'pricing_cards', 'stats', 'testimonial_grid', 'comparison_table', 'pros_cons', 'logo_cloud'), true)) {
            return '';
        }

        $attrs = isset($component['attrs']) && is_array($component['attrs']) ? $component['attrs'] : array();
        $parts = array(
            $type,
            wp_strip_all_tags((string) ($attrs['title'] ?? '')),
            wp_strip_all_tags((string) ($attrs['headline'] ?? '')),
            wp_strip_all_tags((string) ($attrs['subtitle'] ?? '')),
        );

        if (!empty($attrs['items']) && is_array($attrs['items'])) {
            foreach (array_slice($attrs['items'], 0, 8) as $item) {
                if (!is_array($item)) {
                    continue;
                }

                $parts[] = wp_strip_all_tags((string) ($item['title'] ?? $item['name'] ?? $item['value'] ?? $item['question'] ?? ''));
            }
        }

        if (!empty($attrs['columns']) && is_array($attrs['columns'])) {
            foreach ($attrs['columns'] as $column) {
                if (is_array($column)) {
                    $column = $column['title'] ?? $column['label'] ?? $column['name'] ?? '';
                }

                if (is_scalar($column)) {
                    $parts[] = wp_strip_all_tags((string) $column);
                }
            }
        }

        $signature = trim(strtolower(preg_replace('/\s+/', ' ', implode(' ', array_filter($parts)))));

        return $signature !== '' ? md5($signature) : '';
    }

    protected function dedupe_components($components)
    {
        $clean = array();
        $seen = array();

        foreach ((array) $components as $component) {
            $signature = $this->get_component_signature($component);

            if ($signature !== '') {
                if (isset($seen[$signature])) {
                    continue;
                }

                $seen[$signature] = true;
            }

            $clean[] = $component;
        }

        return $clean;
    }

    protected function validate_final_page()
    {
        if (empty($this->final_page['components'])) {
            throw new Exception('No valid page components generated.');
        }

        $clean = array();

        foreach ($this->final_page['components'] as $component) {
            $validated = $this->validate_and_normalize_component($component);

            if ($validated) {
                $validated = $this->strip_untrusted_component_images($validated);
                $clean[] = $validated;
            }
        }

        $clean = $this->dedupe_components($clean);

        if (empty($clean)) {
            throw new Exception('No valid page components generated.');
        }

        $this->final_page['components'] = $clean;
        $this->final_page['blocks'] = $clean;
        $this->generated_components = $clean;
        $this->final_page['quality_audit'] = $this->quality_audit;

        $this->log_step('Final validation completed');
    }

    protected function tree_has_component($type)
    {
        foreach ($this->component_tree as $item) {
            if (($item['component'] ?? '') === $type) {
                return true;
            }
        }

        return false;
    }

    protected function tree_has_any_component($types)
    {
        foreach ($types as $type) {
            if ($this->tree_has_component($type)) {
                return true;
            }
        }

        return false;
    }

    protected function summarize_generated_components()
    {
        if (empty($this->generated_components)) {
            return 'No components generated yet.';
        }

        $summary = array();

        foreach ($this->generated_components as $component) {
            $attrs = $component['attrs'] ?? array();
            $title = $attrs['headline'] ?? $attrs['title'] ?? $attrs['eyebrow'] ?? '';
            $content = wp_strip_all_tags($attrs['content'] ?? $attrs['subheadline'] ?? '');
            $summary[] = ($component['component'] ?? 'unknown') .
                ($title ? ': ' . $title : '') .
                ($content ? ' | ' . aiomatic_substr($content, 0, 180) : '');
        }

        return implode("\n", array_slice($summary, -10));
    }

    protected function update_context_from_generated_component($component)
    {
        $this->remember_content_points($component);

        if (($component['component'] ?? '') !== 'hero') {
            return;
        }

        $attrs = $component['attrs'] ?? array();

        if (!empty($attrs['headline'])) {
            $this->context_window['headline_style'] = sanitize_text_field($attrs['headline']);
        }

        if (!empty($attrs['primary_cta'])) {
            $this->context_window['primary_cta'] = sanitize_text_field($attrs['primary_cta']);
        }

        if (!empty($attrs['secondary_cta'])) {
            $this->context_window['secondary_cta'] = sanitize_text_field($attrs['secondary_cta']);
        }

        if (!empty($attrs['subheadline'])) {
            $this->context_window['core_promise'] = sanitize_text_field($attrs['subheadline']);
        }
    }

    protected function extract_image_url_from_tool_result($result)
    {
        if (empty($result)) {
            return '';
        }

        if (is_string($result)) {
            if (filter_var($result, FILTER_VALIDATE_URL)) {
                return esc_url_raw($result);
            }

            $decoded = json_decode($result, true);
            if (is_array($decoded)) {
                $result = $decoded;
            }
        }

        if (is_array($result)) {
            foreach (array('output', 'url', 'image_url', 'src') as $key) {
                if (!empty($result[$key]) && filter_var($result[$key], FILTER_VALIDATE_URL)) {
                    return esc_url_raw($result[$key]);
                }
            }

            if (!empty($result[0]) && is_array($result[0])) {
                return $this->extract_image_url_from_tool_result($result[0]);
            }
        }

        return '';
    }

    protected function get_default_layout_variant($type, $index = 0)
    {
        $type = sanitize_key($type);

        $map = array(
            'hero' => 'hero_split',
            'feature_grid' => 'centered_grid',
            'card_grid' => 'centered_grid',
            'product_showcase' => 'product_cards',
            'steps' => 'alternating_steps',
            'timeline' => 'vertical_timeline',
            'comparison_table' => 'wide_table',
            'pricing_cards' => 'pricing_grid',
            'faq' => 'accordion_stack',
            'cta_banner' => 'dark_band',
            'image_banner' => ($index % 2 === 0 ? 'media_right' : 'media_left'),
            'text' => ($index % 2 === 0 ? 'text_narrow' : 'text_wide'),
            'highlight_box' => 'contrast_callout',
            'table_of_contents' => 'toc_card',
            'editorial_summary' => 'summary_box',
            'logo_cloud' => 'muted_wordmarks',
        );

        return $map[$type] ?? 'standard';
    }

    protected function get_available_image_tools()
    {
        if (function_exists('aiomatic_super_pages_get_available_image_tools')) {
            return aiomatic_super_pages_get_available_image_tools($this);
        }

        $settings = get_option('aiomatic_Main_Settings', false);

        $tools = array();

        if (!empty($settings['app_id']) && trim((string) $settings['app_id']) !== '') {
            $tools[] = 'generate_ai_image_openai';
        }

        if (!empty($settings['stability_app_id'])) {
            $tools[] = 'generate_ai_image_stable_diffusion';
        }

        if (!empty($settings['app_id_google'])) {
            $tools[] = 'generate_ai_image_google';
        }

        if (!empty($settings['midjourney_app_id'])) {
            $tools[] = 'generate_ai_image_midjourney';
        }

        if (!empty($settings['replicate_app_id'])) {
            $tools[] = 'generate_ai_image_replicate';
        }

        if (!empty($settings['ideogram_app_id'])) {
            $tools[] = 'generate_ai_image_ideogram';
        }

        if (
            !empty($settings['cloudflare_worker_url']) &&
            !empty($settings['cloudflare_worker_secret'])
        ) {
            $tools[] = 'generate_ai_image_cloudflare';
        }
        $tools[] = 'royalty_free_image_search';
        return apply_filters(
            'aimogen_super_page_image_tools',
            $tools,
            $settings,
            $this
        );
    }

    protected function get_image_source()
    {
        $source = $this->runtime_config['image_source'] ?? ($this->runtime_config['include_images'] ?? 'none');

        if (function_exists('aiomatic_super_pages_normalize_image_source')) {
            return aiomatic_super_pages_normalize_image_source($source, $this->get_available_image_tools());
        }

        if (is_bool($source)) {
            return $source ? 'royalty_free' : 'none';
        }

        $source = sanitize_key((string) $source);

        if (in_array($source, array('', '0', 'false', 'no', 'off', 'none'), true)) {
            return 'none';
        }

        return $source;
    }

    protected function images_enabled()
    {
        return $this->get_image_source() !== 'none';
    }

    protected function get_image_tools_for_selected_source()
    {
        $source = $this->get_image_source();

        if ($source === 'none') {
            return array();
        }

        if (function_exists('aiomatic_super_pages_image_source_to_tool')) {
            $tool = aiomatic_super_pages_image_source_to_tool($source);

            if ($tool !== '') {
                return array($tool);
            }
        }

        return $this->get_available_image_tools();
    }

    protected function generate_and_import_image($prompt, $title = '', $ratio = '16:9', $style = '')
    {
        $prompt = trim((string) $prompt);

        if ($prompt === '') {
            return false;
        }

        $image_tools = $this->get_image_tools_for_selected_source();

        if (empty($image_tools)) {
            $this->log_step('No image generation tool is available.');
            return false;
        }

        if ($style === '') {
            $style = 'ultra premium SaaS landing page visual, cinematic lighting, modern startup branding, glassmorphism, clean UI/UX aesthetic, highly detailed, marketing website quality';
        }

        $final_prompt = trim($prompt . "\n\nStyle: " . $style . "\nAspect ratio: " . $ratio);

        foreach ($image_tools as $tool_name) {

            if (!$this->tool_is_allowed($tool_name)) {
                continue;
            }
            if($tool_name === 'royalty_free_image_search')
            {
                $keyword = $this->build_royalty_free_image_query($prompt, $title);

                if ($keyword === '') {
                    $keyword = $this->state['intent'];
                }

                $this->log_step('Searching royalty-free image for: ' . $keyword);

                $result = $this->execute_tool_safe(
                    $tool_name,
                    array(
                        'keyword' => $keyword,
                    )
                );
            }
            else
            {
                $result = $this->execute_tool_safe(
                    $tool_name,
                    array(
                        'prompt' => $final_prompt,
                    )
                );
            }

            $image_url = $this->extract_image_url_from_tool_result($result);

            if (!$image_url) {
                $this->log_step('Image tool returned no usable URL: ' . $tool_name);
                continue;
            }

            $attachment = $this->import_generated_image(
                $image_url,
                $title ?: $this->state['intent']
            );

            if (!empty($attachment['url'])) {
                $this->remember_visual_asset($final_prompt, $attachment['url']);
                return $attachment;
            }
        }

        return false;
    }

    protected function build_royalty_free_image_query($prompt, $title = '')
    {
        $prompt = html_entity_decode(wp_strip_all_tags((string) $prompt), ENT_QUOTES | ENT_HTML5, get_bloginfo('charset') ?: 'UTF-8');
        $title = html_entity_decode(wp_strip_all_tags((string) $title), ENT_QUOTES | ENT_HTML5, get_bloginfo('charset') ?: 'UTF-8');

        $candidates = array();

        if (preg_match('/\b(?:photo|photograph|image|visual|illustration|picture)\s+of\s+(?:a|an|the)?\s*([^,.;:]+)/i', $prompt, $match)) {
            $candidates[] = $match[1];
        }

        if (preg_match('/\b(?:of|showing|featuring|depicting)\s+(?:a|an|the)?\s*([^,.;:]+)/i', $prompt, $match)) {
            $candidates[] = $match[1];
        }

        if ($title !== '') {
            $candidates[] = $title;
        }

        $candidates[] = $prompt;

        foreach ($candidates as $candidate) {
            $query = $this->normalize_royalty_free_image_query($candidate);

            if ($query !== '') {
                return $query;
            }
        }

        return '';
    }

    protected function normalize_royalty_free_image_query($text)
    {
        $text = strtolower((string) $text);
        $text = preg_replace('/\b(?:with|against|on|in|at|for|from|using|positioned|suitable)\b.*$/i', '', $text);
        $text = preg_replace('/[^a-z0-9\s-]+/i', ' ', $text);
        $text = preg_replace('/\s+/', ' ', trim($text));

        if ($text === '') {
            return '';
        }

        $stopwords = array(
            'a', 'an', 'the', 'and', 'or', 'but', 'to', 'of', 'by', 'as', 'is', 'are',
            'this', 'that', 'these', 'those', 'best', 'top', 'guide', 'buyer', 'buyers',
            '2024', '2025', '2026', 'expert', 'reviewed', 'reviews', 'premium', 'modern',
            'clean', 'style', 'styles', 'suitable', 'use', 'using', 'needs',
            'modern', 'premium', 'editorial', 'lighting', 'background', 'negative',
            'space', 'text', 'website', 'landing', 'page', 'visual', 'image', 'photo',
            'photograph', 'illustration', 'high', 'contrast', 'high-contrast',
            'cinematic', 'minimalistic', 'minimalist', 'detailed', 'texture', 'detail',
            'ample', 'left', 'right', 'side', 'sleek', 'alert', 'striking',
            'professional', 'quality', 'brand', 'branding', 'layout', 'composition',
            'focal', 'point', 'ui', 'ux', 'aesthetic'
        );

        $words = array();

        foreach (preg_split('/\s+/', $text) as $word) {
            $word = trim($word, " \t\n\r\0\x0B-");

            if ($word === '' || in_array($word, $stopwords, true)) {
                continue;
            }

            $words[] = $word;
        }

        if (empty($words)) {
            return '';
        }

        $words = array_values(array_unique($words));
        $count = count($words);

        if ($count > 4) {
            $words = array_slice($words, max(0, $count - 4), 4);
        }

        return sanitize_text_field(implode(' ', $words));
    }

    protected function build_default_image_prompt($component, $tree_item, $kind = 'section')
    {
        $attrs = $component['attrs'] ?? array();
        $title = $attrs['headline'] ?? $attrs['title'] ?? $this->state['intent'];
        $purpose = $tree_item['purpose'] ?? '';
        $layout = $tree_item['layout_variant'] ?? '';
        $mood = $tree_item['section_mood'] ?? '';
        $visual_weight = $tree_item['visual_weight'] ?? 'medium';
        $design = $this->context_window['design_system'] ?? array();

        return trim(
            'Premium landing page visual for: ' . $title . ". " .
            'Purpose: ' . $purpose . ". " .
            'Visual direction: ' . ($this->context_window['page_visual_direction'] ?? '') . ". " .
            'Layout: ' . $layout . ', visual weight: ' . $visual_weight . ', mood: ' . $mood . ". " .
            'Design system: ' . wp_json_encode($design) . ". " .
            'Clean composition, professional marketing website quality, strong focal point, coherent branding, polished UI/UX feel, cinematic lighting, modern web design aesthetic.'
        );
    }

    protected function remember_visual_asset($prompt, $url = '')
    {
        if (empty($this->context_window['visual_memory']) || !is_array($this->context_window['visual_memory'])) {
            $this->context_window['visual_memory'] = array();
        }

        $this->context_window['visual_memory'][] = array(
            'prompt' => aiomatic_substr(wp_strip_all_tags((string) $prompt), 0, 220),
            'url' => esc_url_raw((string) $url),
        );

        $this->context_window['visual_memory'] = array_slice($this->context_window['visual_memory'], -10);
    }

    protected function remember_content_points($component)
    {
        if (empty($this->context_window['content_memory']) || !is_array($this->context_window['content_memory'])) {
            $this->context_window['content_memory'] = array();
        }

        $attrs = $component['attrs'] ?? array();

        $this->context_window['content_memory'][] = array(
            'component' => $component['component'] ?? '',
            'title' => sanitize_text_field($attrs['headline'] ?? $attrs['title'] ?? ''),
            'cta' => sanitize_text_field($attrs['primary_cta'] ?? $attrs['button'] ?? ''),
            'excerpt' => sanitize_text_field(aiomatic_substr(wp_strip_all_tags($attrs['content'] ?? $attrs['subheadline'] ?? ''), 0, 220)),
        );

        $this->context_window['content_memory'] = array_slice($this->context_window['content_memory'], -12);
    }

    protected function generate_page_title()
    {
        $title = '';

        if (!empty($this->component_strategy['title'])) {
            $title = $this->component_strategy['title'];
        } elseif (!empty($this->state['intent'])) {
            $title = $this->state['intent'];
        } elseif (!empty($this->context_window['core_promise'])) {
            $title = $this->context_window['core_promise'];
        }

        if (!$title) {
            $title = $this->is_article_format() ? 'AI Generated Article' : 'AI Generated Landing Page';
        }

        return sanitize_text_field(aiomatic_substr($title, 0, 90));
    }

    protected function generate_meta_description()
    {
        $description = $this->context_window['main_offer'] ?? '';

        if (!$description) {
            $description = $this->state['primary_goal'] ?: $this->state['prompt'];
        }

        return sanitize_text_field(aiomatic_substr($description, 0, 155));
    }

    protected function generate_ai_json_with_retry($prompt, $request_suffix = 'json')
    {
        $last_response = '';
        $last_error = '';

        for ($attempt = 1; $attempt <= self::MAX_RETRIES; $attempt++) {
            $temperature = $attempt === 1 ? (float) ($this->runtime_config['temperature'] ?? 0.65) : 0.25;

            $response = $this->generate_ai_raw(
                $prompt,
                $temperature,
                $request_suffix . '-' . $attempt,
                $last_response,
                $last_error
            );

            if (!$response) {
                $last_error = 'Empty AI response.';
                continue;
            }

            $last_response = $response;
            $decoded = $this->decode_json($response);

            if (is_array($decoded)) {
                return $decoded;
            }

            $last_error = 'Invalid JSON.';
            $prompt = $this->build_json_repair_prompt($prompt, $response);
        }

        return false;
    }

    protected function generate_ai_raw($prompt, $temperature = 0.65, $request_suffix = 'request', $last_response = '', $last_error = '')
    {
        $aiomatic_Main_Settings = get_option('aiomatic_Main_Settings', false);

        $token = isset($aiomatic_Main_Settings['app_id']) ? trim((string) $aiomatic_Main_Settings['app_id']) : '';
        if (strpos($token, "\n") !== false || strpos($token, "\r") !== false) {
            $tokens = array_filter(preg_split('/\r\n|\r|\n/', $token));
            $token = !empty($tokens) ? reset($tokens) : '';
        }

        $token = apply_filters('aimogen_openai_api_key', $token);
        $token = apply_filters('aiomatic_openai_api_key', $token);

        $full_prompt = $prompt;

        if ($last_error !== '') {
            $full_prompt .= "\n\nPrevious error: " . $last_error;
        }

        if ($last_response !== '') {
            $full_prompt .= "\n\nPrevious invalid response excerpt:\n" . aiomatic_substr($last_response, 0, 1500);
        }

        $model = $this->runtime_config['model'] ?? self::DEFAULT_MODEL;

        if (function_exists('aiomatic_get_all_models') && function_exists('aiomatic_get_default_model_name')) {
            $all_models = aiomatic_get_all_models(true);
            if (is_array($all_models) && !in_array($model, $all_models, true)) {
                $model = aiomatic_get_default_model_name($aiomatic_Main_Settings);
            }
        }

        $query_token_count = function_exists('aiomatic_encode') ? count(aiomatic_encode($full_prompt)) : 0;
        $max_tokens = function_exists('aimogenpro_get_max_tokens') ? aimogenpro_get_max_tokens($model) : 8000;

        if (function_exists('aiomatic_compute_available_tokens')) {
            $available_tokens = aiomatic_compute_available_tokens($model, $max_tokens, $full_prompt, $query_token_count);
        } else {
            $available_tokens = 4000;
        }

        if (defined('AIMOGEN_MINIMUM_TOKENS_FOR_COMPLETIONS') && $available_tokens <= AIMOGEN_MINIMUM_TOKENS_FOR_COMPLETIONS) {
            $string_len = intval(0 - (aiomatic_strlen($full_prompt) / 2));
            $full_prompt = trim(aiomatic_substr($full_prompt, 0, $string_len));
            $query_token_count = function_exists('aiomatic_encode') ? count(aiomatic_encode($full_prompt)) : 0;
            $available_tokens = $max_tokens - $query_token_count;
        }

        $thread_id = '';
        $finish_reason = '';
        $aierror = '';

        $response = aiomatic_generate_text(
            $token,
            $model,
            $full_prompt,
            $available_tokens,
            $temperature,
            1,
            0,
            0,
            false,
            'aiPagesDynamic-' . sanitize_key($request_suffix),
            0,
            $finish_reason,
            $aierror,
            true,
            true,
            false,
            '',
            '',
            'user',
            '',
            $thread_id,
            '',
            'disabled',
            '',
            true,
            false,
            array(),
            '',
            '',
            ''
        );

        if (!$response && !empty($aierror)) {
            $this->log_step('AI error on ' . $request_suffix . ': ' . $aierror);
        }

        return $response;
    }

    protected function build_json_repair_prompt($original_prompt, $bad_response)
    {
        return "The previous response was not valid JSON. Repair it.\n\nReturn ONLY valid JSON. Do not use markdown or code fences.\n\nOriginal task:\n" .
            $original_prompt .
            "\n\nInvalid response:\n" .
            aiomatic_substr((string) $bad_response, 0, 4000);
    }

    protected function decode_json($content)
    {
        $content = trim((string) $content);
        $content = preg_replace('/^\xEF\xBB\xBF/', '', $content);
        $content = preg_replace('/^```json\s*/i', '', $content);
        $content = preg_replace('/^```\s*/', '', $content);
        $content = preg_replace('/\s*```$/', '', $content);
        $content = trim($content);

        $decoded = json_decode($content, true);
        if (is_array($decoded)) {
            return $decoded;
        }

        $first = strpos($content, '{');
        $last = strrpos($content, '}');

        if ($first !== false && $last !== false && $last > $first) {
            $decoded = json_decode(substr($content, $first, $last - $first + 1), true);
            if (is_array($decoded)) {
                return $decoded;
            }
        }

        return false;
    }

    protected function execute_tool_safe($tool_name, $args = array())
    {
        if (!$this->tool_is_allowed($tool_name)) {
            $this->log_step('Tool blocked by runtime config: ' . $tool_name);
            return false;
        }

        if (!method_exists($this, 'execute_tool')) {
            $this->log_step('execute_tool method is unavailable. Make Aiomatic_Agent::execute_tool protected.');
            return false;
        }

        try {
            return $this->execute_tool($tool_name, $args);
        } catch (Throwable $e) {
            $this->log_step('Tool failed: ' . $tool_name . ' - ' . $e->getMessage());
            return false;
        }
    }

    protected function tool_is_allowed($tool_name)
    {
        if (empty($this->runtime_config['allowed_tools']) || !is_array($this->runtime_config['allowed_tools'])) {
            return true;
        }

        return in_array($tool_name, $this->runtime_config['allowed_tools'], true);
    }

    protected function normalize_serp_results($result)
    {
        if (empty($result)) {
            return array();
        }

        if (is_string($result)) {

            $decoded = json_decode($result, true);

            if (is_array($decoded)) {
                $result = $decoded;
            } else {

                $items = array();

                $lines = preg_split('/\r\n|\r|\n/', $result);

                foreach ($lines as $line) {

                    $line = trim($line);

                    if (empty($line)) {
                        continue;
                    }

                    if (
                        preg_match(
                            '/^\[\d+\]\:\s*(.*?)\s*-\s*(.*?)\s*\((https?:\/\/[^\s\)]+)\)\s*$/i',
                            $line,
                            $matches
                        )
                    ) {
                        $items[] = array(
                            'url'     => esc_url_raw($matches[3]),
                            'title'   => sanitize_text_field($matches[1]),
                            'snippet' => sanitize_text_field($matches[2]),
                        );
                    } elseif (
                        preg_match(
                            '/^\[\d+\]\:\s*(.+)$/',
                            $line,
                            $matches
                        )
                    ) {
                        $content = trim($matches[1]);

                        $parts = explode(' - ', $content, 2);

                        $items[] = array(
                            'url'     => '',
                            'title'   => sanitize_text_field($parts[0] ?? ''),
                            'snippet' => sanitize_text_field($parts[1] ?? ''),
                        );
                    }
                }

                return $items;
            }
        }

        if (!is_array($result)) {
            return array();
        }

        if (isset($result['results']) && is_array($result['results'])) {
            $result = $result['results'];
        } elseif (isset($result['items']) && is_array($result['items'])) {
            $result = $result['items'];
        }

        $items = array();

        foreach ($result as $item) {

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

            $url = $item['url'] ?? $item['link'] ?? $item['href'] ?? '';
            $title = $item['title'] ?? $item['name'] ?? '';
            $snippet = $item['snippet'] ?? $item['description'] ?? '';

            if (!$title) {
                continue;
            }

            $items[] = array(
                'url'     => esc_url_raw($url),
                'title'   => sanitize_text_field($title),
                'snippet' => sanitize_text_field($snippet),
            );
        }

        return $items;
    }

    protected function extract_structured_content($content)
    {
        if (is_array($content)) {
            $content = wp_json_encode($content);
        }

        $html = (string) $content;

        $structure = array(
            'title' => '',
            'headings' => array(),
            'lists' => array(),
            'tables' => array(),
            'ctas' => array(),
            'text' => '',
        );

        if ($html === '') {
            return $structure;
        }

        if (preg_match('/<title[^>]*>(.*?)<\/title>/is', $html, $m)) {
            $structure['title'] = sanitize_text_field(html_entity_decode(wp_strip_all_tags($m[1])));
        }

        if (preg_match_all('/<h([1-6])[^>]*>(.*?)<\/h\1>/is', $html, $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                $heading = trim(html_entity_decode(wp_strip_all_tags($match[2])));
                if ($heading !== '') {
                    $structure['headings'][] = array('level' => (int) $match[1], 'text' => sanitize_text_field($heading));
                }
            }
        }

        if (preg_match_all('/<(ul|ol)[^>]*>(.*?)<\/\1>/is', $html, $matches, PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                if (preg_match_all('/<li[^>]*>(.*?)<\/li>/is', $match[2], $lis)) {
                    $items = array();
                    foreach ($lis[1] as $li) {
                        $text = trim(html_entity_decode(wp_strip_all_tags($li)));
                        if ($text !== '') {
                            $items[] = sanitize_text_field($text);
                        }
                    }
                    if ($items) {
                        $structure['lists'][] = array_slice($items, 0, 12);
                    }
                }
            }
        }

        if (preg_match_all('/<table[^>]*>(.*?)<\/table>/is', $html, $tables)) {
            foreach ($tables[1] as $table_html) {
                $table_text = trim(preg_replace('/\s+/', ' ', html_entity_decode(wp_strip_all_tags($table_html))));
                if ($table_text !== '') {
                    $structure['tables'][] = sanitize_text_field(aiomatic_substr($table_text, 0, 1000));
                }
            }
        }

        if (preg_match_all('/<a[^>]*>(.*?)<\/a>/is', $html, $links)) {
            foreach ($links[1] as $link_text) {
                $text = trim(html_entity_decode(wp_strip_all_tags($link_text)));
                if ($text !== '' && aiomatic_strlen($text) <= 80 && $this->looks_like_cta($text)) {
                    $structure['ctas'][] = sanitize_text_field($text);
                }
            }
        }

        $plain = trim(preg_replace('/\s+/', ' ', html_entity_decode(wp_strip_all_tags($html))));
        $structure['text'] = aiomatic_substr($plain, 0, 18000);

        $structure['headings'] = array_slice($structure['headings'], 0, 60);
        $structure['lists'] = array_slice($structure['lists'], 0, 20);
        $structure['tables'] = array_slice($structure['tables'], 0, 8);
        $structure['ctas'] = array_values(array_unique(array_slice($structure['ctas'], 0, 20)));

        return $structure;
    }

    protected function compress_structured_content($structure)
    {
        $out = '';

        if (!empty($structure['title'])) {
            $out .= "Title: " . $structure['title'] . "\n";
        }

        if (!empty($structure['headings'])) {
            $out .= "Headings:\n";
            foreach ($structure['headings'] as $heading) {
                $out .= 'H' . (int) $heading['level'] . ': ' . $heading['text'] . "\n";
            }
        }

        if (!empty($structure['ctas'])) {
            $out .= "CTA phrases:\n- " . implode("\n- ", $structure['ctas']) . "\n";
        }

        if (!empty($structure['lists'])) {
            $out .= "Important lists:\n";
            foreach ($structure['lists'] as $list) {
                $out .= '- ' . implode('; ', array_slice($list, 0, 8)) . "\n";
            }
        }

        if (!empty($structure['tables'])) {
            $out .= "Tables:\n";
            foreach ($structure['tables'] as $table) {
                $out .= '- ' . $table . "\n";
            }
        }

        if (!empty($structure['text'])) {
            $out .= "Compressed text:\n" . aiomatic_substr($structure['text'], 0, 9000);
        }

        return trim($out);
    }

    protected function looks_like_cta($text)
    {
        $text = strtolower($text);
        foreach (array('get', 'start', 'try', 'buy', 'download', 'learn', 'contact', 'book', 'schedule', 'request', 'sign up', 'subscribe', 'join', 'demo', 'pricing', 'quote', 'order') as $pattern) {
            if (strpos($text, $pattern) !== false) {
                return true;
            }
        }

        return false;
    }

    protected function is_duplicate_competitor($competitors, $url)
    {
        $host = wp_parse_url($url, PHP_URL_HOST);

        if (!$host) {
            return false;
        }

        $host = preg_replace('/^www\./', '', strtolower($host));

        foreach ($competitors as $competitor) {
            $existing_host = wp_parse_url($competitor['url'] ?? '', PHP_URL_HOST);
            $existing_host = preg_replace('/^www\./', '', strtolower((string) $existing_host));

            if ($host === $existing_host) {
                return true;
            }
        }

        return false;
    }

    protected function json_prompt($task, $schema, $context = '')
    {
        return $this->get_builder_persona() . "\n\n" .
            "Task:\n" . $task . "\n\n" .
            "Return ONLY valid JSON. No markdown. No code fences. No explanations.\n\n" .
            "Required JSON shape:\n" . wp_json_encode($schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "\n\n" .
            "Context:\n" . $context;
    }

    protected function sanitize_string_list($items, $limit = 20)
    {
        if (!is_array($items)) {
            return array();
        }

        $clean = array();

        foreach ($items as $item) {
            if (is_array($item) || is_object($item)) {
                continue;
            }

            $item = sanitize_text_field((string) $item);

            if ($item !== '') {
                $clean[] = $item;
            }

            if (count($clean) >= $limit) {
                break;
            }
        }

        return array_values(array_unique($clean));
    }

    protected function sanitize_deep_array($value)
    {
        if (is_array($value)) {
            $clean = array();

            foreach ($value as $key => $item) {
                $clean_key = is_string($key) ? sanitize_key($key) : $key;
                $clean[$clean_key] = $this->sanitize_deep_array($item);
            }

            return $clean;
        }

        if (is_string($value)) {
            return wp_kses_post($value);
        }

        if (is_bool($value) || is_numeric($value) || is_null($value)) {
            return $value;
        }

        return '';
    }

    protected function log_step($message)
    {
        if (function_exists('aiomatic_log_to_file')) {
            aiomatic_log_to_file('[SuperPageAgent] ' . $message);
        }
    }

    public function get_state() { return $this->state; }
    public function get_context_window() { return $this->context_window; }
    public function get_component_strategy() { return $this->component_strategy; }
    public function get_component_tree() { return $this->component_tree; }
    public function get_generated_components() { return $this->generated_components; }
    public function get_quality_audit() { return $this->quality_audit; }
    public function get_final_page() { return $this->final_page; }
    public function get_component_registry() { return $this->component_registry; }
}

}
