<?php
declare(strict_types=1);

/**
 * OG link-preview + JS redirect  —  TEMPLATE dung chung cho nhieu domain.
 *
 * Deploy nguyen xi (khong sua theo tung domain): domain tu nhan dien qua
 * Host header. Cau hinh chung o config.php.
 *
 *  - Bot (Telegram / Twitter(X) / FB / Zalo / Discord...) doc <meta og:* /
 *    twitter:*> -> hien card kem 1 anh trong /imgs chon "ngau nhien nhung
 *    on dinh" theo slug + 1 tieu de tu headlines.txt.  Bot KHONG chay JS.
 *  - Nguoi that: <script> (setTimeout) chuyen huong:
 *      /<slug>.mp4      -> {redirect_base}<slug>{redirect_suffix}
 *      duong dan khac   -> 1 URL "moi nhu that" ngau nhien (decoy_urls)
 *
 * KHONG dung <meta http-equiv="refresh"> (Twitterbot/facebookexternalhit
 * di theo no -> mat card). Redirect chi bang JS nen crawler khong bi anh huong.
 */

$cfg = require __DIR__ . '/config.php';

/* ─────────────────────────── 1. Lay slug ─────────────────────────── */
$reqPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?? '/';
$raw     = $_GET['slug'] ?? $reqPath;
$slug    = basename((string)$raw);
$slug    = (string)preg_replace('/\.(mp4|html?|php)$/i', '', $slug);

/* ─────────── 2. Host / URL goc (KHONG co domain co dinh trong src) ── */
$https = (($_SERVER['HTTPS'] ?? '') === 'on')
      || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https')
      || ((int)($_SERVER['SERVER_PORT'] ?? 80) === 443);
$proto    = $https ? 'https' : 'http';
$hostname = strtolower(explode(':', (string)($_SERVER['HTTP_HOST'] ?? 'localhost'))[0]);
$host     = rtrim((string)($cfg['site_url'] ?: ($proto . '://' . $hostname)), '/');

// og:image + manifest phuc vu duoi CHINH ten mien cua link (nginx alias /v/
// -> 1 ban vat ly tren server). image_host:
//   null / ''  -> DUNG HOST cua link (same-origin voi og:url) — an toan nhat
//                 cho crawler cua X (khong co heuristic cross-origin).
//   'apex'     -> apex 2 nhan cuoi (moi subdomain chung 1 bo URL anh).
//   URL cu the -> dung nguyen.
$imgHost = (string)($cfg['image_host'] ?? '');
if ($imgHost === '' || $imgHost === $hostname) {
    $imgHost = $proto . '://' . $hostname;
} elseif ($imgHost === 'apex') {
    $p    = explode('.', $hostname);
    $apex = count($p) >= 2 ? implode('.', array_slice($p, -2)) : $hostname;
    $imgHost = $proto . '://' . $apex;
}
$imgHost     = rtrim($imgHost, '/');
$manifestUrl = str_replace('{origin}', $imgHost, (string)($cfg['manifest_url'] ?? ''));

/* ───────────────────── 2b. Tac vu admin (co token) ──────────────── */
if (isset($_GET['__refresh']) && hash_equals((string)$cfg['admin_token'], (string)$_GET['__refresh'])) {
    if (function_exists('apcu_delete')) { apcu_delete('og_imgs'); apcu_delete('og_hl'); }
    $list = og_manifest($cfg, $manifestUrl);
    $hl   = og_headlines($cfg);
    header('Content-Type: text/plain; charset=utf-8');
    header('Cache-Control: no-store');
    $src = $manifestUrl !== '' ? 'shared: ' . $manifestUrl : 'local: ' . ($cfg['imgs_dir'] ?? '');
    echo "manifest ($src)\n" . count($list) . " images, " . count($hl) . " headlines\n";
    exit;
}

/* ─────────────────────── 3. Landing hay preview ──────────────────── */
// slug rong / la (ke ca "/") -> trang landing (redirect decoy, khong card).
$isLanding = !preg_match('/^[A-Za-z0-9_-]{1,64}$/', $slug);
if ($isLanding) { $slug = 'home'; }

/* ──────────────────── 4. Danh sach anh (cache) ───────────────────── */
$images = og_manifest($cfg, $manifestUrl);
if (!$images) {
    http_response_code(503);
    header('Content-Type: text/plain; charset=utf-8');
    header('Cache-Control: no-store');
    echo "No thumbnails available";
    exit;
}

/* ───────── 5. Chon anh: deterministic hash(slug [+ bien the]) ─────── */
// 1 slug -> luon ra 1 anh. Muon post lai voi anh khac: them ?v=2, ?v=3...
$variant = isset($_GET['v']) ? preg_replace('/[^A-Za-z0-9_-]/', '', (string)$_GET['v']) : '';
$idx     = (int)(sprintf('%u', crc32($slug . '|' . $variant)) % count($images));
$picked  = $images[$idx];

/* ───────────────────────── 6. Dung cac URL ───────────────────────── */
$qs       = ($variant !== '') ? '?v=' . rawurlencode($variant) : '';
$imageUrl = $imgHost . ((string)($cfg['imgs_path'] ?? '/v')) . '/' . rawurlencode($picked);
$pageUrl  = $host . $reqPath . $qs;   // og:url = dung URL da duoc post

// Dich khi nguoi that bam vao card.
if ($isLanding) {
    $decoys      = $cfg['decoy_urls'] ?? [];
    $redirectUrl = $decoys ? (string)$decoys[array_rand($decoys)] : '';
} else {
    $redirectUrl = rtrim((string)($cfg['redirect_base'] ?? ''), '/')
        . '/' . rawurlencode($slug) . (string)($cfg['redirect_suffix'] ?? '');
    if (($cfg['redirect_base'] ?? '') === '') { $redirectUrl = ''; }
}

/* ───────── 6b. Chon tieu de / mo ta: deterministic theo slug ─────── */
$headlines = og_headlines($cfg);
$title = (string)($cfg['title'] ?? '');
$desc  = (string)($cfg['description'] ?? '');
if ($headlines) {
    $hIdx = (int)(sprintf('%u', crc32($slug . '|hl' . $variant)) % count($headlines));
    [$hT, $hD] = array_pad(explode('|||', $headlines[$hIdx], 2), 2, '');
    $hT = trim($hT); $hD = trim($hD);
    if ($hT !== '') { $title = $hT; }
    if ($hD !== '') { $desc  = $hD; }
}
if ($desc === '') { $desc = $title; }

$ext  = strtolower(pathinfo($picked, PATHINFO_EXTENSION));
$mime = ['jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'png' => 'image/png', 'webp' => 'image/webp'][$ext] ?? 'image/jpeg';

/* ───────────────────── 7. Debug (co token) ───────────────────────── */
if (isset($_GET['__debug']) && hash_equals((string)$cfg['admin_token'], (string)$_GET['__debug'])) {
    header('Content-Type: application/json; charset=utf-8');
    header('Cache-Control: no-store');
    echo json_encode([
        'slug' => $slug, 'variant' => $variant, 'is_landing' => $isLanding,
        'image_index' => $idx, 'image_count' => count($images),
        'image' => $imageUrl, 'page' => $pageUrl, 'redirect' => $redirectUrl,
        'title' => $title, 'description' => $desc,
        'headline_count' => count($headlines),
    ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    exit;
}

/* ─────────────────────── 8. Trang HTML ───────────────────────────── */
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: public, max-age=600, s-maxage=86400');

$delay = (int)($cfg['redirect_delay_ms'] ?? 400);

$T  = htmlspecialchars($title, ENT_QUOTES);
$D  = htmlspecialchars($desc,  ENT_QUOTES);
$I  = htmlspecialchars($imageUrl, ENT_QUOTES);
$U  = htmlspecialchars($pageUrl,  ENT_QUOTES);
$S  = htmlspecialchars((string)parse_url($host, PHP_URL_HOST) ?: 'site', ENT_QUOTES);
$Rj = json_encode($redirectUrl, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP);

$redirectJs = ($redirectUrl !== '')
    ? "<script>setTimeout(function(){location.replace($Rj);},$delay);</script>"
    : '';

if ($isLanding) {
    // Trang goc: khong card, chi redirect decoy (neu co) / trang trong.
    echo "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\">"
       . "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">"
       . "<title>$S</title>$redirectJs</head><body></body></html>";
    exit;
}

$sizeTags = '';
if (is_array($cfg['og_image_size'] ?? null)) {
    [$w, $h] = $cfg['og_image_size'];
    $sizeTags = "<meta property=\"og:image:width\" content=\"{$w}\">\n"
              . "<meta property=\"og:image:height\" content=\"{$h}\">\n";
}

echo <<<HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>$T</title>
<link rel="canonical" href="$U">

<meta property="og:type" content="website">
<meta property="og:site_name" content="$S">
<meta property="og:title" content="$T">
<meta property="og:description" content="$D">
<meta property="og:url" content="$U">
<meta property="og:image" content="$I">
<meta property="og:image:secure_url" content="$I">
<meta property="og:image:type" content="$mime">
{$sizeTags}<meta property="og:image:alt" content="$T">

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="$T">
<meta name="twitter:description" content="$D">
<meta name="twitter:image" content="$I">
<meta name="twitter:image:src" content="$I">
<meta name="twitter:image:alt" content="$T">
$redirectJs
</head>
<body style="margin:0;background:#000">
<a href="$U"><img src="$I" alt="$T" style="display:block;width:100%;height:auto;max-width:1200px;margin:0 auto;border:0"></a>
</body>
</html>
HTML;
exit;


/* ═══════════════════════════ Helpers ═══════════════════════════════ */

function og_manifest(array $cfg, string $manifestUrl = ''): array
{
    if (function_exists('apcu_fetch')) {
        $hit = apcu_fetch('og_imgs', $ok);
        if ($ok && is_array($hit) && $hit) { return $hit; }
    }

    $local = __DIR__ . '/lib/manifest.php';
    @mkdir(dirname($local), 0755, true);

    // 1) Kho anh DUNG CHUNG: tai manifest.json qua HTTP (URL da resolve
    //    theo ten mien cua chinh link). Cache APCu 1h + ghi lai
    //    lib/manifest.php lam ban du phong (host anh tam chet van chay).
    $url = $manifestUrl !== '' ? $manifestUrl : (string)($cfg['manifest_url'] ?? '');
    if ($url !== '' && strpos($url, '{origin}') === false) {
        $json = og_http_get($url, 3);
        $list = $json !== '' ? json_decode($json, true) : null;
        if (is_array($list)) {
            $list = array_values(array_filter($list, static function ($x) {
                return is_string($x) && preg_match('/^[A-Za-z0-9_-]+\.jpe?g$/i', $x);
            }));
            if ($list) {
                if (function_exists('apcu_store')) { apcu_store('og_imgs', $list, 3600); }
                @file_put_contents($local, "<?php return " . var_export($list, true) . ";\n", LOCK_EX);
                if (function_exists('opcache_invalidate')) { @opcache_invalidate($local, true); }
                return $list;
            }
        }
    }

    // 2) Ban du phong da luu
    if (is_file($local)) {
        $list = @include $local;
        if (is_array($list) && $list) {
            if (function_exists('apcu_store')) { apcu_store('og_imgs', $list, 600); }
            return $list;
        }
    }

    // 3) Standalone: quet thu muc imgs cuc bo
    $list = og_scan_dir((string)($cfg['imgs_dir'] ?? ''));
    if ($list) {
        og_write_manifest($list);
        if (function_exists('apcu_store')) { apcu_store('og_imgs', $list, 3600); }
    }
    return $list;
}

/** GET ngan gon, tra '' khi loi. Uu tien curl, fallback file_get_contents. */
function og_http_get(string $url, int $timeout = 3): string
{
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => $timeout,
            CURLOPT_CONNECTTIMEOUT => $timeout,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_USERAGENT      => 'og-preview/manifest',
        ]);
        $r    = curl_exec($ch);
        $code = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        curl_close($ch);
        return ($r !== false && $code >= 200 && $code < 300) ? (string)$r : '';
    }
    $ctx = stream_context_create(['http' => ['timeout' => $timeout, 'ignore_errors' => true]]);
    $r   = @file_get_contents($url, false, $ctx);
    return $r !== false ? (string)$r : '';
}

/** Doc file headlines.txt -> mang dong (bo comment / dong trong). Cache APCu. */
function og_headlines(array $cfg): array
{
    if (function_exists('apcu_fetch')) {
        $hit = apcu_fetch('og_hl', $ok);
        if ($ok && is_array($hit)) { return $hit; }
    }
    $out  = [];
    $file = (string)($cfg['headlines_file'] ?? '');
    if ($file !== '' && is_file($file)) {
        foreach (file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: [] as $line) {
            $line = trim($line);
            if ($line === '' || $line[0] === '#') { continue; }
            $out[] = $line;
        }
    }
    if (function_exists('apcu_store')) { apcu_store('og_hl', $out, 3600); }
    return $out;
}

function og_scan_dir(string $dir): array
{
    // Chi nhan file DA CHUAN HOA: "<slug>.jpg" (tools/optimize.php luon xuat .jpg,
    // ten chi gom [A-Za-z0-9_-]). File la upload nham vao thu muc (co dau cach,
    // ngoac, .png, .gif...) bi bo qua -> manifest khong bao gio dinh anh rac.
    $out = [];
    foreach (glob($dir . '/*.{jpg,jpeg,JPG,JPEG}', GLOB_BRACE) ?: [] as $f) {
        $b = basename($f);
        if (is_file($f) && preg_match('/^[A-Za-z0-9_-]+\.jpe?g$/i', $b)) {
            $out[] = $b;
        }
    }
    $out = array_values(array_unique($out));
    sort($out, SORT_STRING);
    return $out;
}

function og_write_manifest(array $list): void
{
    $file = __DIR__ . '/lib/manifest.php';
    @mkdir(dirname($file), 0755, true);
    @file_put_contents($file, "<?php return " . var_export($list, true) . ";\n", LOCK_EX);
    if (function_exists('opcache_invalidate')) { @opcache_invalidate($file, true); }
}
