<?php
/**
 * Class ImgSEO_API
 * Manages all interactions with the ImgSEO API for alt text generation
 */

// Impedisce l'accesso diretto
if (!defined('ABSPATH')) {
    exit;
}

// FIX: Add a check to avoid class redeclarations
if (!class_exists('ImgSEO_API')) {

class ImgSEO_API {
    /**
   /**
     * API Endpoint
     */
    const API_ENDPOINT = 'https://api.imgseo.net';
    
    /**
     * ImgSEO Token
     *
     * @var string
     */
    private $api_key;
    
    /**
     * Singleton instance
     */
    private static $instance = null;
    
    /**
     * Ottiene la chiave API corrente
     * 
     * @return string La chiave API
     */
    public function get_api_key() {
        return $this->api_key;
    }
    
    /**
     * Constructor
     *
     * @param string $api_key API Key (optional, otherwise taken from options)
     */
    private function __construct($api_key = null) {
        if ($api_key === null) {
            $this->api_key = get_option('imgseo_api_key', '');
        } else {
            $this->api_key = $api_key;
        }
    }
    
    /**
     * Get the singleton instance
     */
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Verifies if the API key is valid via AJAX
     */
    public function ajax_verify_api_key() {
        check_ajax_referer('imgseo_settings_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Insufficient permissions', 'imgseo-ai-alt-text-generator')]);
        }
        
        // Security: Rate limiting - max 5 attempts per 10 minutes per user
        $user_id = get_current_user_id();
        $rate_key = 'imgseo_api_verify_attempts_' . $user_id;
        $attempts = get_transient($rate_key) ?: 0;
        
        if ($attempts >= 5) {
            wp_send_json_error(['message' => __('Too many verification attempts. Please wait 10 minutes.', 'imgseo-ai-alt-text-generator')]);
        }
        
        set_transient($rate_key, $attempts + 1, 600); // 10 minutes
        
        $api_key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : '';
        
        if (empty($api_key)) {
            wp_send_json_error(['message' => __('ImgSEO Token not provided', 'imgseo-ai-alt-text-generator')]);
        }
        
        // Security: Validate API key format (basic validation)
        if (strlen($api_key) < 10 || strlen($api_key) > 100) {
            wp_send_json_error(['message' => __('Invalid ImgSEO Token format', 'imgseo-ai-alt-text-generator')]);
        }
        
        // Security: Check for malicious patterns
        if (preg_match('/[<>"\']/', $api_key)) {
            wp_send_json_error(['message' => __('Invalid ImgSEO Token format', 'imgseo-ai-alt-text-generator')]);
        }
        
        // Verify the API key - create a new instance with the specified API key
        $api = new self($api_key);  // We use self to maintain access to the private constructor within the class
        $account_details = $api->verify_api_key();
        
        if ($account_details !== false) {
            // Save the API key and account details
            update_option('imgseo_api_key', $api_key);
            update_option('imgseo_api_verified', true);
            
            wp_send_json_success([
                'message' => __('ImgSEO Token verified successfully!', 'imgseo-ai-alt-text-generator'),
                'plan' => $account_details['plan'],
                'credits' => $account_details['available']
            ]);
        } else {
            update_option('imgseo_api_verified', false);
            wp_send_json_error(['message' => __('Invalid ImgSEO Token', 'imgseo-ai-alt-text-generator')]);
        }
    }
    
    /**
     * Updates available credits via AJAX
     */
    public function ajax_refresh_credits() {
        check_ajax_referer('imgseo_settings_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Insufficient permissions', 'imgseo-ai-alt-text-generator')]);
        }
        
        // Usa l'endpoint /credits per controllare i crediti
        // senza consumarli
        $credits_check = wp_remote_get(
            self::API_ENDPOINT . '/credits',
            array(
                'headers' => array(
                    'Accept' => 'application/json',
                    'imgseo-token' => $this->api_key
                ),
                'timeout' => 15
            )
        );
        
        $credits = 0;
        $update_success = false;
        
        if (!is_wp_error($credits_check)) {
            $response_code = wp_remote_retrieve_response_code($credits_check);
            $response_body = json_decode(wp_remote_retrieve_body($credits_check), true);
            
            // Log safe response info without sensitive data
            
            if ($response_code === 200) {
                if (isset($response_body['credits_remaining'])) {
                    $credits = intval($response_body['credits_remaining']);
                    update_option('imgseo_credits', $credits);
                    update_option('imgseo_last_check', time());
                    $update_success = true;
                    

                    
                    // Check if credits are sufficient
                    if ($credits <= 0) {
                        set_transient('imgseo_insufficient_credits', true, 3600);
                    } else {
                        delete_transient('imgseo_insufficient_credits');
                    }
                }
            }
        }
        
        if ($update_success) {
            $last_check_time = human_time_diff(time(), time() + 1) . ' ' . __('ago', 'imgseo-ai-alt-text-generator');
            
            wp_send_json_success([
                'credits' => $credits,
                'last_check' => $last_check_time,
                'message' => __('Credits updated successfully!', 'imgseo-ai-alt-text-generator')
            ]);
        } else {
            // In caso di errore utilizziamo i crediti memorizzati
            $credits = get_option('imgseo_credits', 0);
            $last_check_time = human_time_diff(get_option('imgseo_last_check', time()), time()) . ' ' . __('ago', 'imgseo-ai-alt-text-generator');
            
            wp_send_json_success([
                'credits' => $credits,
                'last_check' => $last_check_time,
                'message' => __('Using saved credits information.', 'imgseo-ai-alt-text-generator')
            ]);
        }
    }
    
    /**
     * Handles API disconnection via AJAX
     */
    public function ajax_disconnect_api() {
        check_ajax_referer('imgseo_settings_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(['message' => __('Insufficient permissions', 'imgseo-ai-alt-text-generator')]);
        }
        
        // Remove API options
        delete_option('imgseo_api_key');
        delete_option('imgseo_api_verified');
        delete_option('imgseo_credits');
        delete_option('imgseo_plan');
        delete_option('imgseo_last_check');
        
        wp_send_json_success(['message' => __('API disconnected successfully', 'imgseo-ai-alt-text-generator')]);
    }
    
    /**
     * Verifies if the API key is valid
     *
     * @return bool|array False if invalid, or array with account details
     */
    public function verify_api_key() {
        $account_details = $this->get_account_details();
        return $account_details !== false ? $account_details : false;
    }
    
    /**
     * Gets account details, including available credits
     * Ottimizzato per ridurre le chiamate API ridondanti
     *
     * @return array|bool False in case of error, or array with account details
     */
    public function get_account_details() {
        if (empty($this->api_key)) {
            return false;
        }
        
        // Verifica se c'è una cache recente per evitare richieste multiple ravvicinate
        $cache_key = 'imgseo_account_details_' . md5($this->api_key);
        $cached_details = get_transient($cache_key);
        
        // Usa la cache se disponibile e fresca (5 minuti)
        if ($cached_details !== false) {
            return $cached_details;
        }
        
        // Usa l'endpoint /credits per verificare il token
        // e recuperare i crediti senza consumarli
        $credits_response = wp_remote_get(
             self::API_ENDPOINT . '/credits',
            array(
                'headers' => array(
                    'Accept' => 'application/json',
                    'imgseo-token' => $this->api_key
                ),
                'timeout' => 15
            )
        );
        
        // Prepara i dettagli dell'account
        $account_details = array();
        $account_details['plan'] = "ImgSEO Plan"; // Valore di default
        $account_details['expires_at'] = 'never';
        
        // Verifica errori di connessione
        if (is_wp_error($credits_response)) {

            
            // Usa i valori memorizzati come fallback
            $account_details['available'] = get_option('imgseo_credits', 0);
            return $account_details;
        }
        
        $response_code = wp_remote_retrieve_response_code($credits_response);
        
        // Verifica di validità token
        if ($response_code === 401) {

            return false;
        }
        
        // Verifica del successo della richiesta
        if ($response_code !== 200) {

            
            // Usa i valori memorizzati come fallback
            $account_details['available'] = get_option('imgseo_credits', 0);
            return $account_details;
        }
        
        // Elabora la risposta
        $credits_body = json_decode(wp_remote_retrieve_body($credits_response), true);
        
        if (isset($credits_body['credits_remaining'])) {
            $account_details['available'] = intval($credits_body['credits_remaining']);

            
            // Aggiorna anche user_id e status se disponibili
            if (isset($credits_body['user_id'])) {
                $account_details['user_id'] = $credits_body['user_id'];
            }
            if (isset($credits_body['status'])) {
                $account_details['status'] = $credits_body['status'];
            }
        } else {
            // Se l'endpoint non restituisce i crediti, utilizza quelli memorizzati
            $account_details['available'] = get_option('imgseo_credits', 0);

        }
        
        // Store credits in WordPress options
        update_option('imgseo_credits', $account_details['available']);
        update_option('imgseo_plan', $account_details['plan']);
        update_option('imgseo_last_check', time());
        
        // Check if credits are sufficient
        if ($account_details['available'] <= 0) {
            set_transient('imgseo_insufficient_credits', true, 3600);
        } else {
            delete_transient('imgseo_insufficient_credits');
        }
        
        // Salva la cache per 5 minuti per evitare troppe chiamate ripetute
        set_transient($cache_key, $account_details, 5 * MINUTE_IN_SECONDS);
        
        return $account_details;
    }
    
    /**
     * Verifica i crediti disponibili senza consumarli
     *
     * @return array|WP_Error Risposta con i crediti disponibili o errore
     */
    public function verify_credits_only() {
        if (empty($this->api_key)) {
            return new WP_Error('no_api_key', 'API key not configured');
        }

        $response = wp_remote_get(
            self::API_ENDPOINT . '/credits',
            array(
                'headers' => array(
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json',
                    'imgseo-token' => $this->api_key
                ),
                'timeout' => 15
            )
        );

        if (is_wp_error($response)) {
            return $response;
        }

        $response_code = wp_remote_retrieve_response_code($response);
        $response_body = wp_remote_retrieve_body($response);
        $decoded_response = json_decode($response_body, true);

        if ($response_code === 200 && isset($decoded_response['credits_remaining'])) {
            return array(
                'success' => true,
                'credits_remaining' => intval($decoded_response['credits_remaining']),
                'can_process' => intval($decoded_response['credits_remaining']) > 0
            );
        }

        return new WP_Error('verification_failed', 'Failed to verify credits: ' . $response_body);
    }

    /**
     * Consuma un credito dopo il successo dell'elaborazione
     *
     * @param string $image_url URL dell'immagine
     * @param string $image_name Nome dell'immagine
     * @param string $alt_text Testo alternativo generato
     * @param float $credit_cost Costo in crediti (default 1.0)
     * @return array|WP_Error Risposta dell'API o errore
     */
    public function consume_credit($image_url = '', $image_name = '', $alt_text = '', $credit_cost = 1.0) {
        if (empty($this->api_key)) {
            return new WP_Error('no_api_key', 'API key not configured');
        }

        $response = wp_remote_post(
            self::API_ENDPOINT . '/api-v1-images',
            array(
                'headers' => array(
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json',
                    'imgseo-token' => $this->api_key
                ),
                'body' => json_encode(array(
                    'image_url' => $image_url,
                    'image_name' => $image_name
                )),
                'timeout' => 15
            )
        );

        if (is_wp_error($response)) {
            return $response;
        }

        $response_code = wp_remote_retrieve_response_code($response);
        $response_body = wp_remote_retrieve_body($response);
        $decoded_response = json_decode($response_body, true);

        if ($response_code === 200) {
            // Aggiorna i crediti locali se forniti
            if (isset($decoded_response['credits_remaining'])) {
                update_option('imgseo_credits', intval($decoded_response['credits_remaining']));
            }
            return array(
                'success' => true,
                'credits_remaining' => isset($decoded_response['credits_remaining']) ? intval($decoded_response['credits_remaining']) : null
            );
        }

        return new WP_Error('consumption_failed', 'Failed to consume credit: ' . $response_body);
    }

    /**
     * Genera il testo alternativo per un'immagine
     *
     * @param string $image_url URL dell'immagine
     * @param string $prompt Prompt per la generazione
     * @param array $options Opzioni aggiuntive
     * @return array|WP_Error Risposta dell'API o errore
     */
    public function generate_alt_text_no_credit_consumption($image_url, $prompt = '', $options = array()) {
        if (empty($this->api_key)) {
            return new WP_Error('no_api_key', 'API key not configured');
        }

        $attachment_id = isset($options['attachment_id']) ? absint($options['attachment_id']) : 0;
        $parent_post_title = isset($options['parent_post_title']) ? sanitize_text_field($options['parent_post_title']) : '';
        $language = isset($options['language']) ? sanitize_text_field($options['language']) : 'it';

        // Prepara il corpo della richiesta secondo la nuova API
        $body = array(
            'image_url' => $image_url,
            'prompt' => $prompt,
            'lang' => $language,
            'model' => isset($options['model']) ? $options['model'] : 'google/gemini-2.0-flash-001',
            'optimize' => isset($options['optimize']) ? (bool)$options['optimize'] : true
        );
        
        // Aggiungi image_name se disponibile
        if (isset($options['image_name']) && !empty($options['image_name'])) {
            $body['image_name'] = sanitize_file_name($options['image_name']);
        } elseif ($attachment_id > 0) {
            // Prova a ottenere il nome del file dall'attachment
            $filename = get_post_meta($attachment_id, '_wp_attached_file', true);
            if ($filename) {
                $body['image_name'] = sanitize_file_name(basename($filename));
            }
        }

        // parent_post_title non è supportato nell'API v1
        // Il titolo della pagina può essere incluso nel prompt se necessario



        // Esegui la richiesta API
        $response = wp_remote_post(
            self::API_ENDPOINT . '/api-v1-images',
            array(
                'headers' => array(
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json',
                    'imgseo-token' => $this->api_key
                ),
                'body' => wp_json_encode($body),
                'timeout' => 30
            )
        );

        if (is_wp_error($response)) {

            return $response;
        }

        $response_code = wp_remote_retrieve_response_code($response);
        $response_body = wp_remote_retrieve_body($response);

        if ($response_code !== 200 && $response_code !== 201) {

            return new WP_Error('api_error', 'API request failed with code: ' . $response_code);
        }

        $decoded_response = json_decode($response_body, true);

        if (!$decoded_response || !isset($decoded_response['data']) || !isset($decoded_response['data']['altText'])) {

            return new WP_Error('invalid_response', 'Invalid API response format');
        }

        $alt_text = trim($decoded_response['data']['altText']);

        if (empty($alt_text)) {

            return new WP_Error('empty_alt_text', 'Empty alt text received from API');
        }



        // Prepara la risposta con i crediti rimanenti se disponibili
        $response_data = array(
            'success' => true,
            'alt_text' => $alt_text,
            'credits_consumed' => true // I crediti sono stati consumati da questa chiamata API
        );
        
        // Aggiungi i crediti rimanenti se forniti dall'API
        if (isset($decoded_response['credits_remaining'])) {
            $response_data['credits_remaining'] = intval($decoded_response['credits_remaining']);
        }
        
        return $response_data;
    }

    /**
     * Generate alt text for an image using the ImgSEO API
     * Versione migliorata con protezione contro chiamate multiple
     *
     * @param string $image_url The image URL
     * @param string $prompt The prompt for text generation
     * @param array $options Additional options for the API request
     * @return array|WP_Error API response or WP_Error in case of error
     */
    public function generate_alt_text($image_url, $prompt, $options = array()) {
       $attachment_id = isset($options['attachment_id']) ? absint($options['attachment_id']) : 0;
       
       // Genera un ID univoco basato su URL e attachment ID
       $request_key = md5($image_url . '_' . $attachment_id);
       
       // Sistema di lock migliorato per evitare elaborazioni duplicate
       if ($attachment_id > 0) {
           $lock_key = 'imgseo_processing_' . $attachment_id;
           $request_id = uniqid('req_', true); // ID univoco per questa richiesta
           
           // Verifica se esiste un lock recente (ultimi 5 secondi per migliori performance)
           $processing_lock = get_transient($lock_key);
           
           if ($processing_lock) {
               $lock_data = is_array($processing_lock) ? $processing_lock : array('time' => (int)$processing_lock, 'request_id' => 'unknown');
               $lock_time = isset($lock_data['time']) ? (int)$lock_data['time'] : 0;
               $lock_request_id = isset($lock_data['request_id']) ? $lock_data['request_id'] : 'unknown';
               $time_diff = time() - $lock_time;
               
               // Se il lock è recente (meno di 5 secondi), verifica se abbiamo un risultato cached
               if ($time_diff < 5) {
                   $last_result = get_transient('imgseo_last_result_' . $attachment_id);
                   
                   // Se abbiamo un risultato recente, lo restituiamo
                   if ($last_result) {

                       return $last_result;
                   }
                   
                   // Se non abbiamo un risultato cached, aspettiamo un po' e ritorniamo un errore temporaneo

                   return new WP_Error('processing_in_progress', 'Elaborazione già in corso per questa immagine. Riprova tra qualche secondo.');
               }
               
               // Lock scaduto, lo rimuoviamo

               delete_transient($lock_key);
           }
           
           // Imposta un nuovo lock con timestamp e request ID (durata 5 secondi)
           $lock_data = array(
               'time' => time(),
               'request_id' => $request_id
           );
           set_transient($lock_key, $lock_data, 15); // Ridotto a 15 secondi per migliori performance

       }
       
       if (empty($this->api_key)) {
           if ($attachment_id > 0) {
               delete_transient('imgseo_processing_' . $attachment_id);
           }
           return new WP_Error('api_key_missing', 'ImgSEO Token not provided');
       }
       
       // Funzione per il cleanup dei transient in caso di errore
       $cleanup = function() use ($attachment_id) {
           if ($attachment_id > 0) {
               // Rilascia tutti i lock e cache
               delete_transient('imgseo_processing_' . $attachment_id);
               delete_transient('imgseo_global_processing_' . $attachment_id);
               delete_transient('imgseo_last_result_' . $attachment_id);

           }
       };
       
       // Controllo dei crediti: blocchiamo definitivamente se crediti insufficienti
       $credits_exhausted = get_transient('imgseo_insufficient_credits');
       $credits = get_option('imgseo_credits', 0);
       
       // Controllo più rigoroso: se siamo a zero o sotto, o se abbiamo già impostato il flag
       if ($credits_exhausted || $credits < 1) {
           // Aggiorniamo il flag se non è già impostato
           if (!$credits_exhausted) {
               set_transient('imgseo_insufficient_credits', true, 3600); // 1 ora
           }
           // Debug: Operation blocked - insufficient credits
           $cleanup();
           return new WP_Error('insufficient_credits', 'Crediti ImgSEO insufficienti. Acquista altri crediti per continuare.');
       }
       
       // Log informativo sui crediti disponibili
       // Debug: Available credits before operation
       
       try {
           // Check if we should always use the base64 method (bypass hotlinking protections and Cloudflare)
           $always_use_base64 = get_option('imgseo_always_use_base64', 0);
           
           // If always_use_base64 is enabled, skip the URL method and go straight to base64
           if ($always_use_base64) {
               error_log('ImgSEO API: Using base64 method directly as per settings (imgseo_always_use_base64 enabled)');
               return $this->generate_alt_text_with_base64($image_url, $prompt, $options);
           }
           
           // Check if the site is offline or online
           $is_offline = $this->is_site_offline();
           
           // Set request parameters according to new API format
           $body = array(
               'image_url' => $image_url,
               'prompt' => $prompt,
               'lang' => isset($options['lang']) ? sanitize_text_field($options['lang']) : 'it',
               'model' => isset($options['model']) ? sanitize_text_field($options['model']) : 'google/gemini-2.0-flash-001',
               'optimize' => isset($options['optimize']) ? (bool)$options['optimize'] : true
           );
           
           // Aggiungi image_name se disponibile
           if (isset($options['image_name']) && !empty($options['image_name'])) {
               $body['image_name'] = sanitize_file_name($options['image_name']);
           } elseif ($attachment_id > 0) {
               // Prova a ottenere il nome del file dall'attachment
               $filename = get_post_meta($attachment_id, '_wp_attached_file', true);
               if ($filename) {
                   $body['image_name'] = sanitize_file_name(basename($filename));
               }
           }
       
           // If the site is offline, use file content instead of URL
           if ($is_offline) {
               try {
                   // Get file path from WordPress upload system
                   $upload_dir = wp_upload_dir();
                   $file_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $image_url);
                   
                   // Check if file exists
                   if (!file_exists($file_path)) {
                       $cleanup();
                       return new WP_Error('file_not_found', 'Image file not found');
                   }
                   
                   // Per il momento, se il sito è offline, non possiamo processare 
                   // l'immagine direttamente poiché la nuova API non supporta
                   // l'invio diretto di file in base64
                   $cleanup();
                   return new WP_Error('offline_site', 'La nuova API richiede che le immagini siano accessibili tramite URL pubblici. Il sito appare essere offline.');
               } catch (Exception $e) {
                   $cleanup();
                   return new WP_Error('file_processing_error', "Error processing the file: " . $e->getMessage());
               }
           }
        
           error_log('ImgSEO API: Sending request to generate alt text for attachment ID: ' . $attachment_id);
           
           // Execute API request with new format
           $response = wp_remote_post(
               self::API_ENDPOINT . '/api-v1-images',
               array(
                   'headers' => array(
                       'Content-Type' => 'application/json',
                       'Accept' => 'application/json',
                       'imgseo-token' => $this->api_key
                   ),
                   'body' => wp_json_encode($body),
                   'timeout' => 30
               )
           );
           
           // Check for connection errors
           if (is_wp_error($response)) {
               $error_message = $response->get_error_message();
               error_log('ImgSEO API: Connection error - ' . $error_message);
               $cleanup();
               return $response;
           }
           
           // Check response code
           $response_code = wp_remote_retrieve_response_code($response);
           if ($response_code !== 200 && $response_code !== 201) {
               // Ottieni il corpo della risposta per analizzarlo
               $response_body_text = wp_remote_retrieve_body($response);
               error_log('ImgSEO API: Risposta non-200 ricevuta. Codice: ' . $response_code . ', Corpo: ' . $response_body_text);
               $response_body_json = json_decode($response_body_text, true);
               
               // Verifica se è un errore che può beneficiare del fallback con base64
               $should_try_fallback = false;
               
               // Errore 403 (protezione hotlinking)
               if ($response_code === 403) {
                   error_log('ImgSEO API: Rilevata protezione hotlinking (403 Forbidden). Tentativo di fallback al metodo base64.');
                   $should_try_fallback = true;
               }
               // Errore 5xx (problemi lato server)
               elseif ($response_code >= 500) {
                   error_log('ImgSEO API: Rilevato errore server ' . $response_code . '. Tentativo di fallback al metodo base64.');
                   $should_try_fallback = true;
               }
               // Errore 400 - analizza il contenuto per determinare la causa
               elseif ($response_code === 400 && $response_body_json) {
                   // Verifica per errori di immagine non trovata o non accessibile
                   $error_message = isset($response_body_json['error']) ? strtolower($response_body_json['error']) : '';
                   $error_details = isset($response_body_json['details']) ? strtolower($response_body_json['details']) : '';
                   
                   // Controlla se è un errore di immagine non trovata
                   if (
                       strpos($error_message, 'image not found') !== false ||
                       strpos($error_message, 'file not found') !== false ||
                       strpos($error_message, 'not found') !== false ||
                       strpos($error_message, '404') !== false ||
                       strpos($error_details, 'image not found') !== false ||
                       strpos($error_details, 'file not found') !== false ||
                       strpos($error_details, 'not found') !== false ||
                       strpos($error_details, '404') !== false
                   ) {
                       error_log('ImgSEO API: Rilevato errore 400 - immagine non trovata o non accessibile: ' . $response_body_text);
                       $cleanup();
                       return new WP_Error('image_not_found', 'Immagine non trovata o non accessibile: ' . (isset($response_body_json['error']) ? $response_body_json['error'] : 'Errore sconosciuto'));
                   }
                   
                   // Verifica per errore Cloudflare 520 o altri errori server nel corpo JSON
                   if (
                       (isset($response_body_json['status_code']) && ($response_body_json['status_code'] >= 500 || $response_body_json['status_code'] == 520)) ||
                       (isset($response_body_json['error']) && strpos(strtolower($response_body_json['error']), 'server error') !== false)
                   ) {
                       $status_code = isset($response_body_json['status_code']) ? $response_body_json['status_code'] : 'sconosciuto';
                       error_log('ImgSEO API: Rilevato errore server (codice ' . $status_code . ') all\'interno di risposta 400. Tentativo di fallback al metodo base64.');
                       $should_try_fallback = true;
                   }
               }
               // Altri errori server inclusi nel corpo della risposta
               elseif ($response_body_json && (
                   (isset($response_body_json['status_code']) && ($response_body_json['status_code'] >= 500 || $response_body_json['status_code'] == 520)) ||
                   (isset($response_body_json['error']) && strpos(strtolower($response_body_json['error']), 'server error') !== false)
               )) {
                   error_log('ImgSEO API: Rilevato errore server nel corpo della risposta (codice ' .
                       (isset($response_body_json['status_code']) ? $response_body_json['status_code'] : 'sconosciuto') .
                       '). Tentativo di fallback al metodo base64.');
                   $should_try_fallback = true;
               }
               
               // Se abbiamo identificato un caso in cui il fallback è appropriato, proviamo
               if ($should_try_fallback) {
                   // Tentativo di fallback con base64
                   $base64_result = $this->generate_alt_text_with_base64($image_url, $prompt, $options);
                   
                   // Se il fallback ha avuto successo, restituisci il risultato
                   if (!is_wp_error($base64_result)) {
                       $cleanup();
                       return $base64_result;
                   }
                   
                   // Se anche il fallback fallisce, log dell'errore specifico
                   error_log('ImgSEO API: Anche il fallback base64 è fallito: ' . $base64_result->get_error_message());
               }
               
               // Gestione degli errori originale per altri codici di errore
               $error_message = wp_remote_retrieve_body($response);
               error_log('ImgSEO API: Invalid response - Code ' . $response_code . ' - ' . $error_message);
               $cleanup();
               return new WP_Error('api_error', 'API Error (' . $response_code . '): ' . $error_message);
           }
           
           // Decode response
           $response_body = json_decode(wp_remote_retrieve_body($response), true);
           
           // Verifica che la risposta contenga l'alt text nella nuova struttura
           if (!isset($response_body['data']) || !isset($response_body['data']['altText'])) {
               error_log('ImgSEO API: Missing data.altText in response');
               $cleanup();
               return new WP_Error('invalid_response', 'Risposta API non valida: manca data.altText');
           }
           
           // Estrai l'alt text dalla nuova struttura
           $alt_text = $response_body['data']['altText'];
           
           // Estrai i crediti residui se disponibili
           $remaining_credits = isset($response_body['credits_remaining']) 
               ? intval($response_body['credits_remaining']) 
               : null;
           
           // Aggiorna i crediti se disponibili nella risposta
           if ($remaining_credits !== null) {
               update_option('imgseo_credits', $remaining_credits);
               
               // If credits are exhausted, set a warning
               if ($remaining_credits <= 0) {
                   set_transient('imgseo_insufficient_credits', true, 3600);
               } else {
                   delete_transient('imgseo_insufficient_credits');
               }
           } else {
               // Se non riceviamo i crediti, diminuiamo manualmente di 1
               $credits = get_option('imgseo_credits', 0);
               update_option('imgseo_credits', max(0, $credits - 1));
               
               if ($credits - 1 <= 0) {
                   set_transient('imgseo_insufficient_credits', true, 3600);
               }
           }
           
           // Prepara la risposta nel formato compatibile con il resto del plugin
           $result = array(
               'alt_text' => $alt_text,
               'credits_remaining' => $remaining_credits,
               'model' => isset($response_body['model']) ? $response_body['model'] : null,
               'image_optimized' => isset($response_body['image_optimized']) ? $response_body['image_optimized'] : null,
               'file_name' => isset($response_body['file_name']) ? $response_body['file_name'] : null,
               'processing_method' => isset($response_body['processing_method']) ? $response_body['processing_method'] : null
           );
           
           // Cache il risultato per un breve periodo (30 secondi)
           // così possiamo restituirlo in caso di richieste duplicate
           if ($attachment_id > 0) {
               set_transient('imgseo_last_result_' . $attachment_id, $result, 30);
           }
           
           error_log('ImgSEO API: Alt text generated successfully for attachment ID: ' . $attachment_id);
           
           // Release the lock
           $cleanup();
           
           return $result;
       } catch (Exception $e) {
           error_log('ImgSEO API: Exception during alt text generation: ' . $e->getMessage());
           $cleanup(); // Assicurati che il lock venga rimosso anche in caso di eccezione
           throw $e; // Rilancia l'eccezione per gestione errori superiore
       }
    }
    
   /**
    * Genera alt text utilizzando il metodo base64 con thumbnail ottimizzate
    *
    * @param string $image_url URL dell'immagine originale
    * @param string $prompt Il prompt per la generazione
    * @param array $options Opzioni aggiuntive
    * @return array|WP_Error Risposta API o errore
    */
   private function generate_alt_text_with_base64($image_url, $prompt, $options = array()) {
       $attachment_id = isset($options['attachment_id']) ? absint($options['attachment_id']) : 0;
       
       try {
           // Se abbiamo un ID allegato valido, utilizziamo le thumbnail di WordPress
           if ($attachment_id > 0) {
               // Tenta di ottenere la migliore thumbnail disponibile
               list($thumbnail_url, $thumbnail_path) = $this->get_best_thumbnail($attachment_id);
               
               if ($thumbnail_path && file_exists($thumbnail_path)) {
                   error_log('ImgSEO API: Utilizzo thumbnail per base64: ' . basename($thumbnail_path));
                   $image_path = $thumbnail_path;
               } else {
                   // Fallback all'immagine originale
                   $image_path = $this->get_local_path_from_url($image_url);
                   error_log('ImgSEO API: Thumbnail non disponibile, utilizzo immagine originale per base64');
               }
           } else {
               // Senza ID allegato, utilizziamo l'URL originale
               $image_path = $this->get_local_path_from_url($image_url);
           }
           
           // Verifica che il file esista
           if (!file_exists($image_path)) {
               return new WP_Error('file_not_found', 'Unable to find local image file for base64 fallback');
           }
           
           // Verifica che il formato dell'immagine sia supportato
           $mime_type = mime_content_type($image_path);
           $supported_formats = array(
               'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'
           );
           
           if (!in_array($mime_type, $supported_formats)) {
               if ($mime_type === 'image/svg+xml') {
                   error_log('ImgSEO API: File SVG non supportato dall\'API: ' . $image_path);
                   return new WP_Error('unsupported_format', 'SVG files are not supported by the ImgSEO API. Consider converting them to PNG format.');
               } else {
                   error_log('ImgSEO API: Formato immagine non supportato: ' . $mime_type . ' - Path: ' . $image_path);
                   return new WP_Error('unsupported_format', 'Unsupported image format: ' . $mime_type);
               }
           }
           
           // Verifica la dimensione del file
           $file_size = filesize($image_path);
           $max_size_warning = 1 * 1024 * 1024; // 1MB come soglia di avviso
           
           if ($file_size > $max_size_warning) {
               error_log('ImgSEO API: ATTENZIONE - Immagine grande (' . round($file_size / 1024, 2) . ' KB) - Path: ' . basename($image_path));
           } else {
               error_log('ImgSEO API: Dimensione immagine accettabile: ' . round($file_size / 1024, 2) . ' KB - Path: ' . basename($image_path));
           }
           
           // Converti l'immagine in base64
           $base64_data = $this->get_image_as_base64($image_path);
           if (empty($base64_data)) {
               return new WP_Error('base64_conversion_failed', 'Error converting the image to base64');
           }
           
           // Prepara i dati per l'API con base64 invece dell'URL
           $body = array(
               'image_data' => $base64_data,
               'prompt' => $prompt,
               'lang' => isset($options['lang']) ? sanitize_text_field($options['lang']) : 'it',
               'model' => isset($options['model']) ? sanitize_text_field($options['model']) : 'google/gemini-2.0-flash-001',
               'optimize' => isset($options['optimize']) ? (bool)$options['optimize'] : true
           );
           
           // Aggiungi image_name se disponibile
           if (isset($options['image_name']) && !empty($options['image_name'])) {
               $body['image_name'] = sanitize_file_name($options['image_name']);
           } elseif ($attachment_id > 0) {
               // Prova a ottenere il nome del file dall'attachment
               $filename = get_post_meta($attachment_id, '_wp_attached_file', true);
               if ($filename) {
                   $body['image_name'] = sanitize_file_name(basename($filename));
               }
           }
           
           error_log('ImgSEO API: Invio immagine con metodo base64 per attachment ID: ' . $attachment_id);
           
           // Esegui la richiesta API con gli stessi endpoint ma dati diversi
           $response = wp_remote_post(
               self::API_ENDPOINT . '/api-v1-images',  // Endpoint unificato per tutte le operazioni
               array(
                   'headers' => array(
                       'Content-Type' => 'application/json',
                       'Accept' => 'application/json',
                       'imgseo-token' => $this->api_key
                   ),
                   'body' => wp_json_encode($body),
                   'timeout' => 45  // Timeout più lungo per le richieste base64
               )
           );
           
           // Check for connection errors
           if (is_wp_error($response)) {
               $error_message = $response->get_error_message();
               error_log('ImgSEO API (base64): Connection error - ' . $error_message);
               return $response;
           }
           
           // Check response code
           $response_code = wp_remote_retrieve_response_code($response);
           if ($response_code !== 200 && $response_code !== 201) {
               $error_message = wp_remote_retrieve_body($response);
               error_log('ImgSEO API (base64): Invalid response - Code ' . $response_code . ' - ' . $error_message);
               
               // Log più dettagliato in base al tipo di errore
               $error_type = 'api_error';
               $error_message_user = 'API Error (' . $response_code . '): ' . $error_message;
               
               // Gestione specifica errore 413 (Payload Too Large)
               if ($response_code === 413) {
                   error_log('ImgSEO API (base64): Immagine troppo grande per API - Dimensione: ' . round(filesize($image_path) / 1024, 2) . ' KB - Path: ' . basename($image_path));
                   $error_type = 'image_too_large';
                   $error_message_user = 'Image too large for the API (max ~10MB). Try optimizing the image.';
               }
               // Log per errori di formato immagine
               else if ($response_json = json_decode($error_message, true)) {
                   if (isset($response_json['error']) &&
                       (strpos($response_json['error'], 'Invalid image data') !== false ||
                       strpos($response_json['details'], 'unsupported image format') !== false)) {
                       
                       error_log('ImgSEO API (base64): Formato immagine non supportato - MIME: ' . mime_content_type($image_path) .
                               ' - Dimensione: ' . round(filesize($image_path) / 1024, 2) . ' KB' .
                               ' - Path: ' . $image_path);
                   }
               }
               
               return new WP_Error($error_type, $error_message_user);
           }
           
           // Decode response
           $response_body = json_decode(wp_remote_retrieve_body($response), true);
           
           // Verifica che la risposta contenga l'alt text nella nuova struttura
           if (!isset($response_body['data']) || !isset($response_body['data']['altText'])) {
               error_log('ImgSEO API (base64): Missing data.altText in response');
               return new WP_Error('invalid_response', 'Invalid API response: data.altText is missing');
           }
           
           // Estrai l'alt text dalla nuova struttura
           $alt_text = $response_body['data']['altText'];
           
           // Estrai i crediti residui se disponibili
           $remaining_credits = isset($response_body['credits_remaining'])
               ? intval($response_body['credits_remaining'])
               : null;
           
           // Aggiorna i crediti se disponibili nella risposta
           if ($remaining_credits !== null) {
               update_option('imgseo_credits', $remaining_credits);
               
               // If credits are exhausted, set a warning
               if ($remaining_credits <= 0) {
                   set_transient('imgseo_insufficient_credits', true, 3600);
               } else {
                   delete_transient('imgseo_insufficient_credits');
               }
           } else {
               // Se non riceviamo i crediti, diminuiamo manualmente di 1
               $credits = get_option('imgseo_credits', 0);
               update_option('imgseo_credits', max(0, $credits - 1));
               
               if ($credits - 1 <= 0) {
                   set_transient('imgseo_insufficient_credits', true, 3600);
               }
           }
           
           // Prepara la risposta nel formato compatibile con il resto del plugin
           $result = array(
               'alt_text' => $alt_text,
               'credits_remaining' => $remaining_credits,
               'model' => isset($response_body['model']) ? $response_body['model'] : null,
               'image_optimized' => isset($response_body['image_optimized']) ? $response_body['image_optimized'] : null,
               'file_name' => isset($response_body['file_name']) ? $response_body['file_name'] : null,
               'processing_method' => isset($response_body['processing_method']) ? $response_body['processing_method'] : 'base64'
           );
           
           error_log('ImgSEO API: Alt text generato con successo tramite base64 per attachment ID: ' . $attachment_id);
           
           return $result;
           
       } catch (Exception $e) {
           error_log('ImgSEO API: Eccezione durante il fallback base64: ' . $e->getMessage());
           return new WP_Error('base64_fallback_error', 'Error during base64 fallback: ' . $e->getMessage());
       }
   }
   
   /**
    * Trova la migliore thumbnail disponibile per un allegato
    *
    * @param int $attachment_id ID dell'allegato
    * @return array Array con [url_thumbnail, percorso_file_locale]
    */
   private function get_best_thumbnail($attachment_id) {
       // Dimensione massima accettabile per l'API (in byte)
       $max_acceptable_size = 10 * 1024 * 1024; // 10MB come limite
       
       // Array delle dimensioni thumbnail in ordine di preferenza
       $sizes = array('large', 'medium_large', 'medium', 'thumbnail');
       
       // Verifica se l'originale è sotto il limite
       $original_path = get_attached_file($attachment_id);
       $original_url = wp_get_attachment_url($attachment_id);
       
       if (file_exists($original_path) && filesize($original_path) <= $max_acceptable_size) {
           error_log('ImgSEO API: Usando immagine originale, dimensione accettabile: ' . round(filesize($original_path) / 1024, 2) . ' KB');
           return array($original_url, $original_path);
       }
       
       // Se l'originale è troppo grande, cerca una thumbnail adatta
       foreach ($sizes as $size) {
           // Ottieni l'URL della thumbnail
           $thumb = wp_get_attachment_image_src($attachment_id, $size);
           if ($thumb) {
               $thumb_url = $thumb[0];
               
               // Converti URL in percorso locale
               $upload_dir = wp_upload_dir();
               $thumb_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $thumb_url);
               
               // Verifica che il file esista e sia sotto il limite di dimensione
               if (file_exists($thumb_path)) {
                   $file_size = filesize($thumb_path);
                   if ($file_size <= $max_acceptable_size) {
                       error_log('ImgSEO API: Usando thumbnail ' . $size . ', dimensione: ' . round($file_size / 1024, 2) . ' KB');
                       return array($thumb_url, $thumb_path);
                   } else {
                       error_log('ImgSEO API: Thumbnail ' . $size . ' troppo grande (' . round($file_size / 1024, 2) . ' KB), provo la successiva');
                   }
               }
           }
       }
       
       // Se arriviamo qui, tutte le thumbnail sono troppo grandi o non disponibili
       // Restituisci la thumbnail più piccola disponibile come ultimo tentativo
       foreach (array_reverse($sizes) as $size) {
           $thumb = wp_get_attachment_image_src($attachment_id, $size);
           if ($thumb) {
               $thumb_url = $thumb[0];
               $upload_dir = wp_upload_dir();
               $thumb_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $thumb_url);
               
               if (file_exists($thumb_path)) {
                   error_log('ImgSEO API: Tutte le immagini sono oltre il limite di dimensione. Usando ' . $size . ' come ultima risorsa: ' .
                             round(filesize($thumb_path) / 1024, 2) . ' KB');
                   return array($thumb_url, $thumb_path);
               }
           }
       }
       
       // Se proprio non troviamo alternative, restituisci l'originale e lascia che l'API gestisca l'errore
       error_log('ImgSEO API: Nessuna thumbnail trovata, provo con l\'originale: ' . round(filesize($original_path) / 1024, 2) . ' KB');
       return array($original_url, $original_path);
   }
   
   /**
    * Converte un'immagine in stringa base64
    *
    * @param string $file_path Percorso del file immagine
    * @return string|false Stringa base64 o false in caso di errore
    */
   private function get_image_as_base64($file_path) {
       // Security: Validate path is within upload directory
       $upload_dir = wp_upload_dir();
       $upload_basedir = realpath($upload_dir['basedir']);
       $resolved_path = realpath($file_path);
       
       if ($resolved_path === false || strpos($resolved_path, $upload_basedir) !== 0) {
           error_log('ImgSEO Security: Blocked base64 conversion for unsafe path: ' . $file_path);
           return false;
       }
       
       // Verifica che il file esista
       if (!file_exists($file_path)) {
           error_log('ImgSEO API: File non trovato per conversione base64: ' . $file_path);
           return false;
       }
       
       // Ottieni tipo MIME
       $mime_type = mime_content_type($file_path);
       
       // Log della dimensione del file per debug
       $file_size = filesize($file_path);
       error_log('ImgSEO API: Dimensione file per base64: ' . round($file_size / 1024, 2) . ' KB');
       
       // Leggi e codifica file
       $image_data = file_get_contents($file_path);
       $base64 = base64_encode($image_data);
       
       // Restituisci solo la stringa base64 senza prefisso data URI
       // L'API si aspetta solo il contenuto base64 puro, non il formato data URI completo
       return $base64;
   }
   
   /**
    * Converte un URL immagine nel percorso file locale
    *
    * @param string $image_url URL dell'immagine
    * @return string Percorso locale del file
    */
   private function get_local_path_from_url($image_url) {
       // Gestione URL WordPress standard
       $upload_dir = wp_upload_dir();
       $file_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $image_url);
       
       // Security: Validate that the path is within upload directory
       $upload_basedir = realpath($upload_dir['basedir']);
       $resolved_path = realpath($file_path);
       
       if ($resolved_path === false || strpos($resolved_path, $upload_basedir) !== 0) {
           // Path is outside upload directory - security risk
           error_log('ImgSEO Security: Blocked path traversal attempt: ' . $image_url);
           
           // Fallback: try to get safe path via attachment ID
           $attachment_id = attachment_url_to_postid($image_url);
           if ($attachment_id) {
               $safe_path = get_attached_file($attachment_id);
               $safe_resolved = realpath($safe_path);
               if ($safe_resolved && strpos($safe_resolved, $upload_basedir) === 0) {
                   return $safe_path;
               }
           }
           return false; // Reject unsafe path
       }
       
       // Gestione URL con CDN o personalizzati
       if (!file_exists($file_path)) {
           // Tenta di risolvere l'URL tramite l'ID dell'allegato
           $attachment_id = attachment_url_to_postid($image_url);
           if ($attachment_id) {
               $safe_path = get_attached_file($attachment_id);
               $safe_resolved = realpath($safe_path);
               if ($safe_resolved && strpos($safe_resolved, $upload_basedir) === 0) {
                   return $safe_path;
               }
           }
       }
       
       return $file_path;
   }
   
   /**
     * Checks if the site is offline (not accessible from the internet)
     *
     * @return bool True if the site is offline, false otherwise
     */
    private function is_site_offline() {
       $site_url = get_site_url();
       
       // List of known local domains
       $local_domains = array(
           'localhost',
           '.local',
           '.test',
           '.dev',
           '127.0.0.1',
           '192.168.',
           '10.',
           '172.16.',
           '172.17.',
           '172.18.',
           '172.19.',
           '172.20.',
           '172.21.',
           '172.22.',
           '172.23.',
           '172.24.',
           '172.25.',
           '172.26.',
           '172.27.',
           '172.28.',
           '172.29.',
           '172.30.',
           '172.31.'
       );
       
       // Check if the site URL contains one of the local domains
       foreach ($local_domains as $domain) {
           if (strpos($site_url, $domain) !== false) {
               return true;
           }
       }
       
       return false;
   }
   
   /**
    * Gets available credits
    *
    * @param bool $refresh If true, forces an update from ImgSEO servers
    * @return int The number of available credits
    */
   public function get_available_credits($refresh = false) {
       // If an update is requested or the last check is older than an hour
       $last_check = get_option('imgseo_last_check', 0);
        if ($refresh || time() - $last_check > 3600) {
            $account_details = $this->get_account_details();
            if ($account_details !== false) {
                return $account_details['available'];
            }
        }
        
        return get_option('imgseo_credits', 0);
    }
}

} // Fine controllo class_exists
