<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-image-source.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-manager.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-text-helper.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-gemini.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-workers-ai.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-pexels.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-pixabay.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-flickr.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-giphy.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-openverse.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-unsplash.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-google-image.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-youtube.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-dallev1.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-stability.php';
require_once plugin_dir_path( __FILE__ ) . 'sources/class-allsi-source-replicate.php';

/**
 * The functionalities for ASI Images generation
 *
 * @package    All_Sources_Images
 * @subpackage All_Sources_Images/admin
 */
class All_Sources_Images_Generation extends All_Sources_Images_Admin {
    /**
     * The ID of this plugin.
     *
     * @since    4.0.0
     * @access   private
     * @var      string    $plugin_name    The ID of this plugin.
     */
    private $plugin_name;

    /**
     * The version of this plugin.
     *
     * @since    4.0.0
     * @access   private
     * @var      string    $version    The current version of this plugin.
     */
    private $version;

    /**
     * Lazy-loaded source manager used to resolve modular image providers.
     *
     * @var ALLSI_Source_Manager|null
     */
    private $source_manager = null;

    /**
     * Track if built-in sources have already been registered.
     *
     * @var bool
     */
    private $sources_registered = false;

    /**
     * Initialize the class and set its properties.
     *
     * @since    4.0.0
     * @param      string    $plugin_name       The name of this plugin.
     * @param      string    $version    The version of this plugin.
     */
    public function __construct( $plugin_name, $version ) {
        $this->plugin_name = $plugin_name;
        $this->version = $version;
        // Ajax calls
        // AJAX endpoints for image generation (authenticated users only)
        add_action( 'wp_ajax_allsi_generate_image', array(&$this, 'ALLSI_ajax_call') );
        $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( FALSE ) );
        $auto_image_settings = wp_parse_args( get_option( 'ALLSI_plugin_auto_image_settings' ), $this->ALLSI_default_options_auto_image_settings( FALSE ) );
        $auto_image_enabled = ( ! empty( $auto_image_settings['enabled'] ) && 'enable' === $auto_image_settings['enabled'] );
        // Enable save_post hook
        if ( isset( $main_settings['enable_save_post_hook'] ) && 'enable' == $main_settings['enable_save_post_hook'] && ! $auto_image_enabled ) {
            add_action(
                'save_post',
                array(&$this, 'ALLSI_check_post_type'),
                10,
                3
            );
        }
    }

    /**
     * Retrieve the shared source manager and register built-in sources on demand.
     *
     * @return ALLSI_Source_Manager|null
     */
    public function ALLSI_get_source_manager_instance() {
        if ( ! class_exists( 'ALLSI_Source_Manager' ) ) {
            return null;
        }

        if ( null === $this->source_manager ) {
            $this->source_manager = ALLSI_Source_Manager::instance();
        }

        if ( false === $this->sources_registered ) {
            $this->ALLSI_register_builtin_sources();
            $this->sources_registered = true;
        }

        return $this->source_manager;
    }

    /**
     * Register core sources shipped with the plugin.
     */
    private function ALLSI_register_builtin_sources() {
        if ( ! $this->source_manager ) {
            return;
        }

        if ( class_exists( 'ALLSI_Source_Gemini' ) && ! $this->source_manager->has_source( 'gemini' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Gemini() );
        }

        if ( class_exists( 'ALLSI_Source_Workers_AI' ) && ! $this->source_manager->has_source( 'workers_ai' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Workers_AI() );
        }

        if ( class_exists( 'ALLSI_Source_Pexels' ) && ! $this->source_manager->has_source( 'pexels' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Pexels() );
        }

        if ( class_exists( 'ALLSI_Source_Pixabay' ) && ! $this->source_manager->has_source( 'pixabay' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Pixabay() );
        }

        if ( class_exists( 'ALLSI_Source_Flickr' ) && ! $this->source_manager->has_source( 'flickr' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Flickr() );
        }

        if ( class_exists( 'ALLSI_Source_Giphy' ) && ! $this->source_manager->has_source( 'giphy' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Giphy() );
        }

        if ( class_exists( 'ALLSI_Source_Stability' ) && ! $this->source_manager->has_source( 'stability' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Stability() );
        }

        if ( class_exists( 'ALLSI_Source_Replicate' ) && ! $this->source_manager->has_source( 'replicate' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Replicate() );
        }

        if ( class_exists( 'ALLSI_Source_Google_Image' ) && ! $this->source_manager->has_source( 'google_image' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Google_Image() );
        }

        if ( class_exists( 'ALLSI_Source_Youtube' ) && ! $this->source_manager->has_source( 'youtube' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Youtube() );
        }

        if ( class_exists( 'ALLSI_Source_Dallev1' ) && ! $this->source_manager->has_source( 'dallev1' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Dallev1() );
        }

        if ( class_exists( 'ALLSI_Source_Unsplash' ) && ! $this->source_manager->has_source( 'unsplash' ) ) {
            $this->source_manager->register_source( new ALLSI_Source_Unsplash() );
        }

        if ( class_exists( 'ALLSI_Source_Openverse' ) ) {
            if ( ! $this->source_manager->has_source( 'openverse' ) ) {
                $this->source_manager->register_source( new ALLSI_Source_Openverse( 'openverse' ) );
            }
            if ( ! $this->source_manager->has_source( 'cc_search' ) ) {
                $this->source_manager->register_source( new ALLSI_Source_Openverse( 'cc_search' ) );
            }
        }
    }

    /**
     * Ajax call for bulk generation
     *
     * @since    4.0.0
     */
    public function ALLSI_ajax_call() {
        // Security check: Verify nonce first before processing any input
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- This line is where nonce is retrieved for verification
        $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
        if ( ! wp_verify_nonce( $nonce, 'ajax_nonce_All_Sources_Images' ) ) {
            wp_send_json_error( array( 'message' => __( 'Security check failed.', 'all-sources-images' ) ) );
        }
        
        // Security check: Verify user capability
        if ( ! current_user_can( 'edit_posts' ) ) {
            wp_send_json_error( array( 'message' => __( 'Permission denied.', 'all-sources-images' ) ) );
        }
        
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above with wp_verify_nonce
        // Check if button "Generate Automatically" is clicked
        $button_autogenerate = ( isset( $_POST['buttonAutoGenerate'] ) ? filter_var( wp_unslash( $_POST['buttonAutoGenerate'] ), FILTER_VALIDATE_BOOLEAN ) : false );
        
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
        // Convert the JSON-encoded post IDs into an array and sanitize them.
        $ids_json = isset( $_POST['ids_mpt_generation'] ) ? sanitize_text_field( wp_unslash( $_POST['ids_mpt_generation'] ) ) : '[]';
        $post_ids = array_map( 'absint', json_decode( $ids_json ) );
        
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
        // Validate the presence of post IDs.
        if ( ! isset( $_POST['ids_mpt_generation'] ) ) {
            wp_send_json_error( array( 'message' => __( 'No posts selected.', 'all-sources-images' ) ) );
        }
        // Exit if no post IDs are provided.
        // Count the number of posts for bulk processing.
        $count = count( $post_ids );
        // Re-index post IDs starting from 1 for consistency.
        foreach ( $post_ids as $key => $val ) {
            $post_ids_with_keys[$key + 1] = $val;
        }
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
        // Retrieve the current post index and ID from the AJAX request.
        $current_post_index = isset( $_POST['currentPostIndex'] ) ? absint( $_POST['currentPostIndex'] ) : 0;
        $current_post_id = $post_ids_with_keys[$current_post_index];
        // Load plugin settings for image generation (with defaults).
        $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( true ) );
        // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
        // Check if forceRewrite is set from AJAX request (user confirmed replacement)
        $force_rewrite = isset( $_POST['forceRewrite'] ) && filter_var( wp_unslash( $_POST['forceRewrite'] ), FILTER_VALIDATE_BOOLEAN );
        // Check if the 'rewrite featured image' option is enabled or forceRewrite is set.
        if ( $force_rewrite || ( isset( $main_settings['rewrite_featured'] ) && $main_settings['rewrite_featured'] == true ) ) {
            $rewrite_featured = true;
        } else {
            $rewrite_featured = false;
        }
        $int_blockIndex = isset( $_POST['blockIndex'] ) ? absint( wp_unslash( $_POST['blockIndex'] ) ) : 0;
        $img_blocks = isset( $main_settings['image_block'] ) && is_array( $main_settings['image_block'] ) ? $main_settings['image_block'] : array(
            1 => array(
                'image_location'  => 'featured',
                'based_on'        => 'title',
                'translation_EN'  => 'true',
                'title_selection' => 'full_title',
                'selected_image'  => 'first_result',
            ),
        );
        $counter_blocks = count( $img_blocks );
        if ( 0 === $counter_blocks ) {
            $img_blocks = array(
                1 => array(
                    'image_location'  => 'featured',
                    'based_on'        => 'title',
                    'translation_EN'  => 'true',
                    'title_selection' => 'full_title',
                    'selected_image'  => 'first_result',
                ),
            );
            $counter_blocks = 1;
        }
        if ( $int_blockIndex >= $counter_blocks ) {
            $int_blockIndex = 0;
        }
        $speed = '500';
        // Default speed for image generation.
        $current_image_index = $int_blockIndex;
        // Current image block index.
        $counter_img = $counter_blocks;
        // Total number of image blocks.
        $keys = array_keys( $img_blocks );
        $img_block = $img_blocks[$keys[$current_image_index]];
        // Current image block data.
        // display all infos under $img_block
        // Determine image location (featured or content).
        $image_location = ( !empty( $img_block['image_location'] ) ? $img_block['image_location'] : 'featured' );
        $generation_status = 'pending';
        $ALLSI_return = null;
        $image_generation_result = null;
        // Handle generation of the featured image.
        if ( has_post_thumbnail( $current_post_id ) && $rewrite_featured == false && $image_location == 'featured' ) {
            $generation_status = 'already-done';
            // Image already exists and rewriting is not needed.
        } elseif ( (!has_post_thumbnail( $current_post_id ) || $rewrite_featured == true || $image_location != 'featured') && $current_post_id != 0 ) {
            // Generate featured image if not present or if rewriting is enabled.
            $image_generation_result = $this->ALLSI_create_thumb(
                $current_post_id,       // $id
                '0',                     // $check_value_enable
                '0',                     // $check_post_type
                '0',                     // $check_category
                $rewrite_featured,       // $rewrite_featured
                false,                   // $get_only_thumb
                null,                    // $extracted_search_term
                null,                    // $api_chosen
                null,                    // $key_img_block
                null,                    // $avoid_revision
                null,                    // $include_datas
                $button_autogenerate     // $button_autogenerate
            );

            if ( is_array( $image_generation_result ) ) {
                $ALLSI_return = isset( $image_generation_result['id'] ) ? $image_generation_result['id'] : null;
                $generation_status = $ALLSI_return ? 'successful' : 'error';
            } else {
                $ALLSI_return = $image_generation_result;
                $generation_status = $ALLSI_return ? 'successful' : 'error';
            }
        } else {
            $generation_status = 'error';
        }
        $thumbnail_url = '';
        if ( ($generation_status == 'already-done' || $generation_status == 'successful') && !empty( $ALLSI_return ) ) {
            // Display the newly generated image.
            $new_image = wp_get_attachment_image_src( $ALLSI_return, array(70, 70) );
            $thumbnail_preview_html = '<a class="generated-img" target="_blank" href="' . esc_url( admin_url( 'upload.php?item=' . absint( $ALLSI_return ) ) ) . '"><img src="' . esc_url( $new_image[0] ) . '" width="70" height="70" /></a>';
            $datas['thumbnail_id'] = $ALLSI_return;
            $datas['postimagediv'] = _wp_post_thumbnail_html( $ALLSI_return, $current_post_id );
        } elseif ( $generation_status == 'already-done' && "featured" === $image_location ) {
            // Display existing featured image.
            $thumbnail_preview_html = '<a class="generated-img" target="_blank" href="' . esc_url( admin_url( 'upload.php?item=' . absint( get_post_thumbnail_id( $current_post_id ) ) ) ) . '">' . get_the_post_thumbnail( $current_post_id, array('70', '70') ) . '</a>';
        } else {
            // Display a placeholder image if generation fails.
            $thumbnail_preview_html = '<img src="' . esc_url( plugins_url( 'img/no-image.jpg', __FILE__ ) ) . '" />';
        }
        // Prepare data for the next image block iteration.
        $current_image_index++;
        $datas['id'] = $current_post_id;
        $datas['status'] = $generation_status;
        $datas['img'] = $thumbnail_url;
        $datas['fimg'] = $thumbnail_preview_html;
        $datas['speed'] = $speed;
        $datas['blockIndex'] = $current_image_index;
        if ( is_array( $image_generation_result ) ) {
            $datas['keyword'] = ( isset( $image_generation_result['keyword'] ) ? $image_generation_result['keyword'] : '' );
            $datas['img_resolution'] = ( isset( $image_generation_result['img_resolution'] ) ? $image_generation_result['img_resolution'] : '' );
            $datas['img_size'] = ( isset( $image_generation_result['img_size'] ) ? $image_generation_result['img_size'] : '' );
            $datas['api_chosen'] = ( isset( $image_generation_result['api_chosen'] ) ? $image_generation_result['api_chosen'] : '' );
        }
        // If more image blocks are remaining, continue processing.
        if ( $current_image_index < $counter_img ) {
            $datas['nextPost'] = true;
            wp_send_json_success( $datas );
            // Send successful response for next iteration.
        } else {
            $datas['nextPost'] = false;
            // Send final response or error if data is incomplete.
            if ( !empty( $datas['id'] ) ) {
                wp_send_json_success( $datas );
            } else {
                wp_send_json_error( $datas );
            }
        }
    }

    public function ALLSI_check_post_type( $ID, $post, $update ) {
        // Checks whether the capacity has already been checked for this session
        if ( get_option( 'ALLSI_hook_checked' ) ) {
            // Deletes the option immediately after execution
            delete_option( 'ALLSI_hook_checked' );
            return;
            // Exits the function if it has already been executed
        }
        // Set capacity as verified to avoid additional calls
        update_option( 'ALLSI_hook_checked', true );
        $transient_key = 'ALLSI_wp_insert_processing_post_' . $ID;
        if ( wp_is_post_revision( $ID ) || wp_is_post_autosave( $ID ) ) {
            return;
        }
        if ( get_transient( $transient_key ) ) {
            return;
            // This post is already being processed
        } else {
            // Defines the transient to indicate that the post is being processed
            set_transient( $transient_key, true, 120 );
            // Expires after 2 minutes
        }
        global $pagenow;
        // Avoid not selected post types
        $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( FALSE ) );
        if ( empty( $main_settings['choosed_save_post_post_type'] ) ) {
            $choosed_post_type = $this->ALLSI_default_posts_types();
            $main_settings['choosed_save_post_post_type'] = $choosed_post_type["choosed_post_type"];
        }
        if ( !in_array( get_post_type( $ID ), $main_settings['choosed_save_post_post_type'] ) ) {
            return false;
        }
        //$active_posts_types	= wp_parse_args( get_option( 'ALLSI_plugin_posts_settings' ), $this->ALLSI_default_options_posts_settings( FALSE ) );
        $active_posts_types = $this->ALLSI_default_posts_types();
        // Avoid generation when click "Add New"
        if ( ($pagenow == 'index.php' || $pagenow == 'post.php') && in_array( get_post_type( $ID ), $active_posts_types['choosed_post_type'] ) ) {
            $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( true ) );
            if ( isset( $main_settings['rewrite_featured'] ) && $main_settings['rewrite_featured'] == true ) {
                $rewrite_featured = true;
            } else {
                $rewrite_featured = false;
            }
            $img_blocks = isset( $main_settings['image_block'] ) && is_array( $main_settings['image_block'] ) ? $main_settings['image_block'] : $this->ALLSI_default_options_main_settings( true )['image_block'];
            foreach ( $img_blocks as $key_img_block => $img_block ) {
                $this->ALLSI_create_thumb(
                    $ID,
                    '0',
                    '1',
                    '0',
                    $rewrite_featured
                );
            }
        }
    }

    /**
     * based on the provided title and filename. It first cleans the filename
     * by removing numbers and extension, then performs a search in the 
     * WordPress database.
     *
     * @since    6.0.5
     * @param string $title The title of the image to search for
     * @param string $filename The filename of the image to search for
     * 
     * @return int|false Returns the attachment ID if found, false otherwise
     *
     * @access private
     */
    private function ALLSI_check_existing_image( $title, $filename ) {
        // Clean the base filename (remove extension and numbers)
        $base_filename = preg_replace( '/[0-9]+\\./', '.', $filename );
        $base_filename = pathinfo( $base_filename, PATHINFO_FILENAME );
        // Search in media library
        $args = array(
            'post_type'      => 'attachment',
            'post_status'    => 'inherit',
            'posts_per_page' => 1,
            'meta_query'     => array(array(
                'key'     => '_wp_attached_file',
                'value'   => $base_filename,
                'compare' => 'LIKE',
            )),
        );
        $query = new WP_Query($args);
        if ( $query->have_posts() ) {
            // If image already exists, return its ID
            return $query->posts[0]->ID;
        }
        return false;
    }

    /**
     * Retrieve Image from Database, save it into Media Library, and attach it to the post as featured image
     *
     * @since    4.0.0
     */
    public function ALLSI_create_thumb(
        $id,
        $check_value_enable = 0,
        $check_post_type = 1,
        $check_category = 1,
        $rewrite_featured = 0,
        $get_only_thumb = false,
        $extracted_search_term = null,
        $api_chosen = null,
        $key_img_block = null,
        $avoid_revision = null,
        $include_datas = null,
        $button_autogenerate = false,
        $additional_context = array()
    ) {
        ALLSI_log( array(
            'id' => $id,
            'get_only_thumb' => $get_only_thumb,
            'api_chosen' => $api_chosen,
            'extracted_search_term' => $extracted_search_term
        ), 'CREATE_THUMB_START' );
        
        // Launch logs
        $log = $this->ALLSI_monolog_call();
        $log->info( 'New generation starting', array(
            'post' => $id,
        ) );
        //Avoid revision post type
        if ( 'revision' == get_post_type( $id ) && true !== $avoid_revision ) {
            ALLSI_log( 'Post is revision, avoiding', 'CREATE_THUMB_SKIP' );
            $log->error( 'This post is a revision. Avoided.', array(
                'post' => $id,
            ) );
            return false;
        }
        // Settings
        $main_settings = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( true ) );
        
        // For Gutenberg block (get_only_thumb), we don't need image_block config
        if ( TRUE == $get_only_thumb ) {
            // Create a minimal img_block array for Gutenberg / Abilities API
            $img_block = array(
                'api_chosen'     => $api_chosen,
                'based_on'       => 'title', // Not used in get_only_thumb mode
                'selected_image' => isset( $additional_context['selected_image'] ) ? $additional_context['selected_image'] : 'random_result',
            );
        } else {
            // one shot generation - use saved configuration
            if ( null == $key_img_block ) {
                if ( !isset($main_settings['image_block']) || empty($main_settings['image_block']) ) {
                    ALLSI_log( 'No image_block configuration found', 'CREATE_THUMB_ERROR' );
                    return false;
                }
                $key_img_block = array_key_first( $main_settings['image_block'] );
            }
            $img_block = $main_settings['image_block'][$key_img_block];
            if ( !isset( $img_block ) ) {
                return false;
            }
            
            // Merge with default block settings to ensure all fields have defaults
            $default_block = array(
                'image_location'  => 'featured',
                'based_on'        => 'title',
                'translation_EN'  => 'true', // Default to ON for translation
                'title_selection' => 'full_title',
                'selected_image'  => 'first_result',
            );
            $img_block = wp_parse_args( $img_block, $default_block );
            
            // Ensure api_chosen is set from banks settings if not in img_block
            if ( !isset( $img_block['api_chosen'] ) || empty( $img_block['api_chosen'] ) ) {
                $banks_settings = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( true ) );
                $img_block['api_chosen'] = isset( $banks_settings['api_chosen_auto'] ) ? $banks_settings['api_chosen_auto'] : array( 'openverse' );
            }
        }
        
        // Skip most validations for Gutenberg block mode (get_only_thumb)
        if ( TRUE !== $get_only_thumb ) {
            // Image location
            $image_location = ( !empty( $img_block['image_location'] ) ? $img_block['image_location'] : 'featured' );
            if ( "featured" !== $image_location ) {
                // Check if image generation into content is already done
                $content_post = get_post( $id );
                /*$image_generated = strpos( $content_post->post_content, 'mpt-img' ) ? true : false;
                		if( $image_generated ) {
                			return false;
                		}*/
            }
            // Check if thumbnail already exists
            if ( has_post_thumbnail( $id ) && $rewrite_featured == false && "featured" === $image_location ) {
                ALLSI_log( 'Featured image already exists', 'CREATE_THUMB_SKIP' );
                $log->error( 'Featured image already exists', array(
                    'post' => $id,
                ) );
                return false;
            }
            /* Action 'save_post' triggered when deleting posts. Check if post not trashed */
            if ( 'trash' == get_post_status( $id ) ) {
                ALLSI_log( 'Post is trashed', 'CREATE_THUMB_SKIP' );
                $log->error( 'Post is in the trash', array(
                    'post' => $id,
                ) );
                return false;
            }
            if ( ! current_user_can( 'ALLSI_manage' ) && ! wp_doing_cron() && ! class_exists( 'Main_WPeMatico' ) && ! class_exists( 'FeedWordPress' ) && ! class_exists( 'rssPostImporter' ) && ! class_exists( 'CyberSyn_Syndicator' ) && ! class_exists( 'wp_automatic' ) ) {
                ALLSI_log( 'User lacks permissions', 'CREATE_THUMB_SKIP' );
                $log->error( 'The user does not have sufficient rights', array(
                    'post' => $id,
                ) );
                return false;
            }
            // Choosed Post types
            $post_types_default = $this->ALLSI_default_posts_types();
            $post_type_availables = $post_types_default['choosed_post_type'];
            $categories_availables = $post_types_default['choosed_categories'];
            /*
            		$post_type_availables  = ( ! empty( $posts_settings['choosed_post_type'] ) )  ? $posts_settings['choosed_post_type']  : '';
            		// Choosed Categories
            		$categories_availables = ( ! empty( $posts_settings['choosed_categories'] ) ) ? $posts_settings['choosed_categories'] : '';*/
            if ( !empty( $post_type_availables ) && $check_post_type ) {
                if ( !in_array( get_post_type( $id ), $post_type_availables ) ) {
                    ALLSI_log( 'Post type not in allowed list', 'CREATE_THUMB_SKIP' );
                    $log->error( 'The post is not in selected post types', array(
                        'post' => $id,
                    ) );
                    return false;
                }
            }
            // Check if category match and is a post
            if ( !empty( $categories_availables ) && $check_category && 'post' == get_post_type( $id ) ) {
                if ( !in_category( $categories_availables, $id ) ) {
                    ALLSI_log( 'Post category not in allowed list', 'CREATE_THUMB_SKIP' );
                    $log->error( 'The post is not in selected categories', array(
                        'post' => $id,
                    ) );
                    return false;
                }
            }
        }
        $options = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( TRUE ) );
        $options_banks = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( TRUE ) );
        $options_cron = wp_parse_args( get_option( 'ALLSI_plugin_cron_settings' ), $this->ALLSI_default_options_cron_settings( TRUE ) );
        $options = array_merge( $options, $options_banks, $options_cron );
        if ( isset( $api_chosen ) ) {
            $options['api_chosen'] = $api_chosen;
            $img_block['api_chosen'] = $api_chosen;
        } else {
            $options['api_chosen'] = $img_block['api_chosen'];
        }
        $executeElseBlock = true;
        $postcategories = get_the_category( $id );
        if ( $executeElseBlock ) {
            if ( TRUE == $get_only_thumb ) {
                $search = $extracted_search_term;
            } else {
                // Handle all based_on options
                $based_on = isset( $img_block['based_on'] ) ? $img_block['based_on'] : 'title';
                
                switch ( $based_on ) {
                    case 'text_analyser':
                    case 'text_analyser_previous_paragraph':
                    case 'text_analyser_next_paragraph':
                        $content = get_the_content( '', false, $id );
                        $content = str_replace( "&nbsp;", ' ', $content );
                        
                        // For paragraph-specific analysis, extract relevant paragraph
                        if ( $based_on === 'text_analyser_previous_paragraph' || $based_on === 'text_analyser_next_paragraph' ) {
                            $paragraphs = preg_split( '/\n\s*\n/', wp_strip_all_tags( $content ) );
                            $paragraphs = array_filter( array_map( 'trim', $paragraphs ) );
                            $paragraphs = array_values( $paragraphs );
                            
                            // Get image position from settings (default to first paragraph)
                            $image_position = isset( $img_block['image_location'] ) ? $img_block['image_location'] : 'featured';
                            $para_index = 0;
                            
                            if ( preg_match( '/after_paragraph_(\d+)/', $image_position, $matches ) ) {
                                $para_index = intval( $matches[1] );
                            }
                            
                            if ( $based_on === 'text_analyser_previous_paragraph' ) {
                                $content = isset( $paragraphs[ $para_index - 1 ] ) ? $paragraphs[ $para_index - 1 ] : ( isset( $paragraphs[0] ) ? $paragraphs[0] : '' );
                            } else {
                                $content = isset( $paragraphs[ $para_index ] ) ? $paragraphs[ $para_index ] : ( isset( $paragraphs[0] ) ? $paragraphs[0] : '' );
                            }
                        }
                        
                        $selected_lang = isset( $img_block['text_analyser_lang'] ) ? $img_block['text_analyser_lang'] : 'en';
                        $search = $this->get_extracted_term( $content, $selected_lang );
                        $log->info( 'Extracted search term from text analysis', array(
                            'post'        => $id,
                            'based_on'    => $based_on,
                            'search term' => $search,
                        ) );
                        break;
                        
                    case 'tags':
                        $tags = wp_get_post_tags( $id );
                        if ( ! empty( $tags ) ) {
                            $tags_option = isset( $img_block['tags'] ) ? $img_block['tags'] : 'first_tag';
                            
                            switch ( $tags_option ) {
                                case 'last_tag':
                                    $tag = end( $tags );
                                    break;
                                case 'random_tag':
                                    $tag = $tags[ array_rand( $tags ) ];
                                    break;
                                case 'first_tag':
                                default:
                                    $tag = reset( $tags );
                                    break;
                            }
                            
                            $search = $tag->name;
                            $log->info( 'Search term from tag', array(
                                'post'        => $id,
                                'tag_option'  => $tags_option,
                                'search term' => $search,
                            ) );
                        } else {
                            // Fallback to title if no tags
                            $search = get_post_field( 'post_title', $id, 'raw' );
                            $log->info( 'No tags found, using title as fallback', array( 'post' => $id ) );
                        }
                        break;
                        
                    case 'categories':
                        $categories = get_the_category( $id );
                        if ( ! empty( $categories ) ) {
                            $cat_option = isset( $img_block['categories'] ) ? $img_block['categories'] : 'first_category';
                            $cat_level = isset( $img_block['categories_level'] ) ? $img_block['categories_level'] : 'child';
                            
                            // Select category based on option
                            switch ( $cat_option ) {
                                case 'last_category':
                                    $category = end( $categories );
                                    break;
                                case 'random_category':
                                    $category = $categories[ array_rand( $categories ) ];
                                    break;
                                case 'first_category':
                                default:
                                    $category = reset( $categories );
                                    break;
                            }
                            
                            // Adjust for hierarchy level
                            if ( $cat_level === 'parent' && $category->parent > 0 ) {
                                $parent = get_category( $category->parent );
                                if ( $parent && ! is_wp_error( $parent ) ) {
                                    $category = $parent;
                                }
                            } elseif ( $cat_level === 'grandparent' ) {
                                $ancestors = get_ancestors( $category->term_id, 'category' );
                                if ( ! empty( $ancestors ) ) {
                                    $top_ancestor = end( $ancestors );
                                    $grandparent = get_category( $top_ancestor );
                                    if ( $grandparent && ! is_wp_error( $grandparent ) ) {
                                        $category = $grandparent;
                                    }
                                }
                            }
                            
                            $search = $category->name;
                            $log->info( 'Search term from category', array(
                                'post'         => $id,
                                'cat_option'   => $cat_option,
                                'cat_level'    => $cat_level,
                                'search term'  => $search,
                            ) );
                        } else {
                            // Fallback to title if no categories
                            $search = get_post_field( 'post_title', $id, 'raw' );
                            $log->info( 'No categories found, using title as fallback', array( 'post' => $id ) );
                        }
                        break;
                        
                    case 'custom_field':
                        $field_name = isset( $img_block['custom_field'] ) ? $img_block['custom_field'] : '';
                        if ( ! empty( $field_name ) ) {
                            $field_value = get_post_meta( $id, $field_name, true );
                            if ( ! empty( $field_value ) ) {
                                $search = $field_value;
                                $log->info( 'Search term from custom field', array(
                                    'post'        => $id,
                                    'field_name'  => $field_name,
                                    'search term' => $search,
                                ) );
                            } else {
                                // Fallback to title
                                $search = get_post_field( 'post_title', $id, 'raw' );
                                $log->info( 'Custom field empty, using title as fallback', array( 'post' => $id, 'field' => $field_name ) );
                            }
                        } else {
                            $search = get_post_field( 'post_title', $id, 'raw' );
                            $log->info( 'Custom field name not specified, using title', array( 'post' => $id ) );
                        }
                        break;
                        
                    case 'custom_request':
                        $template = isset( $img_block['custom_request'] ) ? $img_block['custom_request'] : '%%Title%%';
                        $search = $template;
                        
                        // Replace %%Title%%
                        $post_title = get_post_field( 'post_title', $id, 'raw' );
                        $search = str_replace( '%%Title%%', $post_title, $search );
                        
                        // Replace %%Category%%
                        $post_categories = get_the_category( $id );
                        $category_name = ! empty( $post_categories ) ? $post_categories[0]->name : '';
                        $search = str_replace( '%%Category%%', $category_name, $search );
                        
                        // Replace %%Tag%%
                        $post_tags = wp_get_post_tags( $id );
                        $tag_name = ! empty( $post_tags ) ? $post_tags[0]->name : '';
                        $search = str_replace( '%%Tag%%', $tag_name, $search );
                        
                        // Replace %%Taxonomy%% (custom taxonomies)
                        $taxonomies = get_object_taxonomies( get_post_type( $id ), 'names' );
                        $taxonomy_terms = array();
                        foreach ( $taxonomies as $taxonomy ) {
                            if ( $taxonomy !== 'category' && $taxonomy !== 'post_tag' ) {
                                $terms = wp_get_post_terms( $id, $taxonomy );
                                if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
                                    $taxonomy_terms[] = $terms[0]->name;
                                }
                            }
                        }
                        $taxonomy_value = ! empty( $taxonomy_terms ) ? implode( ' ', $taxonomy_terms ) : '';
                        $search = str_replace( '%%Taxonomy%%', $taxonomy_value, $search );
                        
                        // Clean up multiple spaces
                        $search = preg_replace( '/\s+/', ' ', trim( $search ) );
                        
                        $log->info( 'Search term from custom request template', array(
                            'post'        => $id,
                            'template'    => $template,
                            'search term' => $search,
                        ) );
                        break;
                        
                    case 'openai_extractor':
                        $api_key = isset( $img_block['openai_extractor_apikey'] ) ? $img_block['openai_extractor_apikey'] : '';
                        $num_keywords = isset( $img_block['openai_number_of_keywords'] ) ? $img_block['openai_number_of_keywords'] : '2';
                        
                        if ( ! empty( $api_key ) ) {
                            $post_title = get_post_field( 'post_title', $id, 'raw' );
                            $post_content = get_the_content( '', false, $id );
                            $post_content = wp_strip_all_tags( $post_content );
                            $post_content = substr( $post_content, 0, 1000 ); // Limit content length
                            
                            $extracted = $this->ALLSI_openai_extract_keywords( $api_key, $post_title, $post_content, $num_keywords );
                            
                            if ( $extracted ) {
                                $search = $extracted;
                                $log->info( 'Search term from OpenAI keyword extraction', array(
                                    'post'        => $id,
                                    'search term' => $search,
                                ) );
                            } else {
                                // Fallback to title
                                $search = $post_title;
                                $log->info( 'OpenAI extraction failed, using title as fallback', array( 'post' => $id ) );
                            }
                        } else {
                            $search = get_post_field( 'post_title', $id, 'raw' );
                            $log->info( 'OpenAI API key not provided, using title', array( 'post' => $id ) );
                        }
                        break;
                        
                    case 'ai_image_prompt':
                        $api_key = isset( $img_block['ai_prompt_apikey'] ) ? $img_block['ai_prompt_apikey'] : '';
                        $style = isset( $img_block['ai_prompt_style'] ) ? $img_block['ai_prompt_style'] : 'photorealistic';
                        $custom_instructions = isset( $img_block['ai_prompt_custom_instructions'] ) ? $img_block['ai_prompt_custom_instructions'] : '';
                        
                        if ( ! empty( $api_key ) ) {
                            $post_title = get_post_field( 'post_title', $id, 'raw' );
                            $post_content = get_the_content( '', false, $id );
                            $post_content = wp_strip_all_tags( $post_content );
                            $post_content = substr( $post_content, 0, 1500 ); // Limit content length
                            
                            $generated_prompt = $this->ALLSI_openai_generate_image_prompt( $api_key, $post_title, $post_content, $style, $custom_instructions );
                            
                            if ( $generated_prompt ) {
                                $search = $generated_prompt;
                                $log->info( 'AI-generated image prompt', array(
                                    'post'        => $id,
                                    'style'       => $style,
                                    'search term' => $search,
                                ) );
                            } else {
                                // Fallback to title
                                $search = $post_title;
                                $log->info( 'AI prompt generation failed, using title as fallback', array( 'post' => $id ) );
                            }
                        } else {
                            $search = get_post_field( 'post_title', $id, 'raw' );
                            $log->info( 'AI prompt API key not provided, using title', array( 'post' => $id ) );
                        }
                        break;
                        
                    case 'title':
                    default:
                        $search = get_post_field( 'post_title', $id, 'raw' );
                        $log->info( 'Using post title as search term', array(
                            'post'        => $id,
                            'search term' => $search,
                        ) );
                        break;
                }
            }
        }
        if ( isset( $img_block['title_selection'] ) && $img_block['title_selection'] == 'cut_title' && isset( $img_block['title_length'] ) ) {
            $length_title = (int) $img_block['title_length'] - 1;
            $search = preg_replace( '/((\\w+\\W*){' . $length_title . '}(\\w+))(.*)/', '${1}', $search );
        }
        
        // Translate search keywords to English if enabled (defaults to ON if not set)
        $do_translation = ! isset( $img_block['translation_EN'] ) || $img_block['translation_EN'] === 'true';
        
        ALLSI_log( array(
            'post_id' => $id,
            'translation_EN_value' => isset( $img_block['translation_EN'] ) ? $img_block['translation_EN'] : 'NOT SET (defaulting to true)',
            'do_translation' => $do_translation ? 'YES' : 'NO',
            'original_search' => $search,
        ), 'TRANSLATION_CHECK' );
        
        if ( $do_translation ) {
            // Use configured source language or auto-detect from WordPress
            $block_settings = wp_parse_args( get_option( 'ALLSI_plugin_block_settings' ), array( 'source_lang' => '' ) );
            if ( ! empty( $block_settings['source_lang'] ) ) {
                $source_lang = $block_settings['source_lang'];
            } else {
                $wp_lang = get_bloginfo('language');
                $source_lang = substr( $wp_lang, 0, 2 );
            }
            
            ALLSI_log( array(
                'post_id' => $id,
                'source_lang' => $source_lang,
                'target_lang' => 'en',
                'will_translate' => $source_lang !== 'en' ? 'YES' : 'NO (already English)',
            ), 'TRANSLATION_LANG_DETECT' );
            
            if ( $source_lang !== 'en' ) {
                $translated_search = $this->ALLSI_translate_text( $search, $source_lang, 'en' );
                
                ALLSI_log( array(
                    'post_id' => $id,
                    'original' => $search,
                    'translated' => $translated_search !== false ? $translated_search : 'TRANSLATION FAILED',
                    'success' => $translated_search !== false ? 'YES' : 'NO',
                ), 'TRANSLATION_RESULT' );
                
                if ( $translated_search !== false ) {
                    $search = $translated_search;
                    $log->info( 'Search term translated to English', array(
                        'post'   => $id,
                        'search' => $search,
                    ) );
                }
            }
        }
        if ( TRUE == $get_only_thumb ) {
            $source_manager = $this->ALLSI_get_source_manager_instance();
            if ( $source_manager && $source_manager->has_source( $img_block['api_chosen'] ) ) {
                $source = $source_manager->get_source( $img_block['api_chosen'] );
                $result = $source->generate( array(
                    'img_block'      => $img_block,
                    'options'        => $options,
                    'search'         => $search,
                    'log'            => $log,
                    'post_id'        => $id,
                    'get_only_thumb' => true,
                    'selected_image' => $img_block['selected_image'],
                    'proxy_args'     => $this->ALLSI_get_proxy_args(),
                    'generation'     => $this,
                    'page'           => isset( $additional_context['page'] ) ? max( 1, intval( $additional_context['page'] ) ) : 1,
                ) );
                if ( is_wp_error( $result ) ) {
                    $log->error( 'Source generation failed', array(
                        'post'       => $id,
                        'error'      => $result->get_error_message(),
                        'error_code' => $result->get_error_code(),
                        'error_data' => $result->get_error_data(),
                    ) );
                    ALLSI_log( array(
                        'post'    => $id,
                        'bank'    => $img_block['api_chosen'],
                        'message' => $result->get_error_message(),
                        'code'    => $result->get_error_code(),
                        'data'    => $result->get_error_data(),
                    ), 'GUTENBERG_BLOCK_SOURCE_ERROR' );
                    return false;
                }
                return $result;
            }

            /* SET ALL PARAMETERS */
            $array_parameters = $this->ALLSI_Get_Parameters( $img_block, $options, $search );
            
            ALLSI_log( array(
                'array_parameters' => $array_parameters,
                'has_url' => isset($array_parameters['url'])
            ), 'CREATE_THUMB_PARAMS' );
            
            $api_url = $array_parameters['url'];
            unset($array_parameters['url']);
            if ( !isset( $api_url ) ) {
                ALLSI_log( 'API URL not provided for bank: ' . $img_block['api_chosen'], 'CREATE_THUMB_ERROR' );
                $log->error( 'API URL not provided', array(
                    'post' => $id,
                ) );
                return false;
            }
            $result_body = $this->ALLSI_Generate(
                $img_block['api_chosen'],
                $api_url,
                $array_parameters,
                $img_block['selected_image'],
                $get_only_thumb,
                $search
            );
            return $result_body;
        }
        // Check if button "Generate Automatically" is clicked (but NOT for bulk cron processing)
        // When $button_autogenerate is 'bulk', we use the specific api_chosen from the image block
        if ( true === $button_autogenerate && is_array( $options_banks['api_chosen_auto'] ) ) {
            $log->info( 'Button "Generate Automatically" clicked', array(
                'post' => $id,
            ) );
            $last_bank_element = end( $options_banks['api_chosen_auto'] );
            $proxy_args = $this->ALLSI_get_proxy_args();
            foreach ( $options_banks['api_chosen_auto'] as $bank ) {
                // Reset options according new image bank
                $options['api_chosen'] = $bank;

                $source_manager = $this->ALLSI_get_source_manager_instance();
                if ( $source_manager && $source_manager->has_source( $bank ) ) {
                    $context_block = $img_block;
                    $context_block['api_chosen'] = $bank;
                    $source = $source_manager->get_source( $bank );
                    $result = $source->generate( array(
                        'img_block'      => $context_block,
                        'options'        => $options,
                        'search'         => $search,
                        'log'            => $log,
                        'post_id'        => $id,
                        'get_only_thumb' => false,
                        'selected_image' => $context_block['selected_image'],
                        'proxy_args'     => $proxy_args,
                        'generation'     => $this,
                    ) );

                    if ( is_wp_error( $result ) ) {
                        $log->info( 'No results with ' . $bank, array(
                            'post'  => $id,
                            'error' => $result->get_error_message(),
                        ) );
                        if ( $bank === $last_bank_element ) {
                            $log->info( 'No image found with all banks selected', array(
                                'post' => $id,
                            ) );
                            return false;
                        }
                        continue;
                    }

                    $url_results = $result['url_results'];
                    $file_media = $result['file_media'];
                    $alt_img = isset( $result['alt_img'] ) ? $result['alt_img'] : '';
                    $caption_img = isset( $result['caption_img'] ) ? $result['caption_img'] : '';
                if ( !isset( $url_results ) || !isset( $file_media ) ) {
                    $log->info( 'No results with ' . $bank, array(
                        'post' => $id,
                    ) );
                    // Return false with no results with each image bank
                    if ( $bank === $last_bank_element ) {
                        $log->info( 'No image found with all banks selected', array(
                            'post' => $id,
                        ) );
                        return false;
                    }
                } else {
                    // OK
                    break;
                }
            }
            }
        } else {
            // Log the search term before processing
            ALLSI_log( array(
                'post_id' => $id,
                'api_chosen' => $img_block['api_chosen'],
                'search_term' => $search,
                'based_on' => isset( $img_block['based_on'] ) ? $img_block['based_on'] : 'title',
                'translation_EN' => isset( $img_block['translation_EN'] ) ? $img_block['translation_EN'] : 'not set',
            ), 'GENERATION_SEARCH_TERM' );
            
            // Process the main image block
            $result = $this->ALLSI_Process_Image_Block(
                $img_block,
                $options,
                $search,
                $log,
                $id
            );
            // If the first API call fails, try the second image bank
            if ( $result === false && isset( $img_block['api_chosen_2'] ) && $img_block['api_chosen_2'] !== 'none' ) {
                $log->info( 'Second image bank used', array(
                    'post' => $id,
                ) );
                $img_block['api_chosen'] = $img_block['api_chosen_2'];
                $result = $this->ALLSI_Process_Image_Block(
                    $img_block,
                    $options,
                    $search,
                    $log,
                    $id
                );
            }
            // If both API calls fail, return false
            if ( $result === false ) {
                return false;
            }
            
            // Log the image result
            ALLSI_log( array(
                'post_id' => $id,
                'api_chosen' => $img_block['api_chosen'],
                'image_url' => isset( $result['url_results'] ) ? $result['url_results'] : 'N/A',
                'file_name' => isset( $result['file_media']['headers']['content-disposition'] ) ? $result['file_media']['headers']['content-disposition'] : 'N/A',
            ), 'GENERATION_IMAGE_RESULT' );
            
            // Extract results and continue processing
            extract( $result );
        }
        $path_parts = pathinfo( $url_results );
        $filename = $path_parts['basename'];
        $wp_upload_dir = wp_upload_dir();
        /* Get the good file extension */
        $filetype = array(
            'image/png',
            'image/jpeg',
            'image/gif',
            'image/bmp',
            'image/vnd.microsoft.icon',
            'image/tiff',
            'image/svg+xml',
            'image/svg+xml',
            'image/webp'
        );
        $extensions = array(
            'png',
            'jpg',
            'gif',
            'bmp',
            'ico',
            'tif',
            'svg',
            'svgz',
            'webp'
        );
        if ( isset( $file_media['headers']['content-type'] ) ) {
            $imgextension = str_replace(
                $filetype,
                $extensions,
                $file_media['headers']['content-type'],
                $count_extension
            );
            /* Default type if not found : jpg */
            if ( (int) $count_extension == 0 ) {
                $imgextension = 'jpg';
            }
        } else {
            $imgextension = $path_parts['extension'];
        }
        $keywords_search = $search;
        $log->info( 'Search term', array(
            'post'        => $id,
            'Search term' => $keywords_search,
        ) );
        /* Image filename : title extension */
        $search = str_replace( '%', '', sanitize_title( $search ) );
        // Remove % for non-latin characters
        // Check if the 'resuse image' option is enabled.
        if ( isset( $main_settings['image_reuse'] ) && $main_settings['image_reuse'] == true ) {
            // Check if image file already exist if option is set
            $proposed_filename = sanitize_title( $search );
            $existing_image_id = $this->ALLSI_check_existing_image( get_the_title( $id ), $proposed_filename );
            if ( $existing_image_id ) {
                // Use the existing image instead of downloading a new one
                $log->info( 'Featured image with existing image (option set)', array(
                    'post'  => $id,
                    'image' => $existing_image_id,
                ) );
                set_post_thumbnail( $id, $existing_image_id );
                do_action( 'ALLSI_after_create_thumb', $id, $existing_image_id );
                return $existing_image_id;
            }
        }
        if ( $options['image_filename'] == 'date' ) {
            $current_time = current_time( 'Y-m-d' );
            $filename = wp_unique_filename( $wp_upload_dir['path'], $current_time . '.' . $imgextension );
        } elseif ( $options['image_filename'] == 'random' ) {
            $filename_rand = wp_rand( 1, 999999 );
            $filename = wp_unique_filename( $wp_upload_dir['path'], $filename_rand . '.' . $imgextension );
        } else {
            $filename = wp_unique_filename( $wp_upload_dir['path'], $search . '.' . $imgextension );
        }
        $folder = $wp_upload_dir['path'] . '/' . $filename;
        if ( $file_media['response']['code'] != '200' || empty( $file_media['body'] ) ) {
            $log->error( 'Problem with scrapping', array(
                'post' => $id,
            ) );
            return false;
        }
        if ( $file_media['body'] ) {
            /* Upload the file to wordpress directory */
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Writing image data to wp_upload_dir path.
            $file_upload = file_put_contents( $folder, $file_media['body'] );
            /* Convert png to jpeg for dalle */
            $png_jpg = ( !empty( $options['dallev1']['convert_jpg'] ) ? $options['dallev1']['convert_jpg'] : '' );
            //if( ( true == $png_jpg ) && ( 'dallev1' == $options['api_chosen'] ) ) {
            if ( true == $png_jpg && 'dallev1' == $img_block['api_chosen'] ) {
                $image = imagecreatefrompng( $folder );
                // Remove old png file
                wp_delete_file( $folder );
                $folder = str_replace( ".png", ".jpg", $folder );
                $filename = str_replace( ".png", ".jpg", $filename );
                imagejpeg( $image, $folder, 90 );
                imagedestroy( $image );
            }
            if ( $file_upload ) {
                $wp_filetype = wp_check_filetype( basename( $filename ), null );
                $wp_upload_dir = wp_upload_dir();
                $attachment = array(
                    'guid'           => $wp_upload_dir['url'] . '/' . urlencode( $filename ),
                    'post_mime_type' => $wp_filetype['type'],
                    'post_title'     => $search,
                    'post_content'   => '',
                    'post_status'    => 'inherit',
                );
                $attach_id = wp_insert_attachment( $attachment, $wp_upload_dir['path'] . '/' . urlencode( $filename ) );
                // Add alt text for image
                update_post_meta( $attach_id, '_wp_attachment_image_alt', $alt_img );
                // Add caption text for image
                if ( !empty( $caption_img ) ) {
                    wp_update_post( array(
                        'ID'           => $attach_id,
                        'post_excerpt' => $caption_img,
                    ) );
                }
                /* Allow integrations to react after attachment creation. */
                $img_values = array(
                    'file' => $wp_upload_dir['path'] . '/' . urlencode( $filename ),
                    'url'  => $wp_upload_dir['url'] . '/' . urlencode( $filename ),
                    'type' => $wp_filetype['type'],
                );
                do_action( 'allsi_after_attachment_created', $attach_id, $img_values );
                require_once ABSPATH . 'wp-admin/includes/image.php';
                $attach_data = wp_generate_attachment_metadata( $attach_id, $wp_upload_dir['path'] . '/' . urlencode( $filename ) );
                $update_attach_data = wp_update_attachment_metadata( $attach_id, $attach_data );
                $executeElseBlock = true;
                $plugin_desactivated = false;
                $missing_field = false;
                // If a field plugin is disabled and should be used
                if ( true === $plugin_desactivated || true === $missing_field ) {
                    return false;
                }
                if ( $executeElseBlock ) {
                    if ( "custom" === $image_location ) {
                        $tag = $img_block['image_custom_location_tag'];
                        $placement = $img_block['image_custom_location_placement'];
                        $position = $img_block['image_custom_location_position'];
                        $image_size = $img_block['image_custom_image_size'];
                        $content = $this->ALLSI_insert_content_image(
                            $content_post->post_content,
                            $attach_id,
                            $tag,
                            $placement,
                            $position,
                            $image_size
                        );
                    } else {
                        $log->info( 'Featured image added', array(
                            'post'  => $id,
                            'image' => $attach_id,
                        ) );
                        set_post_thumbnail( $id, $attach_id );
                    }
                }
                // Link the media to the post
                $media_link_uploaded_to = wp_update_post( array(
                    'ID'          => $attach_id,
                    'post_parent' => $id,
                ), true );
                if ( "custom" === $image_location ) {
                    // Array of post category ids
                    $arr_post_category = array();
                    foreach ( $postcategories as $postcategory ) {
                        $arr_post_category[] = (int) $postcategory->cat_ID;
                    }
                    /*
                     * Remove save_post Action to avoid infinite loop.
                     * cf https://developer.wordpress.org/reference/hooks/save_post/#avoiding-infinite-loops
                     * Use "remove_all_actions" instead of "remove_action". Otherwise the log file bug
                     * remove_action( 'save_post', array( &$this, 'ALLSI_create_thumb' ) );
                     */
                    remove_all_actions( 'save_post' );
                    wp_insert_post( array(
                        'ID'                    => $id,
                        'post_content'          => $content,
                        'post_category'         => $arr_post_category,
                        'post_title'            => $content_post->post_title,
                        'post_status'           => $content_post->post_status,
                        'post_author'           => $content_post->post_author,
                        'post_date'             => $content_post->post_date,
                        'post_date_gmt'         => $content_post->post_date_gmt,
                        'post_excerpt'          => $content_post->post_excerpt,
                        'comment_status'        => $content_post->comment_status,
                        'ping_status'           => $content_post->ping_status,
                        'post_password'         => $content_post->post_password,
                        'post_name'             => $content_post->post_name,
                        'to_ping'               => $content_post->to_ping,
                        'pinged'                => $content_post->pinged,
                        'post_modified'         => $content_post->post_modified,
                        'post_modified_gmt'     => $content_post->post_modified_gmt,
                        'post_content_filtered' => $content_post->post_content_filtered,
                        'post_parent'           => $content_post->post_parent,
                        'menu_order'            => $content_post->menu_order,
                        'post_type'             => $content_post->post_type,
                        'post_mime_type'        => $content_post->post_mime_type,
                    ) );
                    add_action( 'save_post', array(&$this, 'ALLSI_create_thumb') );
                    $log->info( 'Image added into the post', array(
                        'post'  => $id,
                        'image' => $attach_id,
                    ) );
                }
                do_action( 'ALLSI_after_create_thumb', $id, $attach_id );
                if ( true === $include_datas ) {
                    return array(
                        'id'             => $attach_id,
                        'keyword'        => $keywords_search,
                        'img_resolution' => $attach_data['width'] . 'x' . $attach_data['height'] . 'px',
                        'img_size'       => $this->ALLSI_get_image_size_in_bytes( $attach_id ),
                        'api_chosen'     => $img_block['api_chosen'],
                    );
                } else {
                    return $attach_id;
                }
            }
        }
    }

    /**
     * Generate an image and handle related errors
     * 
     * @param array $img_block Image block settings
     * @param array $options Plugin options
     * @param string $search Search term
     * @param object $log Logger instance
     * @param int $id Post ID
     * @return array|false Returns generated image data or false on failure
     */
    private function ALLSI_Process_Image_Block(
        $img_block,
        $options,
        $search,
        $log,
        $id
    ) {
        $source_manager = $this->ALLSI_get_source_manager_instance();
        
        // Debug logging for source resolution
        $api_chosen = isset( $img_block['api_chosen'] ) ? $img_block['api_chosen'] : null;
        ALLSI_log( array(
            'post_id' => $id,
            'api_chosen' => $api_chosen,
            'api_chosen_type' => gettype( $api_chosen ),
            'source_manager_exists' => ( $source_manager !== null ),
            'has_source' => ( $source_manager && is_string( $api_chosen ) ) ? $source_manager->has_source( $api_chosen ) : false,
            'all_sources' => $source_manager ? array_keys( $source_manager->all() ) : array(),
        ), 'PROCESS_IMAGE_BLOCK_DEBUG' );
        
        if ( $source_manager && $source_manager->has_source( $img_block['api_chosen'] ) ) {
            $source = $source_manager->get_source( $img_block['api_chosen'] );
            $result = $source->generate( array(
                'img_block'      => $img_block,
                'options'        => $options,
                'search'         => $search,
                'log'            => $log,
                'post_id'        => $id,
                'get_only_thumb' => false,
                'selected_image' => $img_block['selected_image'],
                'proxy_args'     => $this->ALLSI_get_proxy_args(),
                'generation'     => $this,
            ) );
            if ( is_wp_error( $result ) ) {
                $log->error( 'Source generation failed', array(
                    'post'       => $id,
                    'error'      => $result->get_error_message(),
                    'error_code' => $result->get_error_code(),
                    'error_data' => $result->get_error_data(),
                ) );
                return false;
            }
            
            // Log the source result with image URL
            ALLSI_log( array(
                'post_id' => $id,
                'source' => $img_block['api_chosen'],
                'search_term' => $search,
                'image_url' => isset( $result['url_results'] ) ? $result['url_results'] : 'N/A',
                'alt_img' => isset( $result['alt_img'] ) ? $result['alt_img'] : 'N/A',
            ), 'SOURCE_GENERATION_SUCCESS' );
            
            return $result;
        }

        // Source manager did not find the source - falling back to legacy ALLSI_Get_Parameters
        ALLSI_log( array(
            'post_id' => $id,
            'api_chosen' => isset( $img_block['api_chosen'] ) ? $img_block['api_chosen'] : null,
            'message' => 'Source not found in source_manager, falling back to ALLSI_Get_Parameters',
        ), 'PROCESS_IMAGE_BLOCK_FALLBACK' );
        
        // Set all parameters
        $array_parameters = $this->ALLSI_Get_Parameters( $img_block, $options, $search );
        
        ALLSI_log( array(
            'post_id' => $id,
            'api_chosen' => isset( $img_block['api_chosen'] ) ? $img_block['api_chosen'] : null,
            'array_parameters' => $array_parameters,
            'has_url' => isset( $array_parameters['url'] ),
        ), 'PROCESS_IMAGE_BLOCK_LEGACY_PARAMS' );
        
        $api_url = ( isset( $array_parameters['url'] ) ? $array_parameters['url'] : null );
        unset($array_parameters['url']);
        // Check if API URL is provided
        if ( !$api_url ) {
            $log->error( 'API URL not provided', array(
                'post' => $id,
            ) );
            return false;
        }
        // Get the image URL
        list( $url_results, $file_media, $alt_img, $caption_img ) = $this->ALLSI_Generate(
            $img_block['api_chosen'],
            $api_url,
            $array_parameters,
            $img_block['selected_image'],
            false,
            $search
        );
        // Check if results are valid
        if ( !isset( $url_results ) || !isset( $file_media ) ) {
            $log->error( 'No results', array(
                'post' => $id,
            ) );
            return false;
        }
        // Return the generated image data
        return compact(
            'url_results',
            'file_media',
            'alt_img',
            'caption_img'
        );
    }

    /**
     * Get Image size in ko
     *
     * @since 6.0.0
     */
    private function ALLSI_get_image_size_in_bytes( $attachment_id ) {
        // Full path of the image
        $image_path = get_attached_file( $attachment_id );
        if ( $image_path && file_exists( $image_path ) ) {
            // File size in bytes
            $image_size = filesize( $image_path );
        }
        // Convert to kilobytes
        $image_size_kb = round( $image_size / 1024, 2 );
        return $image_size_kb . 'ko';
    }

    /**
     * Insert an image before or after a specific Gutenberg block
     *
     * @since 5.2.0
     */
    private function ALLSI_insert_content_image(
        $content,
        $attach_id,
        $tag = 'p',
        $placement = 'after',
        $position = '1',
        $image_size = 'large'
    ) {
        // If content is plain text without HTML tags, apply wpautop first
        // This handles cases like WP All Import where content comes as plain text
        if ( ! preg_match('/<[^>]+>/', $content) || ( $tag == 'p' && stripos($content, '<p') === false ) ) {
            $content = wpautop( $content );
        }
        
        // Check if the Classic Editor is being used
        $classic_editor = $this->ALLSI_is_using_classic_editor();
        $match = false;
        $loop_count = 0;
        $max_loops = 2; // Prevent infinite loops
        
        // Variable to track if the image was inserted successfully
        // Loop until the image insertion is successful
        while ( !$match && $loop_count < $max_loops ) {
            $loop_count++;
            // Prepare the HTML block for the image depending on the editor type
            if ( $classic_editor ) {
                $match = true;
                // Set match to true since we'll insert the image for Classic Editor
                $image = wp_get_attachment_image(
                    $attach_id,
                    $image_size,
                    false,
                    array(
                        'class' => 'wp-image-' . $attach_id,
                    )
                );
                $image_block = '<p>' . $image . '</p>';
            } else {
                // Get image details for Gutenberg
                $image_src = wp_get_attachment_image_src( $attach_id, $image_size, false );
                $alt_text = get_post_meta( $attach_id, '_wp_attachment_image_alt', true );
                $image = '<img src="' . esc_url( $image_src[0] ) . '" alt="' . esc_attr( $alt_text ) . '" class="wp-image-' . esc_attr( $attach_id ) . '"/>';
                // Include caption if enabled in settings
                $options = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( TRUE ) );
                if ( isset( $options['enable_caption'] ) && 'enable' == $options['enable_caption'] ) {
                    $caption_text = wp_get_attachment_caption( $attach_id );
                    $image .= '<figcaption class="wp-element-caption">' . esc_html( $caption_text ) . '</figcaption>';
                }
                // Wrap the image in a Gutenberg image block format
                $image_block = '<!-- wp:image {"id":' . $attach_id . ',"linkDestination":"none"} -->';
                $image_block .= '<figure class="wp-block-image">' . $image . '</figure>';
                $image_block .= '<!-- /wp:image -->';
            }
            // Define the tag-specific search pattern
            if ( $classic_editor ) {
                // Patterns for Classic Editor content
                $start_pattern = '<' . $tag;
                $end_pattern = '</' . $tag . '>';
                $pattern = '/(' . preg_quote( $start_pattern, '/' ) . '.*?' . preg_quote( $end_pattern, '/' ) . ')/s';
                $parts = preg_split(
                    $pattern,
                    $content,
                    -1,
                    PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
                );
                // Remove empty content
                $filtered_array = array_filter( $parts, function ( $value ) {
                    return trim( $value ) !== '';
                } );
                // Re-indexing of table keys if necessary
                $parts = array_values( $filtered_array );
                // Restart the loop if can not find paragraphs
                if ( 'p' == $tag && count( $parts ) < 2 && $loop_count == 1 ) {
                    //Apply wpautop() for next loop
                    $content = wpautop( $content );
                    $match = false;
                    continue;
                } elseif ( 'p' == $tag && count( $parts ) < 2 ) {
                    // If still no paragraphs after wpautop, insert at beginning of content
                    $new_content = $image_block . $content;
                    return $new_content;
                }
            } else {
                // Patterns for Gutenberg Editor, ensuring separate blocks
                if ( $tag == 'p' ) {
                    $start_pattern = '<!-- wp:paragraph';
                    $end_pattern = '<\\/p>\\s*<!-- \\/wp:paragraph -->';
                } elseif ( $tag == 'a' ) {
                    $start_pattern = '<!-- wp:html -->';
                    $end_pattern = '<!-- /wp:html -->';
                } else {
                    $start_pattern = '<!-- wp:heading';
                    $end_pattern = '<\\/h[1-6]>\\s*<!-- \\/wp:heading -->';
                }
                $pattern = '/(' . preg_quote( $start_pattern, '/' ) . '.*?' . $end_pattern . ')/s';
                $parts = preg_split(
                    $pattern,
                    $content,
                    -1,
                    PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY
                );
            }
            // Initialize variables for constructing the new content
            $new_content = '';
            $counter = 0;
            $total_tags = substr_count( $content, $start_pattern );
            // Loop through each part to build the new content with the image block inserted
            foreach ( $parts as $part ) {
                // Check if part contains the target tag
                $contains_tag = preg_match( $pattern, $part );
                // Insert image before tag if 'before' placement is specified
                if ( $placement == 'before' && $contains_tag ) {
                    $counter++;
                    if ( $position == 'last' && $counter == $total_tags || $counter == $position ) {
                        if ( $classic_editor ) {
                            $new_content .= '</p>' . $image_block . '<p>';
                        } else {
                            $new_content .= $image_block;
                        }
                        $match = true;
                    }
                }
                // Add the current part to new content
                $new_content .= $part;
                // Insert image after tag if 'after' placement is specified
                if ( $placement == 'after' && $contains_tag ) {
                    $counter++;
                    if ( $position == 'last' && $counter == $total_tags || $counter == $position ) {
                        if ( $classic_editor ) {
                            $new_content .= '</p>' . $image_block . '<p>';
                        } else {
                            $new_content .= $image_block;
                        }
                        $match = true;
                    }
                }
            }
            // If no match found, switch to Classic Editor as a fallback
            if ( !$match ) {
                $classic_editor = true;
            }
        }
        return $new_content;
    }

    /**
     * Extract a specific paragraph from the post content.
     *
     * @since    6.0.0
     */
    private function ALLSI_extract_adjacent_element(
        $content,
        $element = 'p',
        $element_number = 1,
        $direction = 'text_analyser_previous_paragraph'
    ) {
        // Define the pattern to match the specified element
        $pattern = '/<(' . preg_quote( $element, '/' ) . ')(.*?)>(.*?)<\\/\\1>/s';
        // Find all matches of the specified element
        preg_match_all( $pattern, $content, $matches );
        // Check if the element_number is "last"
        if ( $element_number === 'last' ) {
            // Ensure the index is valid and points to the last element
            $index = count( $matches[0] ) - 1;
        } else {
            // Convert to zero-based index
            $index = $element_number - 1;
        }
        // Check if we have a valid index
        if ( isset( $matches[0][$index] ) ) {
            if ( $direction === 'text_analyser_previous_paragraph' || $element_number === 'last' ) {
                // Get the position of the target element in the content
                if ( 'p' == $element ) {
                    $target_position = strpos( $content, $matches[0][$index + 1] );
                } else {
                    $target_position = strpos( $content, $matches[0][$index] );
                }
                // Get the content before the target element
                $content_before = substr( $content, 0, $target_position );
                // Match all paragraphs before the target element
                $paragraph_pattern = '/<p\\b[^>]*>(.*?)<\\/p>/s';
                preg_match_all( $paragraph_pattern, $content_before, $paragraph_matches );
                // Remove too shorts paragraphs. For exemple "<p>&nbsp;</p>"
                if ( strlen( $paragraph_matches[0][0] ) < 15 ) {
                    unset($paragraph_matches[0][0]);
                    $paragraph_matches[0] = array_values( $paragraph_matches[0] );
                }
                // Return the last paragraph found before the target element
                if ( !empty( $paragraph_matches[0] ) ) {
                    // Return only the last paragraph, cleaned of HTML tags
                    return ( is_string( $paragraph_matches[0][count( $paragraph_matches[0] ) - 1] ) ? trim( wp_strip_all_tags( $paragraph_matches[0][count( $paragraph_matches[0] ) - 1] ) ) : '' );
                }
            } elseif ( $direction === 'text_analyser_next_paragraph' ) {
                // Get the position of the target element in the content
                $target_position = strpos( $content, $matches[0][$index] );
                // Get the content before the target element
                $content_before = substr( $content, 0, $target_position );
                // Get the content after the target element
                $content_after = substr( $content, $target_position + strlen( $matches[0][$index] ) );
                // Match the first paragraph after the target element
                $paragraph_pattern = '/<p\\b[^>]*>(.*?)<\\/p>/s';
                preg_match_all( $paragraph_pattern, $content_after, $paragraph_matches );
                // Remove too shorts paragraphs. For exemple "<p>&nbsp;</p>"
                if ( strlen( $paragraph_matches[0][0] ) < 15 ) {
                    unset($paragraph_matches[0][0]);
                    $paragraph_matches[0] = array_values( $paragraph_matches[0] );
                }
                // Return the first paragraph found after the target element
                if ( !empty( $paragraph_matches[0] ) ) {
                    return ( is_string( $paragraph_matches[0][0] ) ? trim( wp_strip_all_tags( $paragraph_matches[0][0] ) ) : '' );
                }
            }
        }
        return '';
        // Return empty if not found
    }

    /**
     * Check Classic Editor plugin
     *
     * @since    5.2.0
     */
    private function ALLSI_is_using_classic_editor() {
        // Include the is_plugin_active function if it's not already defined
        if ( !function_exists( 'is_plugin_active' ) ) {
            include_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        // Check if the Classic Editor plugin is active
        return is_plugin_active( 'classic-editor/classic-editor.php' );
    }

    /**
     * Get all settings from user
     *
     * @since    4.0.0
     */
    private function ALLSI_Get_Parameters( $img_block, $options, $search ) {
        ALLSI_log( array(
            'bank' => $img_block['api_chosen'],
            'search' => $search
        ), 'GET_PARAMETERS' );
        
        if ( isset( $img_block['api_chosen'] ) && $img_block['api_chosen'] === 'replicate' ) {
            $api_key = ( !empty( $options['replicate']['apikey'] ) ? $options['replicate']['apikey'] : '' );
            $model = ( !empty( $options['replicate']['model'] ) ? $options['replicate']['model'] : 'black-forest-labs/flux-schnell' );
            $output_format = ( !empty( $options['replicate']['output_format'] ) ? $options['replicate']['output_format'] : 'webp' );
            $aspect_ratio = ( !empty( $options['replicate']['aspect_ratio'] ) ? $options['replicate']['aspect_ratio'] : '16:9' );
            
            // Get version ID from model name (simplified - use latest version)
            $version_map = array(
                'black-forest-labs/flux-schnell' => 'latest',
                'stability-ai/sdxl' => 'latest',
            );
            $version = isset( $version_map[$model] ) ? $version_map[$model] : 'latest';
            
            $array_parameters = array(
                'url'     => 'https://api.replicate.com/v1/predictions',
                'method'  => 'POST',
                'timeout' => 30,
                'headers' => array(
                    'Authorization' => 'Token ' . $api_key,
                    'Content-Type'  => 'application/json',
                ),
                'body'    => json_encode( array(
                    'version' => $version,
                    'input'   => array(
                        'prompt'        => $search,
                        'output_format' => $output_format,
                        'aspect_ratio'  => $aspect_ratio,
                    ),
                ) ),
            );
        } elseif ( $img_block['api_chosen'] == 'stability' ) {
            $api_key = ( !empty( $options['stability']['apikey'] ) ? $options['stability']['apikey'] : '' );
            $model = ( !empty( $options['stability']['model'] ) ? $options['stability']['model'] : 'sd3-large' );
            $aspect_ratio = ( !empty( $options['stability']['aspect_ratio'] ) ? $options['stability']['aspect_ratio'] : '16:9' );
            $output_format = ( !empty( $options['stability']['output_format'] ) ? $options['stability']['output_format'] : 'jpeg' );
            $use_negative_prompt = ( !empty( $options['stability']['use_negative_prompt'] ) && 'true' === $options['stability']['use_negative_prompt'] );

            $endpoint_map = array(
                'sd3-large'         => 'sd3',
                'sd3-large-turbo'   => 'sd3-turbo',
                'sd3-medium'        => 'sd3',
                'sd3.5-large-turbo' => 'sd3',
                'sd3.5-large'       => 'sd3',
                'core'              => 'core',
                'ultra'             => 'ultra',
            );
            $endpoint = isset( $endpoint_map[$model] ) ? $endpoint_map[$model] : 'sd3';

            $payload = array(
                'prompt'        => $search,
                'model'         => $model,
                'aspect_ratio'  => $aspect_ratio,
                'output_format' => $output_format,
            );

            if ( in_array( $endpoint, array('core', 'ultra'), true ) ) {
                $aspect_map = array(
                    '21:9' => array('width' => 2560, 'height' => 1097),
                    '16:9' => array('width' => 2560, 'height' => 1440),
                    '3:2'  => array('width' => 2304, 'height' => 1536),
                    '5:4'  => array('width' => 2048, 'height' => 1638),
                    '1:1'  => array('width' => 2048, 'height' => 2048),
                    '4:5'  => array('width' => 1638, 'height' => 2048),
                    '2:3'  => array('width' => 1536, 'height' => 2304),
                    '9:16' => array('width' => 1440, 'height' => 2560),
                    '9:21' => array('width' => 1097, 'height' => 2560),
                );
                $dimensions = isset( $aspect_map[$aspect_ratio] ) ? $aspect_map[$aspect_ratio] : $aspect_map['16:9'];
                $payload['width']  = $dimensions['width'];
                $payload['height'] = $dimensions['height'];
            }

            if ( $use_negative_prompt ) {
                $payload['negative_prompt'] = 'blurry, low quality, distorted, disfigured, ugly, low resolution';
            }

            $boundary = 'ASI-' . wp_generate_password( 24, false );
            $body = '';
            foreach ( $payload as $field => $value ) {
                if ( $value === '' ) {
                    continue;
                }
                $body .= '--' . $boundary . "\r\n";
                $body .= 'Content-Disposition: form-data; name="' . $field . '"' . "\r\n\r\n";
                $body .= $value . "\r\n";
            }
            $body .= '--' . $boundary . "--\r\n";

            $array_parameters = array(
                'url'     => 'https://api.stability.ai/v2beta/stable-image/generate/' . $endpoint,
                'method'  => 'POST',
                'timeout' => 60,
                'headers' => array(
                    'Authorization' => 'Bearer ' . $api_key,
                    'Accept'        => 'image/*',
                    'Content-Type'  => 'multipart/form-data; boundary=' . $boundary,
                ),
                'body'    => $body,
            );
        } else {
            ALLSI_log( 'Unknown bank: ' . $img_block['api_chosen'], 'GET_PARAMETERS_ERROR' );
            return false;
        }
        
        ALLSI_log( array(
            'url' => isset($array_parameters['url']) ? $array_parameters['url'] : 'NO URL',
            'params_count' => count($array_parameters)
        ), 'GET_PARAMETERS_SUCCESS' );
        
        return $array_parameters;
    }

    /**
     * Generate image process
     *
     * @since    4.0.0
     */
    public function ALLSI_Generate(
        $service,
        $url,
        $url_parameters,
        $selected_image,
        $get_only_thumb = false,
        $search = ''
    ) {
        ALLSI_log( array(
            'service' => $service,
            'url' => $url,
            'search' => $search,
            'get_only_thumb' => $get_only_thumb
        ), 'ALLSI_GENERATE_START' );
        
        $log = $this->ALLSI_monolog_call();
        list( $result_body, $result ) = $this->ALLSI_get_results( $service, $url, $url_parameters );
        // In case of API problem
        if ( empty( $result_body ) ) {
            ALLSI_log( 'Empty result_body from API: ' . $service, 'ALLSI_GENERATE_ERROR' );
            return false;
        }
        
        ALLSI_log( 'API response received for: ' . $service, 'ALLSI_GENERATE_RESPONSE' );

        $log = $this->ALLSI_monolog_call();
        $log->info( 'Source used', array(
            'Service' => $service,
        ) );
        // ── INSERT REPLICATE POLLING HERE ────────────────────────────────────────
        if ( $service === 'replicate' ) {
            // extract prediction ID and status URL
            $predictionId = $result_body['id'];
            $getUrl = $result_body['urls']['get'];
            // retrieve API token from settings
            $options = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( true ) );
            $apiToken = ( !empty( $options['replicate']['apikey'] ) ? $options['replicate']['apikey'] : '' );
            // poll until prediction is complete
            do {
                usleep( 500000 );
                // wait 0.5s
                $request_args = array(
                    'headers' => array(
                        'Authorization' => 'Token ' . $apiToken,
                        'Content-Type'  => 'application/json',
                    ),
                    'timeout' => 10,
                );
                $resp = $this->ALLSI_remote_get( 'replicate', $getUrl, $request_args );
                // DEBUG
                /*
                			$log->info( 'Replicate polling status', [
                				'http_code' => wp_remote_retrieve_response_code( $resp ),
                				'body'      => substr( wp_remote_retrieve_body( $resp ), 0, 100 ) // Start of JSON
                			] );*/
                if ( is_wp_error( $resp ) ) {
                    return false;
                }
                $body = json_decode( wp_remote_retrieve_body( $resp ), true );
                $status = isset( $body['status'] ) ? $body['status'] : '';
            } while ( in_array( $status, array('starting', 'processing'), true ) );
            // on success, replace output so subsequent logic sees the final URL
            if ( $status === 'succeeded' && !empty( $body['output'][0] ) ) {
                $result_body['output'] = $body['output'];
            } else {
                return false;
            }
        }
        // ── END OF REPLICATE POLLING ────────────────────────────────────────────
        if ( $service === 'stability' ) {
            $loop_results = $result_body;
            $url_path = 'image';
        } elseif ( $service == 'replicate' ) {
            $loop_results = ( isset( $result_body['output'] ) ? (array) $result_body['output'] : array() );
            $url_path = null;
        } else {
            return false;
        }
        // Check if function is launch for Gutenberg block
        if ( TRUE == $get_only_thumb ) {
            return $result_body;
        }
        /* Random Image */
        if ( $selected_image == 'random_result' && $service != 'stability' ) {
            @shuffle( $loop_results );
        }
        // Testing images
        if ( !empty( $loop_results ) ) {
            $loop_count = 0;
            $numUrl = count( $loop_results );
            foreach ( $loop_results as $fetch_result_key => $fetch_result ) {
                if ( 'image' != $fetch_result_key && $service == 'stability' ) {
                    continue;
                }
                if ( $service == 'replicate' ) {
                    $url_result = $fetch_result;
                } elseif ( $service !== 'stability' ) {
                    $url_result = $fetch_result[$url_path];
                }
                // Change default url image
                if ( $service == 'stability' ) {
                    $url_result = $fetch_result;
                } elseif ( $service == 'replicate' ) {
                    // For replicate, $fetch_result is already the final URL
                    $url_result = $fetch_result;
                } else {
                    $url_result = $fetch_result[$url_path];
                }
                $options = wp_parse_args( get_option( 'ALLSI_plugin_main_settings' ), $this->ALLSI_default_options_main_settings( TRUE ) );
                
                // ALT text generation
                $alt = '';
                if ( isset( $options['enable_alt'] ) && 'enable' == $options['enable_alt'] ) {
                    // Get ALT text source
                    if ( isset( $options['alt_from'] ) && $options['alt_from'] == 'source' ) {
                        // Use image bank name as ALT
                        $alt = ucfirst( $service );
                    } elseif ( isset( $options['alt_from'] ) && $options['alt_from'] == 'based_on' ) {
                        // Use search term as ALT
                        $alt = $search;
                    }
                    
                    // Translate ALT text if enabled
                    if ( !empty( $alt ) && isset( $options['translate_alt'] ) && $options['translate_alt'] == 'true' ) {
                        $target_lang = ( !empty( $options['translate_alt_lang'] ) ? $options['translate_alt_lang'] : 'en' );
                        if ( $target_lang !== 'en' ) {
                            $translated_alt = $this->ALLSI_translate_text( $alt, 'en', $target_lang );
                            if ( $translated_alt !== false ) {
                                $alt = $translated_alt;
                            }
                        }
                    }
                }
                
                // Caption texts
                if ( isset( $options['enable_caption'] ) && 'enable' == $options['enable_caption'] ) {
                    $caption = '';
                    if ( 'author_bank' == $options['caption_from'] ) {
                        $caption .= esc_html__( ' from ', 'all-sources-images' ) . ucfirst( $service );
                    }
                } else {
                    $caption = '';
                }
                if ( empty( $url_result ) ) {
                    continue;
                }
                // Avoid unknown image type
                if ( $service != 'stability' ) {
                    $url_result = $url_result;
                    $wp_filetype = wp_check_filetype( $url_result );
                    if ( false == $wp_filetype['type'] ) {
                        continue;
                    }
                }
                if ( TRUE == $get_only_thumb ) {
                    $url_result_ar['photos'][]['url'] = $url_result;
                } else {
                    if ( 'stability' == $service ) {
                        if ( base64_decode( $url_result, true ) !== false ) {
                            // Decoding the image in Base64
                            $image_data = base64_decode( $url_result );
                            $options_banks = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( TRUE ) );
                            // Specify a file path for the image in the download directory
                            $upload_dir = wp_upload_dir();
                            $file_path = $upload_dir['path'] . '/temp_mpt_stability_' . uniqid() . '.' . $options_banks['stability']['output_format'];
                            // Save the decoded image in the file
                            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Saving temporary image to uploads.
                            file_put_contents( $file_path, $image_data );
                            if ( file_exists( $file_path ) ) {
                                // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- Reading local temp file.
                                $file_content = file_get_contents( $file_path );
                            }
                            $file_media['response']['code'] = '200';
                            $file_media['body'] = $file_content;
                            $file_media['headers']['content-type'] = 'image/' . $options_banks['stability']['output_format'];
                            // Remove temporary file
                            wp_delete_file( $file_path );
                        }
                    } else {
                        $proxy_args = $this->ALLSI_get_proxy_args();
                        $file_media = @wp_remote_request( $url_result, $proxy_args );
                        if ( isset( $file_media->errors ) || $file_media['response']['code'] != 200 || strpos( $file_media['headers']['content-type'], 'text/html' ) !== false ) {
                            if ( ++$loop_count === $numUrl ) {
                                return false;
                            } else {
                                continue;
                            }
                        } else {
                            break;
                        }
                    }
                }
            }
            if ( TRUE == $get_only_thumb ) {
                return $url_result_ar;
            }
        } else {
            return false;
        }
        return array(
            $url_result,
            $file_media,
            $alt,
            $caption
        );
    }

    /**
     * Image results to get thumbnails
     *
     * @since    4.0.0
     */
    private function ALLSI_get_results( $service, $url, $url_parameters ) {
        if ( $service == 'stability' || $service == 'replicate' ) {
            $defaults = $url_parameters;
        } else {
            /* Retrieve 3 images as result */
            $url = add_query_arg( $url_parameters, $url );
            // Simulate Default Browser
            $defaults = array(
                'redirection'        => 9,
                'user-agent'         => 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96',
                'reject_unsafe_urls' => false,
                'sslverify'          => false,
            );
        }
        $proxy_args = $this->ALLSI_get_proxy_args();
        ALLSI_log( array(
            'service'     => $service,
            'url'         => $url,
            'has_proxy'   => ! empty( $proxy_args ),
            'proxy_mode'  => $this->ALLSI_current_proxy_mode(),
        ), 'HTTP_REQUEST' );

        $result = $this->ALLSI_remote_request( $service, $url, $defaults );
        
        $response_code = is_wp_error( $result ) ? 'ERROR' : wp_remote_retrieve_response_code( $result );
        $body_preview = '';
        if ( ! is_wp_error( $result ) && isset( $result['body'] ) ) {
            $body_preview = substr( $result['body'], 0, 1200 );
        }
        ALLSI_log( array(
            'response_code' => $response_code,
            'is_error' => is_wp_error( $result ),
            'error_message' => is_wp_error( $result ) ? $result->get_error_message() : '',
            'body_preview' => $body_preview,
        ), 'HTTP_RESPONSE' );
        // If error happen
        if ( !empty( $result->errors['http_request_failed'] ) ) {
            return false;
        }
        if ( $service == 'stability' ) {
            $code = intval( $result['response']['code'] );
            if ( 200 !== $code ) {
                return false;
            }
            $result_body = array(
                'image' => base64_encode( $result['body'] ),
            );
        } else {
            $result_body = json_decode( $result['body'], true );
            // accept 200 for most services, 201 for replicate
            $code = intval( $result['response']['code'] );
            if ( $service === 'replicate' && $code !== 201 || $service !== 'replicate' && $code !== 200 ) {
                return false;
            }
        }
        return array($result_body, $result);
    }

    /**
     * Remove gstatic images
     *
     * @since    4.0.0
     */
    public function ALLSI_order_array_urls( $str, $str_alt, $str_caption ) {
        // Get only the url and exclude Google image url (domain gstatic)
        $pattern = '/,\\["(http[^"]((?!gstatic).)*)",\\d+?,\\d+?\\]/';
        $replacement = '$1';
        // Check if $str is not null before using preg_replace
        $real_url = ( $str !== null ? preg_replace( $pattern, $replacement, $str ) : '' );
        return array(
            'url'     => $real_url,
            'alt'     => $str_alt,
            'caption' => $str_caption,
        );
    }

    /**
     * Function to get the depth of a category
     *
     * @since    5.2.11
     */
    private function get_category_depth( $cat_id, $current_depth = 0 ) {
        $category = get_category( $cat_id );
        if ( $category->parent == 0 ) {
            return $current_depth;
        } else {
            return $this->get_category_depth( $category->parent, $current_depth + 1 );
        }
    }

    /**
     * Function to get the desired category based on the user's choice
     *
     * @since    5.2.11
     */
    private function get_desired_category( $post_id, $category_choice ) {
        // Retrieve the categories of the post
        $postcategories = get_the_category( $post_id );
        $categories_with_depth = array();
        // Check if the post has any categories
        if ( empty( $postcategories ) ) {
            // Handle the case where no categories are associated
            return null;
        }
        // Get the depth of each category associated with the post
        foreach ( $postcategories as $category ) {
            $depth = $this->get_category_depth( $category->term_id );
            // Store the category with its depth as the key
            $categories_with_depth[$depth] = $category;
        }
        // Find the category with the greatest depth (most specific)
        $max_depth = max( array_keys( $categories_with_depth ) );
        $child_category = $categories_with_depth[$max_depth];
        // Determine the category to use based on the user's choice
        $desired_category = $child_category;
        if ( $category_choice && $child_category ) {
            if ( $category_choice == 'second_level' ) {
                if ( $child_category->parent ) {
                    $desired_category = get_category( $child_category->parent );
                }
            } elseif ( $category_choice == 'third_level' ) {
                if ( $child_category->parent ) {
                    $parent_category = get_category( $child_category->parent );
                    if ( $parent_category->parent ) {
                        $desired_category = get_category( $parent_category->parent );
                    } else {
                        $desired_category = $parent_category;
                    }
                }
            }
        }
        return $desired_category;
    }

    /**
     * Function to get the desired term based on the user's choice and a custom taxonomy
     *
     * @since    6.0.0
     */
    private function get_desired_taxonomy( $post_id, $taxonomy, $term_choice ) {
        // Retrieve the terms of the post in the specified taxonomy
        $post_terms = get_the_terms( $post_id, $taxonomy );
        $terms_with_depth = array();
        // Check if the post has any terms in the taxonomy
        if ( empty( $post_terms ) || is_wp_error( $post_terms ) ) {
            // Handle the case where no terms are associated or there's an error
            return null;
        }
        // Get the depth of each term associated with the post
        foreach ( $post_terms as $term ) {
            $depth = $this->get_term_depth( $term->term_id, $taxonomy );
            // Store the term with its depth as the key
            $terms_with_depth[$depth] = $term;
        }
        // Find the term with the greatest depth (most specific)
        $max_depth = max( array_keys( $terms_with_depth ) );
        $child_term = $terms_with_depth[$max_depth];
        // Determine the term to use based on the user's choice
        $desired_term = $child_term;
        if ( $term_choice && $child_term ) {
            if ( $term_choice == 'second_level' ) {
                if ( $child_term->parent ) {
                    $desired_term = get_term( $child_term->parent, $taxonomy );
                }
            } elseif ( $term_choice == 'third_level' ) {
                if ( $child_term->parent ) {
                    $parent_term = get_term( $child_term->parent, $taxonomy );
                    if ( $parent_term->parent ) {
                        $desired_term = get_term( $parent_term->parent, $taxonomy );
                    } else {
                        $desired_term = $parent_term;
                    }
                }
            }
        }
        return $desired_term;
    }

    /**
     * Helper function to get the depth of a term in a custom taxonomy.
     *
     * @since    6.0.0
     */
    private function get_term_depth( $term_id, $taxonomy ) {
        $depth = 0;
        $term = get_term( $term_id, $taxonomy );
        while ( $term && $term->parent ) {
            $term = get_term( $term->parent, $taxonomy );
            $depth++;
        }
        return $depth;
    }

    /**
     * Helper function to get the depth of a term in a custom taxonomy.
     *
     * @since    6.0.0
     */
    private function get_extracted_term( $text, $selected_lang = 'en' ) {
        require_once dirname( __FILE__ ) . '/../includes/php-ml/index.php';
        $extractor = new ALLSI_KeywordExtractor( $selected_lang );
        $keywords = $extractor->extractKeywords( $text );
        return $keywords[0];
    }

    /**
     * Calculate dimensions from aspect ratio for models that use width/height
     *
     * @since    6.0.0
     * @param string $aspect_ratio The aspect ratio (e.g., '16:9', '4:3')
     * @param int $max_resolution Maximum resolution for the model
     * @return array Array with 'width' and 'height' keys
     */
    private function calculate_dimensions_from_aspect_ratio( $aspect_ratio, $max_resolution = 2048 ) {
        // Seedream-4 specific dimensions as per official documentation
        $seedream_dimensions = array(
            '1:1'  => array(
                'width'  => 2048,
                'height' => 2048,
            ),
            '4:3'  => array(
                'width'  => 2304,
                'height' => 1728,
            ),
            '16:9' => array(
                'width'  => 2560,
                'height' => 1440,
            ),
            '3:2'  => array(
                'width'  => 2304,
                'height' => 1536,
            ),
            '9:16' => array(
                'width'  => 1440,
                'height' => 2560,
            ),
        );
        // Check if we have specific dimensions for this aspect ratio
        if ( isset( $seedream_dimensions[$aspect_ratio] ) ) {
            return $seedream_dimensions[$aspect_ratio];
        }
        // Fallback to calculated dimensions for other ratios
        $ratio_parts = explode( ':', $aspect_ratio );
        if ( count( $ratio_parts ) !== 2 ) {
            // Default to 16:9 if invalid format
            $ratio_parts = array(16, 9);
        }
        $ratio_width = (int) $ratio_parts[0];
        $ratio_height = (int) $ratio_parts[1];
        // Calculate base dimensions
        $base_width = $max_resolution;
        $base_height = round( $max_resolution * $ratio_height / $ratio_width );
        // Ensure we don't exceed max resolution
        if ( $base_height > $max_resolution ) {
            $base_height = $max_resolution;
            $base_width = round( $max_resolution * $ratio_width / $ratio_height );
        }
        // Round to even numbers for better compatibility
        $width = $base_width - $base_width % 2;
        $height = $base_height - $base_height % 2;
        return array(
            'width'  => $width,
            'height' => $height,
        );
    }

    /**
     * Translate text using Google Translate
     *
     * @since    6.2.0
     * @param    string    $text          Text to translate
     * @param    string    $source_lang   Source language code (default: auto)
     * @param    string    $target_lang   Target language code (default: en)
     * @return   string|false             Translated text or false on error
     */
    public function ALLSI_translate_text( $text, $source_lang = 'auto', $target_lang = 'en' ) {
        if ( empty( $text ) || $source_lang === $target_lang ) {
            return $text;
        }
        
        $log = $this->ALLSI_monolog_call();
        $options_banks = wp_parse_args( get_option( 'ALLSI_plugin_banks_settings' ), $this->ALLSI_default_options_banks_settings( TRUE ) );
        $api_key = ( !empty( $options_banks['google_translate']['apikey'] ) ? $options_banks['google_translate']['apikey'] : '' );
        
        // Use official Google Translate API if API key is provided
        if ( !empty( $api_key ) ) {
            $url = 'https://translation.googleapis.com/language/translate/v2';
            $params = array(
                'key'    => $api_key,
                'q'      => $text,
                'source' => $source_lang,
                'target' => $target_lang,
                'format' => 'text',
            );
            
            $response = $this->ALLSI_remote_post( 'google_translate', $url, array(
                'body'    => $params,
                'timeout' => 10,
            ) );
            
            if ( is_wp_error( $response ) ) {
                $log->error( 'Google Translate API error', array(
                    'error' => $response->get_error_message(),
                ) );
                return false;
            }
            
            $body = json_decode( wp_remote_retrieve_body( $response ), true );
            if ( isset( $body['data']['translations'][0]['translatedText'] ) ) {
                $translated = $body['data']['translations'][0]['translatedText'];
                $log->info( 'Text translated (API)', array(
                    'from' => $text,
                    'to'   => $translated,
                ) );
                return $translated;
            }
        }
        
        // Fallback to free Google Translate scraping method
        $url = 'https://translate.googleapis.com/translate_a/single';
        $params = array(
            'client' => 'gtx',
            'sl'     => $source_lang,
            'tl'     => $target_lang,
            'dt'     => 't',
            'q'      => $text,
        );
        
        $url = add_query_arg( $params, $url );
        $response = $this->ALLSI_remote_get( 'google_translate', $url, array(
            'timeout' => 10,
        ) );
        
        if ( is_wp_error( $response ) ) {
            $log->error( 'Google Translate scraping error', array(
                'error' => $response->get_error_message(),
            ) );
            return false;
        }
        
        $body = wp_remote_retrieve_body( $response );
        $result = json_decode( $body, true );
        
        if ( isset( $result[0][0][0] ) ) {
            $translated = $result[0][0][0];
            $log->info( 'Text translated (free)', array(
                'from' => $text,
                'to'   => $translated,
            ) );
            return $translated;
        }
        
        return false;
    }

    /**
     * Extract keywords using OpenAI GPT
     * 
     * @since 6.2.0
     * @param string $api_key OpenAI API key
     * @param string $title Post title
     * @param string $content Post content (optional)
     * @param string $num_keywords Number of keywords to extract ('1-2', '2', '3')
     * @return string|false Extracted keywords or false on failure
     */
    public function ALLSI_openai_extract_keywords( $api_key, $title, $content = '', $num_keywords = '2' ) {
        $log = $this->ALLSI_monolog_call();
        
        if ( empty( $api_key ) ) {
            return false;
        }
        
        // Determine keyword count
        $keyword_count = 2;
        if ( $num_keywords === '1-2' ) {
            $keyword_count = '1 or 2';
        } elseif ( $num_keywords === '3' ) {
            $keyword_count = 3;
        }
        
        $prompt = "Extract the {$keyword_count} most relevant keywords for image search from the following content. Return ONLY the keywords separated by spaces, nothing else. The keywords should be suitable for searching stock photos or generating AI images.\n\nTitle: {$title}";
        
        if ( ! empty( $content ) ) {
            $prompt .= "\n\nContent excerpt: {$content}";
        }
        
        $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', array(
            'timeout' => 30,
            'headers' => array(
                'Authorization' => 'Bearer ' . $api_key,
                'Content-Type'  => 'application/json',
            ),
            'body' => json_encode( array(
                'model'       => 'gpt-3.5-turbo',
                'messages'    => array(
                    array(
                        'role'    => 'system',
                        'content' => 'You are a keyword extraction assistant. Extract concise, relevant keywords for image search. Return only the keywords, nothing else.',
                    ),
                    array(
                        'role'    => 'user',
                        'content' => $prompt,
                    ),
                ),
                'max_tokens'  => 50,
                'temperature' => 0.3,
            ) ),
        ) );
        
        if ( is_wp_error( $response ) ) {
            $log->error( 'OpenAI keyword extraction error', array(
                'error' => $response->get_error_message(),
            ) );
            return false;
        }
        
        $body = wp_remote_retrieve_body( $response );
        $result = json_decode( $body, true );
        
        if ( isset( $result['choices'][0]['message']['content'] ) ) {
            $keywords = trim( $result['choices'][0]['message']['content'] );
            // Clean up any punctuation or formatting
            $keywords = preg_replace( '/[,;:\-\n]/', ' ', $keywords );
            $keywords = preg_replace( '/\s+/', ' ', $keywords );
            
            $log->info( 'OpenAI keywords extracted', array(
                'title'    => $title,
                'keywords' => $keywords,
            ) );
            
            return $keywords;
        }
        
        if ( isset( $result['error'] ) ) {
            $log->error( 'OpenAI API error', array(
                'error' => $result['error']['message'],
            ) );
        }
        
        return false;
    }

    /**
     * Generate optimized image prompt using OpenAI GPT
     * 
     * @since 6.2.0
     * @param string $api_key OpenAI API key
     * @param string $title Post title
     * @param string $content Post content (optional)
     * @param string $style Image style (photorealistic, illustration, etc.)
     * @param string $custom_instructions Additional user instructions
     * @return string|false Generated prompt or false on failure
     */
    public function ALLSI_openai_generate_image_prompt( $api_key, $title, $content = '', $style = 'photorealistic', $custom_instructions = '' ) {
        $log = $this->ALLSI_monolog_call();
        
        if ( empty( $api_key ) ) {
            return false;
        }
        
        // Style descriptions
        $style_descriptions = array(
            'photorealistic' => 'a highly realistic photograph',
            'illustration'   => 'a detailed illustration',
            'digital_art'    => 'digital art style',
            '3d_render'      => 'a 3D rendered image',
            'oil_painting'   => 'an oil painting style',
            'watercolor'     => 'a watercolor painting',
            'sketch'         => 'a pencil sketch or drawing',
            'minimalist'     => 'a minimalist design',
            'vintage'        => 'a vintage or retro style',
            'comic'          => 'a comic or cartoon style',
            'anime'          => 'anime or manga art style',
            'cinematic'      => 'a cinematic movie-like shot',
            'custom'         => 'a professional image',
        );
        
        $style_desc = isset( $style_descriptions[ $style ] ) ? $style_descriptions[ $style ] : $style_descriptions['photorealistic'];
        
        $system_prompt = "You are an expert at creating image generation prompts for AI tools like DALL-E, Stable Diffusion, and Midjourney. Create detailed, visually descriptive prompts that will generate beautiful, relevant images.";
        
        $user_prompt = "Create an optimized image generation prompt for the following blog post. The image should be {$style_desc}.\n\n";
        $user_prompt .= "Title: {$title}\n";
        
        if ( ! empty( $content ) ) {
            $user_prompt .= "Content summary: {$content}\n";
        }
        
        if ( ! empty( $custom_instructions ) ) {
            $user_prompt .= "Additional requirements: {$custom_instructions}\n";
        }
        
        $user_prompt .= "\nReturn ONLY the image prompt, no explanations. The prompt should be detailed but under 200 characters for best results.";
        
        $response = wp_remote_post( 'https://api.openai.com/v1/chat/completions', array(
            'timeout' => 30,
            'headers' => array(
                'Authorization' => 'Bearer ' . $api_key,
                'Content-Type'  => 'application/json',
            ),
            'body' => json_encode( array(
                'model'       => 'gpt-3.5-turbo',
                'messages'    => array(
                    array(
                        'role'    => 'system',
                        'content' => $system_prompt,
                    ),
                    array(
                        'role'    => 'user',
                        'content' => $user_prompt,
                    ),
                ),
                'max_tokens'  => 150,
                'temperature' => 0.7,
            ) ),
        ) );
        
        if ( is_wp_error( $response ) ) {
            $log->error( 'OpenAI image prompt generation error', array(
                'error' => $response->get_error_message(),
            ) );
            return false;
        }
        
        $body = wp_remote_retrieve_body( $response );
        $result = json_decode( $body, true );
        
        if ( isset( $result['choices'][0]['message']['content'] ) ) {
            $prompt = trim( $result['choices'][0]['message']['content'] );
            // Remove quotes if present
            $prompt = trim( $prompt, '"\'');
            
            $log->info( 'AI image prompt generated', array(
                'title'  => $title,
                'style'  => $style,
                'prompt' => $prompt,
            ) );
            
            return $prompt;
        }
        
        if ( isset( $result['error'] ) ) {
            $log->error( 'OpenAI API error', array(
                'error' => $result['error']['message'],
            ) );
        }
        
        return false;
    }

}
