<?php
require_once 'db.php';

// Atur header dan timeout untuk long-polling/stream
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-cache');
set_time_limit(300);
ob_implicit_flush(true);
while (ob_get_level()) ob_end_flush();

function stream_log($msg, $type = 'info') {
    echo "<p class='log-{$type}'>{$msg}</p>";
    flush();
}

try {
    session_start();
if(!isset($_SESSION['user_id'])) {
    exit;
}
$instansi_id = $_SESSION['instansi_id'];
session_write_close(); // Instansi Pemko Banjarbaru
    
    // Ambil Pengaturan (Instansi ID = 7)
    $stmt_instansi = $pdo->prepare("SELECT * FROM instansi WHERE id = ?");
    $stmt_instansi->execute([$instansi_id]);
    $instansi = $stmt_instansi->fetch(PDO::FETCH_ASSOC);

    if (!$instansi) {
        stream_log("Error: Data Instansi tidak ditemukan.", "error");
        exit;
    }

    $api_key = trim($instansi['api_key_ai']);
    $ai_agent = trim($instansi['ai_agent'] ?? 'Groq');
    $ai_model = trim($instansi['ai_model'] ?? 'llama3-70b-8192');
    $keywords_raw = trim($instansi['keyword_global']);
    $blacklist_raw = trim($instansi['blacklist'] ?? 'judi, slot, kasino, togel, porn, pinjol, bokep, judol');
    $demoted_raw = trim($instansi['demoted_keywords'] ?? '');
    
    if (empty($api_key)) {
        stream_log("Error: API Key Groq belum disetting.", "error");
        exit;
    }

    $keyword_list = array_map('trim', explode(',', $keywords_raw));
    $keyword_list = array_filter($keyword_list);

    // Ambil Aturan Entitas (Weighted Scoring)
    $stmt_entities = $pdo->prepare("SELECT entity, type, score FROM instansi_entities WHERE instansi_id = ?");
    $stmt_entities->execute([$instansi_id]);
    $instansi_entities = $stmt_entities->fetchAll(PDO::FETCH_ASSOC);

    if (empty($instansi_entities)) {
        stream_log("Peringatan: Aturan Entity Matching kosong. Silakan jalankan migration_entities.php terlebih dahulu.", "warn");
    }

    // Ambil Media
    $kategori_filter = $_GET['kategori'] ?? '';
    $media_query = "SELECT * FROM media WHERE instansi_id = ?";
    $params = [$instansi_id];
    
    if ($kategori_filter !== '') {
        $media_query .= " AND kategori = ?";
        $params[] = $kategori_filter;
    }
    
    $stmt_media = $pdo->prepare($media_query);
    $stmt_media->execute($params);
    $medias = $stmt_media->fetchAll(PDO::FETCH_ASSOC);

    $report = [
        'masuk' => 0,
        'gagal' => 0,
        'kategori' => [
            'HIGH' => 0,
            'MEDIUM' => 0,
            'LOW' => 0,
            'NOT RELEVANT' => 0
        ],
        'accepted_list' => [],
        'rejected_list' => []
    ];

    stream_log(">> Memulai pengecekan " . count($medias) . " Media RSS...", "info");

    foreach ($medias as $media) {
        stream_log("-----------------------------------------");
        stream_log(">> Memproses Media: " . htmlspecialchars($media['nama']), "warn");
        
        $rss_url = $media['url'];
        $tier_media = $media['tier'] ?? 'Tier 3';

        // 1. Fetch XML
        $ch = curl_init($rss_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 15);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)');
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $rss_content = curl_exec($ch);
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if (!$rss_content || $http_code != 200) {
            stream_log("-> Gagal load RSS (HTTP $http_code) / Mati. Skip.", "error");
            continue;
        }

        // Clean XML
        $rss_content = preg_replace('/xmlns[^=]*="[^"]*"/i', '', $rss_content);
        $rss = @simplexml_load_string($rss_content, 'SimpleXMLElement', LIBXML_NOCDATA);

        $items = [];
        if ($rss && isset($rss->channel->item)) $items = $rss->channel->item; 
        elseif ($rss && isset($rss->entry)) $items = $rss->entry; 

        if (empty($items)) {
            stream_log("-> Format XML tidak dikenali / Kosong. Skip.", "error");
            continue;
        }

        $berita_baru = 0;
        $count_item = 0;

        foreach ($items as $item) {
            if ($count_item >= 5) break; // Limit 5 berita per media per run

            $judul = isset($item->title) ? strip_tags((string)$item->title) : '';
            $link = isset($item->link['href']) ? (string)$item->link['href'] : (string)$item->link;
            $raw_desc = isset($item->description) ? (string)$item->description : ((string)$item->content ?: (string)$item->summary);
            $tanggal = isset($item->pubDate) ? (string)$item->pubDate : ((string)$item->published ?: (string)$item->updated);
            $deskripsi = strip_tags($raw_desc);

            // Thumbnail
            $thumbnail_url = '';
            if (isset($item->enclosure) && strpos((string)$item->enclosure['type'], 'image') !== false) {
                $thumbnail_url = (string) $item->enclosure['url'];
            }
            if (empty($thumbnail_url) && preg_match('/<img[^>]+src=[\'"]([^\'"]+)[\'"]/i', $raw_desc, $matches)) {
                $thumbnail_url = $matches[1];
            }

            // Cek apakah sudah ada di DB untuk instansi ini
            $stmt_cek = $pdo->prepare("SELECT id FROM berita WHERE guid = ? AND instansi_id = ?");
            $stmt_cek->execute([$link, $instansi_id]);
            if ($stmt_cek->rowCount() > 0) {
                continue; // Skip kalau sudah ada di instansi ini
            }

            stream_log("-> Analisa Berita: " . substr($judul, 0, 40) . "...");

            // 2. Rule Score PHP (Weighted Dominance)
            $target_score = 0;
            $conflict_score = 0;
            $matched_target_kws = [];
            $matched_conflict_kws = [];
            
            $judul_lower = strtolower($judul);
            $desc_lower = strtolower($deskripsi);

            // Cek entitas (Exact Word Matching)
            foreach ($instansi_entities as $rule) {
                $entity = strtolower($rule['entity']);
                $entity_escaped = preg_quote($entity, '/');
                $pattern = '/\b' . $entity_escaped . '\b/i';
                
                $matched = false;
                if (preg_match($pattern, $judul_lower) || preg_match($pattern, $desc_lower)) {
                    $matched = true;
                }

                if ($matched) {
                    if ($rule['type'] === 'target') {
                        $target_score += (int)$rule['score'];
                        if (!in_array($entity, $matched_target_kws)) $matched_target_kws[] = $entity;
                    } elseif ($rule['type'] === 'conflict') {
                        $conflict_score += (int)$rule['score'];
                        if (!in_array($entity, $matched_conflict_kws)) $matched_conflict_kws[] = $entity;
                    }
                }
            }

            // Base Score dari Weighted Dominance
            $score = $target_score - $conflict_score;

            // Source trusted
            $trusted_tiers = ['Tier 1', 'Tier 2'];
            if (in_array($tier_media, $trusted_tiers)) {
                $score += 20;
            }

            // Demoted Keywords (Penurun Skor Dinamis)
            $demoted = array_filter(array_map('trim', explode(',', $demoted_raw)));
            foreach ($demoted as $demotedKw) {
                $pattern = '/\b' . preg_quote($demotedKw, '/') . '\b/i';
                if (preg_match($pattern, $judul) || preg_match($pattern, $deskripsi)) {
                    $score -= 10; // Penalti 10 poin
                }
            }

            // Blacklist
            $blacklist = array_filter(array_map('trim', explode(',', $blacklist_raw)));
            if (empty($blacklist)) {
                $blacklist = ['judi', 'slot', 'kasino', 'togel', 'porn', 'pinjol', 'bokep', 'judol'];
            }
            $is_blacklisted = false;
            foreach ($blacklist as $bad) {
                $pattern = '/\b' . preg_quote($bad, '/') . '\b/i';
                if (preg_match($pattern, $judul) || preg_match($pattern, $deskripsi)) {
                    $score -= 80;
                    $is_blacklisted = true;
                    break;
                }
            }

            if ($is_blacklisted) {
                stream_log("   [SKIP] Terkena Blacklist. Score: $score", "error");
                $report['gagal']++;
                $report['rejected_list'][] = "[Skor: $score] " . mb_strimwidth($judul, 0, 60, '...') . " (Blacklisted)";
                $kategori = ($score < 30) ? 'NOT RELEVANT' : (($score <= 59) ? 'LOW' : (($score <= 99) ? 'MEDIUM' : 'HIGH'));
                $report['kategori'][$kategori]++;
                continue;
            }

            // 3. Ambigu handling (Jika target_score 0, cari di isi konten html)
            $content_to_analyze = $deskripsi;
            if (empty($matched_target_kws)) {
                stream_log("   [INFO] Berita ambigu (Tidak ada Target Entity di feed). Cek full content...", "warn");
                
                $ch_html = curl_init($link);
                curl_setopt($ch_html, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch_html, CURLOPT_FOLLOWLOCATION, true);
                curl_setopt($ch_html, CURLOPT_TIMEOUT, 10);
                curl_setopt($ch_html, CURLOPT_USERAGENT, 'Mozilla/5.0');
                $html_content = curl_exec($ch_html);
                curl_close($ch_html);

                if ($html_content) {
                    $html_text = strip_tags($html_content);
                    foreach ($instansi_entities as $rule) {
                        if ($rule['type'] !== 'target') continue;
                        $pattern = '/\b' . preg_quote($rule['entity'], '/i') . '\b/i';
                        if (preg_match($pattern, $html_text)) {
                            $matched_target_kws[] = $rule['entity'];
                            $target_score += 10; // Ditemukan di isi
                            $score += 10;
                            break;
                        }
                    }
                    $content_to_analyze = mb_strimwidth($html_text, 0, 1000, '...'); // Potong buat AI
                }
            }

            if (empty($matched_target_kws) || $score < 30) {
                stream_log("   [SKIP] Dominasi Konflik / Tidak Relevan (Target: $target_score, Conflict: $conflict_score, Final: $score)", "error");
                $report['gagal']++;
                $report['rejected_list'][] = "[Skor: $score] " . mb_strimwidth($judul, 0, 60, '...') . " (No Target / Kalah Dominan)";
                $kategori = ($score < 30) ? 'NOT RELEVANT' : (($score <= 59) ? 'LOW' : (($score <= 99) ? 'MEDIUM' : 'HIGH'));
                $report['kategori'][$kategori]++;
                continue; 
            }

            stream_log("   [INFO] Pre-Score PHP: $score | Lanjut proses AI...");

            // 4. Proses Groq AI
            $sentimen_ai = 'netral';
            $urgensi_ai = 'rendah';
            $kategori_ai = 'Lainnya';
            $is_relevan = false;

            $keywords_str = implode(', ', $matched_target_kws);
            $conflict_str = implode(', ', $matched_conflict_kws);
            
           $system_prompt = "
AI monitoring berita instansi.
Target: {$keywords_str}
Aturan relevansi:
- Fokus utama harus membahas target.
- Banjar != Banjarbaru != Banjarmasin.
";
if (!empty($matched_conflict_kws)) {
    $system_prompt .= "
- Jika fokus berita pada entitas konflik [{$conflict_str}] maka relevansi=TIDAK.
";
}
if (!empty($demoted_raw)) {
    $system_prompt .= "
- Jika fokus utama pada [{$demoted_raw}] maka relevansi=TIDAK.
";
}
$system_prompt .= "
Kategori:
Infrastruktur
Pelayanan
Pendidikan
Kesehatan
Sosial
Keamanan
Politik
Lingkungan
Ekonomi
Lainnya
Rule:
- polisi/kriminal/narkoba/pencurian/pembunuhan=Keamanan
- jalan/jembatan/banjir=Infrastruktur
- rumah sakit/BPJS/puskesmas=Kesehatan
- sekolah/guru/siswa=Pendidikan
Tentukan:
- relevansi
- sentimen
- urgensi
- kategori
Balas JSON saja:
{
\"r\":\"YA/TIDAK\",
\"s\":\"POSITIF/NEGATIF/NETRAL\",
\"u\":\"TINGGI/SEDANG/RENDAH\",
\"k\":Sesuai list Kategori 
}
";
$user_prompt =
$judul . "\n" .
mb_substr(strip_tags($content_to_analyze), 0, 300);

            $headers = [
                'Content-Type: application/json',
                'Authorization: Bearer ' . $api_key
            ];

            $model_to_use = !empty($ai_model) ? $ai_model : 'llama3-70b-8192';
            $data = [
                "model" => $model_to_use,
                "messages" => [
                    ["role" => "system", "content" => $system_prompt], 
                    ["role" => "user", "content" => $user_prompt]
                ],
                "temperature" => 0.2
            ];

            $json_payload = json_encode($data, JSON_INVALID_UTF8_SUBSTITUTE | JSON_UNESCAPED_UNICODE);
            if ($json_payload === false) {
                stream_log("   [ERROR] Gagal menyusun request JSON (Invalid UTF-8).", "error");
                continue;
            }

            $api_url = "https://api.groq.com/openai/v1/chat/completions";
            if ($ai_agent === 'KoboiLLM') {
                $api_url = "https://api.koboillm.com/v1/chat/completions";
            }

            $ch_ai = curl_init($api_url);
            curl_setopt($ch_ai, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch_ai, CURLOPT_POST, true);
            curl_setopt($ch_ai, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch_ai, CURLOPT_POSTFIELDS, $json_payload);
            curl_setopt($ch_ai, CURLOPT_TIMEOUT, 20);
            curl_setopt($ch_ai, CURLOPT_SSL_VERIFYPEER, false);
            
            $ai_response = curl_exec($ch_ai);
            curl_close($ch_ai);

            if ($ai_response) {
                $res_json = json_decode($ai_response, true);
                $raw_ai = $res_json['choices'][0]['message']['content'] ?? '';
                
                // Extract JSON using regex just in case AI adds some text
                if (preg_match('/\{[\s\S]*\}/', str_replace(['```json', '```'], '', $raw_ai), $matches)) {
                    $hasil_ai = json_decode($matches[0], true);
                    if ($hasil_ai && isset($hasil_ai['r']) && trim(strtoupper($hasil_ai['r'])) === 'YA') {
                        $is_relevan = true;
                        $score += 50; // Tambah AI Relevance High score = +50
                        $sentimen_ai = strtolower(trim($hasil_ai['s'] ?? 'netral'));
                        $urgensi_ai = strtolower(trim($hasil_ai['u'] ?? 'rendah'));
                        $kategori_ai = trim($hasil_ai['k'] ?? 'Lainnya');
                    }
                }
            }

            if (!$is_relevan) {
                stream_log("   [SKIP] AI memutuskan berita TIDAK relevan.", "error");
                $report['gagal']++;
                $report['rejected_list'][] = "[Skor: $score] " . mb_strimwidth($judul, 0, 60, '...') . " (AI Rejected)";
                $kategori = ($score < 30) ? 'NOT RELEVANT' : (($score <= 59) ? 'LOW' : (($score <= 99) ? 'MEDIUM' : 'HIGH'));
                $report['kategori'][$kategori]++;
                sleep(2); // Jeda rate limit Groq (Skip case)
                continue;
            }

            stream_log("   [SUCCESS] AI Relevan! Skor Akhir: $score | Sentimen: ".strtoupper($sentimen_ai)." | Urgensi: ".strtoupper($urgensi_ai));
            $report['masuk']++;
            $report['accepted_list'][] = "[Skor: $score] " . mb_strimwidth($judul, 0, 60, '...') . " (AI: ".strtoupper($sentimen_ai).")";
            $kategori = ($score < 30) ? 'NOT RELEVANT' : (($score <= 59) ? 'LOW' : (($score <= 99) ? 'MEDIUM' : 'HIGH'));
            $report['kategori'][$kategori]++;

            // Penyesuaian ke kolom enum database lama ('baik', 'buruk', 'netral')
            $sentimen_db = $sentimen_ai;
            if ($sentimen_ai === 'positif') $sentimen_db = 'baik';
            if ($sentimen_ai === 'negatif') $sentimen_db = 'buruk';

            // Format tanggal MySQL
            $tgl_mysql = date('Y-m-d H:i:s', strtotime($tanggal));

            // 5. Insert ke DB
            $sql_insert = "INSERT INTO berita (instansi_id, guid, sumber, judul, link, tanggal, cuplikan, matched_keywords, thumbnail, sentimen, urgensi, kategori_berita) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            $insert = $pdo->prepare($sql_insert);
            $insert->execute([
                $instansi_id, 
                $link, 
                $media['nama'], 
                $judul, 
                $link, 
                $tgl_mysql, 
                mb_strimwidth($deskripsi, 0, 500, '...'), 
                implode(', ', $matched_target_kws), 
                $thumbnail_url, 
                $sentimen_db, 
                $urgensi_ai,
                $kategori_ai
            ]);

            $berita_baru++;
            $count_item++;
            
            // JEDA RATE LIMIT GROQ API:
            // Karena Groq (tier gratis) rentan limit / menit, kita pasang jeda 3 detik tiap artikel sukses.
            sleep(3); 
        }

        if ($berita_baru == 0) {
            stream_log(">> Selesai: Tidak ada berita baru ditambahkan dari " . htmlspecialchars($media['nama']), "warn");
        } else {
            stream_log(">> Selesai: $berita_baru berita ditambahkan dari " . htmlspecialchars($media['nama']), "success");
        }
    }

    // Final Report
    stream_log("<br>=========================================");
    stream_log("📊 REPORT HASIL SCRAPING 📊", "info");
    stream_log("Berita Masuk (Disetujui): " . $report['masuk'], "success");
    stream_log("Berita Gagal (Ditolak): " . $report['gagal'], "error");
    stream_log("Distribusi Kategori Skor Berita (Masuk & Gagal):", "info");
    stream_log("- HIGH (>= 100): " . $report['kategori']['HIGH'], "success");
    stream_log("- MEDIUM (60 - 99): " . $report['kategori']['MEDIUM'], "warn");
    stream_log("- LOW (30 - 59): " . $report['kategori']['LOW'], "error");
    stream_log("- NOT RELEVANT (< 30): " . $report['kategori']['NOT RELEVANT'], "error");
    
    stream_log("<br>✅ DAFTAR BERITA DITERIMA (" . count($report['accepted_list']) . "):", "success");
    foreach ($report['accepted_list'] as $item) {
        stream_log("   -> $item", "success");
    }
    
    stream_log("<br>❌ DAFTAR BERITA DITOLAK (" . count($report['rejected_list']) . "):", "error");
    foreach ($report['rejected_list'] as $item) {
        stream_log("   -> $item", "error");
    }
    
    stream_log("=========================================");

} catch (Exception $e) {
    stream_log("Terjadi Kesalahan Server: " . $e->getMessage(), "error");
}
?>
