<?php
/**
 * Cloudflare AI Provider
 */

if ( ! defined( 'ABSPATH' ) ) exit; // Thoát nếu truy cập trực tiếp

class AIAutotool_AI_Provider_Cloudflare extends AIAutotool_AI_Provider_Base {
    
    protected $name = 'Cloudflare';
    protected $id = 'cloudflare';
    protected $base_url = 'https://api.cloudflare.com/client/v4';
    protected $default_model = '@cf/openai/gpt-oss-120b';
    protected $capabilities = array('text_generation', 'image_generation');
    
    protected $available_models = array(
        '@cf/openai/gpt-oss-120b' => 'GPT-OSS 120B (Open Source GPT)',
        '@cf/google/gemma-7b-it-lora' => 'Gemma 7B IT LoRA',
        '@cf/google/gemma-2b-it-lora' => 'Gemma 2B IT LoRA',
        '@cf/microsoft/phi-2' => 'Phi-2',
        '@cf/defog/sqlcoder-7b-2' => 'SQLCoder 7B v2',
        '@cf/meta/llama-2-7b-chat-fp16' => 'Llama 2 7B Chat FP16',
        '@cf/meta/llama-2-7b-chat-int8' => 'Llama 2 7B Chat Int8',
        '@cf/meta/llama-3.1-70b-instruct' => 'Llama 3.1 70B Instruct',
    );

    public function get_image_models() {
        return array(
            '@cf/stabilityai/stable-diffusion-xl-base-1.0' => 'Stable Diffusion XL',
            '@cf/bytedance/stable-diffusion-xl-lightning' => 'Stable Diffusion XL Lightning',
            '@cf/lykon/dreamshaper-8-lcm' => 'DreamShaper 8 LCM',
        );
    }

    public function generate_image($prompt, $options = array()) {
        if (!$this->is_configured()) {
            return array('success' => false, 'error' => 'Cloudflare credentials not configured');
        }

        $prompt = trim((string) $prompt);
        if ($prompt === '') {
            return array('success' => false, 'error' => 'Image prompt is required');
        }

        $this->ensure_credentials_parsed();
        if (empty($this->account_id) || empty($this->api_token)) {
            $credentials = $this->get_rotated_credentials();
            $this->account_id = isset($credentials['account_id']) ? $credentials['account_id'] : '';
            $this->api_token = isset($credentials['api_token']) ? $credentials['api_token'] : '';
        }

        if (empty($this->account_id) || empty($this->api_token)) {
            return array('success' => false, 'error' => 'Cloudflare account ID and API token not configured');
        }

        $models = $this->get_image_models();
        $model = isset($options['model']) ? sanitize_text_field($options['model']) : '@cf/stabilityai/stable-diffusion-xl-base-1.0';
        if (!isset($models[$model])) {
            $model = '@cf/stabilityai/stable-diffusion-xl-base-1.0';
        }

        $response = $this->make_request(
            $this->base_url . '/accounts/' . $this->account_id . '/ai/run/' . $model,
            array('prompt' => $prompt),
            'POST',
            array(
                'Authorization' => 'Bearer ' . $this->api_token,
                'Content-Type' => 'application/json',
            ),
            array('timeout' => isset($options['timeout']) ? (int) $options['timeout'] : 90)
        );

        if (!$response['success']) {
            return $response;
        }

        $data = $response['data'];
        if (is_array($data) && !empty($data['result']['image'])) {
            return array(
                'success' => true,
                'data_url' => 'data:image/png;base64,' . $data['result']['image'],
                'model' => $model,
                'provider' => $this->id,
            );
        }

        if (is_string($data) && $data !== '') {
            return array(
                'success' => true,
                'data_url' => 'data:image/png;base64,' . base64_encode($data),
                'model' => $model,
                'provider' => $this->id,
            );
        }

        return array('success' => false, 'error' => 'Cloudflare image response missing image data');
    }
    
    /**
     * Account ID
     */
    protected $account_id = '720b83369596a8123d04b830f97952bc';
    
    /**
     * API Token
     */
    protected $api_token = 'ikof9WLob7Nfq1L8WXRTEoouBO--iW8Ko6S-8cmx';
    
    public function __construct($api_key = '') {
        parent::__construct($api_key);
        
        if (empty($this->api_key)) {
            $credentials = $this->get_rotated_credentials();
            if (!empty($credentials)) {
                $this->account_id = $credentials['account_id'];
                $this->api_token = $credentials['api_token'];
            }
        } else {
            $this->parse_credentials($this->api_key);
        }
    }
    
    /**
     * Parse credentials from key string
     * Format: "account_id|api_token"
     */
    protected function parse_credentials($key_string) {
        if (empty($key_string)) {
            return;
        }
        
        // Check if it's in the format "account_id|api_token"
        if (strpos($key_string, '|') !== false) {
            $parts = explode('|', $key_string, 2);
            if (count($parts) === 2) {
                $this->account_id = trim($parts[0]);
                $this->api_token = trim($parts[1]);
            }
        } else {
            // If no separator, treat as api_token only (backward compatibility)
            $this->api_token = $key_string;
        }
    }
    
    /**
     * Đảm bảo credentials được parse từ key
     * Gọi method này trước khi sử dụng account_id và api_token
     */
    protected function ensure_credentials_parsed() {
        // Nếu đã có cả account_id và api_token thì OK
        if (!empty($this->account_id) && !empty($this->api_token)) {
            return;
        }
        
        // Nếu có api_key nhưng chưa parse, parse nó
        if (!empty($this->api_key)) {
            $this->parse_credentials($this->api_key);
            if (!empty($this->account_id) && !empty($this->api_token)) {
                return; // Đã parse xong
            }
        }
        
        // Nếu vẫn chưa có, lấy từ tất cả các nguồn có thể
        if (empty($this->account_id) || empty($this->api_token)) {
            $key_to_parse = '';
            
            // 1. Kiểm tra từ base class method
            if (class_exists('AIAutotool_API_Manager')) {
                $base_key = AIAutotool_API_Manager::get_cloudflare_key();
                if (!empty($base_key)) {
                    $key_to_parse = $base_key;
                }
            }
            
            // 2. Nếu base class không có, kiểm tra trực tiếp từ option
            if (empty($key_to_parse)) {
                $old_key = get_option('aiautotool_cloudflare_api_key', '');
                if (!empty($old_key)) {
                    $key_to_parse = $old_key;
                }
            }
            
            // 3. Nếu vẫn chưa có, kiểm tra từ API Keys Manager (ALL keys, không chỉ active)
            if (empty($key_to_parse) && class_exists('AIAutotool_AI_Provider_API_Keys')) {
                $keys_manager = AIAutotool_AI_Provider_API_Keys::get_instance();
                $all_keys = $keys_manager->get_all_keys('cloudflare');
                if (!empty($all_keys) && is_array($all_keys)) {
                    // Lấy key đầu tiên (dù enabled hay disabled)
                    foreach ($all_keys as $key_data) {
                        if (isset($key_data['key']) && !empty($key_data['key'])) {
                            $key_to_parse = $key_data['key'];
                            break;
                        }
                    }
                }
            }
            
            // 4. Nếu vẫn chưa có, thử get_rotated_credentials()
            if (empty($key_to_parse)) {
                $credentials = $this->get_rotated_credentials();
                if (!empty($credentials['account_id']) && !empty($credentials['api_token'])) {
                    $this->account_id = $credentials['account_id'];
                    $this->api_token = $credentials['api_token'];
                    return;
                } elseif (!empty($credentials['api_token'])) {
                    $this->api_token = $credentials['api_token'];
                    return;
                }
            }
            
            // 5. Parse key đã tìm được
            if (!empty($key_to_parse)) {
                $this->parse_credentials($key_to_parse);
                $this->api_key = $key_to_parse; // Lưu lại để dùng sau
            }
        }
    }
    
    /**
     * Get rotated credentials (account_id + api_token pair)
     */
    protected function get_rotated_credentials() {
        $keys_manager = AIAutotool_AI_Provider_API_Keys::get_instance();
        $active_keys = $keys_manager->get_active_keys($this->id);
        
        // Also check old single key format
        $old_key = get_option('aiautotool_' . $this->id . '_api_key', '');
        $has_old_key = !empty($old_key);
        
        // Collect all available keys (new format + old format)
        $all_keys = array();
        foreach ($active_keys as $key_data) {
            if (isset($key_data['key'])) {
                $all_keys[] = $key_data['key'];
            }
        }
        if ($has_old_key) {
            // Check if old key is different from any active key
            $old_key_in_active = false;
            foreach ($active_keys as $key_data) {
                if (isset($key_data['key']) && $key_data['key'] === $old_key) {
                    $old_key_in_active = true;
                    break;
                }
            }
            if (!$old_key_in_active) {
                $all_keys[] = $old_key;
            }
        }
        
        // If no keys available, return empty
        if (empty($all_keys)) {
            return array('account_id' => '', 'api_token' => '');
        }
        
        // Use rotation index to rotate between keys
        $rotation_index_option = 'aiautotool_' . $this->id . '_rotation_index';
        $current_index = get_option($rotation_index_option, 0);
        
        // Ensure index is valid
        if ($current_index >= count($all_keys)) {
            $current_index = 0;
        }
        
        $selected_key = $all_keys[$current_index];
        
        // Update rotation index for next call
        $next_index = ($current_index + 1) % count($all_keys);
        update_option($rotation_index_option, $next_index, false);
        
        // Parse credentials from selected key
        $this->parse_credentials($selected_key);
        
        return array(
            'account_id' => $this->account_id,
            'api_token' => $this->api_token
        );
    }
    
    /**
     * Chat completion
     */
    public function chat_completion($messages, $options = array()) {
        if (!$this->is_configured()) {
            return array(
                'success' => false,
                'error' => 'Cloudflare credentials not configured'
            );
        }
        
        $options = $this->parse_options($options);
        
        // Đảm bảo credentials được parse từ key
        $this->ensure_credentials_parsed();
        
        // Get rotated credentials if needed
        if (empty($this->account_id) || empty($this->api_token)) {
            $credentials = $this->get_rotated_credentials();
            if (!empty($credentials['account_id']) && !empty($credentials['api_token'])) {
                $this->account_id = $credentials['account_id'];
                $this->api_token = $credentials['api_token'];
            }
        }
        
        if (empty($this->account_id) || empty($this->api_token)) {
            return array(
                'success' => false,
                'error' => 'Cloudflare account ID and API token not configured'
            );
        }
        
        // Determine API endpoint and format based on model type
        $api_config = $this->get_model_api_config($options['model']);
        
        // Build URL with account ID
        $url = $this->base_url . '/accounts/' . $this->account_id . $api_config['endpoint'];
        
        // Build request body based on model type
        $body = array(
            'model' => $options['model']
        );
        
        // Add input data based on format type
        if ($api_config['format'] === 'messages') {
            // OpenAI-compatible format: use messages array
            $body['messages'] = $messages;
        } elseif ($api_config['format'] === 'prompt') {
            // Text completion format: convert messages to prompt string
            $body['prompt'] = $this->convert_messages_to_prompt($messages);
        } else {
            // Default: use input field (legacy format)
            $body['input'] = $this->convert_messages_to_input($messages);
        }
        
        // Cloudflare API doesn't support temperature, max_tokens, top_p in the same way
        // But we can add them if the API supports it
        if (isset($options['temperature'])) {
            $body['temperature'] = floatval($options['temperature']);
        }
        if (isset($options['max_tokens'])) {
            $body['max_tokens'] = intval($options['max_tokens']);
        }
        if (isset($options['top_p'])) {
            $body['top_p'] = floatval($options['top_p']);
        }
        
        $headers = array(
            'Authorization' => 'Bearer ' . $this->api_token,
            'Content-Type' => 'application/json'
        );
        
        $this->log('Chat completion request', array('model' => $options['model'], 'account_id' => $this->mask_api_key($this->account_id)));
        
        $response = $this->make_request($url, $body, 'POST', $headers);
        
        if (!$response['success']) {
            // Ensure error is always set
            if (!isset($response['error'])) {
                $response['error'] = 'API request failed';
            }
            return $response;
        }
        
        $data = $response['data'];
        
        // Log raw response for debugging
        $this->log('Cloudflare API response', array('data' => $data));
        
        // Cloudflare /chat/completions endpoint returns OpenAI-compatible format:
        // {
        //   "id": "...",
        //   "object": "chat.completion",
        //   "choices": [{
        //     "message": {
        //       "role": "assistant",
        //       "content": "..."
        //     },
        //     "finish_reason": "stop"
        //   }],
        //   "usage": {"prompt_tokens": ..., "completion_tokens": ..., "total_tokens": ...},
        //   "model": "@cf/..."
        // }
        
        $content = '';
        $usage = null;
        $model = $options['model'];
        $finish_reason = null;
        
        // Extract content from OpenAI-compatible format
        // /chat/completions uses choices[0].message.content
        // /completions uses choices[0].text
        if (isset($data['choices']) && is_array($data['choices']) && !empty($data['choices'])) {
            $choice = $data['choices'][0];
            
            // Try chat completion format first (message.content)
            if (isset($choice['message']['content'])) {
                $content = $choice['message']['content'];
            }
            // Try text completion format (text)
            elseif (isset($choice['text'])) {
                $content = $choice['text'];
            }
            
            if (isset($choice['finish_reason'])) {
                $finish_reason = $choice['finish_reason'];
            }
        }
        
        // Extract usage
        if (isset($data['usage']) && is_array($data['usage'])) {
            $usage = $data['usage'];
        }
        
        // Extract model
        if (isset($data['model'])) {
            $model = $data['model'];
        }
        
        // If we found content, return success
        if (!empty($content)) {
            return array(
                'success' => true,
                'content' => $content,
                'usage' => $usage,
                'model' => $model,
                'finish_reason' => $finish_reason
            );
        }
        
        // Fallback: try old /responses endpoint format
        if (isset($data['output']) && is_array($data['output'])) {
            foreach ($data['output'] as $output_item) {
                if (isset($output_item['type']) && $output_item['type'] === 'message' &&
                    isset($output_item['role']) && $output_item['role'] === 'assistant' &&
                    isset($output_item['content']) && is_array($output_item['content'])) {
                    
                    foreach ($output_item['content'] as $content_item) {
                        if (isset($content_item['text']) && !empty($content_item['text'])) {
                            $content = $content_item['text'];
                            break;
                        }
                    }
                    
                    if (!empty($content)) {
                        break;
                    }
                }
            }
            
            if (!empty($content)) {
                return array(
                    'success' => true,
                    'content' => $content,
                    'usage' => $usage,
                    'model' => $model,
                    'finish_reason' => $finish_reason
                );
            }
        }
        
        // Fallback: try other formats
        if (isset($data['result']['response'])) {
            return array(
                'success' => true,
                'content' => $data['result']['response'],
                'usage' => isset($data['result']['usage']) ? $data['result']['usage'] : $usage,
                'model' => isset($data['result']['model']) ? $data['result']['model'] : $model,
                'finish_reason' => $finish_reason
            );
        }
        
        if (isset($data['response'])) {
            return array(
                'success' => true,
                'content' => $data['response'],
                'usage' => $usage,
                'model' => $model,
                'finish_reason' => $finish_reason
            );
        }
        
        // If we can't parse, return error with raw data for debugging
        return array(
            'success' => false,
            'error' => 'Invalid response structure from Cloudflare API: Could not extract content from response',
            'raw_response' => $data
        );
    }
    
    /**
     * Get API configuration for a specific model
     * Determines endpoint and format (messages/prompt/input) based on model type
     * 
     * Based on Cloudflare AI test results:
     * - /chat/completions: OpenAI-compatible endpoint, uses "messages" format
     * - /responses: Legacy endpoint, uses "input" or "prompt" format
     * 
     * @param string $model Model identifier
     * @return array Configuration with 'endpoint' and 'format' keys
     */
    private function get_model_api_config($model) {
        // Models that use /responses endpoint with input format (legacy)
        $responses_input_models = array(
            '@cf/openai/gpt-oss-120b',
        );
        
        // Models that use /responses endpoint with prompt format
        $responses_prompt_models = array(
            '@cf/google/gemma-7b-it-lora',
            '@cf/google/gemma-2b-it-lora',
            '@cf/microsoft/phi-2',
            '@cf/defog/sqlcoder-7b-2',
            '@cf/meta/llama-2-7b-chat-fp16',
            '@cf/meta/llama-2-7b-chat-int8',
            '@cf/meta/llama-3.1-70b-instruct',
        );
        
        // Models that use /chat/completions endpoint with messages format
        $chat_completions_models = array(
            '@cf/google/gemma-7b-it-lora',
            '@cf/google/gemma-2b-it-lora',
            '@cf/microsoft/phi-2',
            '@cf/defog/sqlcoder-7b-2',
            '@cf/meta/llama-2-7b-chat-fp16',
            '@cf/meta/llama-2-7b-chat-int8',
            '@cf/meta/llama-3.1-70b-instruct',
        );
        
        // Check explicit mappings first
        if (in_array($model, $responses_input_models)) {
            return array(
                'endpoint' => '/ai/v1/responses',
                'format' => 'input'
            );
        }
        
        if (in_array($model, $responses_prompt_models)) {
            // Prefer /chat/completions if model supports both
            if (in_array($model, $chat_completions_models)) {
                return array(
                    'endpoint' => '/ai/v1/chat/completions',
                    'format' => 'messages'
                );
            }
            return array(
                'endpoint' => '/ai/v1/responses',
                'format' => 'prompt'
            );
        }
        
        // Default: Use /chat/completions with messages format
        // This is the most common and recommended endpoint for modern Cloudflare AI models
        return array(
            'endpoint' => '/ai/v1/chat/completions',
            'format' => 'messages'
        );
    }
    
    /**
     * Convert OpenAI-style messages to prompt string for completion models
     * 
     * @param array $messages Messages array
     * @return string Prompt string
     */
    private function convert_messages_to_prompt($messages) {
        $prompt_parts = array();
        
        foreach ($messages as $message) {
            $role = $message['role'];
            $content = $message['content'];
            
            // Format based on role
            switch ($role) {
                case 'system':
                    $prompt_parts[] = "System: " . $content;
                    break;
                case 'user':
                    $prompt_parts[] = "User: " . $content;
                    break;
                case 'assistant':
                    $prompt_parts[] = "Assistant: " . $content;
                    break;
                default:
                    $prompt_parts[] = $content;
            }
        }
        
        return implode("\n\n", $prompt_parts);
    }
    
    /**
     * Convert OpenAI-style messages to input string for legacy /responses endpoint
     * 
     * @param array $messages Messages array
     * @return string Input string
     */
    private function convert_messages_to_input($messages) {
        // Same as prompt conversion for now
        return $this->convert_messages_to_prompt($messages);
    }
    
    /**
     * Test connection
     * @param string $model Optional model to test (if not provided, uses default)
     */
    public function test_connection($model = '') {
        if (!$this->is_configured()) {
            return array(
                'success' => false,
                'message' => 'Cloudflare credentials not configured'
            );
        }
        
        // Đảm bảo credentials được parse từ key
        $this->ensure_credentials_parsed();
        
        // Get rotated credentials if needed
        if (empty($this->account_id) || empty($this->api_token)) {
            $credentials = $this->get_rotated_credentials();
            if (!empty($credentials['account_id']) && !empty($credentials['api_token'])) {
                $this->account_id = $credentials['account_id'];
                $this->api_token = $credentials['api_token'];
            }
        }
        
        if (empty($this->account_id) || empty($this->api_token)) {
            return array(
                'success' => false,
                'message' => 'Cloudflare account ID and API token not configured'
            );
        }
        
        // Get available models for display
        $available_models = $this->get_available_models();
        // Use provided model or default
        $test_model = !empty($model) ? $model : $this->default_model;
        $model_name = isset($available_models[$test_model]) ? $available_models[$test_model] : $test_model;
        
        // Test with prompt asking model to introduce itself
        $test_prompt = sprintf(
            __('Hãy giới thiệu về bạn (model AI) cùng tên model (%s) và ngày cuối cùng cập nhật dữ liệu của bạn. Trả lời bằng tiếng Việt.', 'ai-auto-tool'),
            $model_name
        );
        
        $test_messages = array(
            array(
                'role' => 'user',
                'content' => $test_prompt
            )
        );
        
        $test_result = $this->chat_completion($test_messages, array('model' => $test_model));
        
        if ($test_result['success']) {
            // Get the actual model used in response
            $response_model = isset($test_result['model']) ? $test_result['model'] : $test_model;
            $response_model_name = isset($available_models[$response_model]) ? $available_models[$response_model] : $response_model;
            
            // Get response content
            $response_content = '';
            if (isset($test_result['content'])) {
                $response_content = is_string($test_result['content']) ? trim($test_result['content']) : '';
            } elseif (isset($test_result['response'])) {
                $response_content = is_string($test_result['response']) ? trim($test_result['response']) : '';
            }
            
            return array(
                'success' => true,
                'message' => 'Cloudflare API connection successful!',
                'response' => $response_content,
                'model' => $response_model,
                'model_name' => $response_model_name,
                'usage' => isset($test_result['usage']) ? $test_result['usage'] : null
            );
        } else {
            return array(
                'success' => false,
                'message' => 'Cloudflare API Error: ' . (isset($test_result['error']) ? $test_result['error'] : 'Unknown error'),
                'model' => $test_model,
                'model_name' => $model_name
            );
        }
    }
    
    /**
     * Get models list
     * Note: Cloudflare API may not have a models endpoint, so we return available models
     */
    public function get_models() {
        if (!$this->is_configured()) {
            return array(
                'success' => false,
                'error' => 'Cloudflare credentials not configured'
            );
        }
        
        // Cloudflare doesn't have a standard models endpoint
        // Return our predefined available models
        $models = array_keys($this->available_models);
        
        return array(
            'success' => true,
            'models' => $models
        );
    }
    
    /**
     * Check if configured
     * Đơn giản: chỉ cần có key được lưu là được, không cần parse phức tạp
     */
    public function is_configured() {
        // Nếu đã có credentials parsed rồi thì OK
        if (!empty($this->account_id) && !empty($this->api_token)) {
            return true;
        }
        
        // Nếu có api_token là OK (dù chưa có account_id)
        if (!empty($this->api_token)) {
            return true;
        }
        
        // Nếu có api_key trong instance thì OK
        if (!empty($this->api_key)) {
            return true;
        }
        
        // Kiểm tra trực tiếp từ database option (old format) - nhanh nhất
        $old_key = get_option('aiautotool_cloudflare_api_key', '');
        if (!empty($old_key)) {
            return true; // Có key old format là OK
        }
        
        // Kiểm tra trực tiếp từ option mới (multiple keys format)
        $new_keys_option = get_option('aiautotool_cloudflare_api_keys', array());
        if (!empty($new_keys_option) && is_array($new_keys_option)) {
            // Có ít nhất 1 key trong array là OK (dù enabled hay disabled)
            foreach ($new_keys_option as $key_data) {
                if (isset($key_data['key']) && !empty($key_data['key'])) {
                    return true;
                }
            }
        }
        
        // Kiểm tra từ API Keys Manager - kiểm tra cả ALL keys (không chỉ active)
        if (class_exists('AIAutotool_AI_Provider_API_Keys')) {
            $keys_manager = AIAutotool_AI_Provider_API_Keys::get_instance();
            
            // Kiểm tra ALL keys trước (bao gồm cả disabled)
            $all_keys = $keys_manager->get_all_keys('cloudflare');
            if (!empty($all_keys) && is_array($all_keys)) {
                // Có ít nhất 1 key được lưu là OK
                foreach ($all_keys as $key_data) {
                    if (isset($key_data['key']) && !empty($key_data['key'])) {
                        return true;
                    }
                }
            }
            
            // Kiểm tra active keys
            $active_keys = $keys_manager->get_active_keys('cloudflare');
            if (!empty($active_keys) && is_array($active_keys)) {
                foreach ($active_keys as $key_data) {
                    if (isset($key_data['key']) && !empty($key_data['key'])) {
                        return true;
                    }
                }
            }
        }
        
        // Fallback: dùng base class method (nó sẽ gọi AIAutotool_API_Manager::get_cloudflare_key())
        $base_result = parent::is_configured();
        if ($base_result) {
            return true;
        }
        
        // Cuối cùng: kiểm tra trực tiếp bằng get_cloudflare_key()
        if (class_exists('AIAutotool_API_Manager')) {
            $direct_key = AIAutotool_API_Manager::get_cloudflare_key();
            if (!empty($direct_key)) {
                return true;
            }
        }
        
        return false;
    }
}
