<?php

namespace IA;

require_once __DIR__ . '/../../includes/env_loader.php';

class Agent
{
    private ?\PDO $kbPdo = null;
    private array $config = [];
    private array $activeLanguages = [];
    private \PDO $mainPdo;

    private const KB_LOG_FILE = __DIR__ . '/../../logs/kb_search.log';

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

    private function loadConfig(): void
    {
        require_once __DIR__ . '/../../includes/db.php';
        $this->mainPdo = getDbConnection();

        $stmt = $this->mainPdo->query("SELECT config_key, config_value FROM ia_agent_config");
        while ($row = $stmt->fetch()) {
            $this->config[$row['config_key']] = $row['config_value'];
        }

        $stmt = $this->mainPdo->query("SELECT language_code, language_name FROM supported_languages WHERE is_active = 1");
        $this->activeLanguages = $stmt->fetchAll(\PDO::FETCH_KEY_PAIR);
    }

    private function getKbConnection(): \PDO
    {
        if ($this->kbPdo !== null) {
            return $this->kbPdo;
        }

        $host = $this->config['kb_db_host'] ?? $_ENV['KB_DB_HOST'] ?? getenv('KB_DB_HOST') ?: 'localhost';
        $port = $this->config['kb_db_port'] ?? $_ENV['KB_DB_PORT'] ?? getenv('KB_DB_PORT') ?: '3306';
        $dbname = $this->config['kb_db_name'] ?? $_ENV['KB_DB_NAME'] ?? getenv('KB_DB_NAME') ?: 'lastwar2';
        $user = $this->config['kb_db_user'] ?? $_ENV['KB_DB_USER'] ?? getenv('KB_DB_USER') ?: 'root';
        $pass = $this->config['kb_db_pass'] ?? $_ENV['KB_DB_PASS'] ?? getenv('KB_DB_PASS') ?: '';

        error_log("KB Connection - Host: {$host}", 3, self::KB_LOG_FILE);
        error_log("KB Connection - Port: {$port}", 3, self::KB_LOG_FILE);
        error_log("KB Connection - DBName: {$dbname}", 3, self::KB_LOG_FILE);
        error_log("KB Connection - User: {$user}", 3, self::KB_LOG_FILE);
        // Do NOT log password for security reasons

        try {
            $dsn = "mysql:host={$host};port={$port};dbname={$dbname};charset=utf8mb4";
            $this->kbPdo = new \PDO($dsn, $user, $pass, [
                \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
            ]);
            error_log("KB Connection - PDO connection established successfully.", 3, self::KB_LOG_FILE);
        } catch (\PDOException $e) {
            error_log("KB Connection Error: " . $e->getMessage(), 3, self::KB_LOG_FILE);
            throw $e; // Re-throw to ensure the original error is propagated
        }


        return $this->kbPdo;
    }

    public function getConfig(string $key, mixed $default = null): mixed
    {
        return $this->config[$key] ?? $default;
    }

    public function updateConfig(string $key, string $value): bool
    {
        $stmt = $this->mainPdo->prepare("
            INSERT INTO ia_agent_config (config_key, config_value) VALUES (?, ?)
            ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)
        ");
        return $stmt->execute([$key, $value]);
    }

    public function getAllConfig(): array
    {
        return $this->config;
    }

    public function getActiveLanguages(): array
    {
        return $this->activeLanguages;
    }

    public function isKbEnabled(): bool
    {
        return ($this->config['kb_enabled'] ?? '1') === '1';
    }

    public function searchKnowledgeBase(string $query, string $userLanguage): array
    {
        if (!$this->isKbEnabled()) {
            return [];
        }

        try {
            $pdo = $this->getKbConnection();
            $maxResults = (int)($this->config['kb_max_results'] ?? 5);
            
            error_log("KB Search - User Query: " . $query, 3, self::KB_LOG_FILE);
            
            $queryMappings = [
                'hero' => ['Heroes', 'hero'],
                'heroes' => ['Heroes', 'hero'],
                'zombie' => ['General', 'zombie'],
                'zombies' => ['General', 'zombie'],
                'invasion' => ['General', 'invasion'],
                'invasión' => ['General', 'zombie invasion'],
                'ghost' => ['Heroes', 'ghost'],
                'weapon' => ['Heroes', 'weapon'],
                'weapons' => ['Heroes', 'weapon'],
                'skill' => ['Heroes', 'skill'],
                'skills' => ['Heroes', 'skill'],
                'season' => ['General', 'season'],
                'temporada' => ['General', 'season'],
                'vip' => ['General', 'vip'],
                'battle' => ['General', 'battle'],
                'sky' => ['General', 'sky'],
                'alliance' => ['General', 'alliance'],
                'alianza' => ['General', 'alliance'],
                'building' => ['General', 'building'],
                'edificio' => ['General', 'building'],
                'troop' => ['General', 'troop'],
                'tropa' => ['General', 'troop'],
            ];
            
            $searchQuery = mb_strtolower($query, 'UTF-8');
            $foundMapping = null;
            
            foreach ($queryMappings as $key => $mapping) {
                if (strpos($searchQuery, $key) !== false) {
                    $foundMapping = $mapping;
                    break;
                }
            }
            
            error_log("KB Search - Found Mapping: " . ($foundMapping ? json_encode($foundMapping) : 'None'), 3, self::KB_LOG_FILE);

            if ($foundMapping) {
                list($topic, $term) = $foundMapping;

                if (in_array($topic, ['General', 'Season 1', 'Season 2', 'Season 3', 'Season 4', 'Season 5']) && 
                    (strpos($searchQuery, 'season') !== false || strpos($searchQuery, 'temporada') !== false)) {
                    if (preg_match('/(season|temporada)\s*(\d+)/i', $searchQuery, $matches)) {
                        $term = $matches[0];
                    }
                }
                
                error_log("KB Search - Term after season adjustment: " . $term, 3, self::KB_LOG_FILE);

                // If user language is Spanish and query is for a season, translate term to English
                if ($userLanguage === 'es' && (strpos($term, 'temporada') !== false)) {
                    if (preg_match('/(temporada)\s*(\d+)/i', $term, $matches)) {
                        $seasonNumber = $matches[2];
                        $term = "season " . $seasonNumber;
                        error_log("KB Search - Translated Spanish season term to English: " . $term, 3, self::KB_LOG_FILE);
                    }
                }
                
                $sql = "
                    SELECT id, topic, entity_type, entity_name, content_preview, article_url, article_title
                    FROM knowledge_base
                    WHERE 
                        (entity_name = ? OR article_title LIKE ? OR content_preview LIKE ?)
                        OR (entity_name LIKE ? OR article_title LIKE ? OR content_preview LIKE ?)
                    ORDER BY 
                        CASE 
                            WHEN entity_name = ? THEN 0
                            WHEN article_title LIKE ? THEN 1
                            WHEN entity_name LIKE ? THEN 2
                            WHEN article_title LIKE ? THEN 3
                            WHEN content_preview LIKE ? THEN 4
                            ELSE 5
                        END,
                        LENGTH(content_preview) DESC,
                        LENGTH(article_title) ASC
                    LIMIT {$maxResults}
                ";
                
                $params = [
                    $term, // Exact match for entity_name
                    "{$term}%", // Prefix match for article_title
                    "%{$term}%", // Broad match for content_preview
                    "%{$term}%", // Broad match for entity_name
                    "%{$term}%", // Broad match for article_title
                    "%{$term}%", // Broad match for content_preview
                    $term, // For ORDER BY: Exact match for entity_name
                    "{$term}%", // For ORDER BY: Prefix match for article_title
                    "%{$term}%", // For ORDER BY: Broad match for entity_name
                    "%{$term}%", // For ORDER BY: Broad match for article_title
                    "%{$term}%"  // For ORDER BY: Broad match for content_preview
                ];

                error_log("KB Search - Mapped SQL: " . $sql, 3, self::KB_LOG_FILE);
                error_log("KB Search - Mapped Params: " . json_encode($params), 3, self::KB_LOG_FILE);
                
                $stmt = $pdo->prepare($sql);
                $stmt->execute($params);
                $results = $stmt->fetchAll();
                
                error_log("KB Search - Mapped Results: " . json_encode($results), 3, self::KB_LOG_FILE);
                
                if (!empty($results)) {
                    return $results;
                }
            }
            
            $stopWords = ['me', 'puedes', 'el', 'la', 'los', 'las', 'un', 'una', 'de', 'del', 'en', 'con', 'para', 'por', 'sobre', 'que', 'es', 'son', 'this', 'the', 'a', 'an', 'is', 'are', 'can', 'could', 'would', 'tell', 'name', 'list', 'show', 'what', 'how', 'can', 'you', 'say', 'tell'];
            $words = explode(' ', $searchQuery);
            $words = array_filter($words, fn($w) => !in_array($w, $stopWords) && strlen($w) > 2);
            $searchTerms = array_values($words);

            if (empty($searchTerms)) {
                $searchTerms = [$searchQuery];
            }
            
            error_log("KB Search - Fallback Search Terms: " . json_encode($searchTerms), 3, self::KB_LOG_FILE);

            $primaryTerm = $searchTerms[0];
            
            $sql = "
                SELECT id, topic, entity_type, entity_name, content_preview, article_url, article_title
                FROM knowledge_base
                WHERE " . implode(' AND ', array_map(fn($term) => "(entity_name LIKE ? OR article_title LIKE ? OR content_preview LIKE ?)", $searchTerms)) . "
                ORDER BY 
                    CASE
                        WHEN entity_name LIKE ? THEN 0
                        WHEN article_title LIKE ? THEN 1
                        WHEN content_preview LIKE ? THEN 2
                        ELSE 3
                    END,
                    LENGTH(content_preview) DESC
                LIMIT {$maxResults}
            ";

            $params = [];
            foreach ($searchTerms as $term) {
                $params[] = "%{$term}%";
                $params[] = "%{$term}%";
                $params[] = "%{$term}%";
            }
            $params[] = "%{$primaryTerm}%";
            $params[] = "%{$primaryTerm}%";
            $params[] = "%{$primaryTerm}%";
            
            error_log("KB Search - Fallback SQL: " . $sql, 3, self::KB_LOG_FILE);
            error_log("KB Search - Fallback Params: " . json_encode($params), 3, self::KB_LOG_FILE);
            
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);

            $results = $stmt->fetchAll();
            error_log("KB Search - Fallback Results: " . json_encode($results), 3, self::KB_LOG_FILE);
            
            return $stmt->fetchAll();
        } catch (\Exception $e) {
            error_log("KB Search Error: " . $e->getMessage(), 3, self::KB_LOG_FILE);
            return [];
        }
    }

    public function generateResponse(string $userMessage): string
    {
        $userLanguage = $this->detectLanguage($userMessage);
        
        $kbResults = $this->searchKnowledgeBase($userMessage, $userLanguage);
        
        if (empty($kbResults)) {
            $kbResults = $this->searchKnowledgeBase('hero zombie ghost', $userLanguage);
        }
        
        if (empty($kbResults)) {
            return $userLanguage === 'es' 
                ? "Soy tu asistente del juego Last War: Survival. Puedo ayudarte con información sobre héroes, eventos, estrategias y más del juego. ¿Sobre qué tema específico quieres saber más?"
                : "I'm your assistant for the game Last War: Survival. I can help you with information about heroes, events, strategies and more. What specific topic would you like to know more about?";
        }

        return $this->generateWithAI($userMessage, $kbResults, $userLanguage);
    }

    private function generateWithAI(string $question, array $kbResults, string $userLanguage): string
    {
        if (empty($kbResults)) {
            return $this->buildFallbackResponse($kbResults, $userLanguage);
        }

        $context = $this->buildContext($kbResults);
        
        $lastWarTerms = ['last war', 'lastwar', 'last war survival', 'lw', 'last war: survival', 'heroes', 'hero', 'héroe', 'héroes', 'zombie', 'invasion', 'battle', 'alliance', 'alianza', 'edificio', 'building', 'tropa', 'troop', 'temporada', 'season', 'skill', 'weapon', 'vip'];
        $questionLower = mb_strtolower($question, 'UTF-8');
        
        $isAboutLastWar = false;
        foreach ($lastWarTerms as $term) {
            if (strpos($questionLower, $term) !== false) {
                $isAboutLastWar = true;
                break;
            }
        }
        
        $isGenericQuestion = preg_match('/^(que|what|me|dime|tell|como|how|cual|which|dame|about|cuales|cual es|como se|cuales son)\b/i', trim($question));
        
        if (!$isAboutLastWar && !$isGenericQuestion) {
            if ($userLanguage === 'es') {
                return "Solo puedo ayudarte con información sobre el juego **Last War: Survival**. ¿Tienes alguna pregunta sobre este juego?";
            } elseif ($userLanguage === 'pt') {
                return "Só posso ajudá-lo com informações sobre o jogo **Last War: Survival**. Você tem alguma pergunta sobre este jogo?";
            } else {
                return "I can only help you with information about the game **Last War: Survival**. Do you have any questions about this jogo?";
            }
        }
        
        $langNames = [
            'es' => 'ESPAÑOL',
            'en' => 'ENGLISH',
            'pt' => 'PORTUGUÊS',
            'fr' => 'FRANÇAIS',
            'de' => 'DEUTSCH',
            'it' => 'ITALIANO',
            'ru' => 'РУССКИЙ',
            'zh' => '中文',
            'ja' => '日本語',
            'ko' => '한국어'
        ];
        
        $langName = $langNames[$userLanguage] ?? strtoupper($userLanguage);
        $langInstruction = "IMPORTANTE: El usuario escribe en {$langName}. Debes responder SIEMPRE en {$langName}. NO mezcles idiomas. Toda la respuesta debe ser en {$langName}.";
        
        $customPrompt = $this->config['system_prompt'] ?? '';
        
        $systemPrompt = $langInstruction . "\n\n" . $customPrompt;

        $userPrompt = match($userLanguage) {
            'es' => "Pregunta del jugador: {$question}\n\nInformación del juego:\n{$context}\n\nResponde en ESPAÑOL de forma clara y útil:",
            'pt' => "Pergunta do jogador: {$question}\n\nInformações do jogo:\n{$context}\n\nResponda em PORTUGUÊS de forma clara e útil:",
            'fr' => "Question du joueur: {$question}\n\nInformations sur le jeu:\n{$context}\n\nRépondez en FRANÇAIS clairement et utilement:",
            'de' => "Frage des Spielers: {$question}\n\nSpielinformationen:\n{$context}\n\nAntworten Sie klar und hilfreich auf DEUTSCH:",
            'it' => "Domanda del giocatore: {$question}\n\nInformazioni sul gioco:\n{$context}\n\nRispondi in ITALIANO in modo chiaro e utile:",
            default => "Player question: {$question}\n\nGame information:\n{$context}\n\nAnswer in ENGLISH clearly and helpfully:"
        };

        return $this->callGroqAPI($systemPrompt, $userPrompt, $kbResults, $userLanguage);
    }

    private function callGroqAPI(string $systemPrompt, string $userPrompt, array $kbResults, string $userLanguage, int $attempt = 0): string
    {
        $freeModels = ['llama-3.1-8b-instant', 'mixtral-8x7b-32768', 'llama3-70b-8192'];
        
        $currentModel = $this->config['ai_model'] ?? 'llama-3.1-8b-instant';
        
        if (!in_array($currentModel, $freeModels)) {
            $currentModel = 'llama-3.1-8b-instant';
        }

        try {
            $apiKey = $_ENV['GROQ_API_KEY'] ?? getenv('GROQ_API_KEY');
            
            if (empty($apiKey)) {
                return $this->buildFallbackResponse($kbResults, $userLanguage);
            }

            $url = 'https://api.groq.com/openai/v1/chat/completions';
            
            $data = [
                'model' => $currentModel,
                'messages' => [
                    ['role' => 'system', 'content' => $systemPrompt],
                    ['role' => 'user', 'content' => $userPrompt]
                ],
                'temperature' => 0.7,
                'max_tokens' => 1024,
            ];

            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $apiKey
            ]);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);

            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            if ($httpCode === 200) {
                $result = json_decode($response, true);
                $aiResponse = $result['choices'][0]['message']['content'] ?? '';
                
                if (!empty($aiResponse)) {
                    return $aiResponse;
                }
            } elseif ($httpCode === 429 || strpos($response, 'quota') !== false) {
                error_log("Groq API: Rate limit or quota exceeded, trying next model");
                
                if ($attempt < count($freeModels) - 1) {
                    $nextModel = $freeModels[$attempt + 1];
                    $this->updateConfig('ai_model', $nextModel);
                    return $this->callGroqAPI($systemPrompt, $userPrompt, $kbResults, $userLanguage, $attempt + 1);
                }
            } else {
                error_log("Groq API Error: HTTP {$httpCode} - {$response}");
            }
        } catch (\Exception $e) {
            error_log("Groq Error: " . $e->getMessage());
        }

        return $this->buildFallbackResponse($kbResults, $userLanguage);
    }

    private function buildContext(array $results): string
    {
        $context = "INFORMACIÓN DE LA BASE DE CONOCIMIENTOS DEL JUEGO:\n\n";
        
        $context .= "TEMAS PRINCIPALES DEL JUEGO:\n";
        $context .= "- Héroes: Mason (Raging Marksman), Murphy, Kimberly, Blade, Shadow Marshall, Striker Carlie, Thunder Tesla, Williams, Schuyler, Morrison, Lucius, DVA\n";
        $context .= "- Tipos de héroes: Defense (Defensa), Attack (Ataque), Support (Apoyo)\n";
        $context .= "- Eventos: Zombie Invasion, Ghost Ops, Sky Battlefront, Season events\n\n";
        
        $uniqueArticles = [];
        foreach ($results as $result) {
            $url = $result['article_url'] ?? '';
            if (!isset($uniqueArticles[$url])) {
                $uniqueArticles[$url] = $result;
            }
        }

        foreach ($uniqueArticles as $result) {
            $title = $result['article_title'] ?? 'Sin título';
            $content = $result['content_preview'] ?? '';
            $topic = $result['topic'] ?? '';
            
            if (!empty($content)) {
                $context .= "--- {$topic}: {$title} ---\n";
                $context .= $content . "\n\n";
            }
        }

        return $context;
    }

    private function buildFallbackResponse(array $kbResults, string $userLanguage): string
    {
        $context = $this->buildContext($kbResults);
        
        if ($userLanguage === 'es') {
            return "Aquí te comparto información sobre lo que preguntaste:\n\n" . $context;
        }
        
        return "Here's the information I found:\n\n" . $context;
    }

    private function detectLanguage(string $text): string
    {
        $textLower = mb_strtolower($text, 'UTF-8');
        
        $scores = [];
        
        foreach ($this->activeLanguages as $code => $name) {
            $scores[$code] = 0;
            
            switch ($code) {
                case 'pt':
                    $words = ['você', 'dizer', 'jogo', 'pode', 'tem', 'quer', 'quando', 'onde', 'quem', 'ajuda', 'obrigado', 'olá', 'dos', 'das', 'seu', 'sua', 'nosso', 'nossa', 'é', 'são', 'está', 'estão', 'disse', 'fazer', 'essa', 'esse', 'bem', 'aqui', 'muito', 'pelo', 'pela', 'diz', 'sobre', 'heroes'];
                    $scores[$code] = preg_match_all('/\b(' . implode('|', $words) . ')\b/i', $textLower, $matches);
                    if (preg_match('/[ãõç]/i', $text)) $scores[$code] += 5;
                    if (strpos($textLower, 'diz') !== false || strpos($textLower, 'você') !== false) $scores[$code] += 3;
                    break;
                    
                case 'es':
                    $words = ['que', 'del', 'los', 'las', 'para', 'como', 'juego', 'puedo', 'tengo', 'quiero', 'dime', 'me', 'cuando', 'cual', 'donde', 'quien', 'por', 'porque', 'ayuda', 'gracias', 'hola', 'decir', 'qué', 'este', 'esta', 'están', 'son', 'está', 'hay', 'hacer', 'tienes', 'aquí', 'más', 'muy', 'heroes'];
                    $scores[$code] = preg_match_all('/\b(' . implode('|', $words) . ')\b/i', $textLower, $matches);
                    if (preg_match('/[áéíóúñü]/i', $text) && !preg_match('/[ãõç]/i', $text)) $scores[$code] += 2;
                    break;
                    
                case 'en':
                    $words = ['what', 'can', 'you', 'tell', 'me', 'about', 'the', 'game', 'how', 'when', 'where', 'who', 'is', 'are', 'has', 'have', 'hello', 'thanks', 'hero', 'heroes', 'this', 'that', 'these', 'those'];
                    $scores[$code] = preg_match_all('/\b(' . implode('|', $words) . ')\b/i', $textLower, $matches);
                    if (!preg_match('/[áéíóúñãõçàèéìíòóùâêîôû]/i', $text)) $scores[$code] += 1;
                    break;
                    
                case 'fr':
                    $words = ['vous', 'dire', 'jeu', 'peut', 'est', 'sont', 'avez', 'bonjour', 'merci', 'quoi', 'comment', 'où', 'quand', 'les', 'des', 'pour', 'une', 'sur', 'cette', 'ce', 'ces', 'plus', 'héros'];
                    $scores[$code] = preg_match_all('/\b(' . implode('|', $words) . ')\b/i', $textLower, $matches);
                    if (preg_match('/[àâçéèêëîïôùûü]/i', $text)) $scores[$code] += 3;
                    break;
                    
                case 'de':
                    $words = ['sie', 'können', 'spiel', 'ist', 'sind', 'haben', 'danke', 'hallo', 'was', 'wie', 'wo', 'wann', 'der', 'die', 'das', 'ein', 'eine', 'für', 'dieser', 'diese', 'dieses', 'helden'];
                    $scores[$code] = preg_match_all('/\b(' . implode('|', $words) . ')\b/i', $textLower, $matches);
                    if (preg_match('/[äöüß]/i', $text)) $scores[$code] += 3;
                    break;
                    
                case 'it':
                    $words = ['puoi', 'gioco', 'è', 'sono', 'hai', 'grazie', 'ciao', 'cosa', 'come', 'dove', 'quando', 'gli', 'che', 'del', 'per', 'una', 'questo', 'questa', 'più', 'eroi'];
                    $scores[$code] = preg_match_all('/\b(' . implode('|', $words) . ')\b/i', $textLower, $matches);
                    if (preg_match('/[àèéìíòóù]/i', $text)) $scores[$code] += 3;
                    break;
                    
                case 'ru':
                    $scores[$code] = preg_match_all('/[а-я]/i', $text, $matches);
                    break;
                    
                case 'zh':
                    $scores[$code] = preg_match_all('/[\x{4e00}-\x{9fff}]/u', $text, $matches);
                    break;
                    
                case 'ja':
                    $scores[$code] = preg_match_all('/[\x{3040}-\x{309f}\x{30a0}-\x{30ff}]/u', $text, $matches);
                    break;
                    
                case 'ko':
                    $scores[$code] = preg_match_all('/[\x{ac00}-\x{d7af}\x{1100}-\x{11ff}]/u', $text, $matches);
                    break;
            }
        }
        
        $maxScore = 0;
        $detectedLang = 'es';
        
        foreach ($scores as $code => $score) {
            if ($score > $maxScore) {
                $maxScore = $score;
                $detectedLang = $code;
            }
        }
        
        return $detectedLang;
    }

    public function testKbConnection(): array
    {
        try {
            $pdo = $this->getKbConnection();
            $stmt = $pdo->query("SELECT COUNT(*) as count FROM knowledge_base");
            $result = $stmt->fetch();
            
            return [
                'success' => true,
                'message' => "Conexión exitosa. Total de artículos en KB: " . $result['count']
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => "Error de conexión: " . $e->getMessage()
            ];
        }
    }
}
