<?php
// =============================================================================
// _wv_common.php — shared helpers for every api/webview/*.php endpoint.
//
// These endpoints render HTML directly to the Android WebView (and to admin
// preview iframes). NO admin session, NO CSRF — the URLs are baked into the
// app at build time. Public-by-design.
// =============================================================================

// Public WebView endpoints — NO admin session, NO CSRF. Include just the DB
// + helpers (skip bootstrap.php's session_start, which would trigger PHP's
// default X-Frame-Options: DENY and break the in-panel iframe previews).
require_once __DIR__ . '/../../includes/config.php';
require_once __DIR__ . '/../../includes/db.php';
require_once __DIR__ . '/../../includes/helpers.php';

header_remove('X-Frame-Options');                // strip any default DENY (PHP/nginx)
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: public, max-age=300');   // 5 min CDN/WebView cache
// CSP frame-ancestors takes precedence over X-Frame-Options in modern browsers,
// so even if nginx/aaPanel injects X-Frame-Options: DENY at the response layer,
// this header lets the panel iframe previews still render.
header("Content-Security-Policy: frame-ancestors 'self' https://*.b3studios.online");
header('X-Frame-Options: SAMEORIGIN');

function wv_html_head(string $title, string $extra_head = ''): void
{
    // <base href> so relative paths emitted by the webview (uploads/...,
    // api/webview/...) resolve against the panel root no matter where the
    // panel is mounted (subdir install, custom path, etc.). Without this,
    // a slideshow image stored as `uploads/slideshows/x.png` resolves
    // against `/api/webview/` and 404s.
    $base = function_exists('panel_base_path') ? panel_base_path() : '/';
    echo '<!doctype html><html lang="en"><head>';
    echo '<base href="' . htmlspecialchars($base, ENT_QUOTES, 'UTF-8') . '">';
    echo '<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">';
    echo '<title>' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '</title>';
    echo '<style>';
    echo ':root{--bg:#0a0a0a;--card:#161616;--text:#fff;--muted:#999;--accent:#f9a825;--live:#ef4444;--finished:#22c55e;}';
    echo '*{box-sizing:border-box;margin:0;padding:0}';
    echo 'html,body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;height:100%;}';
    echo 'a{color:inherit;text-decoration:none}';
    echo 'img{max-width:100%;display:block}';
    echo '</style>';
    echo $extra_head;
    echo '</head><body>';
}

function wv_html_foot(): void { echo '</body></html>'; }

// Kick off a one-shot sports sync in the background when the events table is
// empty so the very first viewer of the WebView gets content on their next
// refresh — without the admin having to know to press a "Pull now" button.
// Throttled to one attempt per 5 minutes via webview_settings.sports_last_attempt.
function wv_maybe_bootstrap_sports(): void
{
    $row = @db_one('SELECT COUNT(*) c FROM sports_events');
    $count = $row ? (int)$row['c'] : 0;
    if ($count > 0) return;

    $last = (int)(db_one("SELECT value FROM webview_settings WHERE key='sports_last_attempt'")['value'] ?? 0);
    if (time() - $last < 300) return;

    db_exec("INSERT INTO webview_settings (key, value, updated_at) VALUES (?, ?, ?)
             ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at",
            ['sports_last_attempt', (string)time(), time()]);

    register_shutdown_function(function () {
        @ignore_user_abort(true);
        @set_time_limit(120);
        if (function_exists('fastcgi_finish_request')) {
            @fastcgi_finish_request();
        } else {
            @ob_end_flush();
            @flush();
        }
        try {
            require_once __DIR__ . '/../../includes/sports/sync.php';
            @sports_sync_once();
        } catch (Throwable $e) { /* swallow — logger will catch */ }
    });
}

// Decode override_json + base row into a single event view-model.
function wv_event_view(array $row): array
{
    $override = [];
    if (!empty($row['override_json'])) {
        $d = json_decode($row['override_json'], true);
        if (is_array($d)) $override = $d;
    }
    $pick = function ($k) use ($row, $override) {
        return array_key_exists($k, $override) ? $override[$k] : ($row[$k] ?? null);
    };
    return [
        'id'             => (int)$row['id'],
        'league_id'      => (int)$row['league_id'],
        'league_name'    => (string)($row['league_name'] ?? ''),
        'league_logo'    => wv_img_proxy((string)($row['league_logo_url'] ?? '')),
        'home_team'      => (string)$pick('home_team'),
        'away_team'      => (string)$pick('away_team'),
        'home_badge_url' => wv_img_proxy((string)$pick('home_badge_url')),
        'away_badge_url' => wv_img_proxy((string)$pick('away_badge_url')),
        'kickoff_ts'     => $pick('kickoff_ts') !== null ? (int)$pick('kickoff_ts') : null,
        'status'         => strtoupper((string)$pick('status')),
        'home_score'     => $pick('home_score'),
        'away_score'     => $pick('away_score'),
        'channels'       => array_filter(array_map('trim', explode(',', (string)$pick('channels_csv')))),
        'thumb_url'      => wv_img_proxy((string)$pick('thumb_url')),
    ];
}

// Rewrites remote image URLs (sportsdb badges, thumbs, league logos) to go
// through api/webview/img.php so the device's WebView fetches them from
// the panel's own host — survives DNS quirks, CSP restrictions, and any
// upstream rate-limiting. Empty / data: / panel-relative URLs pass through.
function wv_img_proxy(string $url): string {
    $url = trim($url);
    if ($url === '') return '';
    if (strncasecmp($url, 'data:', 5) === 0) return $url;
    if (!preg_match('#^https?://#i', $url))  return $url; // local / relative
    $host = parse_url($url, PHP_URL_HOST);
    if (!$host) return $url;
    // Whitelist of external image hosts the panel currently proxies. Extend
    // here when a new sports/feed provider is added.
    $allowed = [
        'thesportsdb.com', 'www.thesportsdb.com',
        'r2.thesportsdb.com',                       // Cloudflare R2 — current CDN
        'cdn.sportsdb.com',
        'image.tmdb.org',
        'www.thecocktaildb.com',
    ];
    $allowed_host = false;
    foreach ($allowed as $h) {
        if (strcasecmp($host, $h) === 0) { $allowed_host = true; break; }
    }
    if (!$allowed_host) return $url;
    $base = function_exists('panel_base_path') ? rtrim(panel_base_path(), '/') : '';
    return $base . '/api/webview/img.php?u=' . rawurlencode($url);
}
