<?php

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

class Ai_gateway
{
    protected $CI;

    public function __construct()
    {
        $this->CI = &get_instance();
    }

  


    public function generate($prompt, $type = 'text')
    {
        $type = strtolower($type);

        // 1. Load Configuration from Database
        $settings = $this->CI->admin_m->get_user_settings();
        $ai_config = !empty($settings['ai_config']) ? json_decode($settings['ai_config'], true) : [];

        $active_provider = isset($ai_config['active_provider']) ? $ai_config['active_provider'] : 'gemini';
        $unsplash_key = isset($ai_config['unsplash_key']) && !empty($ai_config['unsplash_key']) ? $ai_config['unsplash_key'] : '';

        // 2. Prepare AI object based on active provider
        $ai = (object) [
            'provider'   => $active_provider,
            'api_key'    => isset($ai_config[$active_provider . '_key']) ? $ai_config[$active_provider . '_key'] : '',
            'model_name' => isset($ai_config[$active_provider . '_model']) ? $ai_config[$active_provider . '_model'] : '',
            'endpoint'   => isset($ai_config[$active_provider . '_endpoint']) ? $ai_config[$active_provider . '_endpoint'] : '',
            'headers'    => isset($ai_config['custom_headers']) ? json_decode($ai_config['custom_headers'], true) : []
        ];

        // Specific for 'custom' provider which uses custom_* keys
        if ($ai->provider == 'custom') {
            $ai->api_key    = isset($ai_config['custom_key']) ? $ai_config['custom_key'] : '';
            $ai->model_name = isset($ai_config['custom_model']) ? $ai_config['custom_model'] : '';
            $ai->endpoint   = isset($ai_config['custom_endpoint']) ? $ai_config['custom_endpoint'] : '';
        }

        // Fallback models if not defined
        if (empty($ai->model_name)) {
            if ($ai->provider == 'gemini') $ai->model_name = 'gemini-2.5-flash';
            if ($ai->provider == 'openai') $ai->model_name = 'gpt-3.5-turbo';
            if ($ai->provider == 'claude') $ai->model_name = 'claude-3-opus-20240229';
            if ($ai->provider == 'zhipu') $ai->model_name = 'glm-4';
        }

        // --- ROUTING ---
        $result = '';
        switch ($ai->provider) {
            case 'openai':
                $result = $this->call_openai($ai->api_key, $ai->model_name, $prompt, $type, $ai->endpoint);
                break;
            case 'claude':
                $result = $this->call_claude($ai->api_key, $ai->model_name, $prompt, $ai->endpoint);
                break;
            case 'zhipu':
                $result = $this->call_zhipu($ai->api_key, $ai->model_name, $prompt, $type, $ai->endpoint);
                break;
            case 'gemini':
                $result = $this->call_gemini($ai->api_key, $ai->model_name, $prompt, $type, $ai->endpoint);
                break;
            case 'custom':
                $result = $this->call_custom($ai->endpoint, $ai->api_key, $ai->model_name, $prompt, $ai->headers);
                break;
            default:
                $result = "Error: Unknown provider configured";
        }

        // --- AUTOMATIC IMAGE FALLBACK LOGIC ---
        if ($type === 'image') {
            // Extract keywords early for use in fallbacks
            $keywords = $prompt;
            if (strpos($prompt, 'context:') !== false) {
                $parts = explode('context:', $prompt);
                $keywords = end($parts);
            }
            $keywords = trim($keywords);

            $is_error = false;
            // Check if AI result is absent, an error, or specifically "No Image Found"
            if (!$result || strpos($result, 'Error') !== false || strpos($result, 'Connection Error') !== false || strpos($result, 'cURL') !== false || $result === "No Image Found") {
                $is_error = true;
            }

            // If it's supposed to be an image but doesn't look like a URL or Base64, it might be a text prompt or a failure
            if (!$is_error && !preg_match('~^(https?://|data:image/)~i', $result)) {
                // If the provider returned a text prompt, we might want to try Unsplash first for real photos
                $is_error = true;
                $ai_prompt = $result; // Keep the AI prompt in case Unsplash fails
            }

            if ($is_error) {
                $unsplash_res = $this->call_unsplash($unsplash_key, $keywords);

                // If Unsplash found an image, return its URL
                if (strpos($unsplash_res, 'http') === 0) {
                    return $unsplash_res;
                }

                // If Unsplash failed ("No Image Found"), fall back to whatever AI gave us, or the keywords
                // This will be used by Pollinations.ai in the handler as a prompt
                return !empty($ai_prompt) ? $ai_prompt : $keywords;
            }
        }

        return $result;
    }

    private function call_unsplash($key, $prompt)
    {
        $query = urlencode(trim($prompt));
        $url = "https://api.unsplash.com/search/photos?query={$query}&per_page=1&orientation=landscape";
        return $this->execute_curl($url, $key, [], 'unsplash');
    }

    private function call_gemini($key, $model, $prompt, $type = 'text', $endpoint = '')
    {
        $base_url = !empty($endpoint) ? rtrim($endpoint, '/') : "https://generativelanguage.googleapis.com/v1beta";

        if ($type === 'image') {
            // Use the configured model for prediction
            $url = "$base_url/models/$model:predict?key=" . $key;
            $data = [
                "instances" => [["prompt" => $prompt]],
                "parameters" => ["sampleCount" => 1]
            ];
            return $this->execute_curl($url, $key, $data, 'gemini_image');
        }

        $url = "$base_url/models/" . $model . ":generateContent?key=" . $key;
        $data = ["contents" => [["parts" => [["text" => $prompt]]]]];
        return $this->execute_curl($url, $key, $data, 'gemini');
    }

    private function call_openai($key, $model, $prompt, $type = 'text', $endpoint = '')
    {
        $base_url = !empty($endpoint) ? rtrim($endpoint, '/') : "https://api.openai.com/v1";

        if ($type === 'image') {
            $url = "$base_url/images/generations";
            $data = [
                "model" => "dall-e-3",
                "prompt" => $prompt,
                "n" => 1,
                "size" => "1024x1024"
            ];
            return $this->execute_curl($url, $key, $data, 'openai_image');
        }

        $url = "$base_url/chat/completions";
        $data = [
            "model" => $model,
            "messages" => [["role" => "user", "content" => $prompt]]
        ];
        return $this->execute_curl($url, $key, $data, 'openai');
    }

    private function call_claude($key, $model, $prompt, $endpoint = '')
    {
        $base_url = !empty($endpoint) ? rtrim($endpoint, '/') : "https://api.anthropic.com/v1";
        $url = "$base_url/messages";
        $data = [
            "model" => $model,
            "max_tokens" => 1024,
            "messages" => [["role" => "user", "content" => $prompt]]
        ];
        // Note: Headers handled inside execute_curl
        return $this->execute_curl($url, $key, $data, 'claude');
    }

    private function call_custom($endpoint, $key, $model, $prompt, $extra_headers = [])
    {
        if (empty($endpoint)) return "Error: Custom API endpoint not configured";
        
        $url = rtrim($endpoint, '/') . '/chat/completions';
        $data = [
            "model" => $model,
            "messages" => [["role" => "user", "content" => $prompt]]
        ];
        
        return $this->execute_curl($url, $key, $data, 'openai', $extra_headers); // Uses OpenAI response parser
    }

    private function call_zhipu($key, $model, $prompt, $type = 'text', $endpoint = '')
    {
        $base_url = !empty($endpoint) ? rtrim($endpoint, '/') : "https://open.bigmodel.cn/api/paas/v4";

        if ($type === 'image') {
            $url = "$base_url/images/generations";
            $data = [
                "model" => "cogview-3",
                "prompt" => $prompt
            ];
            return $this->execute_curl($url, $key, $data, 'openai_image'); // They use similar response structure
        }

        $url = "$base_url/chat/completions";
        $data = [
            "model" => $model,
            "messages" => [["role" => "user", "content" => $prompt]],
            "temperature" => 0.7
        ];
        // Zhipu is OpenAI-compatible for both request and response
        return $this->execute_curl($url, $key, $data, 'openai');
    }


    private function execute_curl($url, $key, $data, $provider, $extra_headers = [])
    {
        $client = new \GuzzleHttp\Client(['timeout' => 30]);
        $headers = ['Content-Type' => 'application/json'];
        $method = ($provider === 'unsplash') ? 'GET' : 'POST';

        if ($provider == 'openai' || $provider == 'openai_image') {
            $headers['Authorization'] = "Bearer {$key}";
        } elseif ($provider == 'claude') {
            $headers['x-api-key'] = $key;
            $headers['anthropic-version'] = '2023-06-01';
        } elseif ($provider == 'unsplash') {
            $headers['Authorization'] = "Client-ID {$key}";
        }

        // Merge extra/custom headers
        if (!empty($extra_headers) && is_array($extra_headers)) {
            $headers = array_merge($headers, $extra_headers);
        }

        try {
            $options = ['headers' => $headers];
            if ($method === 'POST') $options['json'] = $data;

            $response = $client->request($method, $url, $options);
            $res = json_decode($response->getBody()->getContents(), true);

            // --- STANDARDIZED PARSING ---
            if ($provider == 'unsplash') {
                return $res['results'][0]['urls']['regular'] ?? "No Image Found";
            }
            if ($provider == 'gemini' && isset($res['candidates'][0]['content']['parts'][0]['text'])) {
                return $res['candidates'][0]['content']['parts'][0]['text'];
            }
            if ($provider == 'gemini_image' && isset($res['predictions'][0]['bytesBase64Encoded'])) {
                // Return base64 or save to file
                return 'data:image/png;base64,' . $res['predictions'][0]['bytesBase64Encoded'];
            }
            if ($provider == 'openai' && isset($res['choices'][0]['message']['content'])) {
                return $res['choices'][0]['message']['content'];
            }
            if ($provider == 'openai_image' && isset($res['data'][0]['url'])) {
                return $res['data'][0]['url'];
            }

            return "Error: Unsupported response from $provider";
        } catch (\Exception $e) {
            return "Connection Error: " . $e->getMessage();
        }
    }
    private function execute_curl_($url, $key, $data, $provider, $extra_headers = [])
    {
        $ch = curl_init($url);
        $headers = ["Content-Type: application/json"];

        // 1. Authentication Logic
        if ($provider == 'openai') {
            $headers[] = "Authorization: Bearer $key";
        } elseif ($provider == 'claude') {
            $headers[] = "x-api-key: $key";
            $headers[] = "anthropic-version: 2023-06-01";
        }
        // Gemini key is already in the URL, no auth header needed

        $headers = array_merge($headers, $extra_headers);

        curl_setopt_array($ch, [
            CURLOPT_HTTPHEADER     => $headers,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => json_encode($data),
            CURLOPT_TIMEOUT        => 30
        ]);

        $raw_response = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);

        if ($error) return "cURL Error: " . $error;

        $res = json_decode($raw_response, true);

        // 2. Standardize Output Parsing
        // OpenAI & Zhipu format
        if ($provider == 'openai' && isset($res['choices'][0]['message']['content'])) {
            return $res['choices'][0]['message']['content'];
        }
        // Claude format
        if ($provider == 'claude' && isset($res['content'][0]['text'])) {
            return $res['content'][0]['text'];
        }
        // Gemini format
        if ($provider == 'gemini' && isset($res['candidates'][0]['content']['parts'][0]['text'])) {
            return $res['candidates'][0]['content']['parts'][0]['text'];
        }

        // 3. Detailed Error reporting
        if (isset($res['error'])) {
            $msg = is_array($res['error']) ? ($res['error']['message'] ?? json_encode($res['error'])) : $res['error'];
            return "AI Provider Error ($provider): " . $msg;
        }

        return "AI Provider Error: Unknown response structure from $provider";
    }
}
