<?php
// =========================================================================
// autokoding/api/router_koding.php
// SMART DUAL-LLM ROUTER untuk Aistem Auto Koding
//
// Strateginya:
//   PLANNING   → bot_api.php internal (Gemini/Groq via ekosistem Xieqa)
//   EXECUTION  → Groq LANGSUNG dari database settings (hemat kuota Gemini)
//   Fallback   → Jika satu sisi gagal, otomatis beralih ke yang lain
//
// CATATAN PENTING:
//   - Semua API key dibaca dari tabel `settings` database — TIDAK hardcode.
//   - Header bypass X-Xieqa-Internal dipakai agar autokoding tidak terkena
//     limit billing & anti-DDoS (sama seperti fitur chatbot & analisis lainnya).
//
// Developer: Sikawarsito, S.Kom
// =========================================================================

// Timeout curl Groq (detik) — lebih panjang untuk generasi kode panjang
define('AK_GROQ_TIMEOUT', 180);

/**
 * Fungsi utama router: pilih LLM terbaik berdasarkan fase.
 *
 * @return array ['reply'=>string, 'engine'=>string]
 */
function routeKodingRequest(
    $full_prompt,
    $phase,
    $file_part,
    $temp,
    $conn,
    $cfg,
    $sys_prompt,
    $user_input,
    $hist_ctx
) {
    // ── SEMUA FASE (PLANNING & EXECUTION) MENGGUNAKAN ENGINE YANG SAMA DENGAN PRO EXPERT ──
    // Prioritas UTAMA: bot_api.php internal (Gemini) untuk kualitas UI/UX kelas atas.
    $result = _callBotApiInternal($full_prompt, $file_part, $conn);
    if (_isValidReply($result)) {
        return ['reply' => $result, 'engine' => 'xieqa_internal'];
    }

    // Fallback: Groq langsung dari DB jika Gemini sedang limit atau bermasalah
    $result = _callGroqFromDB($sys_prompt, $hist_ctx, $user_input, $temp, $conn, $cfg);
    if (_isValidReply($result)) {
        return ['reply' => $result, 'engine' => 'groq_db_fallback'];
    }

    return [
        'reply'  => "XIEQA_ENGINE_ERROR: Layanan Xieqa LLM sedang pemulihan. Coba lagi.",
        'engine' => 'error'
    ];
}

// ── PRIVATE: CALL BOT_API.PHP INTERNAL (BYPASS LIMIT) ───────────────────
function _callBotApiInternal($full_prompt, $file_part, $conn) {
    // Ambil master key dari database
    $res = mysqli_query($conn, "SELECT api_key FROM api_key_bot WHERE status = 'active' ORDER BY id ASC LIMIT 1");
    if (!$res || mysqli_num_rows($res) === 0) {
        return "XIEQA_ENGINE_ERROR: Layanan Xieqa LLM belum tersedia. Hubungi administrator.";
    }
    $master_key = mysqli_fetch_assoc($res)['api_key'];

    // Bangun URL bot_api.php secara dinamis
    $scheme       = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host         = $_SERVER['HTTP_HOST'];
    $doc_root     = rtrim(str_replace('\\', '/', $_SERVER['DOCUMENT_ROOT']), '/');
    $bot_real     = str_replace('\\', '/', realpath(__DIR__ . '/../../../llm/api/bot_api.php'));
    $bot_webpath  = str_replace($doc_root, '', $bot_real);
    $bot_url      = $scheme . '://' . $host . $bot_webpath;

    $payload = [
        'pesan'     => $full_prompt,
        'file_part' => $file_part,
    ];

    $ch = curl_init($bot_url);
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER => [
            'Authorization: Bearer ' . $master_key,
            'Content-Type: application/json',
            // Header bypass ekosistem — skip billing & anti-DDoS
            'X-Xieqa-Internal: SikaWarsito2026BypassLimit',
        ],
        CURLOPT_POSTFIELDS     => json_encode($payload, JSON_INVALID_UTF8_SUBSTITUTE),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT        => 600,
    ]);

    $res  = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($code === 200) {
        $data = json_decode($res, true);
        if (isset($data['status']) && $data['status'] === 'success') {
            return $data['choices'][0]['message']['content'] ?? '';
        }
        // bot_api.php melaporkan semua key exhausted
        if (isset($data['status']) && $data['status'] === 'error') {
            return "PEMBERITAHUAN SISTEM: Layanan sedang sibuk.";
        }
    }

    return "XIEQA_ENGINE_ERROR: Layanan sedang tidak tersedia.";
}

// ── PRIVATE: CALL GROQ LANGSUNG DARI TABEL api_keys (DINAMIS) ────────────
function _callGroqFromDB($sys_prompt, $hist_ctx, $user_msg, $temp, $conn, $cfg) {
    // Auto-recovery cooldown
    mysqli_query($conn, "UPDATE api_keys SET status = 'ready', cooldown_until = NULL, fail_count = 0 
                         WHERE provider = 'groq' AND status = 'cooldown' AND cooldown_until <= NOW()");
    // Ambil semua slot Groq yang siap
    $q = mysqli_query($conn, "SELECT id, api_key FROM api_keys 
                              WHERE provider = 'groq' AND status = 'ready' 
                              ORDER BY last_used ASC");

    if (!$q || mysqli_num_rows($q) === 0) {
        return "XIEQA_ENGINE_ERROR: Layanan Xieqa LLM sedang dalam pemeliharaan.";
    }

    // Ambil cfg terbaru jika belum lengkap
    if (empty($cfg)) {
        $cfg = mysqli_fetch_assoc(mysqli_query($conn, "SELECT * FROM settings WHERE id = 1"));
    }

    // Model dari settings, fallback ke default
    $model = trim($cfg['groq_model'] ?? 'llama-3.3-70b-versatile');
    if (empty($model)) $model = 'llama-3.3-70b-versatile';

    // Bangun messages (OpenAI-compatible)
    $messages = [['role' => 'system', 'content' => $sys_prompt]];

    // Parse history
    if (!empty(trim($hist_ctx))) {
        foreach (explode("\n\n", trim($hist_ctx)) as $line) {
            $line = trim($line);
            if (empty($line)) continue;
            if (strpos($line, '[USER]:') === 0) {
                $messages[] = ['role' => 'user', 'content' => trim(substr($line, 7))];
            } elseif (strpos($line, '[AI]:') === 0) {
                $messages[] = ['role' => 'assistant', 'content' => trim(substr($line, 5))];
            }
        }
    }
    $messages[] = ['role' => 'user', 'content' => $user_msg];

    $payload = [
        'model'       => $model,
        'messages'    => $messages,
        'temperature' => (float)$temp,
        'max_tokens'  => 8192,
        'stream'      => false,
    ];

    // Coba tiap key Groq yang tersedia
    while ($row = mysqli_fetch_assoc($q)) {
        $key_id  = (int)$row['id'];
        $api_key = trim($row['api_key']);

        if (empty($api_key)) continue;

        // Update last_used
        mysqli_query($conn, "UPDATE api_keys SET last_used = NOW() WHERE id = $key_id");

        $ch = curl_init('https://api.groq.com/openai/v1/chat/completions');
        curl_setopt_array($ch, [
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $api_key,
                'Content-Type: application/json',
            ],
            CURLOPT_POSTFIELDS     => json_encode($payload, JSON_UNESCAPED_UNICODE),
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_TIMEOUT        => AK_GROQ_TIMEOUT,
        ]);

        $res  = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($code === 200) {
            $data    = json_decode($res, true);
            $content = $data['choices'][0]['message']['content'] ?? '';
            if (!empty($content)) {
                mysqli_query($conn, "UPDATE api_keys SET status='ready', fail_count=0 WHERE id=$key_id");
                return $content;
            }
        } elseif ($code === 429) {
            mysqli_query($conn, "UPDATE api_keys SET status='cooldown', fail_count=fail_count+1, 
                                  cooldown_until=DATE_ADD(NOW(), INTERVAL 60 SECOND) WHERE id=$key_id");
            continue;
        } else {
            mysqli_query($conn, "UPDATE api_keys SET fail_count=fail_count+1 WHERE id=$key_id");
        }
    }

    return "XIEQA_ENGINE_ERROR: Layanan Xieqa LLM sedang tinggi permintaan. Coba beberapa saat lagi.";
}

// ── PRIVATE: VALIDASI BALASAN LLM ────────────────────────────────────────
// Hanya periksa 60 karakter pertama — kode PHP/SQL yang valid bisa saja
// mengandung kata ERROR:, FAIL, dll di dalam komentar atau string literal.
function _isValidReply($reply) {
    if (empty(trim($reply))) return false;
    
    // Minimal panjang balasan AI yang masuk akal adalah 15 karakter
    if (strlen(trim($reply)) < 15) return false;

    // Cek 150 karakter pertama (lebih luas dari sebelumnya) untuk marker error
    $head = strtolower(substr(trim($reply), 0, 150));

    $errorMarkers = [
        'error:', 'error_groq:', 'error_gemini:', 'error_internal:',
        'fail_internal', 'fail (http', 'api_key_invalid',
        'pemberitahuan sistem:', 'akses internal llm ditolak.',
        'sistem mendeteksi akses terlalu padat.', 'internal llm limit reached.',
        'insufficient_quota', 'rate_limit_exceeded', 'service_unavailable'
    ];

    foreach ($errorMarkers as $marker) {
        if (strpos($head, $marker) !== false) {
            return false;
        }
    }

    // Jika balasan hanya berisi satu kata atau sangat pendek, kemungkinan halusinasi/error
    $words = explode(' ', trim($reply));
    if (count($words) < 3 && strlen($reply) < 30) {
        return false;
    }

    return true;
}
?>
