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

trait Niwa_AI_Chat_Media {

    public function resolve_media_only_turn( $context = array() ) {
        // Phase 5 — caption from a photo+caption send is the user's primary
        // signal of intent for that turn. If present, treat it as a clear
        // execute_change request and skip the heuristic / LLM router below.
        $caption = isset( $context['caption'] ) ? trim( (string) $context['caption'] ) : '';
        if ( '' !== $caption ) {
            return array(
                'success'      => true,
                'mode'         => 'execute_change',
                'prompt'       => $caption,
                'force_action' => false,
                'remember_as'  => '[image with caption: ' . $this->truncate_block( $caption, 120 ) . ']',
            );
        }

        $heuristic_prompt = $this->detect_pending_image_change_from_history( $context );
        if ( '' !== $heuristic_prompt ) {
            return array(
                'success'      => true,
                'mode'         => 'execute_change',
                'prompt'       => $heuristic_prompt,
                'force_action' => true,
                'remember_as'  => '[image for site change]',
            );
        }

        $history = isset( $context['history'] ) ? array_slice( (array) $context['history'], -10 ) : array();
        $input   = array();
        if ( ! empty( $history ) ) {
            $input[] = "[RECENT HISTORY]\n" . $this->format_history( $history ) . "\n[/RECENT HISTORY]";
        }
        if ( ! empty( $context['attachment_image_urls'] ) ) {
            $album_note = ! empty( $context['is_album'] )
                ? ' (album_size=' . intval( $context['album_size'] ?? 0 ) . ')'
                : '';
            $input[] = '[ATTACHMENTS]' . "\n" . 'attached_images=' . count( (array) $context['attachment_image_urls'] ) . $album_note . "\n[/ATTACHMENTS]";
        }
        if ( ! empty( $context['forward_marker'] ) ) {
            $input[] = '[FORWARD]' . "\n" . (string) $context['forward_marker'] . "\n[/FORWARD]";
        }
        $turn_note = ! empty( $context['is_album'] )
            ? sprintf( "Founder sent an album of %d images without text in Telegram.", intval( $context['album_size'] ?? 0 ) )
            : 'Founder sent an image without text in Telegram.';
        $input[] = '[CURRENT TURN]' . "\n" . $turn_note . "\n[/CURRENT TURN]";

        if ( ! $this->auth_manager || ! $this->openai_client ) {
            return array(
                'success'    => true,
                'mode'       => 'analyze_image',
                'prompt'     => 'Analiziraj prilozenu sliku i odgovori founderu prirodno i korisno.',
                'force_action' => false,
                'remember_as'  => '[image]',
            );
        }

        $model  = $this->get_founder_model();
        $result = $this->openai_client->generate(
            $model,
            implode( "\n\n", $input ),
            implode(
                "\n",
                array(
                    'Route an image-only Telegram turn for Niwa, a founder-facing WordPress agent.',
                    'Decide whether the image is mainly for execute_change, analyze_image, or ask_clarify.',
                    'Use execute_change when recent history clearly shows the founder had just asked to set, replace, add, upload, or update an image on the site and then sent the image.',
                    'When you choose execute_change, rewrite the intent into one short operational prompt that tells Niwa to use the attached image and do the site change now.',
                    'When you choose analyze_image, write one short prompt for visual analysis only.',
                    'When you choose ask_clarify, write one short natural clarification prompt.',
                    'Do not be timid. If the immediately previous founder request was an image change and the only missing thing was the image, choose execute_change.',
                    'Return minified JSON only in the format {"mode":"execute_change|analyze_image|ask_clarify","prompt":"...","force_action":true|false,"remember_as":"..."}',
                )
            ),
            $this->auth_manager->get_mode(),
            $this->auth_manager->get_credentials(),
            20
        );

        if ( empty( $result['success'] ) ) {
            return array(
                'success'      => true,
                'mode'         => 'analyze_image',
                'prompt'       => 'Analiziraj prilozenu sliku i odgovori founderu prirodno i korisno.',
                'force_action' => false,
                'remember_as'  => '[image]',
            );
        }

        return $this->parse_media_only_turn_payload( isset( $result['answer'] ) ? (string) $result['answer'] : '' );
    }

    /**
     * Synthesize a prompt for the agent when the founder sent media without
     * any typed text. Returns '' if the context truly carries no actionable
     * payload, in which case respond() should still surface "Prazna poruka.".
     *
     * Covers:
     *  - photo without caption (attachment_image_urls non-empty)
     *  - GIF/animation (placeholder <media:video> or sticker_descriptions)
     *  - sticker (sticker_descriptions populated by Phase 5b vision fallback)
     *  - voice that failed to transcribe (placeholder <media:audio>)
     *  - any other media that downloaded only to a placeholder
     */
    private function synthesize_prompt_from_media_context( $context ) {
        $context = is_array( $context ) ? $context : array();

        $has_image = ! empty( $context['attachment_image_urls'] )
            || ! empty( $context['attachment_image_attachment_ids'] )
            || ! empty( $context['attachment_image_url'] )
            || ! empty( $context['attachment_image_attachment_id'] );

        $stickers = isset( $context['sticker_descriptions'] ) && is_array( $context['sticker_descriptions'] )
            ? array_values( array_filter( array_map( 'strval', $context['sticker_descriptions'] ) ) )
            : array();

        $placeholders = isset( $context['attachment_placeholders'] ) && is_array( $context['attachment_placeholders'] )
            ? array_values( array_filter( array_map( 'strval', $context['attachment_placeholders'] ) ) )
            : array();

        $incoming_media = isset( $context['incoming_media'] ) && is_array( $context['incoming_media'] )
            ? array_values( array_filter( $context['incoming_media'], 'is_array' ) )
            : array();

        if ( $has_image ) {
            return 'Korisnik je poslao sliku bez teksta. Pogledaj prilozenu sliku i reaguj prirodno — opisi sta vidis, komentarisi, ili izvrsi akciju ako iz konteksta razgovora vidis sta je trazeno (npr. dodavanje u galeriju proizvoda).';
        }

        if ( ! empty( $incoming_media ) ) {
            $any_preview = false;
            $any_audio   = false;
            $has_sticker  = false;
            foreach ( $incoming_media as $m ) {
                if ( ! is_array( $m ) ) {
                    continue;
                }
                if ( isset( $m['kind'] ) && 'sticker' === (string) $m['kind'] ) {
                    $has_sticker = true;
                }
                if ( ! empty( $m['preview_image_url'] ) ) {
                    $any_preview = true;
                }
                if ( ! empty( $m['extra_frame_urls'] ) ) {
                    $any_preview = true;
                }
                if ( ! empty( $m['audio_transcript'] ) ) {
                    $any_audio = true;
                }
            }

            if ( $any_preview || $any_audio ) {
                if ( $has_sticker ) {
                    return 'Pogledaj prilozeni sticker preview i/ili njegov vizuelni opis u kontekstu, pa reaguj prirodno na ono sto sticker prikazuje ili porucuje. Ne nabrajaj metapodatke.';
                }
                return 'Reaguj prirodno na sadržaj (frejmovi i/ili transkript su priloženi kao kontekst). Ne opisuj medij, ne nabrajaj metapodatke.';
            }
            return 'Founder je poslao Telegram medij bez teksta. Iskoristi dostupni media kontekst iz ovog turna; ako nema dovoljno vizuelnog ili audio signala, pitaj kratko o čemu se radi bez nabrajanja metapodataka.';
        }

        if ( ! empty( $stickers ) ) {
            return 'Reaguj kratko i prirodno na sticker na osnovu dostupnog sticker opisa, bez nabrajanja metapodataka.';
        }

        if ( ! empty( $placeholders ) ) {
            return 'Founder je poslao medij koji nije mogao da se učita. Reaguj kratko i pitaj da pošalje ponovo.';
        }

        // Edge cases: forwarded message without text, location, contact only.
        if ( ! empty( $context['forward_marker'] ) ) {
            return 'Korisnik je prosledio poruku bez dodatnog teksta. Reaguj na prosledjenu poruku.';
        }
        if ( ! empty( $context['location_text'] ) ) {
            return 'Korisnik je poslao lokaciju: ' . (string) $context['location_text'] . '. Reaguj na to.';
        }
        if ( ! empty( $context['contact_text'] ) ) {
            return 'Korisnik je poslao kontakt: ' . (string) $context['contact_text'] . '. Reaguj na to.';
        }

        return '';
    }

    private function extract_context_image_urls( $context ) {
        $context = is_array( $context ) ? $context : array();
        $urls    = array();

        if ( ! empty( $context['attachment_image_urls'] ) && is_array( $context['attachment_image_urls'] ) ) {
            $urls = array_merge( $urls, $context['attachment_image_urls'] );
        }
        if ( ! empty( $context['attachment_image_url'] ) ) {
            $urls[] = (string) $context['attachment_image_url'];
        }

        $urls = array_values(
            array_unique(
                array_filter(
                    array_map(
                        'esc_url_raw',
                        array_map( 'trim', array_map( 'strval', $urls ) )
                    )
                )
            )
        );

        return array_slice( $urls, 0, 5 );
    }

    private function analyze_images_payload( $prompt, $image_urls, $context = array() ) {
        $context = is_array( $context ) ? $context : array();
        $image_urls = array_values(
            array_unique(
                array_filter(
                    array_map(
                        'esc_url_raw',
                        array_map( 'trim', array_map( 'strval', is_array( $image_urls ) ? $image_urls : array() ) )
                    )
                )
            )
        );

        if ( empty( $image_urls ) ) {
            $image_urls = $this->extract_context_image_urls( $context );
        }

        $product_id = isset( $context['analysis_product_id'] ) ? max( 0, intval( $context['analysis_product_id'] ) ) : 0;
        if ( empty( $image_urls ) ) {
            return array(
                'success' => false,
                'error'   => 'Nema slike za analizu.',
            );
        }
        if ( $product_id > 0 && 1 !== count( $image_urls ) ) {
            return array(
                'success'    => false,
                'error'      => 'Catalog image analysis requires exactly one image for one product_id.',
                'product_id' => $product_id,
            );
        }

        if ( ! $this->auth_manager || ! $this->openai_client ) {
            return array(
                'success' => false,
                'error'   => 'AI client nije ucitan za image analysis.',
            );
        }

        $prompt    = trim( (string) $prompt );
        $auth_mode = $this->auth_manager->get_mode();
        $creds     = $this->auth_manager->get_credentials();
        $model     = $this->get_founder_model();
        $requested_count = count( $image_urls );
        $processed_urls  = array_slice( $image_urls, 0, 5 );
        $omitted_count   = max( 0, $requested_count - count( $processed_urls ) );
        $input     = array(
            array(
                'type' => 'text',
                'text' => ( $product_id > 0 ? "[PRODUCT IMAGE BINDING]\nproduct_id=" . $product_id . "\n[/PRODUCT IMAGE BINDING]\n" : '' )
                    . ( '' !== $prompt ? $prompt : 'Analyze these images for the founder. Describe only what is relevant to the request.' ),
            ),
        );

        foreach ( $processed_urls as $image_url ) {
            $input[] = array(
                'type'      => 'image_url',
                'image_url' => array(
                    'url'    => (string) $image_url,
                    'detail' => 'auto',
                ),
            );
        }

        $result = $this->openai_client->generate(
            $model,
            $input,
            implode(
                "\n",
                array(
                    'You are Niwa AI doing direct multimodal image analysis for the founder.',
                    'Use the attached images as primary evidence.',
                    'Respond in the founder language when obvious from the prompt/context.',
                    'Do not guess beyond what is visible.',
                    'If the image is unclear, say what is unclear.',
                )
            ),
            $auth_mode,
            $creds,
            45
        );

        if ( empty( $result['success'] ) ) {
            return array(
                'success' => false,
                'error'   => isset( $result['error'] ) ? (string) $result['error'] : 'Image analysis failed.',
            );
        }

        $payload = array(
            'success'               => true,
            'analysis'              => trim( (string) ( isset( $result['answer'] ) ? $result['answer'] : '' ) ),
            'image_urls'            => $processed_urls,
            'requested_count'       => $requested_count,
            'processed_count'       => count( $processed_urls ),
            'omitted_count'         => $omitted_count,
            'partial'               => $omitted_count > 0,
            'continuation_required' => $omitted_count > 0,
            'model'                 => $model,
        );
        if ( $product_id > 0 ) {
            $payload['product_id'] = $product_id;
        }

        return $payload;
    }

    private function build_site_image_lookup_payload( $query, $source, $limit ) {
        $query  = trim( (string) $query );
        $source = sanitize_key( (string) $source );
        $limit  = max( 1, min( 12, intval( $limit ) ) );
        $items  = array();

        if ( in_array( $source, array( 'any', 'media' ), true ) ) {
            $attachments = get_posts(
                array(
                    'post_type'        => 'attachment',
                    'post_status'      => 'inherit',
                    'post_mime_type'   => 'image',
                    'posts_per_page'   => $limit,
                    's'                => $query,
                    'orderby'          => 'date',
                    'order'            => 'DESC',
                    'suppress_filters' => false,
                )
            );

            foreach ( (array) $attachments as $attachment ) {
                $url = wp_get_attachment_url( $attachment->ID );
                if ( ! $url ) {
                    continue;
                }

                $items[] = array(
                    'kind'          => 'media',
                    'attachment_id' => intval( $attachment->ID ),
                    'title'         => get_the_title( $attachment->ID ),
                    'url'           => $url,
                    'alt'           => (string) get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
                );
                if ( count( $items ) >= $limit ) {
                    break;
                }
            }
        }

        if ( count( $items ) < $limit && in_array( $source, array( 'any', 'product' ), true ) && $this->admin_tools && method_exists( $this->admin_tools, 'lookup_woo_products' ) ) {
            $products = $this->admin_tools->lookup_woo_products( $query, array( 'publish', 'private', 'draft', 'pending', 'future', 'trash' ), $limit );
            foreach ( (array) $products as $product_row ) {
                $product_id = isset( $product_row['ID'] ) ? intval( $product_row['ID'] ) : 0;
                if ( $product_id <= 0 || ! function_exists( 'wc_get_product' ) ) {
                    continue;
                }
                $product = wc_get_product( $product_id );
                if ( ! $product ) {
                    continue;
                }

                $featured_id = method_exists( $product, 'get_image_id' ) ? intval( $product->get_image_id() ) : 0;
                if ( $featured_id > 0 ) {
                    $featured_url = wp_get_attachment_url( $featured_id );
                    if ( $featured_url ) {
                        $items[] = array(
                            'kind'          => 'product_featured',
                            'product_id'    => $product_id,
                            'attachment_id' => $featured_id,
                            'title'         => $product->get_name(),
                            'url'           => $featured_url,
                            'alt'           => (string) get_post_meta( $featured_id, '_wp_attachment_image_alt', true ),
                        );
                    }
                }

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

        if ( count( $items ) < $limit && in_array( $source, array( 'any', 'post', 'page' ), true ) ) {
            $post_types = 'page' === $source ? array( 'page' ) : ( 'post' === $source ? array( 'post' ) : array( 'post', 'page' ) );
            $posts      = get_posts(
                array(
                    'post_type'        => $post_types,
                    'post_status'      => array( 'publish', 'draft', 'private', 'future', 'pending' ),
                    'posts_per_page'   => $limit,
                    's'                => $query,
                    'orderby'          => 'date',
                    'order'            => 'DESC',
                    'suppress_filters' => false,
                )
            );

            foreach ( (array) $posts as $post ) {
                $thumbnail_id = get_post_thumbnail_id( $post->ID );
                if ( $thumbnail_id <= 0 ) {
                    continue;
                }

                $image_url = wp_get_attachment_url( $thumbnail_id );
                if ( ! $image_url ) {
                    continue;
                }

                $items[] = array(
                    'kind'          => 'post_featured',
                    'post_id'       => intval( $post->ID ),
                    'post_type'     => (string) $post->post_type,
                    'attachment_id' => intval( $thumbnail_id ),
                    'title'         => get_the_title( $post->ID ),
                    'url'           => $image_url,
                    'alt'           => (string) get_post_meta( $thumbnail_id, '_wp_attachment_image_alt', true ),
                );
                if ( count( $items ) >= $limit ) {
                    break;
                }
            }
        }

        $items = $this->dedupe_image_items( $items, $limit );

        return array(
            'available' => true,
            'query'     => $query,
            'source'    => '' !== $source ? $source : 'any',
            'images'    => $items,
        );
    }

    private function dedupe_image_items( $items, $limit ) {
        $seen   = array();
        $output = array();

        foreach ( (array) $items as $item ) {
            if ( ! is_array( $item ) || empty( $item['url'] ) ) {
                continue;
            }

            $url = (string) $item['url'];
            if ( isset( $seen[ $url ] ) ) {
                continue;
            }

            $seen[ $url ] = true;
            $output[]     = $item;

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

        return $output;
    }

    private function send_image_to_founder_payload( $image_url, $caption, $context ) {
        $image_url = esc_url_raw( trim( (string) $image_url ) );
        $chat_id   = isset( $context['chat_id'] ) ? trim( (string) $context['chat_id'] ) : '';

        if ( '' === $image_url ) {
            return array(
                'success' => false,
                'error'   => 'image_url je obavezan.',
            );
        }

        if ( '' === $chat_id || ! $this->telegram || ! method_exists( $this->telegram, 'send_photo' ) ) {
            return array(
                'success' => false,
                'error'   => 'Telegram photo send nije dostupan u ovom kontekstu.',
            );
        }

        // WebP detection and conversion — Telegram may reject WebP via URL.
        $send_url    = $image_url;
        $tmp_cleanup = array();
        $ext = strtolower( pathinfo( (string) wp_parse_url( $image_url, PHP_URL_PATH ), PATHINFO_EXTENSION ) );
        if ( 'webp' === $ext ) {
            $tmp = Niwa_AI_Admin_Autonomy_Image_Utils::download_to_temp( $image_url );
            if ( ! is_wp_error( $tmp ) ) {
                $tmp_cleanup[] = $tmp;
                $converted = Niwa_AI_Admin_Autonomy_Image_Utils::convert_to_jpeg( $tmp );
                if ( ! is_wp_error( $converted ) ) {
                    $sideloaded = Niwa_AI_Admin_Autonomy_Image_Utils::sideload_to_media_library( $converted, 'niwa-telegram-send-' . time() );
                    if ( ! empty( $sideloaded['url'] ) ) {
                        $send_url = (string) $sideloaded['url'];
                    }
                    if ( $converted !== $tmp ) {
                        $tmp_cleanup[] = $converted;
                    }
                }
            }
        }

        $sent = $this->telegram->send_photo(
            $chat_id,
            $send_url,
            $caption,
            isset( $context['message_id'] ) ? intval( $context['message_id'] ) : 0
        );

        foreach ( $tmp_cleanup as $f ) {
            if ( is_file( $f ) ) {
                @unlink( $f );
            }
        }

        return array(
            'success'          => ! empty( $sent['success'] ),
            'image_url'        => $send_url,
            'caption'          => trim( (string) $caption ),
            'telegram_delivery' => $sent,
            'error'            => empty( $sent['success'] ) ? ( isset( $sent['error'] ) ? (string) $sent['error'] : 'Telegram sendPhoto failed.' ) : '',
        );
    }

    private function send_sticker_to_founder_payload( $sticker_file_id, $context ) {
        $sticker_file_id = trim( (string) $sticker_file_id );
        $chat_id         = isset( $context['chat_id'] ) ? trim( (string) $context['chat_id'] ) : '';

        if ( '' === $sticker_file_id ) {
            return array(
                'success' => false,
                'error'   => 'sticker_file_id je obavezan.',
            );
        }

        if ( '' === $chat_id || ! $this->telegram || ! method_exists( $this->telegram, 'send_sticker' ) ) {
            return array(
                'success' => false,
                'error'   => 'Telegram sticker send nije dostupan u ovom kontekstu.',
            );
        }

        $sent = $this->telegram->send_sticker(
            $chat_id,
            $sticker_file_id,
            isset( $context['message_id'] ) ? intval( $context['message_id'] ) : 0
        );

        return array(
            'success'          => ! empty( $sent['success'] ),
            'sticker_file_id'  => $sticker_file_id,
            'telegram_delivery' => $sent,
            'error'            => empty( $sent['success'] ) ? ( isset( $sent['error'] ) ? (string) $sent['error'] : 'Telegram sendSticker failed.' ) : '',
        );
    }

    private function send_animation_to_founder_payload( $animation, $caption, $context ) {
        $animation = trim( (string) $animation );
        $chat_id   = isset( $context['chat_id'] ) ? trim( (string) $context['chat_id'] ) : '';

        if ( '' === $animation ) {
            return array(
                'success' => false,
                'error'   => 'animation je obavezan.',
            );
        }

        if ( '' === $chat_id || ! $this->telegram || ! method_exists( $this->telegram, 'send_animation' ) ) {
            return array(
                'success' => false,
                'error'   => 'Telegram animation send nije dostupan u ovom kontekstu.',
            );
        }

        $sent = $this->telegram->send_animation(
            $chat_id,
            $animation,
            $caption,
            isset( $context['message_id'] ) ? intval( $context['message_id'] ) : 0
        );

        return array(
            'success'          => ! empty( $sent['success'] ),
            'animation'        => $animation,
            'caption'          => trim( (string) $caption ),
            'telegram_delivery' => $sent,
            'error'            => empty( $sent['success'] ) ? ( isset( $sent['error'] ) ? (string) $sent['error'] : 'Telegram sendAnimation failed.' ) : '',
        );
    }

    private function build_wp_environment_capabilities_payload() {
        $search_roots   = $this->get_code_search_roots( 'wordpress_env' );
        $editable_roots = array();
        $proc_open_available = ! method_exists( $this, 'is_proc_open_runtime_available' ) || $this->is_proc_open_runtime_available();
        if ( defined( 'ABSPATH' ) ) {
            $editable_roots[] = wp_normalize_path( untrailingslashit( ABSPATH ) );
        }

        return array(
            'available'         => true,
            'searchable_roots'  => array_values( array_map( 'wp_normalize_path', $search_roots ) ),
            'editable_roots'    => array_values( array_map( 'wp_normalize_path', array_filter( $editable_roots ) ) ),
            'code_file_editing' => array(
                'supported' => true,
                'notes'     => $proc_open_available
                    ? 'Workspace file edits are supported inside the local WordPress root. Shell inspection is available through main_coding_shell_run, while edits should still use workspace_prepare/file_edit/apply.'
                    : 'Workspace file edits are supported inside the local WordPress root without shell. Use code_search/file_read/file_list/batch_read for inspection, then workspace_prepare/file_edit/diff/lint/apply.',
            ),
            'process_runtime'   => array(
                'proc_open_available' => $proc_open_available,
                'shell_tools_available' => $proc_open_available,
                'no_shell_workflow' => ! $proc_open_available,
            ),
            'site_mutations'    => array(
                'posts_pages_products' => true,
                'product_restore_from_trash' => true,
                'simple_product_price_stock' => true,
                'product_variations' => true,
                'featured_images' => true,
                'wordpress_core_update' => true,
            ),
            'workspace'         => array(
                'root' => $this->workspace && method_exists( $this->workspace, 'get_paths' ) ? ( $this->workspace->get_paths()['root'] ?? '' ) : '',
            ),
            'multimodal'        => array(
                'telegram_attached_images' => true,
                'site_image_lookup'        => true,
                'image_analysis'           => true,
                'telegram_image_send'      => true,
                'telegram_sticker_send'    => true,
                'telegram_animation_send'  => true,
            ),
            'native_model_tools' => array(
                'web_search' => $this->openai_client && method_exists( $this->openai_client, 'supports_native_web_search' )
                    ? ! empty( $this->openai_client->supports_native_web_search( $this->get_founder_model(), $this->auth_manager ? $this->auth_manager->get_mode() : 'api_key' ) )
                    : false,
            ),
            'agentic_runtime'   => array(
                'turn_engine' => true,
                'session_worklog' => true,
                'subagents' => true,
                'notes' => true,
            ),
        );
    }

    private function parse_media_only_turn_payload( $text ) {
        $text = trim( (string) $text );
        if ( '' === $text ) {
            return array(
                'success'      => true,
                'mode'         => 'analyze_image',
                'prompt'       => 'Analiziraj prilozenu sliku i odgovori founderu prirodno i korisno.',
                'force_action' => false,
                'remember_as'  => '[image]',
            );
        }

        if ( preg_match( '/\{.*\}/s', $text, $matches ) ) {
            $text = (string) $matches[0];
        }

        $decoded = json_decode( $text, true );
        if ( ! is_array( $decoded ) ) {
            return array(
                'success'      => true,
                'mode'         => 'analyze_image',
                'prompt'       => 'Analiziraj prilozenu sliku i odgovori founderu prirodno i korisno.',
                'force_action' => false,
                'remember_as'  => '[image]',
            );
        }

        $mode = isset( $decoded['mode'] ) ? strtolower( trim( (string) $decoded['mode'] ) ) : 'analyze_image';
        if ( ! in_array( $mode, array( 'execute_change', 'analyze_image', 'ask_clarify' ), true ) ) {
            $mode = 'analyze_image';
        }

        $prompt = isset( $decoded['prompt'] ) ? trim( (string) $decoded['prompt'] ) : '';
        if ( '' === $prompt ) {
            $prompt = 'execute_change' === $mode
                ? 'Use the attached image to complete the pending site change now.'
                : 'Analiziraj prilozenu sliku i odgovori founderu prirodno i korisno.';
        }

        $remember_as = isset( $decoded['remember_as'] ) ? trim( (string) $decoded['remember_as'] ) : '';
        if ( '' === $remember_as ) {
            $remember_as = 'execute_change' === $mode ? '[image for site change]' : '[image]';
        }

        return array(
            'success'      => true,
            'mode'         => $mode,
            'prompt'       => $prompt,
            'force_action' => 'execute_change' === $mode ? true : ! empty( $decoded['force_action'] ),
            'remember_as'  => $remember_as,
        );
    }

    private function detect_pending_image_change_from_history( $context ) {
        $history = isset( $context['history'] ) && is_array( $context['history'] ) ? array_slice( (array) $context['history'], -12 ) : array();
        if ( empty( $history ) ) {
            return '';
        }

        for ( $i = count( $history ) - 1; $i >= 0; $i-- ) {
            $item = isset( $history[ $i ] ) && is_array( $history[ $i ] ) ? $history[ $i ] : array();
            if ( 'user' !== ( isset( $item['role'] ) ? strtolower( (string) $item['role'] ) : '' ) ) {
                continue;
            }

            $text = trim( (string) ( isset( $item['text'] ) ? $item['text'] : '' ) );
            if ( '' === $text || '[image]' === $text || '[image for site change]' === $text ) {
                continue;
            }

            if ( ! $this->looks_like_image_change_request( $text ) ) {
                continue;
            }

            return 'Founder already asked for this image change: "' . $this->truncate_block( $text, 220 ) . "\".\nUse the attached image to complete that change now.\nDo not analyze the image. Execute the site change directly. If this is a WooCommerce product image request, call set_product_featured_image_from_url with the target implied by recent history and the attached image from context.";
        }

        return '';
    }

    private function looks_like_image_change_request( $text ) {
        $normalized = remove_accents( strtolower( wp_strip_all_tags( (string) $text ) ) );
        if ( '' === $normalized ) {
            return false;
        }

        $has_image_target = (bool) preg_match( '/\b(slika|sliku|image|photo|fotografij|featured|thumbnail|hero|banner|logo|gallery|galerij)\b/u', $normalized );
        $has_change_verb  = (bool) preg_match( '/\b(promeni|zameni|stavi|postavi|dodaj|azuriraj|update|replace|change|set|swap|use|upload)\b/u', $normalized );

        return $has_image_target && $has_change_verb;
    }
}
