<?php

namespace AIPT\Api\OpenRouter;

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

class OpenRouterClient implements AIClientInterface {
    private $api_key;
    private $api_url = 'https://openrouter.ai/api/v1/chat/completions';
    private $models = [

        'openrouter/free' => [
            'name' => 'openrouter/free',
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ],
        'meta-llama/llama-3.3-70b-instruct:free' => [
            'name' => 'meta-llama/llama-3.3-70b-instruct:free',
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ],
        'google/gemma-4-31b-it:free' => [
            'name' => 'google/gemma-4-31b-it:free',
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ],
        'deepseek/deepseek-v4-flash:free' => [
            'name' => 'deepseek/deepseek-v4-flash:free',
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ],
        'openai/gpt-oss-120b:free' => [
            'name' => 'openai/gpt-oss-120b:free',
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ],
        'qwen/qwen3-coder:free' => [
            'name' => 'qwen/qwen3-coder:free',
            'max_tokens' => 8192,
            'temperature' => 0.7,
            'supports_system_message' => true
        ],

        'anthropic/claude-opus-4.8' => [
            'name' => 'anthropic/claude-opus-4.8',
            'max_tokens' => 8192,
            'temperature' => 0.8,
            'supports_system_message' => true,
            'has_temperature' => false,
        ],
        'anthropic/claude-opus-4.7' => [
            'name' => 'anthropic/claude-opus-4.7',
            'max_tokens' => 8192,
            'temperature' => 0.8,
            'supports_system_message' => true,
            'has_temperature' => false,
        ],
        'anthropic/claude-sonnet-4.6' => [
            'name' => 'anthropic/claude-sonnet-4.6',
            'max_tokens' => 8192,
            'temperature' => 0.8,
            'supports_system_message' => true
        ],
        'openai/gpt-5.5' => [
            'name' => 'openai/gpt-5.5',
            'max_tokens' => 8192,
            'temperature' => 0.8,
            'supports_system_message' => true
        ],
        'google/gemini-3.5-flash' => [
            'name' => 'google/gemini-3.5-flash',
            'max_tokens' => 8192,
            'temperature' => 0.8,
            'supports_system_message' => true
        ],
        'google/gemini-3.1-pro-preview' => [
            'name' => 'google/gemini-3.1-pro-preview',
            'max_tokens' => 8192,
            'temperature' => 0.8,
            'supports_system_message' => true
        ],
        'deepseek/deepseek-v3.2' => [
            'name' => 'deepseek/deepseek-v3.2',
            'max_tokens' => 8192,
            'temperature' => 0.8,
            'supports_system_message' => true
        ],
        'x-ai/grok-4.1-fast' => [
            'name' => 'x-ai/grok-4.1-fast',
            'max_tokens' => 16384,
            'temperature' => 0.8,
            'supports_system_message' => true
        ],
    ];

    public function __construct($api_key) {
        $this->api_key = $api_key;
    }

    public function generate_description(string $system_prompt, string $user_prompt, string $model = 'openrouter/free', ?int $maximum_length = null): string {

        if (!isset($this->models[$model])) {

            $this->models[$model] = [
                'name' => $model,
                'max_tokens' => 8192,
                'temperature' => 0.7,
                'supports_system_message' => true
            ];
        }

        $model_config = $this->models[$model];
        $messages = [];

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

        if ($model_config['supports_system_message']) {
            $messages[] = [
                'role' => 'system',
                'content' => $system_prompt
            ];
            $messages[] = [
                'role' => 'user',
                'content' => $user_prompt
            ];
        } else {
            $messages[] = [
                'role' => 'user',
                'content' => $system_prompt . "\n\n" . $user_prompt
            ];
        }

        $has_temperature = ! array_key_exists('has_temperature', $model_config)
            || $model_config['has_temperature'] !== false;

        $request_body = [
            'model'    => $model_config['name'],
            'messages' => $messages,
        ];

        if ($has_temperature) {
            $request_body['temperature'] = $model_config['temperature'];
        }

        if ($maximum_length) {
            $request_body['max_tokens'] = $maximum_length;
        } else if (isset($model_config['max_tokens'])) {
            $request_body['max_tokens'] = $model_config['max_tokens'];
        }

        if ($has_temperature && isset($model_config['top_p'])) {
            $request_body['top_p'] = $model_config['top_p'];
        }

        $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($this->api_url, [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->api_key,
                'Content-Type' => 'application/json',
                'HTTP-Referer' => self::get_site_url_value(),
                'X-Title' => 'AI Product Tools WordPress Plugin'
            ],
            'body' => $json_body,
            'timeout' => 30,
        ]);

        if ($response instanceof \WP_Error) {
            $error_message = $response->get_error_message();
            throw new \Exception('WP Error: ' . esc_html($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, 'OpenRouter', $response_code);

            throw new \Exception($detailed_error);
        }

        if (!isset($body['choices'][0]['message']['content'])) {
            throw new \Exception('Invalid response from OpenRouter API: Response structure is not as expected');
        }

        \AIPT\Core\Services\UsageTracker::trackApiCall(
            'openrouter',
            (string) ( $body['model'] ?? $model ),
            (int) ( $body['usage']['prompt_tokens'] ?? 0 ),
            (int) ( $body['usage']['completion_tokens'] ?? 0 )
        );

        return trim($body['choices'][0]['message']['content']);
    }

    public function generate_faq_content(string $system_prompt, string $user_prompt, ?string $model = null): string {
        $resolved_model = $model ?: 'openrouter/free';

        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 ?: 'openai/gpt-5.4-mini';

        $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 );
            $image_data_uri = 'data:' . $encoded_image['mime_type'] . ';base64,' . $encoded_image['data'];
        } 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',
                ],
                'OpenRouter',
                0
            );

            throw new \Exception(
                $detailed_error
            );

        }

        $messages = [
            [
                'role'    => 'system',
                'content' => $this->sanitize_prompt_content( $system_prompt ),
            ],
            [
                'role'    => 'user',
                'content' => [
                    [
                        'type' => 'text',
                        'text' => $this->sanitize_prompt_content( $user_prompt ),
                    ],
                    [
                        'type'      => 'image_url',
                        'image_url' => [ 'url' => $image_data_uri ],
                    ],
                ],
            ],
        ];

        $model_config = $this->models[ $resolved_model ] ?? array(
            'name'        => $resolved_model,
        );

        $has_temperature = ! array_key_exists('has_temperature', $model_config)
            || $model_config['has_temperature'] !== false;

        $request_body = [
            'model'      => $model_config['name'],
            'messages'   => $messages,
            'max_tokens' => 150,
        ];

        if ($has_temperature) {
            $request_body['temperature'] = 0.3;
        }

        $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( $this->api_url, [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->api_key,
                'Content-Type'  => 'application/json',
                'HTTP-Referer'  => self::get_site_url_value(),
                'X-Title'       => 'AI Product Tools WordPress Plugin',
            ],
            'body'    => $json_body,
            'timeout' => 60,
        ] );

        if ( $response instanceof \WP_Error ) {
            throw new \Exception( 'WP Error: ' . esc_html( $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 ) {
            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'], 'OpenRouter', $response_code );

            throw new \Exception( $detailed_error );
        }

        if ( ! isset( $body['choices'][0]['message']['content'] ) ) {
            throw new \Exception( 'Invalid response from OpenRouter vision API: unexpected structure' );
        }

        \AIPT\Core\Services\UsageTracker::trackApiCall(
            'openrouter',
            (string) ( $body['model'] ?? $resolved_model ),
            (int) ( $body['usage']['prompt_tokens'] ?? 0 ),
            (int) ( $body['usage']['completion_tokens'] ?? 0 )
        );

        return trim( (string) $body['choices'][0]['message']['content'] );
    }

    /**
     * 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);
    }

    private static function get_site_url_value(): string {
        return (string) \get_site_url();
    }

	public static function validate_api_key(string $api_key): bool {
		$api_key = trim($api_key);
		if ($api_key === '' || strlen($api_key) < 20) {
			throw new \Exception('Invalid API key');
		}

		$key_validation_response = wp_remote_get('https://openrouter.ai/api/v1/key', [
			'headers' => [
                'Authorization' => 'Bearer ' . $api_key,
                'HTTP-Referer' => self::get_site_url_value(),
                'X-Title' => 'AI Product Tools'
            ],
            'timeout' => 20
        ]);

        if (is_wp_error($key_validation_response)) {

            throw new \Exception('Network error contacting OpenRouter: ' . $key_validation_response->get_error_message());
        }

        if ( ! is_array( $key_validation_response ) ) {
            throw new \Exception( 'OpenRouter API returned an invalid response' );
        }

        $key_response_code = wp_remote_retrieve_response_code($key_validation_response);
        $key_body_str = (string) wp_remote_retrieve_body($key_validation_response);

        if ($key_response_code === 200) {
            $key_body = json_decode($key_body_str, true);

            if (json_last_error() !== JSON_ERROR_NONE) {

                throw new \Exception('OpenRouter API returned invalid JSON: ' . json_last_error_msg());
            }

            if (!isset($key_body['data'])) {
                throw new \Exception('OpenRouter API response missing expected data structure');
            }

            return true;
        }

        if ($key_response_code === 401) {
            throw new \Exception('Invalid API key');
        }

        throw new \Exception('OpenRouter API returned unexpected status: ' . $key_response_code);
    }

    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_config) {

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

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

                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;
                    }
                }
                

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

                    if ($freqPenalty >= -2.0 && $freqPenalty <= 2.0) {
                        $model_config['frequency_penalty'] = $freqPenalty;
                    }
                }
                

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

                    if ($presPenalty >= -2.0 && $presPenalty <= 2.0) {
                        $model_config['presence_penalty'] = $presPenalty;
                    }
                }
            }
		} catch (\Exception $e) {

		}
	}
}
