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

/**
 * Admin Chatbot Handler
 *
 * Handles chatbot-related AJAX requests.
 *
 * @package    Kitsune_AI_Platform
 * @subpackage Kitsune_AI_Platform/admin
 */
class Kitsune_AI_Platform_Admin_Chatbot extends Kitsune_AI_Platform_Admin_Ajax_Base {

    /**
     * Register AJAX hooks.
     */
    public function register_hooks() {
        add_action('wp_ajax_kitsune_ai_platform_get_chatbots', array($this, 'ajax_get_chatbots'));
        add_action('wp_ajax_kitsune_ai_platform_get_chatbot', array($this, 'ajax_get_chatbot'));
        add_action('wp_ajax_kitsune_ai_platform_create_chatbot', array($this, 'ajax_create_chatbot'));
        add_action('wp_ajax_kitsune_ai_platform_update_chatbot', array($this, 'ajax_update_chatbot'));
        add_action('wp_ajax_kitsune_ai_platform_delete_chatbot', array($this, 'ajax_delete_chatbot'));
        add_action('wp_ajax_kitsune_ai_platform_duplicate_chatbot', array($this, 'ajax_duplicate_chatbot'));
        add_action('wp_ajax_kitsune_ai_platform_get_chatbot_stats', array($this, 'ajax_get_chatbot_stats'));
        add_action('wp_ajax_kitsune_ai_platform_get_chatbot_templates', array($this, 'ajax_get_chatbot_templates'));
        add_action('wp_ajax_kitsune_ai_platform_create_chatbot_template', array($this, 'ajax_create_chatbot_template'));
        add_action('wp_ajax_kitsune_ai_platform_delete_chatbot_template', array($this, 'ajax_delete_chatbot_template'));
        add_action('wp_ajax_kitsune_ai_platform_get_conversation_logs', array($this, 'ajax_get_conversation_logs'));
        add_action('wp_ajax_kitsune_ai_platform_chatbot_preview_message', array($this, 'ajax_chatbot_preview_message'));
        add_action('wp_ajax_kitsune_ai_platform_get_chatbot_avatar_icons', array($this, 'ajax_get_chatbot_avatar_icons'));
        add_action('wp_ajax_kitsune_ai_platform_upload_chatbot_avatar', array($this, 'ajax_upload_chatbot_avatar'));
    }

    /**
     * AJAX: Get chatbot avatar icon catalog.
     */
    public function ajax_get_chatbot_avatar_icons() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        wp_send_json_success(array(
            'icons' => $this->get_avatar_icon_catalog(),
        ));
    }

    /**
     * AJAX: Upload custom chatbot avatar.
     */
    public function ajax_upload_chatbot_avatar() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        if (empty($_FILES['avatar']) || !isset($_FILES['avatar']['tmp_name'])) {
            wp_send_json_error(array('message' => __('Avatar file is required.', 'kitsune-ai-platform')));
            return;
        }

        $file = $_FILES['avatar']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

        if (!empty($file['error'])) {
            wp_send_json_error(array('message' => __('Failed to upload avatar.', 'kitsune-ai-platform')));
            return;
        }

        $tmp_path = $file['tmp_name'];
        $image_size = @getimagesize($tmp_path);
        if (!$image_size || empty($image_size[0]) || empty($image_size[1])) {
            wp_send_json_error(array('message' => __('Uploaded file is not a valid image.', 'kitsune-ai-platform')));
            return;
        }

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

        $uploads = wp_upload_dir();
        $avatar_dir = trailingslashit($uploads['basedir']) . 'ai-platform/chatbot-avatars';
        $avatar_url_base = trailingslashit($uploads['baseurl']) . 'ai-platform/chatbot-avatars';

        if (!wp_mkdir_p($avatar_dir)) {
            wp_send_json_error(array('message' => __('Failed to prepare avatar upload directory.', 'kitsune-ai-platform')));
            return;
        }

        $filename = wp_unique_filename($avatar_dir, 'chatbot-avatar-' . time() . '.png');
        $target_path = trailingslashit($avatar_dir) . $filename;

        $editor = wp_get_image_editor($tmp_path);
        if (is_wp_error($editor)) {
            wp_send_json_error(array('message' => __('Failed to process avatar image.', 'kitsune-ai-platform')));
            return;
        }

        $dimensions = $editor->get_size();
        $width = isset($dimensions['width']) ? intval($dimensions['width']) : 0;
        $height = isset($dimensions['height']) ? intval($dimensions['height']) : 0;
        $side = min($width, $height);

        if ($side <= 0) {
            wp_send_json_error(array('message' => __('Invalid avatar dimensions.', 'kitsune-ai-platform')));
            return;
        }

        $src_x = (int) floor(($width - $side) / 2);
        $src_y = (int) floor(($height - $side) / 2);
        $crop_result = $editor->crop($src_x, $src_y, $side, $side, 256, 256, false);
        if (is_wp_error($crop_result)) {
            wp_send_json_error(array('message' => __('Failed to crop avatar image.', 'kitsune-ai-platform')));
            return;
        }

        $saved = $editor->save($target_path, 'image/png');
        if (is_wp_error($saved) || empty($saved['path'])) {
            wp_send_json_error(array('message' => __('Failed to save avatar image.', 'kitsune-ai-platform')));
            return;
        }

        $avatar_url = trailingslashit($avatar_url_base) . $filename;

        wp_send_json_success(array(
            'url' => esc_url_raw($avatar_url),
        ));
    }

    /**
     * AJAX: Get Chatbots
     */
    public function ajax_get_chatbots() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/models/class-kitsune-ai-platform-chatbot-model.php';
        $model = new Kitsune_AI_Platform_Chatbot_Model();

        $page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
        $per_page = isset($_GET['per_page']) ? min(100, max(1, intval($_GET['per_page']))) : 20;
        $search = isset($_GET['search']) ? sanitize_text_field(wp_unslash($_GET['search'])) : '';
        $args = array(
            'limit' => $per_page,
            'offset' => ($page - 1) * $per_page,
            'search' => $search
        );

        $chatbots = $model->get_all($args);
        $total = $model->count_all($search);

        wp_send_json_success(array(
            'chatbots' => $chatbots,
            'total' => $total
        ));
    }

    /**
     * AJAX: Get Chatbot
     */
    public function ajax_get_chatbot() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
        if (!$id) {
            wp_send_json_error(array('message' => __('ID required', 'kitsune-ai-platform')));
            return;
        }

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/models/class-kitsune-ai-platform-chatbot-model.php';
        $model = new Kitsune_AI_Platform_Chatbot_Model();
        $chatbot = $model->get($id);

        if (!$chatbot) {
            wp_send_json_error(array('message' => __('Chatbot not found', 'kitsune-ai-platform')));
            return;
        }

        wp_send_json_success($chatbot);
    }

    /**
     * AJAX: Create Chatbot
     */
    public function ajax_create_chatbot() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $data = $this->get_post_payload('data', array());
        if (!$data) {
            $data = map_deep(wp_unslash($_POST), 'sanitize_text_field');
        }
        $data = apply_filters('kitsune_ai_platform_before_create_chatbot_data', $data);
        if (!is_array($data)) {
            $data = array();
        }
        $data = $this->sanitize_and_validate_chatbot_payload($data);
        if (is_wp_error($data)) {
            wp_send_json_error(array('message' => $data->get_error_message()));
            return;
        }

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/models/class-kitsune-ai-platform-chatbot-model.php';
        $model = new Kitsune_AI_Platform_Chatbot_Model();
        
        $result = $model->create($data);

        if (is_wp_error($result)) {
            wp_send_json_error(array('message' => $result->get_error_message()));
        } else {
            $chatbot = $model->get($result);

            do_action('kitsune_ai_platform_chatbot_created', $result, $data, $chatbot);
            Kitsune_AI_Platform_Webhook_Dispatcher::dispatch(
                Kitsune_AI_Platform_Webhook_Events::CHATBOT_CREATED,
                array(
                    'chatbot_id' => (int) $result,
                    'chatbot' => $chatbot,
                    'data' => $data,
                    'actor_id' => get_current_user_id(),
                )
            );

            $response_data = array(
                'message' => __('Chatbot created successfully', 'kitsune-ai-platform'),
                'chatbot' => $chatbot,
            );

            $response_data = apply_filters('kitsune_ai_platform_create_chatbot_response', $response_data, $result, $data, $chatbot);
            wp_send_json_success($response_data);
        }
    }

    /**
     * AJAX: Update Chatbot
     */
    public function ajax_update_chatbot() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        if (!$id) {
            // Try to get ID from data provided
            $data = $this->get_post_payload('data', array());
            if (!$data) {
                $data = map_deep(wp_unslash($_POST), 'sanitize_text_field');
            }
            $id = isset($data['id']) ? intval($data['id']) : 0;
        }

        if (!$id) {
            wp_send_json_error(array('message' => __('ID required', 'kitsune-ai-platform')));
            return;
        }

        $data = $this->get_post_payload('data', array());
        if (!$data && isset($_POST['name'])) {
            $data = map_deep(wp_unslash($_POST), 'sanitize_text_field');
        }
        $data = apply_filters('kitsune_ai_platform_before_update_chatbot_data', $data, $id);
        if (!is_array($data)) {
            $data = array();
        }
        $data = $this->sanitize_and_validate_chatbot_payload($data);
        if (is_wp_error($data)) {
            wp_send_json_error(array('message' => $data->get_error_message()));
            return;
        }

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/models/class-kitsune-ai-platform-chatbot-model.php';
        $model = new Kitsune_AI_Platform_Chatbot_Model();
        
        $result = $model->update($id, $data);

        if (is_wp_error($result)) {
            wp_send_json_error(array('message' => $result->get_error_message()));
        } else {
            $chatbot = $model->get($id);

            do_action('kitsune_ai_platform_chatbot_updated', $id, $data, $chatbot);
            Kitsune_AI_Platform_Webhook_Dispatcher::dispatch(
                Kitsune_AI_Platform_Webhook_Events::CHATBOT_UPDATED,
                array(
                    'chatbot_id' => (int) $id,
                    'chatbot' => $chatbot,
                    'data' => $data,
                    'actor_id' => get_current_user_id(),
                )
            );

            $response_data = array(
                'message' => __('Chatbot updated successfully', 'kitsune-ai-platform'),
                'chatbot' => $chatbot,
            );

            $response_data = apply_filters('kitsune_ai_platform_update_chatbot_response', $response_data, $id, $data, $chatbot);
            wp_send_json_success($response_data);
        }
    }

    /**
     * AJAX: Delete Chatbot
     */
    public function ajax_delete_chatbot() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        if (!$id) {
            wp_send_json_error(array('message' => __('ID required', 'kitsune-ai-platform')));
            return;
        }

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/models/class-kitsune-ai-platform-chatbot-model.php';
        $model = new Kitsune_AI_Platform_Chatbot_Model();
        $chatbot = $model->get($id);
        
        $result = $model->delete($id);

        if ($result) {
            do_action('kitsune_ai_platform_chatbot_deleted', $id, $chatbot);
            Kitsune_AI_Platform_Webhook_Dispatcher::dispatch(
                Kitsune_AI_Platform_Webhook_Events::CHATBOT_DELETED,
                array(
                    'chatbot_id' => (int) $id,
                    'chatbot' => $chatbot,
                    'actor_id' => get_current_user_id(),
                )
            );

            $response_data = array('message' => __('Chatbot deleted successfully', 'kitsune-ai-platform'));
            $response_data = apply_filters('kitsune_ai_platform_delete_chatbot_response', $response_data, $id, $chatbot);
            wp_send_json_success($response_data);
        } else {
            wp_send_json_error(array('message' => __('Failed to delete chatbot', 'kitsune-ai-platform')));
        }
    }

    /**
     * AJAX: Duplicate chatbot
     */
    public function ajax_duplicate_chatbot() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $id = isset($_POST['id']) ? intval($_POST['id']) : 0;
        if (!$id) {
            wp_send_json_error(array('message' => __('ID required', 'kitsune-ai-platform')));
            return;
        }

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/models/class-kitsune-ai-platform-chatbot-model.php';
        $model = new Kitsune_AI_Platform_Chatbot_Model();
        $result = $model->duplicate($id);

        if (is_wp_error($result)) {
            wp_send_json_error(array('message' => $result->get_error_message()));
        } else {
            wp_send_json_success(array(
                'message' => __('Chatbot duplicated successfully', 'kitsune-ai-platform'),
                'chatbot' => $model->get($result)
            ));
        }
    }

    /**
     * AJAX: Get chatbot stats
     */
    public function ajax_get_chatbot_stats() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $id = isset($_GET['id']) ? intval($_GET['id']) : 0;
        if (!$id) {
            wp_send_json_error(array('message' => __('ID required', 'kitsune-ai-platform')));
            return;
        }

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/models/class-kitsune-ai-platform-chatbot-model.php';
        $model = new Kitsune_AI_Platform_Chatbot_Model();
        $stats = $model->get_stats($id);

        wp_send_json_success($stats);
    }

    /**
     * AJAX: Get chatbot templates
     */
    public function ajax_get_chatbot_templates() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $templates = get_option('kitsune_ai_platform_chatbot_templates', array());

        if (empty($templates)) {
            $templates = array(
                array(
                    'id' => 'support-agent',
                    'name' => __('Customer Support Agent', 'kitsune-ai-platform'),
                    'description' => __('A helpful assistant that handles customer support queries and provides quick solutions.', 'kitsune-ai-platform'),
                    'icon' => 'fa-headset',
                    'config' => array(
                        'system_prompt' => __('You are a helpful customer support agent. Be polite, concise, and helpful. If you cannot solve the issue, offer to escalate to a human agent.', 'kitsune-ai-platform'),
                        'welcome_message' => __('Hello! How can I help you today?', 'kitsune-ai-platform'),
                        'temperature' => 0.7,
                    ),
                ),
                array(
                    'id' => 'sales-assistant',
                    'name' => __('Sales Assistant', 'kitsune-ai-platform'),
                    'description' => __('An AI assistant that helps with product inquiries and guides customers through the sales process.', 'kitsune-ai-platform'),
                    'icon' => 'fa-cart-shopping',
                    'config' => array(
                        'system_prompt' => __('You are a friendly sales assistant. Help customers find the right products, answer questions about features and pricing, and guide them toward making a purchase.', 'kitsune-ai-platform'),
                        'welcome_message' => __('Welcome! Looking for something specific today?', 'kitsune-ai-platform'),
                        'temperature' => 0.8,
                    ),
                ),
                array(
                    'id' => 'faq-bot',
                    'name' => __('FAQ Bot', 'kitsune-ai-platform'),
                    'description' => __('Answers frequently asked questions based on your knowledge base content.', 'kitsune-ai-platform'),
                    'icon' => 'fa-comments',
                    'config' => array(
                        'system_prompt' => __('You are an FAQ assistant. Answer questions based on the provided knowledge base. If the answer is not in the knowledge base, politely say you don\'t have that information.', 'kitsune-ai-platform'),
                        'welcome_message' => __('Hi! I can help answer your questions. What would you like to know?', 'kitsune-ai-platform'),
                        'temperature' => 0.5,
                    ),
                ),
            );
        }

        wp_send_json_success($templates);
    }

    /**
     * AJAX: Create chatbot template
     */
    public function ajax_create_chatbot_template() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $data = $this->get_post_payload('data', array());
        if (!$data) {
            $data = map_deep(wp_unslash($_POST), 'sanitize_text_field');
        }

        $templates = get_option('kitsune_ai_platform_chatbot_templates', array());
        $new_id = uniqid('tpl_');
        $data['id'] = $new_id;
        $templates[$new_id] = $data;

        update_option('kitsune_ai_platform_chatbot_templates', $templates);

        wp_send_json_success($data);
    }

    /**
     * AJAX: Delete chatbot template
     */
    public function ajax_delete_chatbot_template() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        $id = isset($_POST['id']) ? sanitize_text_field(wp_unslash($_POST['id'])) : '';
        if (!$id) {
            wp_send_json_error(array('message' => __('ID required', 'kitsune-ai-platform')));
            return;
        }

        $templates = get_option('kitsune_ai_platform_chatbot_templates', array());
        if (isset($templates[$id])) {
            unset($templates[$id]);
            update_option('kitsune_ai_platform_chatbot_templates', $templates);
        }

        wp_send_json_success(array('message' => __('Template deleted', 'kitsune-ai-platform')));
    }

    /**
     * AJAX: Get conversation logs
     */
    public function ajax_get_conversation_logs() {
        if (!$this->verify_admin_request('chatbots')) {
            return;
        }

        global $wpdb;
        $logs_table = $wpdb->prefix . 'kitsune_ai_platform_chat_logs';

        $page = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
        $per_page = isset($_GET['per_page']) ? min(100, max(1, intval($_GET['per_page']))) : 20;
        $offset = ($page - 1) * $per_page;

        $where_clauses = array('1=1');
        $where_params = array();

        if (!empty($_GET['chatbot_id'])) {
            $chatbot_id = intval($_GET['chatbot_id']);
            if (!empty($_GET['search'])) {
                $search = '%' . $wpdb->esc_like(sanitize_text_field(wp_unslash($_GET['search']))) . '%';
                
                $logs_query = $wpdb->prepare(
                    "SELECT * FROM {$logs_table} WHERE chatbot_id = %d AND (user_message LIKE %s OR ai_response LIKE %s) ORDER BY created_at DESC LIMIT %d, %d",
                    $chatbot_id, $search, $search, $offset, $per_page
                );
                $total_query = $wpdb->prepare(
                    "SELECT COUNT(*) FROM {$logs_table} WHERE chatbot_id = %d AND (user_message LIKE %s OR ai_response LIKE %s)",
                    $chatbot_id, $search, $search
                );
            } else {
                $logs_query = $wpdb->prepare(
                    "SELECT * FROM {$logs_table} WHERE chatbot_id = %d ORDER BY created_at DESC LIMIT %d, %d",
                    $chatbot_id, $offset, $per_page
                );
                $total_query = $wpdb->prepare(
                    "SELECT COUNT(*) FROM {$logs_table} WHERE chatbot_id = %d",
                    $chatbot_id
                );
            }
        } else {
            if (!empty($_GET['search'])) {
                $search = '%' . $wpdb->esc_like(sanitize_text_field(wp_unslash($_GET['search']))) . '%';
                
                $logs_query = $wpdb->prepare(
                    "SELECT * FROM {$logs_table} WHERE (user_message LIKE %s OR ai_response LIKE %s) ORDER BY created_at DESC LIMIT %d, %d",
                    $search, $search, $offset, $per_page
                );
                $total_query = $wpdb->prepare(
                    "SELECT COUNT(*) FROM {$logs_table} WHERE (user_message LIKE %s OR ai_response LIKE %s)",
                    $search, $search
                );
            } else {
                $logs_query = $wpdb->prepare(
                    "SELECT * FROM {$logs_table} ORDER BY created_at DESC LIMIT %d, %d",
                    $offset, $per_page
                );
                $total_query = "SELECT COUNT(*) FROM {$logs_table}";
            }
        }

        $logs = $wpdb->get_results($logs_query);
        $total = (int) (is_string($total_query) ? $wpdb->get_var($total_query) : $wpdb->get_var($total_query));

        wp_send_json_success(array(
            'logs' => $logs,
            'total' => $total
        ));
    }

    /**
     * AJAX: Chatbot preview message
     */
    public function ajax_chatbot_preview_message() {
        if (!$this->verify_editor_request()) {
            return;
        }

        $data = $this->get_post_payload('data', array());
        if (!$data) {
            $data = map_deep(wp_unslash($_POST), 'sanitize_text_field');
        }

        $message = sanitize_textarea_field($data['message'] ?? '');
        $history = isset($data['history']) && is_array($data['history']) ? $data['history'] : array();
        $ai_config = isset($data['aiConfig']) && is_array($data['aiConfig']) ? $data['aiConfig'] : array();

        if (empty($message)) {
            wp_send_json_error(array('message' => __('Message is required', 'kitsune-ai-platform')));
            return;
        }

        $system_prompt   = sanitize_textarea_field($ai_config['systemPrompt'] ?? '');
        $model           = sanitize_text_field($ai_config['model'] ?? '');
        $temperature     = floatval($ai_config['temperature'] ?? 0.7);
        $max_tokens      = intval($ai_config['maxTokens'] ?? 500);
        $context_length  = intval($ai_config['contextLength'] ?? 10);
        $use_kb          = !empty($ai_config['useKnowledgeBase']);
        $rag_limit       = isset($ai_config['ragLimit']) ? max(1, min(20, intval($ai_config['ragLimit']))) : 6;
        $kb_sources      = !empty($ai_config['knowledgeSources']) && is_array($ai_config['knowledgeSources'])
            ? array_map('intval', $ai_config['knowledgeSources'])
            : array();

        $model_options = $this->sanitize_and_validate_model_options($ai_config['modelOptions'] ?? array(), $model);
        if (is_wp_error($model_options)) {
            wp_send_json_error(array('message' => $model_options->get_error_message()));
            return;
        }

        $messages = array();
        if (!empty($system_prompt)) {
            $messages[] = array('role' => 'system', 'content' => $system_prompt);
        }

        $clean_history = array();
        foreach ($history as $item) {
            $role = $item['role'] ?? 'user';
            $content = sanitize_textarea_field($item['content'] ?? '');
            if ($content === '') {
                continue;
            }

            if ($role === 'assistant' || $role === 'bot') {
                $role = 'assistant';
            } else {
                $role = 'user';
            }
            $clean_history[] = array('role' => $role, 'content' => $content);
        }

        $max_history = max(0, $context_length * 2);
        if ($max_history > 0 && count($clean_history) > $max_history) {
            $clean_history = array_slice($clean_history, -$max_history);
        }

        $messages = array_merge($messages, $clean_history, array(
            array('role' => 'user', 'content' => $message),
        ));

        require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/class-kitsune-ai-platform-api.php';
        $api = new Kitsune_AI_Platform_API();

        $chat_params = array(
            'model'       => $model,
            'messages'    => $messages,
            'temperature' => $temperature,
            'max_tokens'  => $max_tokens,
            'feature'     => 'chatbot-preview',
            'rag'         => array(
                'enabled'    => $use_kb,
                'limit'      => $rag_limit,
                'source_ids' => $kb_sources,
            ),
        );
        if (!empty($model_options)) {
            $chat_params = array_merge($chat_params, $model_options);
        }

        $response = $api->chatRAG($chat_params);

        if (empty($response['success'])) {
            wp_send_json_error(array('message' => $response['message'] ?? __('Failed to get AI response', 'kitsune-ai-platform')));
            return;
        }

        wp_send_json_success(array(
            'response' => $response['data']['content'] ?? ''
        ));
    }

    /**
     * Sanitize chatbot payload and validate model options before save.
     *
     * @param array $data Chatbot payload.
     * @return array|WP_Error
     */
    private function sanitize_and_validate_chatbot_payload($data) {
        if (!is_array($data)) {
            return new WP_Error('invalid_chatbot_payload', __('Invalid chatbot payload.', 'kitsune-ai-platform'));
        }

        if (!isset($data['config']) || !is_array($data['config'])) {
            return $data;
        }

        if (!isset($data['config']['aiConfig']) || !is_array($data['config']['aiConfig'])) {
            return $data;
        }

        $raw_avatar = isset($data['avatar']) ? $data['avatar'] : ($data['config']['avatar'] ?? 'chat');
        $avatar = $this->sanitize_chatbot_avatar($raw_avatar);
        $data['avatar'] = $avatar;
        $data['config']['avatar'] = $avatar;

        $ai_config = $data['config']['aiConfig'];
        $model = sanitize_text_field($ai_config['model'] ?? '');
        $validated_options = $this->sanitize_and_validate_model_options($ai_config['modelOptions'] ?? array(), $model);
        if (is_wp_error($validated_options)) {
            return $validated_options;
        }

        $data['config']['aiConfig']['modelOptions'] = $validated_options;

        return $data;
    }

    /**
     * Get avatar icon catalog from public icon directory.
     *
     * @return array
     */
    private function get_avatar_icon_catalog() {
        $icon_files = array(
            'chat' => 'chat.svg',
            'service' => 'service.svg',
            'ai' => 'ai.svg',
        );

        $catalog = array();
        foreach ($icon_files as $id => $filename) {
            $path = KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'public/assets/icon/' . $filename;
            if (!file_exists($path)) {
                continue;
            }

            $catalog[] = array(
                'id' => $id,
                'label' => ucfirst($id),
                'url' => esc_url_raw(KITSUNE_AI_PLATFORM_PLUGIN_URL . 'public/assets/icon/' . $filename),
            );
        }

        return $catalog;
    }

    /**
     * Sanitize chatbot avatar value.
     *
     * @param mixed $avatar Avatar value.
     * @return string
     */
    private function sanitize_chatbot_avatar($avatar) {
        $avatar = is_scalar($avatar) ? trim((string) $avatar) : '';
        if ($avatar === '') {
            return 'chat';
        }

        $legacy_map = array(
            'ChatDotRound' => 'chat',
            'CustomChat' => 'chat',
            'Service' => 'service',
            'CustomService' => 'service',
            'Cpu' => 'ai',
            'CustomAI' => 'ai',
        );

        if (isset($legacy_map[$avatar])) {
            return $legacy_map[$avatar];
        }

        $allowed_icon_ids = wp_list_pluck($this->get_avatar_icon_catalog(), 'id');
        if (in_array($avatar, $allowed_icon_ids, true)) {
            return $avatar;
        }

        $avatar_url = esc_url_raw($avatar);
        if ($avatar_url === '') {
            return 'chat';
        }

        $uploads = wp_upload_dir();
        $allowed_base = trailingslashit($uploads['baseurl']) . 'ai-platform/chatbot-avatars/';
        if (strpos($avatar_url, $allowed_base) === 0) {
            return $avatar_url;
        }

        return 'chat';
    }

    /**
     * Validate model options by selected model and option constraints.
     *
     * @param mixed  $model_options Model options payload.
     * @param string $model Selected model.
     * @return array|WP_Error
     */
    private function sanitize_and_validate_model_options($model_options, $model) {
        if (empty($model_options)) {
            return array();
        }

        if (!is_array($model_options)) {
            return new WP_Error('invalid_model_options', __('Model options must be an object.', 'kitsune-ai-platform'));
        }

        if (count($model_options) > 20) {
            return new WP_Error('invalid_model_options', __('Too many model options supplied.', 'kitsune-ai-platform'));
        }

        $model_id = $this->normalize_model_id($model);
        $allowed_keys = $this->get_allowed_model_option_keys($model_id);
        $sanitized_options = array();

        foreach ($model_options as $key => $value) {
            $option_key = sanitize_text_field((string) $key);
            if ($option_key === '') {
                continue;
            }

            if (!in_array($option_key, $allowed_keys, true)) {
                return new WP_Error(
                    'invalid_model_option_key',
                    /* translators: 1: Option key, 2: Model ID */
                    sprintf(__('Option "%1$s" is not supported for model "%2$s".', 'kitsune-ai-platform'), $option_key, $model_id ?: __('unknown', 'kitsune-ai-platform'))
                );
            }

            $rule = $this->get_model_option_validation_rule($option_key, $model_id);
            if (empty($rule) || empty($rule['type'])) {
                return new WP_Error('invalid_model_option_rule', __('Invalid model option rule configuration.', 'kitsune-ai-platform'));
            }

            if ($rule['type'] === 'enum') {
                $enum_value = sanitize_text_field((string) $value);
                $allowed_values = isset($rule['values']) && is_array($rule['values']) ? $rule['values'] : array();
                if (empty($allowed_values) || !in_array($enum_value, $allowed_values, true)) {
                    return new WP_Error(
                        'invalid_model_option_value',
                        /* translators: %s: Option key */
                        sprintf(__('Invalid value for option "%s".', 'kitsune-ai-platform'), $option_key)
                    );
                }
                $sanitized_options[$option_key] = $enum_value;
                continue;
            }

            if (!is_numeric($value)) {
                return new WP_Error(
                    'invalid_model_option_value',
                    /* translators: %s: Option key */
                    sprintf(__('Option "%s" must be numeric.', 'kitsune-ai-platform'), $option_key)
                );
            }

            if ($rule['type'] === 'int') {
                $int_value = intval($value);
                if (isset($rule['min']) && $int_value < intval($rule['min'])) {
                    return new WP_Error(
                        'invalid_model_option_value',
                        /* translators: 1: Option key, 2: Minimum value */
                        sprintf(__('Option "%1$s" must be at least %2$d.', 'kitsune-ai-platform'), $option_key, intval($rule['min']))
                    );
                }
                if (isset($rule['max']) && $int_value > intval($rule['max'])) {
                    return new WP_Error(
                        'invalid_model_option_value',
                        /* translators: 1: Option key, 2: Maximum value */
                        sprintf(__('Option "%1$s" must be at most %2$d.', 'kitsune-ai-platform'), $option_key, intval($rule['max']))
                    );
                }
                $sanitized_options[$option_key] = $int_value;
                continue;
            }

            if ($rule['type'] === 'float') {
                $float_value = floatval($value);
                if (isset($rule['min']) && $float_value < floatval($rule['min'])) {
                    return new WP_Error(
                        'invalid_model_option_value',
                        /* translators: 1: Option key, 2: Minimum value */
                        sprintf(__('Option "%1$s" must be at least %2$s.', 'kitsune-ai-platform'), $option_key, (string) $rule['min'])
                    );
                }
                if (isset($rule['max']) && $float_value > floatval($rule['max'])) {
                    return new WP_Error(
                        'invalid_model_option_value',
                        /* translators: 1: Option key, 2: Maximum value */
                        sprintf(__('Option "%1$s" must be at most %2$s.', 'kitsune-ai-platform'), $option_key, (string) $rule['max'])
                    );
                }
                $sanitized_options[$option_key] = $float_value;
            }
        }

        return $sanitized_options;
    }

    /**
     * Get validation rule for one option and model.
     *
     * @param string $option_key Option key.
     * @param string $model_id Model identifier without provider prefix.
     * @return array|null
     */
    private function get_model_option_validation_rule($option_key, $model_id) {
        $base_rules = $this->get_model_option_validation_rules();
        if (!isset($base_rules[$option_key])) {
            return null;
        }

        $rule = $base_rules[$option_key];

        if ($option_key === 'reasoning_effort') {
            $values = $this->get_reasoning_effort_values($model_id);
            if (empty($values)) {
                return null;
            }
            $rule['values'] = $values;
            return $rule;
        }

        if ($option_key === 'top_k') {
            if (in_array($model_id, KITSUNE_AI_PLATFORM_GOOGLE_MODELS, true)) {
                $rule['max'] = 64;
            }
        }

        return $rule;
    }

    /**
     * Base validation rules per model option key.
     *
     * @return array
     */
    private function get_model_option_validation_rules() {
        return array(
            'top_p' => array('type' => 'float', 'min' => 0, 'max' => 1),
            'top_k' => array('type' => 'int', 'min' => 1, 'max' => 500),
            'frequency_penalty' => array('type' => 'float', 'min' => -2, 'max' => 2),
            'presence_penalty' => array('type' => 'float', 'min' => -2, 'max' => 2),
            'reasoning_effort' => array('type' => 'enum', 'values' => array()),
            'thinking_level' => array('type' => 'enum', 'values' => array('minimal', 'low', 'medium', 'high')),
            'thinking.budget_tokens' => array('type' => 'int', 'min' => 1024, 'max' => 128000),
        );
    }

    /**
     * Option keys allowed for a specific model.
     *
     * @param string $model_id Model identifier without provider prefix.
     * @return array
     */
    private function get_allowed_model_option_keys($model_id) {
        $allowed = array();

        // OpenAI standard models
        if (in_array($model_id, KITSUNE_AI_PLATFORM_OPENAI_STANDARD_MODELS, true)) {
            $allowed = array_merge($allowed, array('top_p', 'frequency_penalty', 'presence_penalty'));
        }

        // OpenAI reasoning models
        if (!empty($this->get_reasoning_effort_values($model_id))) {
            $allowed[] = 'reasoning_effort';
        }

        // Anthropic models
        if (in_array($model_id, KITSUNE_AI_PLATFORM_ANTHROPIC_MODELS, true)) {
            $allowed = array_merge($allowed, array('top_p', 'top_k'));
        }

        // Anthropic extended thinking models
        if (in_array($model_id, KITSUNE_AI_PLATFORM_ANTHROPIC_EXTENDED_THINKING_MODELS, true)) {
            $allowed[] = 'thinking.budget_tokens';
        }

        // Google Gemini 3 models
        if (in_array($model_id, KITSUNE_AI_PLATFORM_GOOGLE_GEMINI3_MODELS, true)) {
            $allowed = array_merge($allowed, array('thinking_level', 'top_p', 'top_k'));
        }

        // Google Gemini 2.5 models
        if (in_array($model_id, KITSUNE_AI_PLATFORM_GOOGLE_GEMINI25_MODELS, true)) {
            $allowed = array_merge($allowed, array('top_p', 'top_k', 'frequency_penalty', 'presence_penalty'));
        }

        return array_values(array_unique($allowed));
    }

    /**
     * Allowed reasoning effort values by model.
     *
     * @param string $model_id Model identifier without provider prefix.
     * @return array
     */
    private function get_reasoning_effort_values($model_id) {
        $values = KITSUNE_AI_PLATFORM_OPENAI_REASONING_MODELS[ $model_id ] ?? null;
        return is_array($values) ? $values : array();
    }

    /**
     * Normalize model id by stripping provider prefix if present.
     *
     * @param string $model Raw model identifier.
     * @return string
     */
    private function normalize_model_id($model) {
        $model = sanitize_text_field((string) $model);
        if (strpos($model, ':') !== false) {
            $parts = explode(':', $model, 2);
            $model = $parts[1] ?? '';
        }
        return sanitize_text_field($model);
    }

    /**
     * Verify editor AJAX request.
     *
     * @return bool
     */
    private function verify_editor_request() {
        check_ajax_referer('kitsune_ai_platform_nonce', 'nonce');

        if (!current_user_can('edit_posts')) {
            wp_send_json_error(array('message' => __('Permission denied', 'kitsune-ai-platform')));
            return false;
        }

        return true;
    }
}
