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

/**
 * AI API Handler
 *
 * Handles communication with AI providers using the Strategy Pattern.
 *
 * @package    Kitsune_AI_Platform
 * @subpackage Kitsune_AI_Platform/includes
 */
class Kitsune_AI_Platform_API {

    private $settings;

    public function __construct() {
        $this->settings = get_option('kitsune_ai_platform_settings', array());
    }

    /**
     * Get the correct provider instance
     *
     * @param string $provider_slug
     * @return Kitsune_AI_Platform_Provider_Interface|WP_Error
     */
    private function get_provider($provider_slug) {
        $api_key = '';
        $normalized_provider = $this->normalize_provider_slug($provider_slug);

        switch ($normalized_provider) {
            case 'openai':
                $api_key = $this->get_provider_api_key('openai');
                if (empty($api_key)) {
                    /* translators: %s: OpenAI provider name */
                    return new WP_Error('missing_key', __('OpenAI API Key is missing.', 'kitsune-ai-platform'));
                }
                return new Kitsune_AI_Platform_OpenAI_Provider($api_key);

            case 'anthropic':
                $api_key = $this->get_provider_api_key('anthropic');
                if (empty($api_key)) {
                    /* translators: %s: Claude provider name */
                    return new WP_Error('missing_key', __('Claude API Key is missing.', 'kitsune-ai-platform'));
                }
                return new Kitsune_AI_Platform_Anthropic_Provider($api_key);

            case 'google':
                $api_key = $this->get_provider_api_key('google');
                if (empty($api_key)) {
                    /* translators: %s: Gemini provider name */
                    return new WP_Error('missing_key', __('Gemini API Key is missing.', 'kitsune-ai-platform'));
                }
                return new Kitsune_AI_Platform_Google_Provider($api_key);

            default:
                /* translators: %s: Unknown provider slug */
                return new WP_Error('invalid_provider', sprintf(__('Unknown provider: %s', 'kitsune-ai-platform'), $provider_slug));
        }
    }

    /**
     * Normalize provider aliases.
     *
     * @param string $provider_slug
     * @return string
     */
    private function normalize_provider_slug($provider_slug) {
        $provider_slug = strtolower(trim((string) $provider_slug));

        if ($provider_slug === 'claude') {
            return 'anthropic';
        }

        if ($provider_slug === 'gemini') {
            return 'google';
        }

        return $provider_slug;
    }

    /**
     * Resolve provider API key from env constants, secure storage, provider config, and legacy settings.
     *
     * @param string $provider_slug
     * @return string
     */
    private function get_provider_api_key($provider_slug) {
        $provider_slug = $this->normalize_provider_slug($provider_slug);

        $constant_candidates = array(
            'openai' => array('KITSUNE_AI_PLATFORM_OPENAI_API_KEY'),
            'anthropic' => array('KITSUNE_AI_PLATFORM_ANTHROPIC_API_KEY', 'KITSUNE_AI_PLATFORM_CLAUDE_API_KEY'),
            'google' => array('KITSUNE_AI_PLATFORM_GOOGLE_API_KEY', 'KITSUNE_AI_PLATFORM_GEMINI_API_KEY'),
        );

        foreach ($constant_candidates[$provider_slug] ?? array() as $constant_name) {
            if (defined($constant_name)) {
                $env_key = trim((string) constant($constant_name));
                if ($env_key !== '') {
                    return $env_key;
                }
            }
        }

        $secure_key = $this->get_secure_provider_key($provider_slug);
        if ($secure_key !== '') {
            return $secure_key;
        }

        $provider_option = get_option('kitsune_ai_platform_provider_' . $provider_slug, array());
        if (is_array($provider_option) && !empty($provider_option['api_key'])) {
            $plaintext_key = trim((string) $provider_option['api_key']);
            if ($plaintext_key !== '') {
                return $plaintext_key;
            }
        }

        $legacy_key_map = array(
            'openai' => 'openai_api_key',
            'anthropic' => 'claude_api_key',
            'google' => 'gemini_api_key',
        );

        $legacy_setting_key = $legacy_key_map[$provider_slug] ?? '';
        if ($legacy_setting_key !== '') {
            $legacy_key = trim((string) ($this->settings[$legacy_setting_key] ?? ''));
            if ($legacy_key !== '') {
                return $legacy_key;
            }
        }

        return '';
    }

    /**
     * Retrieve and decrypt secure provider key from ai_platform_api_keys option.
     *
     * @param string $provider_slug
     * @return string
     */
    private function get_secure_provider_key($provider_slug) {
        $keys = get_option('kitsune_ai_platform_api_keys', array());
        if (!is_array($keys) || empty($keys)) {
            return '';
        }

        $lookup_candidates = array($provider_slug);
        if ($provider_slug === 'anthropic') {
            $lookup_candidates[] = 'claude';
        } elseif ($provider_slug === 'google') {
            $lookup_candidates[] = 'gemini';
        }

        foreach ($lookup_candidates as $candidate) {
            $encrypted = $keys[$candidate] ?? '';
            if (!is_string($encrypted) || $encrypted === '') {
                continue;
            }

            if (!class_exists('Kitsune_AI_Platform_Encryption')) {
                require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/class-kitsune-ai-platform-encryption.php';
            }

            $decrypted = Kitsune_AI_Platform_Encryption::decrypt($encrypted);
            if (is_string($decrypted)) {
                $decrypted = trim($decrypted);
                if ($decrypted !== '') {
                    return $decrypted;
                }
            }
        }

        return '';
    }

    /**
     * Test API connection
     */
    public function test_connection($provider, $api_key) {
        // Temporarily override key for testing
        // We instantiate the provider directly here since the key might not be saved yet
        $provider_instance = null;

        switch (strtolower($provider)) {
            case 'openai':
                $provider_instance = new Kitsune_AI_Platform_OpenAI_Provider($api_key);
                break;
            case 'anthropic':
            case 'claude':
                $provider_instance = new Kitsune_AI_Platform_Anthropic_Provider($api_key);
                break;
            case 'google':
            case 'gemini':
                $provider_instance = new Kitsune_AI_Platform_Google_Provider($api_key);
                break;
            default:
                return array(
                    'success' => false,
                    'message' => sprintf(__('Unknown provider: %s', 'kitsune-ai-platform'), $provider),
                );
        }

        return $provider_instance->validate_key($api_key);
    }

    /**
     * Unified chat method (internal).
     *
     * @param array $params
     * @return array
     */
    private function chat($params) {
        $model = $this->normalize_model_id($params['model'] ?? KITSUNE_AI_PLATFORM_DEFAULT_MODEL);
        $params['model'] = $model;
        $provider_slug = $this->resolve_provider_slug($model, 'chat');
        $feature = sanitize_key($params['feature'] ?? 'chat');

        $provider = $this->get_provider($provider_slug);
        
        if (is_wp_error($provider)) {
            return array(
                'success' => false,
                'message' => $provider->get_error_message(),
            );
        }

        $start_time = microtime(true);
        $response = $provider->chat($params);
        $duration_ms = (int) round((microtime(true) - $start_time) * 1000);

        $status = !empty($response['success']) ? 'success' : 'error';
        $this->log_usage(
            $provider_slug,
            $model,
            $response['data']['usage'] ?? array(),
            array(
                'feature' => $feature,
                'duration' => $duration_ms,
                'status' => $status,
                'user_id' => $params['user_id'] ?? null,
            )
        );

        return $response;
    }

    /**
     * Chat with retrieval-augmented generation (RAG).
     *
     * @param array $params
     * @return array
     */
    public function chatRAG($params) {
        $params = is_array($params) ? $params : array();
        $rag = isset($params['rag']) && is_array($params['rag']) ? $params['rag'] : array();

        if (array_key_exists('enabled', $rag) && empty($rag['enabled'])) {
            return $this->chat($params);
        }

        $messages = isset($params['messages']) && is_array($params['messages']) ? $params['messages'] : array();
        $query = $this->resolve_rag_query($params, $messages);
        if ($query === '') {
            return array(
                'success' => false,
                /* translators: %s: RAG query error */
                'message' => __('RAG query is required.', 'kitsune-ai-platform'),
            );
        }

        $embedding_model = $this->normalize_model_id($rag['embedding_model'] ?? ($params['embedding_model'] ?? ''));
        if ($embedding_model === '') {
            $embedding_model = $this->get_default_embedding_model();
        }

        if ($embedding_model === '') {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log( 'AI Platform RAG fallback [feature=' . sanitize_key( $params['feature'] ?? 'chat' ) . ']: no embedding model configured.' );
            }
            return $this->chat($params);
        }

        $client = $this->get_vector_db_client($rag);
        if (is_wp_error($client)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log( 'AI Platform RAG fallback [feature=' . sanitize_key( $params['feature'] ?? 'chat' ) . ']: vector DB unavailable — ' . $client->get_error_message() );
            }
            return $this->chat($params);
        }

        $embedding_response = $this->embed(array(
            'model' => $embedding_model,
            'input' => $query,
        ));

        if (empty($embedding_response['success'])) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log( 'AI Platform RAG fallback [feature=' . sanitize_key( $params['feature'] ?? 'chat' ) . ']: embedding failed — ' . ( $embedding_response['message'] ?? 'unknown error' ) );
            }
            return $this->chat($params);
        }

        $embedding = $embedding_response['data']['embedding'] ?? null;
        if (!is_array($embedding) || empty($embedding)) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log( 'AI Platform RAG fallback [feature=' . sanitize_key( $params['feature'] ?? 'chat' ) . ']: embedding vector missing in response.' );
            }
            return $this->chat($params);
        }

        $limit = isset($rag['limit']) ? max(1, intval($rag['limit'])) : 6;
        $source_ids = isset($rag['source_ids']) && is_array($rag['source_ids']) ? $rag['source_ids'] : array();
        $search_result = $client->vector_search($query, array(
            'limit'           => $limit,
            'query_embedding' => $embedding,
            'source_ids'      => $source_ids,
        ));

        if (empty($search_result['success'])) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log( 'AI Platform RAG fallback [feature=' . sanitize_key( $params['feature'] ?? 'chat' ) . ']: vector search failed — ' . ( $search_result['message'] ?? 'unknown error' ) );
            }
            return $this->chat($params);
        }

        $context_blocks = array();
        foreach ($search_result['data'] as $index => $match) {
            $metadata = isset($match['metadata']) && is_array($match['metadata']) ? $match['metadata'] : array();
            $source_name = isset($metadata['source_name']) && $metadata['source_name'] !== ''
                ? sanitize_text_field($metadata['source_name'])
                : __('Knowledge Base', 'kitsune-ai-platform');

            $content = wp_strip_all_tags($match['content'] ?? '');
            $content = trim(preg_replace('/\s+/', ' ', $content));
            if ($content === '') {
                continue;
            }

            $context_blocks[] = sprintf('Source %d (%s): %s', $index + 1, $source_name, $content);
        }

        $max_context_chars = isset($rag['max_context_chars']) ? max(400, intval($rag['max_context_chars'])) : 4000;
        $context_text = '';
        foreach ($context_blocks as $block) {
            $next = $context_text === '' ? $block : $context_text . "\n\n" . $block;
            if (strlen($next) > $max_context_chars) {
                break;
            }
            $context_text = $next;
        }

        if ($context_text === '') {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log( 'AI Platform RAG fallback [feature=' . sanitize_key( $params['feature'] ?? 'chat' ) . ']: no relevant KB context found for query.' );
            }
            return $this->chat($params);
        }

        $system_prompt = $this->build_rag_system_prompt($messages, $context_text);
        $messages = $this->strip_system_messages($messages);
        array_unshift($messages, array('role' => 'system', 'content' => $system_prompt));

        if (empty($messages)) {
            $messages = array(
                array('role' => 'system', 'content' => $system_prompt),
                array('role' => 'user', 'content' => $query),
            );
        }

        $chat_params = $params;
        $chat_params['messages'] = $messages;
        unset($chat_params['rag'], $chat_params['embedding_model'], $chat_params['vector_db'], $chat_params['query']);

        return $this->chat($chat_params);
    }

    /**
     * Generate an image from a text prompt.
     *
     * @param string $prompt
     * @param array  $params  (model, style, aspect_ratio, feature, user_id)
     * @return array
     */
    public function generate_image($prompt, $params = array()) {
        $model = $this->normalize_model_id($params['model'] ?? '');
        if ($model === '') {
            $model = $this->get_default_image_model();
        }
        if ($model === '') {
            $model = 'dall-e-3'; // ultimate fallback
        }
        $params['model'] = $model;
        $feature = sanitize_key($params['feature'] ?? 'image');

        $provider_slug = $this->resolve_provider_slug($model, 'image');
        $provider      = $this->get_provider($provider_slug);

        if (is_wp_error($provider)) {
            return array(
                'success' => false,
                'message' => $provider->get_error_message(),
            );
        }

        $start_time  = microtime(true);
        $response    = $provider->generate_image($prompt, $params);
        $duration_ms = (int) round((microtime(true) - $start_time) * 1000);

        $status = !empty($response['success']) ? 'success' : 'error';
        $this->log_usage(
            $provider_slug,
            $model,
            array(),
            array(
                'feature'  => $feature,
                'duration' => $duration_ms,
                'status'   => $status,
                'user_id'  => $params['user_id'] ?? null,
            )
        );

        return $response;
    }

    /**
     * Generate embeddings using the configured provider.
     *
     * @param array $params
     * @return array
     */
    public function embed($params) {
        $model = $this->normalize_model_id($params['model'] ?? '');
        $input = $params['input'] ?? '';
        $feature = sanitize_key($params['feature'] ?? 'embeddings');

        if (!is_string($model) || $model === '') {
            return array(
                'success' => false,
                'message' => __('Embedding model is required.', 'kitsune-ai-platform'),
            );
        }

        $provider_slug = $this->resolve_provider_slug($model, 'embeddings');
        $provider = $this->get_provider($provider_slug);

        if (is_wp_error($provider)) {
            return array(
                'success' => false,
                'message' => $provider->get_error_message(),
            );
        }

        $start_time = microtime(true);
        $response = $provider->embed(array(
            'model' => $model,
            'input' => $input,
        ));
        $duration_ms = (int) round((microtime(true) - $start_time) * 1000);

        $status = !empty($response['success']) ? 'success' : 'error';
        $this->log_usage(
            $provider_slug,
            $model,
            $response['data']['usage'] ?? array(),
            array(
                'feature' => $feature,
                'duration' => $duration_ms,
                'status' => $status,
                'user_id' => $params['user_id'] ?? null,
            )
        );

        return $response;
    }

    /**
     * Resolve provider slug from model name.
     *
     * @param string $model
     * @param string $type
     * @return string
     */
    private function resolve_provider_slug($model, $type = 'chat') {
        $model = strtolower((string) $model);

        if (strpos($model, 'claude') !== false) {
            return 'anthropic';
        }

        if (strpos($model, 'gemini') !== false) {
            return 'google';
        }

        if ($type === 'embeddings') {
            if (strpos($model, 'gemini-embedding-001') !== false) {
                return 'google';
            }
        }

        if ($type === 'image') {
            if (strpos($model, 'imagen') !== false) {
                return 'google';
            }
            // DALL-E and GPT-image models are OpenAI
            if (strpos($model, 'dall-e') !== false || strpos($model, 'gpt-image') !== false) {
                return 'openai';
            }
        }

        return 'openai';
    }

    /**
     * Normalize model IDs by stripping provider prefixes.
     *
     * @param string $model
     * @return string
     */
    private function normalize_model_id($model) {
        if (is_array($model)) {
            $model = $model['model'] ?? '';
        }
        $model = is_string($model) ? trim($model) : '';
        if ($model === '') {
            return '';
        }

        $parts = explode(':', $model, 2);
        return count($parts) === 2 ? $parts[1] : $model;
    }

    /**
     * Resolve query string for RAG.
     *
     * @param array $params
     * @param array $messages
     * @return string
     */
    private function resolve_rag_query($params, $messages) {
        if (!empty($params['query']) && is_string($params['query'])) {
            return trim($params['query']);
        }

        if (!empty($params['message']) && is_string($params['message'])) {
            return trim($params['message']);
        }

        if (!is_array($messages)) {
            return '';
        }

        for ($i = count($messages) - 1; $i >= 0; $i--) {
            $item = $messages[$i];
            if (!is_array($item)) {
                continue;
            }
            if (($item['role'] ?? '') !== 'user') {
                continue;
            }
            $content = isset($item['content']) ? trim((string) $item['content']) : '';
            if ($content !== '') {
                return $content;
            }
        }

        return '';
    }

    /**
     * Build system prompt with retrieved context.
     *
     * @param array  $messages
     * @param string $context_text
     * @return string
     */
    private function build_rag_system_prompt($messages, $context_text) {
        $base_system = '';
        if (!empty($messages) && is_array($messages[0]) && ($messages[0]['role'] ?? '') === 'system') {
            $base_system = trim((string) ($messages[0]['content'] ?? ''));
        }

        $rag_instructions = __(
            'You are a knowledge base assistant. Use only the sources provided. If the answer is not in the sources, say you do not have enough information. Cite sources like [1] or [2].',
            'kitsune-ai-platform'
        );

        $system_prompt = $base_system !== '' ? $base_system . "\n\n" : '';
        $system_prompt .= $rag_instructions;
        $system_prompt .= "\n\nSources:\n" . $context_text;

        return $system_prompt;
    }

    /**
     * Remove existing system messages so we can inject RAG system prompt.
     *
     * @param array $messages
     * @return array
     */
    private function strip_system_messages($messages) {
        if (!is_array($messages)) {
            return array();
        }

        $filtered = array();
        foreach ($messages as $message) {
            if (!is_array($message)) {
                continue;
            }
            if (($message['role'] ?? '') === 'system') {
                continue;
            }
            $filtered[] = $message;
        }

        return $filtered;
    }

    /**
     * Resolve default embedding model from settings.
     *
     * @return string
     */
    private function get_default_embedding_model() {
        $defaults = get_option('kitsune_ai_platform_default_models', array());
        $model = isset($defaults['embeddings']) ? $defaults['embeddings'] : '';
        return $this->normalize_model_id($model);
    }

    /**
     * Resolve default image generation model from settings.
     *
     * @return string
     */
    private function get_default_image_model() {
        $defaults = get_option('kitsune_ai_platform_default_models', array());
        $model = isset($defaults['imageGen']) ? $defaults['imageGen'] : '';
        return $this->normalize_model_id($model);
    }

    /**
     * Resolve vector DB client for RAG.
     *
     * @param array $rag
     * @return Kitsune_AI_Platform_Vector_DB_Interface|WP_Error
     */
    private function get_vector_db_client($rag) {
        $vector_db = isset($rag['vector_db']) && is_array($rag['vector_db']) ? $rag['vector_db'] : array();
        $vector_id = sanitize_key($vector_db['id'] ?? ($rag['vector_db_id'] ?? ''));

        if ($vector_id === '') {
            $state = get_option('kitsune_ai_platform_kb_vector_dbs', array());
            $default_id = isset($state['default']) ? sanitize_key($state['default']) : '';
            $databases = isset($state['databases']) && is_array($state['databases']) ? $state['databases'] : array();

            foreach ($databases as $database) {
                if (!is_array($database)) {
                    continue;
                }
                $db_id = sanitize_key($database['id'] ?? '');
                if ($db_id === '' || $db_id !== ($default_id !== '' ? $default_id : 'chroma')) {
                    continue;
                }
                if (empty($database['connected'])) {
                    return new WP_Error('vector_db_disconnected', __('Default vector database is not connected.', 'kitsune-ai-platform'));
                }

                $vector_id = $db_id;
                $vector_db['config'] = isset($database['config']) && is_array($database['config']) ? $database['config'] : array();
                break;
            }
        }

        if ($vector_id === '') {
            $vector_id = 'chroma';
        }

        $config = isset($vector_db['config']) && is_array($vector_db['config']) ? $vector_db['config'] : array();

        if (!class_exists('Kitsune_AI_Platform_Vector_DB_Factory')) {
            require_once KITSUNE_AI_PLATFORM_PLUGIN_DIR . 'includes/vector-db/class-kitsune-ai-platform-vector-db-factory.php';
        }

        return Kitsune_AI_Platform_Vector_DB_Factory::create($vector_id, $config);
    }

    /**
     * Log API usage
     */
    private function log_usage($provider, $model, $usage, $context = array()) {
        global $wpdb;
        $table = $wpdb->prefix . 'kitsune_ai_platform_api_logs';

        $usage = is_array($usage) ? $usage : array();
        $context = is_array($context) ? $context : array();

        $tokens_in = intval($usage['prompt_tokens'] ?? ($usage['input_tokens'] ?? 0));
        $tokens_out = intval($usage['completion_tokens'] ?? ($usage['output_tokens'] ?? 0));
        $feature = sanitize_key($context['feature'] ?? 'general');
        $duration = max(0, intval($context['duration'] ?? 0));
        $status = sanitize_key($context['status'] ?? 'success');
        if ($status === '') {
            $status = 'success';
        }

        $resolved_user_id = isset($context['user_id']) ? intval($context['user_id']) : 0;
        if ($resolved_user_id <= 0 && function_exists('get_current_user_id')) {
            $resolved_user_id = intval(get_current_user_id());
        }
        $user_id = $resolved_user_id > 0 ? $resolved_user_id : null;
        
        // Simple cost estimation (placeholder logic)
        $cost = ($tokens_in * 0.00001) + ($tokens_out * 0.00003);

        $wpdb->insert(
            $table,
            array(
                'provider' => $provider,
                'model' => $model,
                'feature' => $feature,
                'tokens_input' => $tokens_in,
                'tokens_output' => $tokens_out,
                'cost' => $cost,
                'duration' => $duration,
                'status' => $status,
                'user_id' => $user_id,
                'created_at' => current_time('mysql'),
            )
        );
    }
}
