HEX
Server: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.4.30
System: Linux iZj6c1151k3ad370bosnmsZ 3.10.0-1160.76.1.el7.x86_64 #1 SMP Wed Aug 10 16:21:17 UTC 2022 x86_64
User: root (0)
PHP: 7.4.30
Disabled: NONE
Upload Files
File: /var/www/html/www.winghung.com/wp-content/plugins/upkyk-assistant-ai/admin/class-upkyk-admin.php
<?php
/**
 * Admin functionality for Upkyk AssistantAI
 *
 * @package Upkyk_Assistant_AI
 */

if (!defined('ABSPATH')) {
    exit; // Prevent direct access
}

/**
 * The admin-specific functionality of the plugin.
 *
 * @link       https://www.upkyk.com
 * @since      1.0.0
 *
 * @package    Upkyk_Assistant_AI
 * @subpackage Upkyk_Assistant_AI/admin
 */

/**
 * The admin-specific functionality of the plugin.
 *
 * Defines the plugin name, version, and two examples hooks for
 * enqueuing the admin-specific stylesheet and JavaScript.
 *
 * @package    Upkyk_Assistant_AI
 * @subpackage Upkyk_Assistant_AI/admin
 * @author     UPKYK <info@upkyk.com>
 */
class Upkyk_Assistant_AI_Admin {
    /**
     * Plugin name
     */
    private $plugin_name;
    
    /**
     * Plugin version
     */
    private $version;

    /**
     * Constructor - initialize the admin functionality
     * 
     * @param string $plugin_name The name of the plugin
     * @param string $version The version of the plugin
     */
    public function __construct($plugin_name = 'upkyk-assistant-ai', $version = '1.0') {
        $this->plugin_name = $plugin_name;
        $this->version = $version;
        
        // Ensure database tables exist
        $this->ensure_tables_exist();
        
        // Add action hooks
        add_action('admin_menu', array($this, 'add_admin_menu'));
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
        
        // Register hooks
        $this->register_hooks();

        // Register admin hooks
        $this->register_admin_hooks();
    }
    
    /**
     * Make sure database tables exist
     */
    public function ensure_tables_exist() {
        global $wpdb;
        
        // Create custom phrases table if it doesn't exist
        $custom_phrases_created = $this->create_custom_phrases_table();
        
        // Return the results
        
        // Check if tables are working properly
        $this->verify_tables_functionality();
        
        return $custom_phrases_created;
    }
    
    /**
     * Verify database tables functionality
     */
    private function verify_tables_functionality() {
        global $wpdb;
        
        // Check custom phrases table only
        $phrases_table = $wpdb->prefix . 'upkyk_custom_phrases';
        $cache_key_exists = 'upkyk_table_exists_' . $phrases_table;
        $table_exists = wp_cache_get($cache_key_exists);

        if (false === $table_exists) {
            // Check existence using prepare
            // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
            // @codingStandardsIgnoreStart
            $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $phrases_table)) == $phrases_table);
            // @codingStandardsIgnoreEnd
            wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS); // Cache for 1 hour
        }
        
        // Only attempt to count rows if the table exists
        if ($table_exists) {
            $cache_key_count = 'upkyk_table_count_' . $phrases_table;
            $count = wp_cache_get($cache_key_count);
            if (false === $count) {
                // Direct DB query necessary here as we're working with a custom table
                // @codingStandardsIgnoreStart
                $phrases_table_name = esc_sql($phrases_table);
                $count = $wpdb->get_var("SELECT COUNT(*) FROM `{$phrases_table_name}`"); 
                // @codingStandardsIgnoreEnd
                wp_cache_set($cache_key_count, $count, '', 5 * MINUTE_IN_SECONDS); // Cache count for 5 mins
            }
            return true; // Indicate table is functional
        }
        
        // Table doesn't exist or check failed
        return false;
    }
    
    /**
     * Create custom phrases table
     * 
     * @return bool True if table exists or was created successfully
     */
    private function create_custom_phrases_table(): bool {
        global $wpdb;
        $table_name = $wpdb->prefix . 'upkyk_custom_phrases';
        // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
        // @codingStandardsIgnoreStart
        if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name) {
            return true;
        }
        // @codingStandardsIgnoreEnd
        
        // Create table
        $charset_collate = $wpdb->get_charset_collate();
        $sql = "CREATE TABLE $table_name (
            id mediumint(9) NOT NULL AUTO_INCREMENT,
            question text NOT NULL,
            answer text NOT NULL,
            category varchar(100) DEFAULT NULL,
            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
            PRIMARY KEY  (id)
        ) $charset_collate;";
        
        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        $result = dbDelta($sql);
        
        // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
        // @codingStandardsIgnoreStart
        return ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name);
        // @codingStandardsIgnoreEnd
    }
    
    /**
     * Add admin menu
     */
    public function add_admin_menu() {
        // Main menu
        add_menu_page(
            __('Upkyk Assistant AI', 'upkyk-assistant-ai'),
            __('Assistant AI', 'upkyk-assistant-ai'),
            'manage_options',
            'upkyk-assistant-ai',
            array($this, 'display_settings_page'),
            'dashicons-format-chat',
            30
        );
        
        // Settings submenu
        add_submenu_page(
            'upkyk-assistant-ai',
            __('Settings', 'upkyk-assistant-ai'),
            __('Settings', 'upkyk-assistant-ai'),
            'manage_options',
            'upkyk-assistant-ai',
            array($this, 'display_settings_page')
        );
        
        // Training submenu
        add_submenu_page(
            'upkyk-assistant-ai',
            __('Training', 'upkyk-assistant-ai'),
            __('Training', 'upkyk-assistant-ai'),
            'manage_options',
            'upkyk-assistant-ai-training',
            array($this, 'display_training_page')
        );
        
        // API Diagnostics submenu
        add_submenu_page(
            'upkyk-assistant-ai',
            __('API Diagnostics', 'upkyk-assistant-ai'),
            __('API Diagnostics', 'upkyk-assistant-ai'),
            'manage_options',
            'upkyk-assistant-ai-diagnostics',
            array($this, 'display_api_diagnostics_page')
        );
    }
    
    /**
     * Load API Key Diagnostics file
     */
    public function load_api_key_diagnostics() {
        // Add standard WordPress admin styles
        wp_enqueue_style('wp-admin');
        wp_enqueue_style('dashboard');
        wp_enqueue_style('list-tables');
        wp_enqueue_style('edit');
        wp_enqueue_style('forms');
        wp_enqueue_style('buttons');
        
        // Make sure we have our admin styles for proper rendering
        wp_enqueue_style(
            'upkyk-assistant-ai-admin-css', 
            UPKYK_ASSISTANT_AI_URL . 'admin/css/admin-style.css', 
            array(), 
            UPKYK_ASSISTANT_AI_VERSION
        );
        
        // Use jQuery library 
        wp_enqueue_script('jquery');
    }

    /**
     * Sanitize button shape
     *
     * @param mixed $value The value to sanitize
     * @return string Sanitized button shape
     */
    public function sanitize_button_shape($value) {
        $allowed = array('circle', 'square', 'rounded');
        return in_array($value, $allowed) ? $value : 'circle';
    }

    /**
     * Sanitize button size
     *
     * @param mixed $value The value to sanitize
     * @return string Sanitized button size
     */
    public function sanitize_button_size($value) {
        $allowed = array('small', 'medium', 'large');
        return in_array($value, $allowed) ? $value : 'medium';
    }

    /**
     * Sanitize position
     *
     * @param mixed $value The value to sanitize
     * @return string Sanitized position
     */
    public function sanitize_position($value) {
        $allowed = array('bottom-right', 'bottom-left', 'top-right', 'top-left');
        return in_array($value, $allowed) ? $value : 'bottom-right';
    }

    /**
     * Sanitize AI provider
     *
     * @param mixed $value The value to sanitize
     * @return string Sanitized provider
     */
    public function sanitize_provider($value) {
        $allowed = array('openai', 'deepseek');
        return in_array($value, $allowed) ? $value : 'openai';
    }

    /**
     * Sanitize model name
     *
     * @param mixed $value The value to sanitize
     * @return string Sanitized model name
     */
    public function sanitize_model($value) {
        return preg_replace('/[^a-zA-Z0-9\-\.]/', '', $value);
    }

    /**
     * Register settings
     */
    /**
     * Sanitize boolean settings
     *
     * @param mixed $value The value to sanitize
     * @return string '1' for true, '0' for false
     */
    public function sanitize_boolean($value) {
        return ($value === '1' || $value === 'on' || $value === true) ? '1' : '0';
    }

    /**
     * Sanitize display mode
     *
     * @param mixed $value The value to sanitize
     * @return string Sanitized display mode
     */
    public function sanitize_display_mode($value) {
        $allowed = array('all', 'specific'); // Add more options later if needed
        return in_array($value, $allowed) ? $value : 'all'; // Default to 'all'
    }

    /**
     * Sanitize window size percentage
     *
     * @param mixed $value The value to sanitize
     * @return int Value between 1 and 100
     */
    public function sanitize_window_percentage($value) {
        $value = absint($value);
        return max(1, min(100, $value));
    }

    /**
     * Sanitize window dimensions
     *
     * @param mixed $value The value to sanitize
     * @return int Value between 200 and 1000
     */
    public function sanitize_window_dimension($value) {
        $value = absint($value);
        return max(200, min(1000, $value));
    }

    /**
     * Sanitize delay values
     *
     * @param mixed $value The value to sanitize
     * @return int Value between 0 and 60000 (ms)
     */
    public function sanitize_delay($value) {
        $value = absint($value);
        return max(0, min(60000, $value));
    }

    /**
     * Sanitize max tokens
     *
     * @param mixed $value The value to sanitize
     * @return int Value between 1 and 2000
     */
    public function sanitize_max_tokens($value) {
        $value = absint($value);
        return max(1, min(2000, $value));
    }

    /**
     * Sanitize encryption wrapper for register_setting
     * This function serves as a static wrapper for the encrypt_api_key method
     *
     * @param string $api_key The API key to encrypt
     * @return string The encrypted API key
     */
    public function sanitize_api_key($api_key) {
        return $this->encrypt_api_key($api_key);
    }

    /**
     * Register settings
     */
    public function register_settings() {
        // Register main settings
        register_setting(
            'upkyk_assistant_ai_settings_tab', // Correct group
            'upkyk_assistant_ai_enabled',
            array('type' => 'boolean', 'sanitize_callback' => array($this, 'sanitize_boolean'), 'default' => '1')
        );
        
        add_settings_field(
            'upkyk_assistant_ai_enabled',
            __('Enable Chatbot', 'upkyk-assistant-ai'),
            array($this, 'enabled_callback'),
            'upkyk-assistant-ai',
            'upkyk_assistant_ai_general_section'
        );

        // Display Mode Setting
        register_setting(
            'upkyk_assistant_ai_settings_tab', // Correct group
            'upkyk_assistant_ai_display_mode',
            array('type' => 'string', 'sanitize_callback' => array($this, 'sanitize_display_mode'), 'default' => 'all')
        );

        add_settings_field(
            'upkyk_assistant_ai_display_mode',
            __('Display Mode', 'upkyk-assistant-ai'),
            array($this, 'display_mode_callback'),
            'upkyk-assistant-ai',
            'upkyk_assistant_ai_general_section'
        );
        
        register_setting(
            'upkyk_assistant_ai_settings_tab', // Correct group
            'upkyk_assistant_ai_disable_on_mobile',
            array('type' => 'boolean', 'sanitize_callback' => array($this, 'sanitize_boolean'), 'default' => '0')
        );
        
        add_settings_field(
            'upkyk_assistant_ai_disable_on_mobile',
            __('Disable on Mobile', 'upkyk-assistant-ai'),
            array($this, 'disable_on_mobile_callback'),
            'upkyk-assistant-ai',
            'upkyk_assistant_ai_general_section'
        );
        
        // Appearance settings
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_color', 'sanitize_hex_color');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_user_color', 'sanitize_hex_color');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_position', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_button_shape', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_button_size', 'sanitize_text_field');
        
        // Retain these as hidden fields for compatibility
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_custom_icon', array(
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_custom_icon_size', array(
            'sanitize_callback' => 'sanitize_text_field'
        ));
        
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_input_placeholder', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_animation_style', array(
            'default' => 'fade',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        
        // Settings tab options
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_welcome_message', array(
            'default' => __('Hello! How can I help you today?', 'upkyk-assistant-ai'), // Add translatable default
            'sanitize_callback' => 'sanitize_textarea_field'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_welcome_delay', array(
            'sanitize_callback' => 'absint'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_quick_replies', array(
            'sanitize_callback' => 'sanitize_textarea_field'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_typing_animation', array(
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_name', array(
            'default' => 'Chat Support',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_max_tokens', array(
            'default' => '40',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_response_length_type', array(
            'default' => 'word_count',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_typing_delay', array(
            'sanitize_callback' => 'absint'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_auto_close', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_inactivity_timeout', array(
            'sanitize_callback' => 'absint'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_debug_mode', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_show_branding', array(
            'default' => '0',
            'sanitize_callback' => 'sanitize_text_field'
        )); // Show branding option - OFF by default
        
        // Company information settings
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_phone_number', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_locations', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_target_audience', array(
            'sanitize_callback' => function($input) {
                $sanitized = sanitize_textarea_field($input);
                // Limit to 900 characters
                if (strlen($sanitized) > 900) {
                    $sanitized = substr($sanitized, 0, 900);
                    add_settings_error(
                        'upkyk_assistant_ai_target_audience',
                        'text_too_long',
                        __('Target Audience/Services text has been truncated to 900 characters.', 'upkyk-assistant-ai'),
                        'warning'
                    );
                }
                return $sanitized;
            }
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_website', 'sanitize_text_field');
        
        // Language settings
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_auto_language', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_default_language', 'sanitize_text_field');
        
        // Appearance tab options
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_color', array(
            'sanitize_callback' => 'sanitize_hex_color'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_user_color', array(
            'sanitize_callback' => 'sanitize_hex_color'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_link_bg_color', array(
            'sanitize_callback' => 'sanitize_hex_color'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_link_text_color', array(
            'sanitize_callback' => 'sanitize_hex_color'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_font', array(
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_position', array(
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_avatar', array(
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_button_shape', array(
            'default' => 'circle',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_button_size', array(
            'default' => 'medium',
            'sanitize_callback' => array($this, 'sanitize_button_size')
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_font_size', array(
            'default' => 'medium',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_message_padding', array(
            'default' => 'normal',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_button_icon', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_custom_icon', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_custom_icon_size', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_input_placeholder', 'sanitize_text_field');
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_animation_style', array(
            'default' => 'fade',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        
        // Window size settings
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_window_size', array(
            'default' => 'medium',
            'sanitize_callback' => array($this, 'sanitize_button_size')
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_window_width', array(
            'default' => '380',
            'sanitize_callback' => array($this, 'sanitize_window_dimension')
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_window_height', array(
            'default' => '600',
            'sanitize_callback' => array($this, 'sanitize_window_dimension')
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_window_width_mobile', array(
            'default' => '95',
            'sanitize_callback' => array($this, 'sanitize_window_percentage')
        ));
        register_setting('upkyk_assistant_ai_appearance_tab', 'upkyk_assistant_ai_window_height_mobile', array(
            'default' => '80',
            'sanitize_callback' => array($this, 'sanitize_window_percentage')
        ));
        
        // API settings
        register_setting('upkyk_assistant_ai_api', 'upkyk_assistant_ai_client_id', array(
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_api', 'upkyk_assistant_ai_provider', array(
            'type' => 'string',
            'default' => 'openai',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        
        // We use a named method for API key encryption
        register_setting('upkyk_assistant_ai_api', 'upkyk_assistant_ai_api_key', array(
            'type' => 'string',
            'sanitize_callback' => array($this, 'sanitize_api_key')
        ));
        
        register_setting('upkyk_assistant_ai_api', 'upkyk_assistant_ai_deepseek_model', array(
            'type' => 'string',
            'default' => 'deepseek-chat',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_api', 'upkyk_assistant_ai_openai_model', array(
            'type' => 'string',
            'default' => 'gpt-3.5-turbo',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        
        // Advanced settings
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_debug_mode', array(
            'default' => '0',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        register_setting('upkyk_assistant_ai_settings_tab', 'upkyk_assistant_ai_strict_topic', array(
            'default' => '1',
            'sanitize_callback' => 'sanitize_text_field'
        ));
        
        // Allowed Pages Setting (for 'specific' mode)
        register_setting(
            'upkyk_assistant_ai_settings_tab',
            'upkyk_assistant_ai_allowed_pages',
            array('type' => 'array', 'sanitize_callback' => array($this, 'sanitize_allowed_pages'), 'default' => array())
        );

        add_settings_field(
            'upkyk_assistant_ai_allowed_pages',
            __('Show on Pages', 'upkyk-assistant-ai'),
            array($this, 'allowed_pages_callback'),
            'upkyk-assistant-ai',
            'upkyk_assistant_ai_general_section'
        );
    }
    
    /**
     * Enqueue admin assets
     */
    public function enqueue_admin_assets($hook) {
        global $wpdb; // Get global $wpdb variable
        
        // Only load on plugin pages
        if (strpos($hook, 'upkyk-assistant-ai') === false) {
            return;
        }
        
        // Enqueue styles
        wp_enqueue_style('upkyk-assistant-ai-admin-css', UPKYK_ASSISTANT_AI_URL . 'admin/css/admin-style.css', array(), UPKYK_ASSISTANT_AI_VERSION);
        
        // Enqueue media scripts for avatar upload
        wp_enqueue_media();
        
        // Enqueue training page styles with a high priority and version string to bust cache
        wp_enqueue_style(
            'upkyk-assistant-ai-training-css',
            UPKYK_ASSISTANT_AI_URL . 'admin/css/training-page.css',
            array(),
            UPKYK_ASSISTANT_AI_VERSION . '.' . time() // Add timestamp for cache busting
        );
        
        // Initialize the WordPress Media Library picker
        wp_enqueue_media();
        
        // WordPress color picker
        wp_enqueue_style('wp-color-picker');
        wp_enqueue_script('wp-color-picker');
        wp_enqueue_style('dashicons');
        
        // Register and enqueue admin script
        wp_enqueue_script('upkyk-assistant-ai-admin-js', UPKYK_ASSISTANT_AI_URL . 'admin/js/admin-script.js', array('jquery', 'wp-color-picker'), UPKYK_ASSISTANT_AI_VERSION, true);
        
        // Create nonces for admin AJAX operations
        $admin_nonce = wp_create_nonce('upkyk_assistant_ai_admin_nonce');
        $regular_nonce = wp_create_nonce('upkyk_assistant_ai_nonce');
        $preview_nonce = wp_create_nonce('upkyk_assistant_ai_preview_nonce');
        
        // Initialize nonces
        
        // Localize script with global variables
        wp_localize_script('upkyk-assistant-ai-admin-js', 'upkykAssistantAIAdmin', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'plugin_url' => UPKYK_ASSISTANT_AI_URL,
            'nonce' => $regular_nonce,
            'adminNonce' => $admin_nonce,
            'previewNonce' => $preview_nonce,
            'labels' => array(
                'confirmDelete' => __('Are you sure you want to delete this item?', 'upkyk-assistant-ai'),
                'confirmDeleteMultiple' => __('Are you sure you want to delete the selected items?', 'upkyk-assistant-ai'),
                'success' => __('Success', 'upkyk-assistant-ai'),
                'error' => __('Error', 'upkyk-assistant-ai'),
                'warning' => __('Warning', 'upkyk-assistant-ai'),
                'info' => __('Info', 'upkyk-assistant-ai'),
            ),
            'db_table_exists' => $this->check_table_exists($wpdb->prefix . 'upkyk_documents'),
        ));
        
        // Check if we're on the training page specifically
        if (isset($_GET['page']) && sanitize_text_field(wp_unslash($_GET['page'])) === 'upkyk-assistant-ai-training') {
            // Verify nonce for page access
            if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'upkyk_assistant_ai_training_nonce')) {
                // Don't stop execution, but be prepared for potential unauthorized access
                // Just continue without the scripts for security
            }
            
            // Enqueue training-specific JS
            wp_enqueue_script('upkyk-assistant-ai-training-js', UPKYK_ASSISTANT_AI_URL . 'admin/js/training-page.js', array('jquery'), UPKYK_ASSISTANT_AI_VERSION . '.' . time(), true);
            
            // Add training variables
            wp_localize_script('upkyk-assistant-ai-training-js', 'upkyk_admin_vars', array(
                'ajax_url' => admin_url('admin-ajax.php'),
                'nonce' => $regular_nonce,
                'plugin_url' => UPKYK_ASSISTANT_AI_URL,
                'max_upload_size' => wp_max_upload_size(),
                'db_table_exists' => $this->check_table_exists($wpdb->prefix . 'upkyk_documents'),
                'i18n' => array(
                    'loading' => __('Loading...', 'upkyk-assistant-ai'),
                    'success' => __('Success!', 'upkyk-assistant-ai'),
                    'error' => __('Error', 'upkyk-assistant-ai'),
                    'confirm_delete' => __('Are you sure you want to delete this item?', 'upkyk-assistant-ai'),
                    'delete' => __('Delete', 'upkyk-assistant-ai'),
                    'no_documents' => __('No documents uploaded yet.', 'upkyk-assistant-ai'),
                    'confirm_delete_document' => __('Are you sure you want to delete this document? This action cannot be undone.', 'upkyk-assistant-ai'),
                    'resetting' => __('Resetting...', 'upkyk-assistant-ai'),
                    'reset_training' => __('Reset Training', 'upkyk-assistant-ai'),
                    'training_reset_success' => __('Training reset successfully!', 'upkyk-assistant-ai'),
                    'failed_reset' => __('Failed to reset training.', 'upkyk-assistant-ai'),
                    'server_error' => __('Server error: ', 'upkyk-assistant-ai'),
                    'bytes' => __('Bytes', 'upkyk-assistant-ai'),
                    'kb' => __('KB', 'upkyk-assistant-ai'),
                    'mb' => __('MB', 'upkyk-assistant-ai'),
                    'gb' => __('GB', 'upkyk-assistant-ai'),
                    'pro_feature' => __('PRO Feature', 'upkyk-assistant-ai'),
                    'doc_training_pro' => __('Document training is available in the PRO version.', 'upkyk-assistant-ai'),
                    'info' => __('Info', 'upkyk-assistant-ai'),
                    'train_confirm_message' => __('Are you sure you want to train the Assistant AI with the uploaded documents? This process may take some time.', 'upkyk-assistant-ai'),
                    'training_in_progress' => __('Training in Progress...', 'upkyk-assistant-ai'),
                    'training_completed' => __('Training completed successfully!', 'upkyk-assistant-ai'),
                    'training_failed' => __('Training failed', 'upkyk-assistant-ai'),
                    'train_button_text' => __('Train Assistant AI', 'upkyk-assistant-ai'),
                    'no_file_selected' => __('No file selected', 'upkyk-assistant-ai'),
                    'reset_confirm' => __('Are you sure you want to reset the training? This will delete all training data and cannot be undone.', 'upkyk-assistant-ai'),
                    'error_loading_documents' => __('Error loading documents.', 'upkyk-assistant-ai'),
                    'select_file' => __('Please select a file to upload', 'upkyk-assistant-ai'),
                    'invalid_file_type' => __('Invalid file type. Please upload a TXT, CSV, or JSON file.', 'upkyk-assistant-ai'),
                    'uploading_document' => __('Uploading document...', 'upkyk-assistant-ai'),
                    'document_uploaded' => __('Document uploaded successfully!', 'upkyk-assistant-ai'),
                    'error_uploading' => __('Error uploading document.', 'upkyk-assistant-ai'),
                    'invalid_document_id' => __('Invalid document ID', 'upkyk-assistant-ai'),
                    'deleting_document' => __('Deleting document...', 'upkyk-assistant-ai'),
                    'document_deleted' => __('Document deleted successfully', 'upkyk-assistant-ai'),
                    'failed_delete_document' => __('Failed to delete document', 'upkyk-assistant-ai'),
                    'no_documents_uploaded' => __('No documents uploaded yet.', 'upkyk-assistant-ai')
                ),
                'test_i18n' => array(
                    'question' => __('Question:', 'upkyk-assistant-ai'),
                    'ai_response' => __('AI Response:', 'upkyk-assistant-ai'),
                    'generated_success' => __('Generated successfully', 'upkyk-assistant-ai'),
                    'error' => __('Error:', 'upkyk-assistant-ai'),
                    'unknown_error' => __('Unknown error', 'upkyk-assistant-ai'),
                    'check_api' => __('Please check your API settings and try again.', 'upkyk-assistant-ai'),
                    'server_error' => __('Server error:', 'upkyk-assistant-ai'),
                    'try_again' => __('Please try again later.', 'upkyk-assistant-ai'),
                    'check_network' => __('Please check your network connection and try again.', 'upkyk-assistant-ai')
                )
            ));
        }
        
        // Enqueue settings page script if on the main settings page
        if ($hook === 'toplevel_page_upkyk-assistant-ai') {
            wp_enqueue_script(
                'upkyk-assistant-ai-settings-js',
                UPKYK_ASSISTANT_AI_URL . 'admin/js/settings-page.js',
                array('jquery'),
                UPKYK_ASSISTANT_AI_VERSION,
                true // Load in footer
            );
        }
    }

    /**
     * Display the main settings page
     */
    public function display_settings_page() {
        include_once UPKYK_ASSISTANT_AI_PATH . 'admin/settings-page.php';
    }
    
    /**
     * Log debug messages only when WP_DEBUG is enabled
     * 
     * @param string $message The debug message to log
     * @param string $context Optional context information
     * @return void
     */
    private function log_debug($message, $context = '') {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            // Use do_action for logging to allow for proper WordPress integration
            // This avoids the WordPress.PHP.DevelopmentFunctions.error_log_error_log warning
            $log_message = $context ? "[{$context}] {$message}" : $message;
            do_action('upkyk_assistant_ai_debug_log', $log_message);
        }
    }
    
    /**
     * AJAX: Generate preview
     */
    public function ajax_generate_preview() {
        // Verify nonce
        if (!check_ajax_referer('upkyk_assistant_ai_preview_nonce', 'nonce', false)) {
            $this->log_debug('Upkyk AssistantAI: Preview nonce check failed');
            wp_send_json_error(['message' => 'Security check failed (invalid nonce).']);
            return;
        }
        
        if (!current_user_can('manage_options')) {
            $this->log_debug('Upkyk AssistantAI: Preview permissions check failed');
            wp_send_json_error(['message' => 'Insufficient permissions.']);
            return;
        }
        
        $settings = isset($_POST['settings']) ? map_deep(wp_unslash($_POST['settings']), 'sanitize_text_field') : array();
        
        // Debug settings
        $this->log_debug('Upkyk AssistantAI: Received preview settings: ' . wp_json_encode(array_keys($settings)));
        
        // Sanitize entire settings array first
        $settings = array_map(function($value) {
            if (is_array($value)) {
                return array_map('sanitize_text_field', $value);
            }
            return sanitize_text_field($value);
        }, $settings);
        
        // Sanitize settings with defaults
        $color = isset($settings['color']) ? sanitize_hex_color($settings['color']) : '#0084ff';
        $user_color = isset($settings['user_color']) ? sanitize_hex_color($settings['user_color']) : '#e9ecef';
        $font = isset($settings['font']) ? sanitize_text_field($settings['font']) : 'Roboto, sans-serif';
        $avatar = isset($settings['avatar']) ? esc_url_raw($settings['avatar']) : '';
        $assistant_ai_name = isset($settings['assistant_ai_name']) ? sanitize_text_field($settings['assistant_ai_name']) : 'Chat Support';
        $button_shape = isset($settings['button_shape']) ? sanitize_text_field($settings['button_shape']) : 'circle';
        $button_size = isset($settings['button_size']) ? sanitize_text_field($settings['button_size']) : 'medium';
        $font_size = isset($settings['font_size']) ? sanitize_text_field($settings['font_size']) : 'medium';
        $message_padding = isset($settings['message_padding']) ? sanitize_text_field($settings['message_padding']) : 'normal';
        $input_placeholder = isset($settings['input_placeholder']) ? sanitize_text_field($settings['input_placeholder']) : 'Type your message...';
        $button_icon = isset($settings['button_icon']) ? sanitize_text_field($settings['button_icon']) : 'chat';
        $custom_icon = isset($settings['custom_icon']) ? esc_url_raw($settings['custom_icon']) : '';
        $custom_icon_size = isset($settings['custom_icon_size']) ? sanitize_text_field($settings['custom_icon_size']) : 'medium';
        // Using fixed 'fade' animation for preview only
        $animation_style = 'fade';
        
        // Get appropriate icon SVG
        $icon_svgs = array(
            'chat' => array(
                'solid' => '<path d="M21 11.5C21.0034 12.8199 20.6951 14.1219 20.1 15.3C19.3944 16.7118 18.3098 17.8992 16.9674 18.7293C15.6251 19.5594 14.0782 19.9994 12.5 20C11.1801 20.0035 9.87812 19.6951 8.7 19.1L3 21L4.9 15.3C4.30493 14.1219 3.99656 12.8199 4 11.5C4.00061 9.92179 4.44061 8.37488 5.27072 7.03258C6.10083 5.69028 7.28825 4.6056 8.7 3.90003C9.87812 3.30496 11.1801 2.99659 12.5 3.00003H13C15.0843 3.11502 17.053 3.99479 18.5291 5.47089C20.0052 6.94699 20.885 8.91568 21 11V11.5Z" fill="white"/>',
                'outline' => '<path d="M21 11.5C21.0034 12.8199 20.6951 14.1219 20.1 15.3C19.3944 16.7118 18.3098 17.8992 16.9674 18.7293C15.6251 19.5594 14.0782 19.9994 12.5 20C11.1801 20.0035 9.87812 19.6951 8.7 19.1L3 21L4.9 15.3C4.30493 14.1219 3.99656 12.8199 4 11.5C4.00061 9.92179 4.44061 8.37488 5.27072 7.03258C6.10083 5.69028 7.28825 4.6056 8.7 3.90003C9.87812 3.30496 11.1801 2.99659 12.5 3.00003H13C15.0843 3.11502 17.053 3.99479 18.5291 5.47089C20.0052 6.94699 20.885 8.91568 21 11V11.5Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
            ),
            'message' => array(
                'solid' => '<path d="M21.75 3C21.75 2.59 21.41 2.25 21 2.25H3C2.59 2.25 2.25 2.59 2.25 3V17C2.25 17.41 2.59 17.75 3 17.75H10.24L17.92 21.54C18.29 21.73 18.75 21.46 18.75 21.04V17.75H21C21.41 17.75 21.75 17.41 21.75 17V3Z" fill="white"/>',
                'outline' => '<path d="M22 2L11 13" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M22 2L15 22L11 13L2 9L22 2Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
            ),
            'robot' => array(
                'solid' => '<path d="M12 2C9.79 2 8 3.79 8 6V7H16V6C16 3.79 14.21 2 12 2ZM7 8C5.9 8 5 8.9 5 10V20C5 21.1 5.9 22 7 22H17C18.1 22 19 21.1 19 20V10C19 8.9 18.1 8 17 8H7ZM10 10.5C10.83 10.5 11.5 11.17 11.5 12C11.5 12.83 10.83 13.5 10 13.5C9.17 13.5 8.5 12.83 8.5 12C8.5 11.17 9.17 10.5 10 10.5ZM14 10.5C14.83 10.5 15.5 11.17 15.5 12C15.5 12.83 14.83 13.5 14 13.5C13.17 13.5 12.5 12.83 12.5 12C12.5 11.17 13.17 10.5 14 10.5ZM10 15H14V16.5H10V15Z" fill="white"/>',
                'outline' => '<path d="M12 2C9.79 2 8 3.79 8 6V7H16V6C16 3.79 14.21 2 12 2Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M5 10C5 8.9 5.9 8 7 8H17C18.1 8 19 8.9 19 10V20C19 21.1 18.1 22 17 22H7C5.9 22 5 21.1 5 20V10Z" stroke="white" stroke-width="2"/><circle cx="10" cy="12" r="1.5" stroke="white"/><circle cx="14" cy="12" r="1.5" stroke="white"/><path d="M10 15H14V16.5H10V15Z" stroke="white" stroke-width="1.5"/>'
            ),
            'help' => array(
                'solid' => '<path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22ZM12 17.5C11.4477 17.5 11 17.0523 11 16.5C11 15.9477 11.4477 15.5 12 15.5C12.5523 15.5 13 15.9477 13 16.5C13 17.0523 12.5523 17.5 12 17.5ZM12 7C10.3431 7 9 8.34315 9 10C9 10.5523 9.44772 11 10 11C10.5523 11 11 10.5523 11 10C11 9.44772 11.4477 9 12 9C12.5523 9 13 9.44772 13 10C13 10.3688 12.7971 10.6206 12.5399 10.8802C12.341 11.0801 12.1116 11.3067 11.9013 11.5184C11.691 11.7302 11.4935 11.9498 11.3346 12.1571C11.1727 12.3683 11 12.6491 11 13C11 13.5523 11.4477 14 12 14C12.5523 14 13 13.5523 13 13C13 12.9824 13.0047 12.9711 13.0361 12.9322C13.0696 12.8908 13.124 12.8332 13.2166 12.7379C13.3071 12.6448 13.4334 12.5105 13.5913 12.3503C13.7492 12.1902 13.9389 12.0125 14.1279 11.8048C14.5029 11.3932 15 10.7918 15 10C15 8.34315 13.6569 7 12 7Z" fill="white"/>',
                'outline' => '<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M12 17V17.01" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M9.09009 9.00003C9.32519 8.33169 9.78924 7.76813 10.4 7.40916C11.0108 7.05019 11.729 6.91902 12.4273 7.03879C13.1255 7.15857 13.7589 7.52161 14.2152 8.06361C14.6714 8.60561 14.9211 9.2916 14.92 10.0001C14.92 12.0001 11.92 13.0001 11.92 13.0001" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>'
            )
        );
        
        // Set button icon content
        $button_icon_content = '';
        
        // Create the icon HTML using SVG instead of Font Awesome
        $plugin_url = UPKYK_ASSISTANT_AI_URL;
        
        // Map icon names to SVG files
        $icon_map = array(
            'chat' => 'comment.svg',
            'comment' => 'comment.svg',
            'comments' => 'comments.svg',
            'robot' => 'robot.svg',
            'question' => 'question-circle.svg',
            'envelope' => 'envelope.svg',
            'message' => 'envelope.svg',
            'chat-balloon' => 'chat-balloon.svg'
        );
        
        // Get the appropriate SVG file
        $svg_filename = isset($icon_map[$button_icon]) ? $icon_map[$button_icon] : 'comment.svg';
        $svg_path = $plugin_url . 'assets/images/chat-icons/' . $svg_filename;
        
        // Determine icon size based on button size
        $icon_size = '41px'; // Default for medium
        if ($button_size === 'small') {
            $icon_size = '30px';
        } elseif ($button_size === 'large') {
            $icon_size = '47px';
        }
        
        // Create the icon HTML with the SVG
        $button_icon_content = '<img src="' . esc_url($svg_path) . '" alt="Chat Icon" style="width: ' . $icon_size . '; height: ' . $icon_size . '; filter: brightness(0) invert(1);">';
        
        // Generate preview HTML with separate boxes for chat window and button
        $preview = '
        <div class="upkyk-preview-container upkyk-animation-fade">
            <div class="upkyk-preview-section">
                <h4>Chat Window Preview</h4>
                <div class="upkyk-preview-chat" style="--preview-bot-color: ' . $color . '; --preview-user-color: ' . $user_color . '; font-family: ' . $font . ';">
                    <div class="upkyk-preview-header">
                        <div class="upkyk-preview-avatar">
                            ' . ($avatar ? '<img src="' . $avatar . '" alt="Avatar">' : '<div class="upkyk-preview-no-avatar"></div>') . '
                        </div>
                        <div class="upkyk-preview-title">' . esc_html($assistant_ai_name) . '</div>
                    </div>
                    <div class="upkyk-preview-messages">
                        <div class="upkyk-preview-message upkyk-preview-bot ' . $font_size . ' ' . $message_padding . '">Hello! How can I help you today?</div>
                        <div class="upkyk-preview-message upkyk-preview-user ' . $font_size . ' ' . $message_padding . '">I\'m looking for information about your services</div>
                        <div class="upkyk-preview-message upkyk-preview-bot ' . $font_size . ' ' . $message_padding . '">I\'d be happy to help! Our services include...</div>
                    </div>
                    <div class="upkyk-preview-input">
                        <input type="text" placeholder="' . esc_attr($input_placeholder) . '" disabled>
                        <button disabled>→</button>
                    </div>
                    <div class="upkyk-preview-branding">
                        <span>Powered by</span> <img src="' . esc_url(UPKYK_ASSISTANT_AI_URL . 'assets/images/upkyk-icon-grey.svg') . '" alt="Upkyk" style="height: 16px; vertical-align: middle;">
                    </div>
                </div>
            </div>
            
            <div class="upkyk-preview-section">
                <h4>Chat Button Preview</h4>
                <div class="upkyk-preview-toggle upkyk-preview-shape-' . $button_shape . ' upkyk-preview-size-' . $button_size . '" style="background-color: ' . $color . ';">
                    ' . $button_icon_content . '
                    <div class="upkyk-preview-notification-dot"></div>
                </div>
            </div>
        </div>';
        
        wp_send_json_success(['preview' => $preview]);
    }
    
    /**
     * Display training page (focused on custom phrases management)
     */
    public function display_training_page() {
        // Process form submissions for custom phrases
        if (isset($_POST['action']) && isset($_POST['upkyk_nonce'])) {
            // Verify nonce
            if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['upkyk_nonce'])), 'upkyk_assistant_ai_training_nonce')) {
                add_settings_error('upkyk_custom_phrase', 'nonce_error', 'Security check failed.', 'error');
            } else {
                switch ($_POST['action']) {
                    case 'save_custom_phrase':
                        $this->handle_custom_phrase_submission();
                        break;
                    default:
                    // No other actions are supported
                    break;
                }
            }
        }
        
        // Include training page template
        include_once UPKYK_ASSISTANT_AI_PATH . 'admin/training-page.php';
    }
    
    /**
     * Handle custom phrase form submission
     */
    private function handle_custom_phrase_submission() {
        // Verify nonce
        if (!isset($_POST['upkyk_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['upkyk_nonce'])), 'upkyk_assistant_ai_training_nonce')) {
            add_settings_error('upkyk_custom_phrase', 'nonce_error', 'Security check failed.', 'error');
            return;
        }
        
        // Verify user has permission
        if (!current_user_can('manage_options')) {
            add_settings_error('upkyk_custom_phrase', 'permission_error', 'You do not have permission to make these changes.', 'error');
            return;
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'upkyk_custom_phrases';
        
        // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
        // @codingStandardsIgnoreStart
        if ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) != $table_name) {
            // Table doesn't exist, create it
            $this->create_custom_phrases_table();
        }
        // @codingStandardsIgnoreEnd
        
        // Get form values
        $question = isset($_POST['question']) ? sanitize_text_field(wp_unslash($_POST['question'])) : '';
        $answer = isset($_POST['answer']) ? sanitize_textarea_field(wp_unslash($_POST['answer'])) : '';
        $category = isset($_POST['category']) ? sanitize_text_field(wp_unslash($_POST['category'])) : '';
        
        // Validate required fields
        if (empty($question) || empty($answer)) {
            add_settings_error('upkyk_custom_phrase', 'required_fields', 'Question and Answer are required fields.', 'error');
            return;
        }
        
        // Set default category if empty
        if (empty($category)) {
            $category = 'General';
        }
        
        // Remove word count notes (like "(35 woorden)") from the answer
        $answer = preg_replace('/\s*\(\d+\s*woorden\)\s*$/', '', $answer);
        
        // Replace hyphens with commas in lists, but not in URLs or other valid uses
        $answer = preg_replace('/(?<![\w\/\-])([a-zA-Z]+)\s*-\s*(?![\w\/\-])([a-zA-Z]+)/', '$1, $2', $answer);
        
        // Determine if we're updating an existing phrase or adding a new one
        $phrase_id = isset($_POST['phrase_id']) ? intval($_POST['phrase_id']) : 0;
        
        
        if ($phrase_id > 0) {
            // Direct DB operation necessary here as we're working with a custom table
            // @codingStandardsIgnoreStart
            // Update existing phrase
            $result = $wpdb->update(
                $table_name,
                array(
                    'question' => $question,
                    'answer' => $answer,
                    'category' => $category
                ),
                array('id' => $phrase_id),
                array('%s', '%s', '%s'),
                array('%d')
            );
            // @codingStandardsIgnoreEnd
            
            if ($result !== false) {
                // Clear caches related to custom phrases
                wp_cache_delete('upkyk_custom_phrases_qa');
                wp_cache_delete('upkyk_custom_phrases');
                wp_cache_delete('upkyk_phrases_table_status');
                
                add_settings_error('upkyk_custom_phrase', 'phrase_updated', 'Custom phrase updated successfully.', 'success');
            } else {
                add_settings_error('upkyk_custom_phrase', 'db_error', 'Failed to update custom phrase. Please try again.', 'error');
            }
        } else {
            // Direct DB operation necessary here as we're working with a custom table
            // @codingStandardsIgnoreStart
            // Insert new phrase
            $result = $wpdb->insert(
                $table_name,
                array(
                    'question' => $question,
                    'answer' => $answer,
                    'category' => $category,
                    'created_at' => current_time('mysql', 1) // Use GMT time
                ),
                array(
                    '%s', // question
                    '%s', // answer
                    '%s', // category
                    '%s'  // created_at
                )
            );
            // @codingStandardsIgnoreEnd
            
            if ($result !== false) { // insert returns false on error, or number of rows inserted (1)
                $phrase_id = $wpdb->insert_id;
                $this->log_debug("Successfully added phrase with ID {$phrase_id}", 'ajax_add_custom_phrase');
                
                // Clear caches
                wp_cache_delete('upkyk_custom_phrases_qa');
                wp_cache_delete('upkyk_custom_phrases');
                wp_cache_delete('upkyk_phrases_table_status');

                // Get the newly added phrase to return if needed by the frontend JS
                // Direct DB query necessary here as we're working with a custom table
                // @codingStandardsIgnoreStart
                $safe_table_name = esc_sql($table_name);
                $new_phrase = $wpdb->get_row(
                    $wpdb->prepare(
                        "SELECT id, question, answer, category, created_at FROM `{$safe_table_name}` WHERE id = %d", 
                        $phrase_id
                    ), 
                    ARRAY_A
                );
                // @codingStandardsIgnoreEnd
                
                wp_send_json_success(array(
                    'message' => __('Phrase added successfully.', 'upkyk-assistant-ai'),
                    'phrase_id' => $phrase_id,
                    'phrase' => $new_phrase // Send back the added phrase data
                ));
            } else {
                $this->log_debug('Failed to add phrase. DB Error: ' . $wpdb->last_error, 'ajax_add_custom_phrase');
                wp_send_json_error(array(
                    'message' => __('Failed to add phrase to the database.', 'upkyk-assistant-ai'),
                    'db_error' => $wpdb->last_error // Avoid exposing raw DB errors
                ));
            }
        }
    }

    /**
     * AJAX handler for deleting a phrase
     */
    public function ajax_delete_phrase() {
        // Check nonce first
        if (!check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce', false)) {
            $this->log_debug('Nonce verification failed', 'ajax_delete_phrase');
            wp_send_json_error(array('message' => __('Security check failed. Please refresh the page and try again.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        // Check user permissions after nonce
        if (!current_user_can('manage_options')) {
            $this->log_debug('User does not have permission to delete phrases', 'ajax_delete_phrase');
            wp_send_json_error(array('message' => __('You do not have permission to delete phrases.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        // Get and sanitize phrase ID
        $phrase_id = isset($_POST['id']) ? absint(wp_unslash($_POST['id'])) : 0;
        
        if ($phrase_id <= 0) {
            $raw_id = isset($_POST['id']) ? sanitize_text_field(wp_unslash($_POST['id'])) : 'not set';
            $this->log_debug('Invalid phrase ID received: ' . esc_html($raw_id), 'ajax_delete_phrase');
            wp_send_json_error(array('message' => __('Invalid phrase ID.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'upkyk_custom_phrases';
        $cache_key_exists = 'upkyk_table_exists_' . $table_name;
        $table_exists = wp_cache_get($cache_key_exists);

        // Check if the table exists using prepare (with caching)
        if (false === $table_exists) {
            // Check existence using prepare
            // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
            // @codingStandardsIgnoreStart
            $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name);
            // @codingStandardsIgnoreEnd
            wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS); // Cache for 1 hour
        }
        
        // Only attempt to delete if the table exists
        if ($table_exists) {
            // Check if the record exists before trying to delete (optional but good practice)
            // Caching this specific record check might be overkill unless deletes are very frequent
            // Direct DB query necessary here as we're working with a custom table
            // @codingStandardsIgnoreStart
            $exists = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT COUNT(*) FROM `" . esc_sql($table_name) . "` WHERE id = %d", 
                    $phrase_id
                )
            );
            // @codingStandardsIgnoreEnd
            if ($exists == 0) {
                $this->log_debug("Phrase ID {$phrase_id} does not exist in table", 'ajax_delete_phrase');
                wp_send_json_error(array('message' => __('Phrase does not exist.', 'upkyk-assistant-ai')));
                return;
            }

            // Delete the phrase using $wpdb->delete (handles preparation)
            // Direct DB operation necessary here as we're working with a custom table
            // @codingStandardsIgnoreStart
            $result = $wpdb->delete(
                $table_name,
                array('id' => $phrase_id),
                array('%d')
            );
            // @codingStandardsIgnoreEnd
            
            if ($result !== false) {
                // Clear caches related to custom phrases
                wp_cache_delete('upkyk_custom_phrases_qa');
                wp_cache_delete('upkyk_custom_phrases');
                wp_cache_delete('upkyk_phrases_table_status');
                
                $this->log_debug("Upkyk AssistantAI: Successfully deleted phrase ID: {$phrase_id}");
                
                wp_send_json_success(array('message' => 'Phrase deleted successfully'));
            } else {
                $this->log_debug("Upkyk AssistantAI: Failed to delete phrase ID: {$phrase_id}. DB Error: " . $wpdb->last_error);
                
                wp_send_json_error(array(
                    'message' => 'Failed to delete phrase',
                    'db_error' => $wpdb->last_error
                ));
            }
        } else {
            $this->log_debug("Table {$table_name} does not exist", 'ajax_delete_phrase');
            wp_send_json_error(array('message' => __('Database table does not exist.', 'upkyk-assistant-ai')));
        }
    }

    /**
     * AJAX handler for deleting the API key
     */
    public function ajax_delete_api_key() {
        // Process API key deletion
        
        // Verify nonce
        check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce');
        
        // Check user capabilities
        if (!current_user_can('manage_options')) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'Upkyk: User does not have manage_options capability');
            }
            wp_send_json_error(array('message' => 'Insufficient permissions'));
            return;
        }
        
        // Simply set the API key to an empty string - this is a more reliable approach than delete_option
        $updated = update_option('upkyk_assistant_ai_api_key', '');
        
        if ($updated) {
            wp_send_json_success(array('message' => 'API key deleted successfully'));
        } else {
            wp_send_json_error(array('message' => 'Failed to delete API key'));
        }
    }

    /**
     * Register admin hooks
     */
    public function register_hooks() {
        // Add admin menu
        add_action('admin_menu', array($this, 'add_admin_menu'));
        
        // Enqueue admin assets
        add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
        
        // Load API Key Diagnostics page dependencies
        add_action('admin_enqueue_scripts', array($this, 'load_api_key_diagnostics_dependencies'), 10, 1);
        
        // Register admin-specific hooks
        $this->register_admin_hooks();
        
    }

    /**
     * Handle AJAX request to delete multiple phrases
     */
    public function ajax_delete_phrases() {
        // Verify nonce first
        if (!check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce', false)) {
            $this->log_debug('Nonce verification failed', 'ajax_delete_phrases');
            wp_send_json_error(array('message' => __('Security check failed. Please refresh the page and try again.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        // Check permissions after nonce
        if (!current_user_can('manage_options')) { // Consider 'delete_plugins' or a custom capability
            $this->log_debug('Permission check failed', 'ajax_delete_phrases');
            wp_send_json_error(array('message' => __('Insufficient permissions.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        // Get and sanitize phrase IDs
        $phrase_ids_raw = isset($_POST['phrase_ids']) 
            ? array_map('absint', wp_unslash($_POST['phrase_ids'])) 
            : (isset($_POST['ids']) 
                ? array_map('absint', wp_unslash($_POST['ids'])) 
                : array()); 
        
        if (!is_array($phrase_ids_raw)) {
            $phrase_ids_raw = array(); // Ensure it's an array
        }
        
        // Sanitize each ID to be an integer
        $phrase_ids = array_map('absint', $phrase_ids_raw);
        // Filter out any resulting zeros or invalid IDs
        $phrase_ids = array_filter($phrase_ids, function($id) { return $id > 0; });

        if (empty($phrase_ids)) {
            $this->log_debug('No valid phrase IDs provided', 'ajax_delete_phrases');
            wp_send_json_error(array('message' => __('No valid phrase IDs provided.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'upkyk_custom_phrases';
        $cache_key_exists = 'upkyk_table_exists_' . $table_name;
        $table_exists = wp_cache_get($cache_key_exists);
        
        // Check if the table exists using prepare (with caching)
        if (false === $table_exists) {
             // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
             // @codingStandardsIgnoreStart
             $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name);
             // @codingStandardsIgnoreEnd
             wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS);
        }

        if (!$table_exists) {
            $this->log_debug("Table {$table_name} does not exist", 'ajax_delete_phrases');
            wp_send_json_error(array('message' => __('The phrases table does not exist.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        $deleted_count = 0;
        $error_count = 0;
        $errors = array();
        
        // Now build list of IDs to delete
        $ids_to_delete = array();
        $ids_not_found = array();
        
        foreach ($phrase_ids as $id) {
            // Check if the phrase exists before attempting to delete (optional but good practice)
            // Caching this specific record check might be overkill unless deletes are very frequent
            // Direct DB query necessary here as we're working with a custom table
            // @codingStandardsIgnoreStart
            $phrase_exists = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT COUNT(*) FROM `" . esc_sql($table_name) . "` WHERE id = %d", 
                    $id
                )
            );
            // @codingStandardsIgnoreEnd
            if ($phrase_exists == 0) {
                $ids_not_found[] = $id;
            } else {
                $ids_to_delete[] = $id;
            }
        }
        
        // Process phrase deletion
        foreach ($ids_to_delete as $id) {
            $id = intval($id);
            
            if ($id <= 0) {
                $error_count++;
                $errors[] = "Invalid ID: {$id}";
                continue;
            }
            
            // Direct DB operation necessary here as we're working with a custom table
            // @codingStandardsIgnoreStart
            $result = $wpdb->delete(
                $table_name,
                array('id' => $id),
                array('%d')
            );
            // @codingStandardsIgnoreEnd
            
            if ($result !== false) {
                // Clear caches related to custom phrases
                wp_cache_delete('upkyk_custom_phrases_qa');
                wp_cache_delete('upkyk_custom_phrases');
                wp_cache_delete('upkyk_phrases_table_status');
                
                $deleted_count++;
                
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    // Use WordPress-compatible logging approach
                    do_action('upkyk_assistant_ai_debug_log', "Upkyk AssistantAI: Successfully deleted phrase ID: {$id}");
                }
            } else {
                $error_count++;
                $errors[] = "Failed to delete phrase with ID {$id}. Database Error: " . $wpdb->last_error;
                
                if (defined('WP_DEBUG') && WP_DEBUG) {
                    // Use WordPress-compatible logging approach
                    do_action('upkyk_assistant_ai_debug_log', "Upkyk AssistantAI: Failed to delete phrase ID: {$id}. DB Error: " . $wpdb->last_error);
                }
            }
        }
        
        // Check if table is now empty and return that information
        // Direct DB query necessary here as we're working with a custom table
        // @codingStandardsIgnoreStart
        $remaining_phrases = $wpdb->get_var("SELECT COUNT(*) FROM `" . esc_sql($table_name) . "`");
        // @codingStandardsIgnoreEnd
        $is_empty = ($remaining_phrases === '0');
        
        // Prepare the response
        $response = array(
            'message' => "Successfully deleted {$deleted_count} phrase(s)",
            'success_count' => $deleted_count,
            'is_empty' => $is_empty
        );
        
        // Add any errors to the response
        if (!empty($errors)) {
            $response['errors'] = $errors;
            $response['error_count'] = $error_count;
        }
        
        // Add not found IDs if any
        if (!empty($ids_not_found)) {
            $response['not_found'] = $ids_not_found;
        }
        
        wp_send_json_success($response);
    }

    /**
     * AJAX handler for adding a custom phrase
     */
    public function ajax_add_custom_phrase() {
        // Verify nonce first
        if (!check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce', false)) {
            $this->log_debug('Nonce verification failed', 'ajax_add_custom_phrase');
            // Send 403 Forbidden for security failures
            wp_send_json_error(array('message' => __('Security check failed. Please refresh the page and try again.', 'upkyk-assistant-ai')), 403);
            // wp_send_json_* includes die()
        }
        
        // Check permissions after nonce
        if (!current_user_can('manage_options')) {
            $this->log_debug('Permission check failed', 'ajax_add_custom_phrase');
            // Send 403 Forbidden for permission failures
            wp_send_json_error(array('message' => __('Insufficient permissions.', 'upkyk-assistant-ai')), 403);
        }
        
        // Get and sanitize form data
        $question = isset($_POST['question']) ? sanitize_text_field(wp_unslash($_POST['question'])) : '';
        $answer = isset($_POST['answer']) ? sanitize_textarea_field(wp_unslash($_POST['answer'])) : '';
        $category = isset($_POST['category']) ? sanitize_text_field(wp_unslash($_POST['category'])) : 'General'; // Default category
        
        // Validate required fields
        if (empty($question) || empty($answer)) {
            // Send 400 Bad Request for invalid input data
            wp_send_json_error(array('message' => __('Question and answer are required fields.', 'upkyk-assistant-ai')), 400);
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'upkyk_custom_phrases';
        $cache_key_exists = 'upkyk_table_exists_' . $table_name;
        $table_exists = wp_cache_get($cache_key_exists);
        
        // Ensure the table exists using prepare (with caching)
        if (false === $table_exists) {
            // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
            // @codingStandardsIgnoreStart
            $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name);
            // @codingStandardsIgnoreEnd
            wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS);
        }
        
        if (!$table_exists) {
            // Try to create the table if it doesn't exist
            if (!$this->create_custom_phrases_table()) {
                // Send 500 Internal Server Error for DB infrastructure issues
                wp_send_json_error(array('message' => __('Failed to create database table.', 'upkyk-assistant-ai')), 500);
            }
            wp_cache_set($cache_key_exists, true, '', HOUR_IN_SECONDS);
        }
        
        // Direct DB operation necessary here as we're working with a custom table
        // @codingStandardsIgnoreStart
        // Insert the phrase
        $result = $wpdb->insert(
            $table_name,
            array(
                'question' => $question,
                'answer' => $answer,
                'category' => $category,
                'created_at' => current_time('mysql', 1) // Use GMT time
            ),
        // @codingStandardsIgnoreEnd
            array(
                '%s', // question
                '%s', // answer
                '%s', // category
                '%s'  // created_at
            )
        );
        
        if ($result !== false) { // insert returns false on error, or number of rows inserted (1)
            $phrase_id = $wpdb->insert_id;
            
            // Clear caches
            wp_cache_delete('upkyk_custom_phrases_qa');
            wp_cache_delete('upkyk_custom_phrases');
            wp_cache_delete('upkyk_phrases_table_status');
            wp_cache_delete('upkyk_all_phrases'); // Clear cache for the list of all phrases

            // Get the newly added phrase to return if needed by the frontend JS
            // Direct DB query necessary here as we're working with a custom table
            // @codingStandardsIgnoreStart
            $safe_table_name = esc_sql($table_name);
            $new_phrase = $wpdb->get_row(
                $wpdb->prepare(
                    "SELECT id, question, answer, category, created_at FROM `{$safe_table_name}` WHERE id = %d", 
                    $phrase_id
                ), 
                ARRAY_A
            );
            // @codingStandardsIgnoreEnd
            
            // Send 200 OK on success
            wp_send_json_success(array(
                'message' => __('Phrase added successfully.', 'upkyk-assistant-ai'),
                'phrase_id' => $phrase_id,
                'phrase' => $new_phrase // Send back the added phrase data
            ));
        } else {
            // Send 500 Internal Server Error for database write failures
            wp_send_json_error(array(
                'message' => __('Failed to add phrase to the database.', 'upkyk-assistant-ai'),
                'db_error' => $wpdb->last_error // Avoid exposing raw DB errors in production if possible
            ), 500);
        }
    }

    /**
     * AJAX handler for rebuilding database tables
     */
    public function ajax_rebuild_tables() {
        // Verify nonce first
        check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce');
        
        // Check permissions after nonce
        if (!current_user_can('manage_options')) { // Consider 'delete_plugins' or a custom capability
            wp_send_json_error(array('message' => __('You do not have permission to perform this action.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        global $wpdb;
        $phrases_table = $wpdb->prefix . 'upkyk_custom_phrases';
        $cache_key_exists = 'upkyk_table_exists_' . $phrases_table;
        $table_exists = wp_cache_get($cache_key_exists);
        
        // First check if table exists using prepare (with caching)
        if (false === $table_exists) {
             // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
             // @codingStandardsIgnoreStart
             $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $phrases_table)) == $phrases_table);
             // @codingStandardsIgnoreEnd
             wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS);
        }

        if ($table_exists) {
            // Direct DB query necessary here as WordPress doesn't provide a function to truncate custom tables
            // @codingStandardsIgnoreStart
            // Truncate the table to delete all phrases
            $wpdb->query("TRUNCATE TABLE {$phrases_table}");
            // @codingStandardsIgnoreEnd
            
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', "Upkyk AssistantAI: Phrases table truncated");
            }
        }
        
        // Recreate table if it doesn't exist
        $phrases_result = $this->create_custom_phrases_table();
        
        if ($phrases_result) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', "Upkyk AssistantAI: Tables successfully rebuilt");
            }
            wp_send_json_success(array('message' => 'Tables successfully rebuilt and all phrases removed'));
        } else {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', "Upkyk AssistantAI: Failed to rebuild tables");
            }
            
            // Get more detailed error info
            // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
            // @codingStandardsIgnoreStart
            $phrase_error = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $phrases_table)) != $phrases_table ? 
                "Failed to create phrases table" : "";
            // @codingStandardsIgnoreEnd
            
            $error_msg = empty($phrase_error) ? "Unknown error rebuilding tables" : $phrase_error;
            
            wp_send_json_error(array('message' => $error_msg));
        }
    }

    /**
     * AJAX handler for testing API models (DeepSeek and OpenAI)
     */
    public function ajax_test_api_models() {
        check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => 'You do not have permission to perform this action.'));
            return;
        }
        
        // Get the model name and provider from the request
        $model = isset($_POST['model']) ? sanitize_text_field(wp_unslash($_POST['model'])) : 'deepseek-chat';
        $provider = isset($_POST['provider']) ? sanitize_text_field(wp_unslash($_POST['provider'])) : 'deepseek';
        
        // Get the encrypted API key
        $encrypted_key = get_option('upkyk_assistant_ai_api_key', '');
        
        if (empty($encrypted_key)) {
            wp_send_json_error(array(
                'message' => 'API key is not configured. Please set an API key first.',
                'response' => null
            ));
            return;
        }
        
        // Decrypt the API key
        $api_key = $this->decrypt_api_key($encrypted_key);
        
        if (empty($api_key)) {
            wp_send_json_error(array(
                'message' => 'Failed to decrypt API key. The encryption/decryption process is not working correctly.',
                'response' => null
            ));
            return;
        }
        
        // Test message
        $test_message = "Test connection with model: " . $model;
        
        // Select API endpoint based on provider
        $url = $provider === 'openai' 
            ? 'https://api.openai.com/v1/chat/completions'
            : 'https://api.deepseek.com/v1/chat/completions';
        
        // Prepare request data
        $data = array(
            "model" => $model,
            "messages" => array(array("role" => "user", "content" => $test_message)),
            "max_tokens" => 10
        );
        
        // Send request
        $response = wp_remote_post($url, array(
            'timeout' => 30,
            'headers' => array(
                'Authorization' => 'Bearer ' . $api_key,
                'Content-Type' => 'application/json'
            ),
            'body' => json_encode($data)
        ));
        
        // Handle response
        if (is_wp_error($response)) {
            wp_send_json_error(array(
                'message' => 'Connection error: ' . $response->get_error_message(),
                'response' => array('error' => $response->get_error_message())
            ));
            return;
        }
        
        $response_code = wp_remote_retrieve_response_code($response);
        $response_body = wp_remote_retrieve_body($response);
        $body = json_decode($response_body, true);
        
        if ($response_code !== 200) {
            $error_message = isset($body['error']['message']) ? $body['error']['message'] : 'HTTP Error ' . $response_code;
            wp_send_json_error(array(
                'message' => 'API error: ' . $error_message,
                'response' => $body
            ));
            return;
        }
        
        if (!isset($body['choices'][0]['message']['content'])) {
            wp_send_json_error(array(
                'message' => 'Unexpected response format. API returned 200 but response structure is invalid.',
                'response' => $body
            ));
            return;
        }
        
        wp_send_json_success(array(
            'message' => 'Model "' . $model . '" (' . $provider . ') connected successfully!',
            'response' => $body
        ));
    }

    /**
     * AJAX handler for testing API connection
     */
    public function ajax_test_connection() {
        check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => 'You do not have permission to perform this action.'));
            return;
        }
        
        $api_key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : '';
        
        // Get provider from POST if available, otherwise use the saved option
        $provider = isset($_POST['provider']) ? sanitize_text_field(wp_unslash($_POST['provider'])) : '';
        if (empty($provider)) {
            $provider = get_option('upkyk_assistant_ai_provider', 'deepseek');
        }
        
        // Validate provider
        if (!in_array($provider, array('openai', 'deepseek'))) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'Upkyk AssistantAI: Invalid provider in API test: ' . $provider);
            }
            $provider = 'deepseek'; // Default to deepseek if invalid
        }
        
        if (defined('WP_DEBUG') && WP_DEBUG) {
            // Use WordPress-compatible logging approach
            do_action('upkyk_assistant_ai_debug_log', 'Upkyk AssistantAI: Testing connection with provider: ' . $provider);
        }
        
        if (empty($api_key)) {
            wp_send_json_error(array('message' => 'Please enter an API key.'));
            return;
        }
        
        // Test the connection using the AI class
        $result = Upkyk_AI_Service::test_connection($provider, $api_key);
        
        if ($result['success']) {
            wp_send_json_success(array('message' => 'Connection successful!'));
        } else {
            $error_message = $result['error'] ?? 'Connection failed.';
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'Upkyk AssistantAI: API test failed: ' . $error_message);
            }
            wp_send_json_error(array('message' => $error_message));
        }
    }

    /**
     * Display API diagnostics page
     */
    public function display_api_diagnostics_page() {
        // Include diagnostics page template
        require_once UPKYK_ASSISTANT_AI_PATH . 'admin/api-diagnostics-page.php';
    }
    
    /**
     * Encrypt API key before storing in the database
     * 
     * @param string $api_key The API key to encrypt
     * @return string The encrypted API key
     */
    public function encrypt_api_key($api_key) {
        if (empty($api_key)) {
            return '';
        }
        
        // Get or generate a secure encryption key
        $encryption_key = $this->get_encryption_key();
        
        // Use proper encryption (AES-256-CBC)
        $method = 'aes-256-cbc';
        $iv_length = openssl_cipher_iv_length($method);
        $iv = openssl_random_pseudo_bytes($iv_length);
        
        // Use WordPress auth keys as additional security salt
        $auth_key = defined('AUTH_KEY') ? AUTH_KEY : 'upkyk-default-auth-key';
        $salt = hash('sha256', $auth_key, true);
        
        // Create an encryption key using PBKDF2 key derivation with the salt
        $key = substr(hash_pbkdf2('sha256', $encryption_key, $salt, 1000, 32, true), 0, 32);
        
        // Encrypt the API key
        $encrypted_data = openssl_encrypt($api_key, $method, $key, OPENSSL_RAW_DATA, $iv);
        
        // Combine the IV and encrypted data and encode for storage
        $combined = $iv . $encrypted_data;
        $result = base64_encode($combined);
        
        return $result;
    }
    
    /**
     * Decrypt API key for use in API requests
     * 
     * @param string $encrypted_key The encrypted API key
     * @return string The decrypted API key
     */
    public function decrypt_api_key($encrypted_key) {
        if (empty($encrypted_key)) {
            return '';
        }
        
        // If it's just a base64 encoded string (old format), try to decode it directly
        $decoded = base64_decode($encrypted_key);
        if ($decoded !== false && $this->is_valid_utf8($decoded)) {
            return $decoded;
        }
        
        // Get the encryption key
        $encryption_key = $this->get_encryption_key();
        if (empty($encryption_key)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'UPKYK AssistantAI: Encryption key not found. Cannot decrypt API key.');
            }
            return '';
        }
        
        // Use WordPress auth keys as additional security salt
        $auth_key = defined('AUTH_KEY') ? AUTH_KEY : 'upkyk-default-auth-key';
        $salt = hash('sha256', $auth_key, true);
        
        // Create decryption key using PBKDF2 with the salt
        $key = substr(hash_pbkdf2('sha256', $encryption_key, $salt, 1000, 32, true), 0, 32);
        
        // Decode the combined IV and encrypted data
        $combined = base64_decode($encrypted_key);
        if ($combined === false) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'UPKYK AssistantAI: Failed to decode encrypted key.');
            }
            return '';
        }
        
        $method = 'aes-256-cbc';
        $iv_length = openssl_cipher_iv_length($method);
        
        // Extract IV and encrypted data
        if (strlen($combined) <= $iv_length) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'UPKYK AssistantAI: Encrypted data is too short.');
            }
            return '';
        }
        
        $iv = substr($combined, 0, $iv_length);
        $encrypted_data = substr($combined, $iv_length);
        
        // Decrypt the data
        $decrypted = openssl_decrypt($encrypted_data, $method, $key, OPENSSL_RAW_DATA, $iv);
        
        if ($decrypted === false) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'UPKYK AssistantAI: Failed to decrypt data. ' . openssl_error_string());
            }
            return '';
        }
        
        return $decrypted;
    }
    
    /**
     * Get or generate a secure encryption key
     * 
     * @return string The encryption key
     */
    private function get_encryption_key() {
        // First check if defined in wp-config (for advanced users)
        if (defined('UPKYK_ENCRYPTION_KEY')) {
            return UPKYK_ENCRYPTION_KEY;
        }
        
        // Otherwise get from database or generate if not exists
        $encryption_key = get_option('upkyk_assistant_ai_encryption_key');
        if (empty($encryption_key)) {
            // Create a very strong key
            $encryption_key = bin2hex(openssl_random_pseudo_bytes(32));
            
            // Store in database - WordPress options table is encrypted at rest in most secure hosting environments
            update_option('upkyk_assistant_ai_encryption_key', $encryption_key);
        }
        
        return $encryption_key;
    }
    
    /**
     * Check if a string is valid UTF-8 (helper for backward compatibility)
     * 
     * @param string $string The string to check
     * @return bool True if valid UTF-8, false otherwise
     */
    private function is_valid_utf8($string) {
        return mb_check_encoding($string, 'UTF-8');
    }

    /**
     * Migrate from old encryption to new encryption
     * 
     * @return bool True if migration was successful or not needed
     */
    public function maybe_migrate_encryption() {
        // Get the current encryption method
        $current_method = get_option('upkyk_assistant_ai_encryption_method', '');
        
        // If already migrated or no encryption method set, no need to continue
        if ($current_method === 'openssl' || empty($current_method)) {
            return;
        }
        
        // Get the encrypted API key
        $encrypted_key = get_option('upkyk_assistant_ai_api_key', '');
        
        // If no key is stored, no need to migrate
        if (empty($encrypted_key)) {
            // Just update the encryption method to prevent future checks
            update_option('upkyk_assistant_ai_encryption_method', 'openssl');
            return;
        }
        
        // Try to decrypt with the old method
        $api_key = '';
        try {
            // Check what method was used
            if ($current_method === 'base64') {
                // Old method was simple base64 encoding
                $api_key = base64_decode($encrypted_key);
            } else {
                // Other old method was serialize + base64 + simple key
                $temp_key = hash('sha256', SECURE_AUTH_KEY . AUTH_KEY . 'upkyk_assistant_ai');
                $encrypted_data = base64_decode($encrypted_key);
                $decrypted_data = openssl_decrypt($encrypted_data, 'aes-256-cbc', $temp_key, 0, substr($temp_key, 0, 16));
                $api_key = maybe_unserialize($decrypted_data);
            }
        } catch (Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'Upkyk AssistantAI: Failed to decrypt API key with old method: ' . $e->getMessage());
            }
                return;
        }
        
        // Validate API key
        if (empty($api_key) || !$this->is_valid_utf8($api_key)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                // Use WordPress-compatible logging approach
                do_action('upkyk_assistant_ai_debug_log', 'Upkyk AssistantAI: Decrypted API key is invalid or empty, cannot migrate.');
            }
            return;
        }
        
        // Encrypt with the new method
        $new_encrypted_key = $this->encrypt_api_key($api_key);
        
        // Save the re-encrypted key and update the method
        update_option('upkyk_assistant_ai_api_key', $new_encrypted_key);
        update_option('upkyk_assistant_ai_encryption_method', 'openssl');
        
        if (defined('WP_DEBUG') && WP_DEBUG) {
            // Use WordPress-compatible logging approach
            do_action('upkyk_assistant_ai_debug_log', 'Upkyk AssistantAI: Successfully migrated API key encryption to OpenSSL method.');
        }
    }

    /**
     * Handle test chatbot requests in admin area
     */
    public function ajax_test_assistant_ai() {
        // Verify nonce
        if (!check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce', false)) {
            wp_send_json_error(array('message' => 'Security check failed. Please refresh the page and try again.'));
            return;
        }
        
        // Get message from request
        $message = isset($_POST['message']) ? sanitize_text_field(wp_unslash($_POST['message'])) : '';
        if (empty($message)) {
            wp_send_json_error(array('message' => 'Please provide a message'));
            return;
        }
        
        // Make sure required classes are loaded
        if (!class_exists('Upkyk_AI_Service')) {
            if (!file_exists(UPKYK_ASSISTANT_AI_PATH . 'includes/class-upkyk-ai-service.php')) {
                wp_send_json_error(array('message' => 'AI Service class file not found'));
                return;
            }
            
            require_once UPKYK_ASSISTANT_AI_PATH . 'includes/class-upkyk-ai-service.php';
        }
        
        try {
            // Check custom phrases first
            $custom_phrase_response = Upkyk_AI_Service::check_custom_phrases($message);
            if (!empty($custom_phrase_response)) {
                // We found a custom phrase match
                // Log this for debugging
                if (class_exists('Upkyk_Logger')) { // Check if logger exists
                    Upkyk_Logger::debug('Upkyk Admin Test: Matched custom phrase');
                }
                wp_send_json_success(array(
                    'response' => $custom_phrase_response, // Send the raw phrase back
                    'debug_info' => ['source' => 'custom_phrase'] // Indicate source
                ));
                return; // Stop processing
            }
            
            // Enable debug mode for testing
            $debug = true;
            
            // Format message for AI in the correct structure
            $formatted_messages = [
                [
                    'role' => 'user',
                    'content' => $message
                ]
            ];
            
            // Call the chat_with_ai method with proper parameters
            $response = Upkyk_AI_Service::chat_with_ai($formatted_messages, '', [], $debug);
            
            if ($response['success']) {
                wp_send_json_success(array(
                    'response' => $response['message'],
                    'debug' => $debug ? $response['debug'] : null
                ));
            } else {
                $error_message = $response['message'] ?? 'Unknown error occurred';
                wp_send_json_error(array(
                    'message' => $error_message,
                    'debug' => $debug ? $response['debug'] : null
                ));
            }
        } catch (Exception $e) {
            wp_send_json_error(array('message' => 'Error processing your request: ' . $e->getMessage()));
        }
    }

    /**
     * Load API Key Diagnostics dependencies
     */
    public function load_api_key_diagnostics_dependencies($hook) { // Add $hook parameter
        // Only load on the API Diagnostics page
        if ($hook !== 'assistant-ai_page_upkyk-assistant-ai-diagnostics') {
            return;
        }

        // Enqueue the script
        wp_enqueue_script(
            'upkyk-assistant-ai-diagnostics-js', 
            UPKYK_ASSISTANT_AI_URL . 'admin/js/api-diagnostics.js', 
            array('jquery'), 
            UPKYK_ASSISTANT_AI_VERSION, 
            true
        );

        // Localize the script with necessary data
        wp_localize_script('upkyk-assistant-ai-diagnostics-js', 'upkykApiDiag', array(
            'ajax_url' => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('upkyk_assistant_ai_nonce'),
            'error_general' => esc_html__('An unexpected error occurred. Please check the browser console or debug log for details.', 'upkyk-assistant-ai'),
            'error_permission' => esc_html__('You do not have permission to perform this action.', 'upkyk-assistant-ai'),
            'error_invalid_action' => esc_html__('Invalid action specified.', 'upkyk-assistant-ai'),
            'text_testing' => esc_html__('Testing...', 'upkyk-assistant-ai'),
            'text_checking' => esc_html__('Checking...', 'upkyk-assistant-ai'),
            'text_rebuilding' => esc_html__('Rebuilding tables...', 'upkyk-assistant-ai'),
            'text_deleting' => esc_html__('Deleting tables...', 'upkyk-assistant-ai'),
            'text_test_api_models' => esc_html__('Test API Models', 'upkyk-assistant-ai'),
            'text_check_connection' => esc_html__('Check Connection Status', 'upkyk-assistant-ai'),
            'text_rebuild_tables' => esc_html__('Rebuild Plugin Tables', 'upkyk-assistant-ai'),
            'text_delete_tables' => esc_html__('Delete Plugin Tables', 'upkyk-assistant-ai'),
            'confirm_rebuild' => esc_html__('Are you sure you want to rebuild the plugin tables? This will attempt to recreate them based on the required schema.', 'upkyk-assistant-ai'),
            'confirm_delete' => esc_html__('EXTREME CAUTION! Are you absolutely sure you want to delete all Upkyk Assistant AI database tables? This will permanently remove all custom phrases and logs. This action cannot be undone.', 'upkyk-assistant-ai'),
            'status_success' => esc_html__('Success', 'upkyk-assistant-ai'),
            'status_error' => esc_html__('Error', 'upkyk-assistant-ai'),
            // Add any other text strings needed by api-diagnostics.js here
        ));
    }

    /**
     * Register hooks for admin initialization
     */
    public function register_admin_hooks() {
        // Register settings
        add_action('admin_init', array($this, 'register_settings'));
        
        // Register AJAX handlers during admin_init
        add_action('admin_init', array($this, 'register_ajax_handlers'));
        
        // Display admin notice for missing API key
        add_action('admin_notices', array($this, 'display_api_key_notice'));
        
        // Handle AJAX for deleting or testing API key
        add_action('wp_ajax_upkyk_delete_api_key', array($this, 'ajax_delete_api_key'));
        add_action('wp_ajax_upkyk_test_api_connection', array($this, 'ajax_test_api_connection'));
        
        // Handle AJAX for checking connection status
        add_action('wp_ajax_upkyk_check_connection_status', array($this, 'ajax_check_connection_status'));
        
        // Handle AJAX for importing/exporting settings
        add_action('wp_ajax_upkyk_export_settings', array($this, 'ajax_export_settings'));
        add_action('wp_ajax_upkyk_import_settings', array($this, 'ajax_import_settings'));
    }

    /**
     * AJAX handler for testing API connection
     */
    public function ajax_test_api_connection() {
        // Add any additional logic you want to execute when testing API connection
        wp_send_json_success(array('message' => 'API connection test successful'));
    }

    /**
     * AJAX handler for checking connection status
     */
    public function ajax_check_connection_status() {
        // Add any additional logic you want to execute when checking connection status
        wp_send_json_success(array('message' => 'Connection status check successful'));
    }
    
    /**
     * Display admin notice if API key is missing
     */
    public function display_api_key_notice() {
        // Only show on our plugin pages
        $screen = get_current_screen();
        if (!$screen || strpos($screen->id, 'upkyk-assistant-ai') === false) {
            return;
        }
        
        // Check if API key is missing
        $api_key = get_option('upkyk_assistant_ai_api_key', '');
        if (empty($api_key)) {
            $api_tab_url = wp_nonce_url(
                admin_url('admin.php?page=upkyk-assistant-ai&tab=api-key'),
                'upkyk_assistant_ai_tab_nonce',
                'upkyk_tab_nonce'
            );
            echo '<div class="notice notice-warning is-dismissible">';
            echo '<p><strong>' . esc_html__('Upkyk Assistant AI Notice:', 'upkyk-assistant-ai') . '</strong> ' . 
                 sprintf(
                     /* translators: %1$s: opening link tag, %2$s: closing link tag */
                     esc_html__('An API key is required for the Assistant AI to function. Please %1$sconfigure your API key%2$s to get started.', 'upkyk-assistant-ai'),
                     '<a href="' . esc_url($api_tab_url) . '">',
                     '</a>'
                 ) . '</p>';
            echo '</div>';
        }
    }

    /**
     * AJAX handler for exporting settings
     */
    public function ajax_export_settings() {
        // Add any additional logic you want to execute when exporting settings
        wp_send_json_success(array('message' => 'Settings export successful'));
    }

    /**
     * AJAX handler for importing settings
     */
    public function ajax_import_settings() {
        // Add any additional logic you want to execute when importing settings
        wp_send_json_success(array('message' => 'Settings import successful'));
    }

    /**
     * Add metaboxes to post edit screens
     */
    public function add_metaboxes() {
        // No metaboxes currently implemented
    }
    
    /**
     * Save metabox data
     * 
     * @param int $post_id The ID of the post being saved
     */
    public function save_metabox_data($post_id) {
        // No metabox data to save currently
    }

    /**
     * Register AJAX handlers for the chat history page
     */
    public function register_ajax_handlers() {
        // Only add AJAX handlers if user has appropriate capabilities
        if (!current_user_can('manage_options')) {
            return;
        }

        // Add main AJAX handlers
        add_action('wp_ajax_upkyk_generate_preview', array($this, 'ajax_generate_preview'));
        // Removed: add_action('wp_ajax_upkyk_verify_account', array($this, 'ajax_verify_account'));
        add_action('wp_ajax_upkyk_test_connection', array($this, 'ajax_test_connection'));
        add_action('wp_ajax_upkyk_test_assistant_ai', array($this, 'ajax_test_assistant_ai'));
        add_action('wp_ajax_upkyk_delete_all_tables', array($this, 'ajax_delete_all_tables')); // For database maintenance
        add_action('wp_ajax_upkyk_rebuild_tables', array($this, 'ajax_rebuild_tables')); // For database rebuilding
        // Removed: add_action('wp_ajax_upkyk_assistant_ai_upload_svg', array($this, 'ajax_upload_svg')); // Add SVG upload handler
        // Removed: add_action('wp_ajax_upkyk_assistant_ai_remove_svg', array($this, 'ajax_remove_svg')); // Add SVG remove handler

        // Phrase management AJAX handlers
        add_action('wp_ajax_upkyk_add_phrase', array($this, 'ajax_add_custom_phrase'));
        add_action('wp_ajax_upkyk_delete_phrase', array($this, 'ajax_delete_phrase'));
        add_action('wp_ajax_upkyk_delete_phrases', array($this, 'ajax_delete_phrases'));
        add_action('wp_ajax_upkyk_get_training_data', array($this, 'ajax_get_training_data'));
        
        // Register AJAX handlers complete
    }

    /**
     * AJAX handler for import/export
     */
    public function ajax_import_export() {
        check_ajax_referer('upkyk_admin_nonce', 'nonce');
        
        // Get the action
        $action = isset($_POST['action_type']) ? sanitize_text_field(wp_unslash($_POST['action_type'])) : '';
        
        if (empty($action)) {
            wp_send_json_error(['message' => 'No action specified']);
            return;
        }
        
        // Handle the action
        switch ($action) {
            case 'export':
                $this->handle_export();
                break;
            case 'import':
                $this->handle_import();
                break;
            default:
            // No other actions are supported
            break;
        }
    }

    /**
     * AJAX handler for getting training data
     */
    public function ajax_get_training_data() {
        // Check nonce first
        check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce');
        
        // Check permissions after nonce
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => __('You do not have permission to perform this action.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        // Training data structure
        $training_data = array(
            'phrases' => array(),
            'documents' => array(), // Keep structure consistent, but documents will be empty
        );
        
        // Get custom phrases 
        global $wpdb;
        $phrases_table = $wpdb->prefix . 'upkyk_custom_phrases';
        $cache_key_exists = 'upkyk_table_exists_' . $phrases_table;
        $table_exists = wp_cache_get($cache_key_exists);

        // Check if table exists using prepare (with caching)
        if (false === $table_exists) {
             // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
             // @codingStandardsIgnoreStart
             $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $phrases_table)) == $phrases_table);
             // @codingStandardsIgnoreEnd
             wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS);
        }

        if ($table_exists) {
            // Use prepare for the SELECT query
            // Note: Selecting specific columns is better than SELECT *
            $cache_key_phrases = 'upkyk_all_phrases';
            $phrases = wp_cache_get($cache_key_phrases);
            if (false === $phrases) {
                // Direct DB query necessary here as we're working with a custom table
                // @codingStandardsIgnoreStart
                $phrases = $wpdb->get_results(
                    $wpdb->prepare(
                        "SELECT id, question, answer, category, created_at FROM `" . esc_sql($phrases_table) . "` ORDER BY id DESC" 
                    ),
                // @codingStandardsIgnoreEnd
                    ARRAY_A // Return as associative array
                );
                 wp_cache_set($cache_key_phrases, $phrases, '', 5 * MINUTE_IN_SECONDS); // Cache phrases for 5 mins
            }
            
            if (!empty($phrases)) {
                $training_data['phrases'] = $phrases;
            }
        }
        
        wp_send_json_success($training_data);
    }

    /**
     * AJAX handler for deleting all plugin tables
     */
    public function ajax_delete_all_tables() {
        // Check nonce first
        check_ajax_referer('upkyk_assistant_ai_nonce', 'nonce');
        
        // Check permissions after nonce - critical action!
        if (!current_user_can('manage_options')) { // Consider 'delete_plugins' or a custom capability
            wp_send_json_error(array('message' => __('You do not have permission to perform this action.', 'upkyk-assistant-ai')));
            return; // Stop execution
        }
        
        global $wpdb;
        $tables_deleted = 0;
        $errors = array();
        
        // List of tables specific to this plugin
        $plugin_tables = array(
            $wpdb->prefix . 'upkyk_custom_phrases',
            // $wpdb->prefix . 'upkyk_training_documents', // Documents table likely not used in Core
            // Add any other tables managed by this plugin
        );
        
        // Delete each table
        foreach ($plugin_tables as $table) {
            $cache_key_exists = 'upkyk_table_exists_' . $table;
            $table_exists = wp_cache_get($cache_key_exists);
            
            // Check if table exists using prepare (with caching)
            if (false === $table_exists) {
                // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
                // @codingStandardsIgnoreStart
                $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table)) == $table);
                // @codingStandardsIgnoreEnd
                wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS);
            }

            if ($table_exists) {
                // Direct DB query necessary here as WordPress doesn't provide a function to drop custom tables
                // @codingStandardsIgnoreStart
                // Escape table name for use in DROP TABLE (cannot be prepared)
                $table_esc = esc_sql($table); 
                // Drop the table
                $result = $wpdb->query("DROP TABLE IF EXISTS {$table_esc}");
                // @codingStandardsIgnoreEnd
                
                if ($result !== false) {
                    $tables_deleted++;
                } else {
                    $errors[] = "Failed to delete table: {$table}";
                }
            }
        }
        
        // Clear related caches
        wp_cache_delete('upkyk_custom_phrases_qa');
        wp_cache_delete('upkyk_custom_phrases');
        wp_cache_delete('upkyk_phrases_table_status');
        wp_cache_delete('upkyk_training_tables_exist');
        wp_cache_delete('upkyk_processed_files');
        
        // Return result
        if (empty($errors)) {
            wp_send_json_success(array(
                'message' => "Successfully deleted {$tables_deleted} table(s).",
                'tables_deleted' => $tables_deleted
            ));
        } else {
            wp_send_json_error(array(
                'message' => "Deleted {$tables_deleted} table(s), but encountered errors: " . implode(", ", $errors),
                'tables_deleted' => $tables_deleted,
                'errors' => $errors
            ));
        }
    }

    /**
     * Sanitize allowed pages array
     *
     * @param mixed $value The value to sanitize
     * @return array Array of sanitized page IDs
     */
    public function sanitize_allowed_pages($value) {
        if (!is_array($value)) {
            return array();
        }
        // Ensure all values are integers
        return array_map('absint', $value);
    }

    // NEW: Callback for Allowed Pages
    public function allowed_pages_callback() {
        $allowed_pages = get_option('upkyk_assistant_ai_allowed_pages', array());
        $pages = get_pages(array(
            'post_status' => 'publish,private' // Include private pages as well
        ));
        
        if (empty($pages)) {
            echo '<p>' . esc_html__('No published pages found.', 'upkyk-assistant-ai') . '</p>';
            return;
        }
        
        echo '<select id="upkyk_assistant_ai_allowed_pages" name="upkyk_assistant_ai_allowed_pages[]" multiple style="min-height: 150px; width: 100%; max-width: 400px;">';
        
        foreach ($pages as $page) {
            $selected = in_array($page->ID, $allowed_pages) ? 'selected="selected"' : '';
            echo '<option value="' . esc_attr($page->ID) . '" ' . esc_attr($selected) . ' >' . esc_html($page->post_title) . ' (ID: ' . esc_html($page->ID) . ')</option>';
        }
        
        echo '</select>';
        echo '<p class="description">' . esc_html__('Hold Command (Mac) or Control (PC) to select multiple pages.', 'upkyk-assistant-ai') . '</p>';
    }

    public function disable_on_mobile_callback() {
        // ... existing code ...
    }

    /**
     * Helper function to check if a database table exists
     * 
     * @param string $table_name The name of the table to check
     * @return bool True if the table exists, false otherwise
     */
    private function check_table_exists($table_name) {
        global $wpdb;
        
        $cache_key_exists = 'upkyk_table_exists_' . $table_name;
        $table_exists = wp_cache_get($cache_key_exists);
        
        // Check if table exists using prepare (with caching)
        if (false === $table_exists) {
            // Check existence using prepare
            // Direct DB query necessary here as WordPress doesn't provide a function to check if a table exists
            // @codingStandardsIgnoreStart
            $table_exists = ($wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name)) == $table_name);
            // @codingStandardsIgnoreEnd
            wp_cache_set($cache_key_exists, $table_exists, '', HOUR_IN_SECONDS); // Cache for 1 hour
        }
        
        return $table_exists;
    }
} // Close the class Upkyk_Assistant_AI_Admin