<?php

namespace AIPT\Api\Gemini;

use AIPT\Api\AIClientInterface;
use AIPT\Api\Helpers\VisionImageEncoder;
use AIPT\Utils\PromptFormatter;
use AIPT\Core\ErrorHandler;

class GeminiClient implements AIClientInterface {
    private $api_key;
    private $api_url = 'https://generativelanguage.googleapis.com/v1beta/models';
    private $models = [];

    public function __construct($api_key) {
        $this->api_key = $api_key;
        $this->initializeModels();
    }
    
    /**
     * Initialize model configurations using shared base configurations
     * This eliminates code duplication and makes maintenance easier
     */
    private function initializeModels(): void {

        $gemini2xConfig = [
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ];

        $gemini3xConfig = [
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ];

        $this->models = [

            'gemini-3.5-flash' => ['name' => 'gemini-3.5-flash'] + $gemini3xConfig,
            'gemini-3.1-pro-preview' => ['name' => 'gemini-3.1-pro-preview'] + $gemini3xConfig,
            'gemini-3.1-flash-lite' => ['name' => 'gemini-3.1-flash-lite'] + $gemini3xConfig,
            'gemini-3-flash-preview' => ['name' => 'gemini-3-flash-preview'] + $gemini3xConfig,

            'gemini-2.5-pro' => ['name' => 'gemini-2.5-pro'] + $gemini2xConfig,
            'gemini-2.5-flash' => ['name' => 'gemini-2.5-flash'] + $gemini2xConfig,
            'gemini-2.5-flash-lite' => ['name' => 'gemini-2.5-flash-lite'] + $gemini2xConfig,
        ];
    }

    public function generate_description(string $system_prompt, string $user_prompt, string $model = 'gemini-2.5-flash', ?int $maximum_length = null): string {

        if (!isset($this->models[$model])) {
            throw new \Exception('Invalid model selected: ' . esc_html($model));
        }
        

        $model_config = $this->models[$model];
        $endpoint = $this->api_url . '/' . $model . ':generateContent?key=' . $this->api_key;

        

        $system_prompt = $this->sanitize_prompt_content($system_prompt);
        $user_prompt = $this->sanitize_prompt_content($user_prompt);

        $request_body = [
            'contents' => [
                [
                    'parts' => [
                        ['text' => $system_prompt . "\n\n" . $user_prompt]
                    ]
                ]
            ],
            'generationConfig' => [
                'temperature' => $model_config['temperature']
            ]
        ];

        $json_body = wp_json_encode($request_body, JSON_UNESCAPED_UNICODE);

        if ( false === $json_body ) {
            throw new \Exception(
                esc_html__( 'Failed to encode request body as JSON. The product data may contain invalid characters.', 'ai-product-tools' )
            );
        }

        $response = wp_remote_post($endpoint, [
            'headers' => [
                'Content-Type' => 'application/json',
            ],
            'body' => $json_body,
            'timeout' => 30,
        ]);

        if ($response instanceof \WP_Error) {

            throw new \Exception(
                ErrorHandler::format_api_error_message(
                    'Gemini',
                    $response->get_error_message()
                )
            );

        }

        $response_code = wp_remote_retrieve_response_code($response);
        $content_type = (string) wp_remote_retrieve_header($response, 'content-type');
        $body_str = (string) wp_remote_retrieve_body($response);

        if (strpos($content_type, 'application/json') === false && !empty($body_str) && $body_str[0] === '<') {
            throw new \Exception(esc_html__('The API response was not valid JSON. This is often caused by a server firewall or security plugin blocking outbound requests. Please contact your hosting provider or check your security plugin settings.', 'ai-product-tools'));
        }

        $body = json_decode($body_str, true);
        if (json_last_error() !== JSON_ERROR_NONE) {

            throw new \Exception(
                sprintf(
                    /* translators: %s: JSON error message */
                    __('Invalid JSON response from the API: %s', 'ai-product-tools'),
                    json_last_error_msg()
                )
            );

        }

        if (isset($body['error'])) {
            $error_data = $body['error'];

            $detailed_error = ErrorHandler::format_api_response_error($error_data, 'Gemini', $response_code);

            throw new \Exception($detailed_error);
        }

        if (!isset($body['candidates'][0]['content']['parts'][0]['text'])) {

            throw new \Exception('Invalid response from Gemini API: Response structure is not as expected');
        }

        \AIPT\Core\Services\UsageTracker::trackApiCall(
            'gemini',
            (string) $model,
            (int) ( $body['usageMetadata']['promptTokenCount'] ?? 0 ),
            (int) ( $body['usageMetadata']['candidatesTokenCount'] ?? 0 )
        );

        return trim($body['candidates'][0]['content']['parts'][0]['text']);
    }

    public function generate_faq_content(string $system_prompt, string $user_prompt, ?string $model = null): string {
        $resolved_model = $model ?: 'gemini-2.5-flash';

        return $this->generate_description($system_prompt, $user_prompt, $resolved_model);
    }

    public function generate_from_vision(string $system_prompt, string $user_prompt, string $image_url, ?string $model = null): string {
        $resolved_model = $model ?: 'gemini-2.5-flash';

        if ( ! isset( $this->models[ $resolved_model ] ) ) {
            throw new \Exception( 'Invalid model selected: ' . esc_html( $resolved_model ) );
        }

        $model_config = $this->models[ $resolved_model ];

        $ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
        if ( $ai_gate instanceof \WP_Error ) {
            throw new \Exception( esc_html( $ai_gate->get_error_message() ) );
        }

        try {
            $encoded_image = VisionImageEncoder::fetchAndEncode( $image_url );
        } catch ( \RuntimeException $e ) {
            $detailed_error = ErrorHandler::format_api_response_error(
                [
                    'code'    => 'aipt_vision_fetch_failed',
                    'message' => esc_html( $e->getMessage() ),
                    'type'    => 'vision_image_fetch_failed',
                ],
                'Gemini',
                0
            );

            throw new \Exception(
                $detailed_error
            );

        }

        $endpoint = $this->api_url . '/' . $resolved_model . ':generateContent?key=' . $this->api_key;

        $request_body = [
            'contents' => [
                [
                    'parts' => [
                        [ 'text' => $this->sanitize_prompt_content( $system_prompt ) . "\n\n" . $this->sanitize_prompt_content( $user_prompt ) ],
                        [
                            'inlineData' => [
                                'mimeType' => $encoded_image['mime_type'],
                                'data'     => $encoded_image['data'],
                            ],
                        ],
                    ],
                ],
            ],
            'generationConfig' => [
                'temperature' => $model_config['temperature'],
                'maxOutputTokens' => 150,
            ],
        ];

        if ( isset( $model_config['top_p'] ) && is_numeric( $model_config['top_p'] ) ) {
            $request_body['generationConfig']['topP'] = (float) $model_config['top_p'];
        }

        if ( isset( $model_config['top_k'] ) && is_numeric( $model_config['top_k'] ) ) {
            $request_body['generationConfig']['topK'] = (int) $model_config['top_k'];
        }

        $json_body = wp_json_encode( $request_body, JSON_UNESCAPED_UNICODE );
        if ( false === $json_body ) {
            throw new \Exception( esc_html__( 'Failed to encode vision request body as JSON.', 'ai-product-tools' ) );
        }

        $response = wp_remote_post( $endpoint, [
            'headers' => [ 'Content-Type' => 'application/json' ],
            'body'    => $json_body,
            'timeout' => 60,
        ] );

        if ( $response instanceof \WP_Error ) {
            $detailed_error = ErrorHandler::format_api_error_message( 'Gemini', esc_html( $response->get_error_message() ) );

            throw new \Exception(
                $detailed_error
            );

        }

        $response_code = wp_remote_retrieve_response_code( $response );
        $body_str      = (string) wp_remote_retrieve_body( $response );
        $body          = json_decode( $body_str, true );

        if ( json_last_error() !== JSON_ERROR_NONE ) {
            throw new \Exception(
                sprintf(
                    /* translators: %s: JSON error message */
                    esc_html__( 'Invalid JSON response from the API: %s', 'ai-product-tools' ),
                    esc_html( json_last_error_msg() )
                )
            );
        }

        if ( isset( $body['error'] ) ) {
            $detailed_error = ErrorHandler::format_api_response_error( $body['error'], 'Gemini', $response_code );

            throw new \Exception( $detailed_error );
        }

        if ( ! isset( $body['candidates'][0]['content']['parts'][0]['text'] ) ) {
            throw new \Exception( 'Invalid response from Gemini vision API: unexpected structure' );
        }

        \AIPT\Core\Services\UsageTracker::trackApiCall(
            'gemini',
            (string) $resolved_model,
            (int) ( $body['usageMetadata']['promptTokenCount'] ?? 0 ),
            (int) ( $body['usageMetadata']['candidatesTokenCount'] ?? 0 )
        );

        return trim( (string) $body['candidates'][0]['content']['parts'][0]['text'] );
    }

    /**
     * Prompt içeriğini temizler ve API için hazırlar
     * 
     * @param string $content Temizlenecek prompt içeriği 
     * @return string Temizlenmiş içerik
     */
    private function sanitize_prompt_content(string $content): string {
        return PromptFormatter::cleanContent($content);
    }

    public static function validate_api_key(string $api_key): bool {
        try {

            $endpoint = "https://generativelanguage.googleapis.com/v1beta/models?key={$api_key}";
            $response = wp_remote_get($endpoint, [
                'headers' => [
                    'Content-Type' => 'application/json',
                ],
                'timeout' => 20
            ]);

            if (is_wp_error($response)) {
                /** @var \WP_Error $response */
                throw new \Exception(
                    ErrorHandler::format_api_error_message(
                        'Gemini',
                        $response->get_error_message()
                    )
                );
            }

            $response_code = wp_remote_retrieve_response_code($response);
            $body_str = (string) wp_remote_retrieve_body($response);
            $body = json_decode($body_str, true);

            if (json_last_error() !== JSON_ERROR_NONE || !is_array($body)) {
                throw new \Exception(
                    sprintf(
                        /* translators: %s: JSON error message */
                        __('Invalid response from Gemini API: %s', 'ai-product-tools'),
                        json_last_error_msg()
                    )
                );
            }

            if ($response_code === 200 && isset($body['models'])) {
                return true;
            }

            if (isset($body['error'])) {
                $error_data = $body['error'];
                $detailed_error = ErrorHandler::format_api_response_error($error_data, 'Gemini', $response_code);
                throw new \Exception($detailed_error);
            }

            throw new \Exception(
                ErrorHandler::format_api_error_message(
                    'Gemini',
                    __('Invalid Gemini API key', 'ai-product-tools')
                )
            );

        } catch (\Exception $e) {
            throw $e;
        }
    }

    public function get_available_models(): array {
        return $this->models;
    }
    
    /**
     * API istekleri için parametre ayarlarını yapar
     * 
     * @param array $parameters Ayarlanacak parametreler
     * @return void
     */
    public function setParameters(array $parameters): void {
        if (empty($parameters)) {
            return;
        }
        
        try {

            foreach ($this->models as $model_id => &$model_config) {

                if (isset($parameters['temperature']) && is_numeric($parameters['temperature'])) {
                    $temperature = floatval($parameters['temperature']);

                    if ($temperature >= 0.0 && $temperature <= 1.0) {
                        $model_config['temperature'] = $temperature;
                    } else {
                    }
                }
                

                if (isset($parameters['top_p']) && is_numeric($parameters['top_p'])) {
                    $topP = floatval($parameters['top_p']);

                    if ($topP >= 0.0 && $topP <= 1.0) {
                        $model_config['top_p'] = $topP;
                    } else {
                    }
                }
                

                if (isset($parameters['top_k']) && is_numeric($parameters['top_k'])) {
                    $topK = intval($parameters['top_k']);

                    if ($topK >= 1 && $topK <= 40) {
                        if (strpos($model_id, 'flash') !== false) {
                            $model_config['top_k'] = $topK;
                        }
                    } else {
                    }
                }
                

            }
        } catch (\Exception $e) {

        } catch (\Error $e) {

        }
    }
} 
