<?php
/**
 * sport.php – Sports page (categories row | clock | listings)
 *
 * Fetches the sport-tv-guide widget server-side, extracts the category tabs
 * and the event listings, and renders a clean custom layout:
 *
 *     [ category icons row (wraps to 2 rows if needed) ]
 *     [ clock / date                                    ]
 *     [ sports listings (time | sport | event | channel) ]
 *
 * The widget's lazy-loaded images (data-src) are rewritten to src so icons
 * show in the app's WebView. D-pad navigation: LEFT/RIGHT moves across the
 * category icons, OK selects a category (reloads to that category's events),
 * DOWN/UP moves through the listings, OK opens an event.
 *
 * Theme: TiviMate Nord dark palette — bg #2e3440 (Nord0), stripe #3b4252 (Nord1).
 * Widget settings (token, sports, colors, timezone) are read from the DB.
 */

require_once __DIR__ . '/includes/functions.php';

$cfg = $db->select('sports_fixtures_config', '*', 'id = :id', '', [':id' => 1]);
$c = $cfg[0] ?? [];

// Query-string overrides (used by the panel Live Preview so it reflects the
// unsaved form values). Fall back to the DB settings.
$token  = trim((string) ($_GET['token'] ?? $c['widget_token'] ?? '104cc8ac97da'));
$sports = trim((string) ($_GET['sports'] ?? $c['widget_sports'] ?? '1,7,8,14,15'));
$bg     = ltrim($_GET['bg'] ?? $c['widget_bg'] ?? '#2e3440', '#');
$bgs    = ltrim($_GET['bgs'] ?? $c['widget_bgs'] ?? '#3b4252', '#');
$tz     = trim((string) ($_GET['tz'] ?? $c['widget_timezone'] ?? 'Europe/London'));
$time12 = trim((string) ($_GET['time12'] ?? $c['widget_time12'] ?? '1'));

$src = "https://sport-tv-guide.live/sportwidget/{$token}"
     . "?time_zone=" . urlencode($tz)
     . "&time12={$time12}"
     . "&sports=" . urlencode($sports)
     . "&bg={$bg}&bgs={$bgs}&grp=1&sd=1&lng=1";

// If a category was picked (?typeID=N), fetch that category's events.
$typeID = isset($_GET['typeID']) ? (int) $_GET['typeID'] : 0;
if ($typeID > 0) {
    $src .= '&typeID=' . $typeID;
}

// ---------------------------------------------------------------------------
// HTTP fetch helper (cURL -> file_get_contents)
// ---------------------------------------------------------------------------
function sport_fetch(string $url): ?string {
    $raw = false;
    if (function_exists('curl_init')) {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_TIMEOUT        => 15,
            CURLOPT_CONNECTTIMEOUT => 8,
            CURLOPT_USERAGENT      => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_SSL_VERIFYHOST => 0,
        ]);
        $raw = curl_exec($ch);
        $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        if ($raw === false || $raw === '' || $code < 200 || $code >= 400) { $raw = false; }
    }
    if ($raw === false && ini_get('allow_url_fopen')) {
        $ctx = stream_context_create([
            'http' => ['timeout' => 15, 'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\r\n", 'ignore_errors' => true],
            'ssl' => ['verify_peer' => false, 'verify_peer_name' => false],
        ]);
        $raw = @file_get_contents($url, false, $ctx);
        if ($raw === false || $raw === '') { $raw = false; }
    }
    return $raw === false ? null : $raw;
}

// ---------------------------------------------------------------------------
// Fetch the widget HTML
// ---------------------------------------------------------------------------
$html = sport_fetch($src);
if ($html === null) {
    header('Content-Type: text/html; charset=UTF-8');
    echo '<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">'
       . '<style>body{background:#2e3440;color:#eceff4;font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;text-align:center}</style>'
       . '</head><body><div><h2>Sports guide unavailable</h2><p>Could not reach the sports feed. Please try again later.</p></div></body></html>';
    exit;
}

// ---------------------------------------------------------------------------
// Extract the category tabs (the first .filterTypes list).
// ---------------------------------------------------------------------------
$catsHtml = '';
if (preg_match('/<ul class="filterTypes[^"]*"[^>]*>(.*?)<\/ul>/s', $html, $m)) {
    $catsHtml = $m[1];
}
// Fix lazy-loaded category icons.
$catsHtml = preg_replace('/data-src=/i', 'src=', $catsHtml);

// ---------------------------------------------------------------------------
// Extract and parse each event row into clean structured data.
// ---------------------------------------------------------------------------
$events = [];
if (preg_match_all('/<a class="article"[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/s', $html, $m2, PREG_SET_ORDER)) {
    foreach ($m2 as $row) {
        $href = $row[1];
        $body = $row[2];

        // Time (the <b> in the time column).
        $time = '';
        if (preg_match('/<b>([^<]+)<\/b>/', $body, $t)) { $time = trim($t[1]); }

        // Sport type.
        $sport = '';
        if (preg_match('/<div class="typeName[^"]*">([^<]+)<\/div>/', $body, $s)) { $sport = trim($s[1]); }

        // Event name (first .text-nowrap).
        $name = '';
        if (preg_match('/<div class="text-nowrap">([^<]+)<\/div>/', $body, $n)) { $name = trim($n[1]); }

        // Competition / location (second .text-nowrap, may contain <b>).
        $comp = '';
        if (preg_match('/<div class="text-nowrap">(?:<b>)?([^<]+)(?:<\/b>)?<\/div>/', $body, $c2)) { $comp = trim($c2[1]); }

        // Channel (img title + src).
        $channel = '';
        $channelImg = '';
        if (preg_match('/<img[^>]*title=[\'"]([^\'"]+)[\'"][^>]*src=[\'"]([^\'"]+)[\'"]/', $body, $ch)) {
            $channel = trim($ch[1]);
            $channelImg = trim($ch[2]);
        } elseif (preg_match('/<img[^>]*src=[\'"]([^\'"]+)[\'"][^>]*title=[\'"]([^\'"]+)[\'"]/', $body, $ch)) {
            $channel = trim($ch[2]);
            $channelImg = trim($ch[1]);
        }

        $events[] = [
            'href' => $href,
            'time' => $time,
            'sport' => $sport,
            'name' => $name,
            'comp' => $comp,
            'channel' => $channel,
            'channelImg' => $channelImg,
        ];
    }
}

// ---------------------------------------------------------------------------
// Build the page: categories row | clock | listings
// ---------------------------------------------------------------------------
$time12Attr = $time12 === '1' ? 'true' : 'false';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* { margin:0; padding:0; box-sizing:border-box; }
html,body { height:100%; }
body { background:#2e3440; color:#eceff4; font-family:Roboto,Arial,sans-serif; overflow:hidden; }

.sport-wrap { display:flex; flex-direction:column; height:100vh; }

/* Categories — wrap to a second row if they don't fit */
.cat-row { flex:0 0 auto; padding:8px 10px; background:#3b4252; border-bottom:1px solid #434c5e; }
.cat-row ul { list-style:none; display:flex; flex-wrap:wrap; gap:6px; margin:0; padding:0; }
.cat-row li { flex:0 0 auto; }
.cat-row a { display:flex; flex-direction:column; align-items:center; gap:2px; padding:5px 8px; border-radius:8px; color:#eceff4; text-decoration:none; font-size:11px; min-width:52px; }
.cat-row a:focus, .cat-row a.activeSport { background:#88c0d0; color:#2e3440; outline:none; }
.cat-row img { width:24px; height:24px; object-fit:contain; }

/* Clock */
.clock-row { flex:0 0 auto; text-align:center; padding:6px 0; background:#2e3440; border-bottom:1px solid #3b4252; }
.clock-row .time { font-size:30px; font-weight:700; color:#88c0d0; line-height:1.1; }
.clock-row .date { font-size:14px; color:#d8dee9; }

/* Listings */
.list-row { flex:1 1 auto; overflow-y:auto; padding:6px 10px; }
.event { display:flex; align-items:center; gap:10px; padding:8px 10px; border-bottom:1px solid #3b4252; text-decoration:none; color:#eceff4; }
.event:focus { background:#88c0d0; color:#2e3440; outline:none; }
.event .ev-time { flex:0 0 70px; font-weight:700; color:#88c0d0; font-size:14px; }
.event:focus .ev-time { color:#2e3440; }
.event .ev-sport { flex:0 0 90px; font-size:12px; color:#d8dee9; }
.event:focus .ev-sport { color:#2e3440; }
.event .ev-main { flex:1 1 auto; min-width:0; }
.event .ev-name { font-size:15px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.event .ev-comp { font-size:12px; color:#d8dee9; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.event:focus .ev-comp { color:#2e3440; }
.event .ev-channel { flex:0 0 auto; display:flex; flex-direction:column; align-items:center; gap:2px; font-size:11px; color:#a3be8c; text-align:center; max-width:130px; }
.event:focus .ev-channel { color:#2e3440; }
.event .ch-icon { height:26px; width:auto; max-width:110px; object-fit:contain; }
.event .ch-name { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:120px; }
.empty { padding:20px; text-align:center; color:#d8dee9; font-size:14px; }
</style>
</head>
<body>
<div class="sport-wrap">
  <div class="cat-row">
    <ul class="filterTypes"><?= $catsHtml ?></ul>
  </div>
  <div class="clock-row">
    <div class="time" id="clockTime">--:--</div>
    <div class="date" id="clockDate"></div>
  </div>
  <div class="list-row" id="listRow">
    <?php if (empty($events)): ?>
      <div class="empty">No events for this category.</div>
    <?php else: ?>
      <?php foreach ($events as $ev): ?>
        <a class="event" href="<?= htmlspecialchars($ev['href']) ?>">
          <div class="ev-time"><?= htmlspecialchars($ev['time']) ?></div>
          <div class="ev-sport"><?= htmlspecialchars($ev['sport']) ?></div>
          <div class="ev-main">
            <div class="ev-name"><?= htmlspecialchars($ev['name']) ?></div>
            <div class="ev-comp"><?= htmlspecialchars($ev['comp']) ?></div>
          </div>
          <div class="ev-channel">
            <?php if ($ev['channelImg'] !== ''): ?>
              <img src="<?= htmlspecialchars($ev['channelImg']) ?>" alt="<?= htmlspecialchars($ev['channel']) ?>" title="<?= htmlspecialchars($ev['channel']) ?>" class="ch-icon">
              <div class="ch-name"><?= htmlspecialchars($ev['channel']) ?></div>
            <?php else: ?>
              <?= htmlspecialchars($ev['channel']) ?>
            <?php endif; ?>
          </div>
        </a>
      <?php endforeach; ?>
    <?php endif; ?>
  </div>
</div>

<script>
// Live clock.
(function(){
  var tz = <?= json_encode($tz) ?>;
  var time12 = <?= $time12Attr ?>;
  function pad(n){ return n<10?'0'+n:''+n; }
  function tick(){
    var d = new Date();
    var s = new Date(d.toLocaleString('en-US',{timeZone:tz}));
    var h = s.getHours(), m = s.getMinutes();
    var ampm = '';
    if(time12){ ampm = h>=12?' PM':' AM'; h = h%12; if(h===0) h=12; }
    document.getElementById('clockTime').textContent = pad(h)+':'+pad(m)+ampm;
    document.getElementById('clockDate').textContent = s.toLocaleDateString('en-GB',{weekday:'long',day:'numeric',month:'long'});
  }
  tick(); setInterval(tick, 1000);
})();

// ---------------------------------------------------------------------------
// Navigation.
//
// D-pad navigation is left to the WebView's NATIVE focus (like the Simpsons
// app) — it moves the cursor between the category icons and the event rows,
// and scrolls the .list-row container automatically. We do NOT intercept
// keys: in this WebView the D-pad keys are consumed by native focus before
// they reach the page JS, so a keydown handler never fires and only breaks
// things. Native focus is the approach that works.
//
// We only:
//   1. Intercept category clicks so they reload sport.php with the typeID
//      (keeping the custom layout) instead of navigating cross-origin.
//   2. Scroll the focused event row into view (native focus moves the cursor
//      but doesn't always scroll the inner .list-row container).
(function(){
  var cats = Array.prototype.slice.call(document.querySelectorAll('.cat-row a'));
  var list = document.getElementById('listRow');

  function selectCategory(a){
    var href = a.getAttribute('href') || '';
    var m = href.match(/[?&]typeID=(\d+)/);
    var typeID = m ? m[1] : '0';
    // Use location.replace() so switching categories does NOT add a history
    // entry. That way the remote BACK button goes straight back to the main
    // menu (one press), instead of stepping back through every category.
    location.replace(location.pathname + '?typeID=' + typeID);
  }

  // Intercept category clicks (mouse or OK) so they reload sport.php instead
  // of navigating to the cross-origin widget.
  cats.forEach(function(a){
    a.addEventListener('click', function(e){ e.preventDefault(); selectCategory(a); });
  });

  // Keep the focused row visible. Native focus moves the cursor but does NOT
  // scroll the .list-row container on its own, so on long listings the cursor
  // can move off-screen. This scrolls the focused element into view WITHOUT
  // intercepting keys or calling preventDefault.
  if(list){
    list.addEventListener('focusin', function(e){
      var t = e.target;
      if(t && t.classList && t.classList.contains('event')){
        var r = t.getBoundingClientRect();
        var lr = list.getBoundingClientRect();
        if(r.top < lr.top)      list.scrollTop += (r.top - lr.top);
        else if(r.bottom > lr.bottom) list.scrollTop += (r.bottom - lr.bottom);
      }
    });
  }

  // Start focus on the first category.
  if(cats.length){ cats[0].focus(); }

  // Category icons: make LEFT/RIGHT move BOTH directions across the row.
  // (Native focus only moves one way, forcing the user to go all the way
  // around.) We ONLY handle LEFT/RIGHT here — DOWN/UP are left to native
  // focus so the listings scrolling and auto-scroll keep working.
  document.addEventListener('keydown', function(e){
    var kc = e.keyCode;
    var isLeft  = (e.key === 'ArrowLeft'  || kc === 21);
    var isRight = (e.key === 'ArrowRight' || kc === 22);
    if(!isLeft && !isRight) return; // let DOWN/UP/OK pass through to native
    e.preventDefault();
    var cur = document.activeElement;
    var idx = cats.indexOf(cur);
    if(idx < 0) idx = 0;
    var next = isRight ? idx + 1 : idx - 1;
    if(next < 0) next = cats.length - 1;      // wrap left
    if(next >= cats.length) next = 0;         // wrap right
    cats[next].focus();
  });
})();

// ---------------------------------------------------------------------------
// Auto-scroll (like the XCIPTV sports page).
//
// Continuously scrolls the listings down and loops back to the top, so the
// user can see all events without touching the remote. It pauses while the
// user is actively navigating with the D-pad, then resumes after a few
// seconds of inactivity so it doesn't fight manual control.
//
// Only runs in the APP (top-level page). In the panel Live Preview the page
// is inside an iframe (window.self !== window.top), so auto-scroll is
// disabled there — the preview stays still for the admin to inspect.
(function(){
  // Skip if we're inside an iframe (panel Live Preview).
  try { if(window.self !== window.top) return; } catch(e){ return; }

  var list = document.getElementById('listRow');
  if(!list) return;
  var speed = 0.2;      // px per frame (~12px/sec)
  var acc = 0;
  var enabled = true;
  var idleTimer = null;

  // Pause auto-scroll while the user navigates, resume after 4s idle.
  document.addEventListener('keydown', function(){
    enabled = false;
    clearTimeout(idleTimer);
    idleTimer = setTimeout(function(){ enabled = true; }, 4000);
  });

  function step(){
    if(enabled){
      acc += speed;
      if(acc >= 1){
        list.scrollTop += Math.floor(acc);
        acc -= Math.floor(acc);
      }
      // Loop back to the top when we reach the bottom.
      if(list.scrollTop + list.clientHeight >= list.scrollHeight){
        list.scrollTop = 0;
      }
    }
    requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
})();
</script>
</body>
</html>
