<?php
// index.php
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>My VOD & Live TV</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <!-- Open Graph for shareable channel URLs -->
  <meta property="og:title" content="My VOD & Live TV">
  <meta property="og:description" content="Stream live channels and VOD with EPG, PiP, Chromecast and more.">
  <meta property="og:type" content="website">
  <meta property="og:url" content="">
  <meta property="og:image" content="https://example.com/preview.jpg">

  <style>
    :root {
      --bg: #05060a;
      --bg-elevated: #10121a;
      --accent: #e50914;
      --text: #f5f5f5;
      --muted: #888;
      --radius: 12px;
    }
    * { box-sizing: border-box; }
    body {
      margin: 0;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      background: radial-gradient(circle at top, #1b1f3b 0, #05060a 55%);
      color: var(--text);
      overflow-x: hidden;
    }
    header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 12px 20px;
      background: linear-gradient(to bottom, rgba(0,0,0,0.9), rgba(0,0,0,0));
      position: sticky;
      top: 0;
      z-index: 20;
    }
    .logo {
      font-weight: 800;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      font-size: 18px;
    }
    .logo span {
      color: var(--accent);
    }
    .search-box {
      position: relative;
      max-width: 320px;
      flex: 1;
      margin: 0 16px;
    }
    .search-box input {
      width: 100%;
      padding: 8px 32px 8px 12px;
      border-radius: 999px;
      border: none;
      background: rgba(255,255,255,0.06);
      color: var(--text);
      outline: none;
    }
    .search-box input::placeholder {
      color: var(--muted);
    }
    .search-box svg {
      position: absolute;
      right: 10px;
      top: 50%;
      transform: translateY(-50%);
      width: 16px;
      height: 16px;
      opacity: 0.7;
    }
    .region-tabs {
      display: flex;
      gap: 8px;
      align-items: center;
    }
    .region-tab {
      padding: 6px 12px;
      border-radius: 999px;
      background: rgba(255,255,255,0.06);
      cursor: pointer;
      font-size: 13px;
      border: 1px solid transparent;
    }
    .region-tab.active {
      background: var(--accent);
      border-color: rgba(255,255,255,0.4);
    }

    main {
      display: grid;
      grid-template-columns: 260px minmax(0, 1fr);
      gap: 16px;
      padding: 0 16px 16px;
    }

    /* Sidebar / drawer */
    .sidebar {
      background: rgba(0,0,0,0.5);
      border-radius: var(--radius);
      padding: 12px;
      backdrop-filter: blur(18px);
      max-height: calc(100vh - 80px);
      overflow-y: auto;
      position: sticky;
      top: 64px;
    }
    .sidebar h2 {
      font-size: 14px;
      text-transform: uppercase;
      letter-spacing: 0.12em;
      color: var(--muted);
      margin: 0 0 8px;
    }
    .network-list {
      list-style: none;
      margin: 0;
      padding: 0;
    }
    .network-item {
      padding: 6px 8px;
      border-radius: 8px;
      cursor: pointer;
      font-size: 13px;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    .network-item:hover {
      background: rgba(255,255,255,0.06);
    }
    .network-item.active {
      background: rgba(255,255,255,0.12);
    }

    /* Mobile drawer */
    @media (max-width: 768px) {
      main {
        grid-template-columns: 1fr;
      }
      .sidebar {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        top: auto;
        max-height: 60vh;
        border-radius: 16px 16px 0 0;
        transform: translateY(100%);
        transition: transform 0.25s ease-out;
        z-index: 30;
      }
      .sidebar.open {
        transform: translateY(0);
      }
      .drawer-handle {
        width: 40px;
        height: 4px;
        border-radius: 999px;
        background: rgba(255,255,255,0.3);
        margin: 4px auto 8px;
      }
      .drawer-toggle-btn {
        display: inline-flex;
      }
    }
    @media (min-width: 769px) {
      .drawer-toggle-btn {
        display: none;
      }
    }

    /* Player + grid */
    .content {
      display: flex;
      flex-direction: column;
      gap: 12px;
    }
    .player-card {
      background: radial-gradient(circle at top left, #2b2f55, #05060a);
      border-radius: var(--radius);
      padding: 12px;
      display: grid;
      grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
      gap: 12px;
      box-shadow: 0 18px 40px rgba(0,0,0,0.6);
    }
    @media (max-width: 900px) {
      .player-card {
        grid-template-columns: 1fr;
      }
    }
    .video-shell {
      position: relative;
      border-radius: 12px;
      overflow: hidden;
      background: #000;
    }
    video {
      width: 100%;
      height: 100%;
      display: block;
      background: #000;
    }
    .video-overlay {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      padding: 8px 10px;
      background: linear-gradient(to top, rgba(0,0,0,0.9), transparent);
      display: flex;
      justify-content: space-between;
      align-items: center;
      font-size: 13px;
    }
    .video-overlay .title {
      font-weight: 600;
    }
    .video-actions {
      display: flex;
      gap: 6px;
      align-items: center;
    }
    .pill-btn {
      border-radius: 999px;
      border: none;
      padding: 4px 10px;
      font-size: 12px;
      cursor: pointer;
      background: rgba(255,255,255,0.12);
      color: var(--text);
      display: inline-flex;
      align-items: center;
      gap: 4px;
    }
    .pill-btn.primary {
      background: var(--accent);
    }

    .meta-panel {
      display: flex;
      flex-direction: column;
      gap: 8px;
      font-size: 13px;
    }
    .meta-row-label {
      text-transform: uppercase;
      letter-spacing: 0.12em;
      color: var(--muted);
      font-size: 11px;
    }
    .epg-list {
      max-height: 180px;
      overflow-y: auto;
      border-radius: 8px;
      background: rgba(0,0,0,0.4);
      padding: 6px;
    }
    .epg-item {
      padding: 4px 6px;
      border-radius: 6px;
      margin-bottom: 2px;
      display: flex;
      flex-direction: column;
      gap: 2px;
    }
    .epg-item.current {
      background: rgba(255,255,255,0.08);
    }
    .epg-time {
      color: var(--muted);
      font-size: 11px;
    }

    .row-title {
      font-size: 14px;
      font-weight: 600;
      margin-top: 4px;
      margin-bottom: 4px;
    }
    .channel-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
      gap: 8px;
    }
    .channel-card {
      background: rgba(0,0,0,0.5);
      border-radius: 10px;
      padding: 8px;
      cursor: pointer;
      display: flex;
      flex-direction: column;
      gap: 6px;
      transition: transform 0.12s ease-out, box-shadow 0.12s ease-out, background 0.12s;
      position: relative;
    }
    .channel-card:hover {
      transform: translateY(-2px);
      box-shadow: 0 10px 24px rgba(0,0,0,0.6);
      background: rgba(0,0,0,0.7);
    }
    .channel-card.active {
      outline: 2px solid var(--accent);
    }
    .channel-logo {
      width: 100%;
      height: 60px;
      background: #111;
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
    }
    .channel-logo img {
      max-width: 100%;
      max-height: 100%;
      object-fit: contain;
    }
    .channel-name {
      font-size: 13px;
      font-weight: 500;
    }
    .channel-meta {
      font-size: 11px;
      color: var(--muted);
    }

    /* Keyboard shortcut modal */
    .shortcut-modal-backdrop {
      position: fixed;
      inset: 0;
      background: rgba(0,0,0,0.7);
      display: none;
      align-items: center;
      justify-content: center;
      z-index: 50;
    }
    .shortcut-modal-backdrop.open {
      display: flex;
    }
    .shortcut-modal {
      background: #11131b;
      border-radius: 12px;
      padding: 16px;
      max-width: 420px;
      width: 100%;
      box-shadow: 0 18px 40px rgba(0,0,0,0.8);
    }
    .shortcut-modal h2 {
      margin-top: 0;
      font-size: 18px;
    }
    .shortcut-list {
      list-style: none;
      padding: 0;
      margin: 8px 0 0;
      font-size: 13px;
    }
    .shortcut-list li {
      display: flex;
      justify-content: space-between;
      padding: 4px 0;
    }
    .shortcut-key {
      font-family: monospace;
      background: rgba(255,255,255,0.06);
      padding: 2px 6px;
      border-radius: 4px;
    }
  </style>
</head>
<body>
<header>
  <div class="logo"><span>VOD</span>STREAM</div>

  <button class="pill-btn drawer-toggle-btn" id="drawerToggle">Channels</button>

  <div class="search-box">
    <input id="searchInput" type="search" placeholder="Search channels, tags..." autocomplete="off">
    <svg viewBox="0 0 24 24">
      <path fill="currentColor" d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0016 9.5 6.5 6.5 0 109.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79L20 21.49 21.49 20 15.5 14zm-6 0C8.01 14 6 11.99 6 9.5S8.01 5 10.5 5 15 7.01 15 9.5 12.99 14 10.5 14z"/>
    </svg>
  </div>

  <div class="region-tabs" id="regionTabs">
    <button class="region-tab" data-region="nz">NZ</button>
    <button class="region-tab" data-region="uk">UK</button>
    <button class="region-tab" data-region="us">US</button>
  </div>
</header>

<main>
  <aside class="sidebar" id="sidebar">
    <div class="drawer-handle"></div>
    <h2>Networks</h2>
    <ul class="network-list" id="networkList"></ul>
  </aside>

  <section class="content">
    <div class="player-card">
      <div class="video-shell">
        <video id="player" controls playsinline></video>
        <div class="video-overlay">
          <div>
            <div class="title" id="playerTitle">Select a channel</div>
            <div class="subtitle" id="playerSubtitle"></div>
          </div>
          <div class="video-actions">
            <button class="pill-btn primary" id="pipBtn">PiP</button>
            <button class="pill-btn" id="shareBtn">Share</button>
            <button class="pill-btn" id="castBtn">Cast</button>
          </div>
        </div>
      </div>
      <div class="meta-panel">
        <div>
          <div class="meta-row-label">Now & Next</div>
          <div class="epg-list" id="epgList"></div>
        </div>
        <div>
          <div class="meta-row-label">Details</div>
          <div id="channelDetails"></div>
        </div>
      </div>
    </div>

    <div id="continueRow" style="display:none;">
      <div class="row-title">Continue Watching</div>
      <div class="channel-grid" id="continueGrid"></div>
    </div>

    <div>
      <div class="row-title">All Channels</div>
      <div class="channel-grid" id="channelGrid"></div>
    </div>
  </section>
</main>

<!-- Keyboard shortcut modal -->
<div class="shortcut-modal-backdrop" id="shortcutModal">
  <div class="shortcut-modal">
    <h2>Keyboard Shortcuts</h2>
    <ul class="shortcut-list">
      <li><span>Show shortcuts</span><span class="shortcut-key">?</span></li>
      <li><span>Play / Pause</span><span class="shortcut-key">Space</span></li>
      <li><span>Next channel</span><span class="shortcut-key">→</span></li>
      <li><span>Previous channel</span><span class="shortcut-key">←</span></li>
      <li><span>Toggle PiP</span><span class="shortcut-key">P</span></li>
      <li><span>Mute</span><span class="shortcut-key">M</span></li>
    </ul>
  </div>
</div>

<script>
// --- Global state ---
let catalog = [];
let networks = [];
let filteredChannels = [];
let currentChannel = null;
let currentRegion = null;
let watchHistory = []; // last 20 channel IDs
const HISTORY_KEY = 'vod_watch_history_v1';

// --- Helpers ---
function getLogoUrl(channel) {
  // IPTV-org logo pattern: https://github.com/iptv-org/iptv/tree/master/logos
  // Many setups use: https://iptv-org.github.io/iptv/logos/{country}/{id}.png
  const country = (channel.country || 'us').toLowerCase();
  const id = (channel.logo_id || channel.id || '').toLowerCase();
  if (!id) return '';
  return `https://iptv-org.github.io/iptv/logos/${country}/${encodeURIComponent(id)}.png`;
}

function loadHistory() {
  try {
    const raw = localStorage.getItem(HISTORY_KEY);
    if (!raw) return [];
    return JSON.parse(raw);
  } catch (e) {
    return [];
  }
}

function saveHistory() {
  localStorage.setItem(HISTORY_KEY, JSON.stringify(watchHistory.slice(0, 20)));
}

function addToHistory(channelId) {
  watchHistory = watchHistory.filter(id => id !== channelId);
  watchHistory.unshift(channelId);
  if (watchHistory.length > 20) watchHistory.length = 20;
  saveHistory();
  renderContinueWatching();
}

function getChannelById(id) {
  return catalog.find(ch => ch.id === id);
}

function getRegionFromChannel(ch) {
  const id = ch.id || '';
  if (id.startsWith('nz-')) return 'nz';
  if (id.startsWith('uk-')) return 'uk';
  if (id.startsWith('us-')) return 'us';
  return ch.country ? ch.country.toLowerCase() : null;
}

// --- Fetch initial data ---
async function fetchCatalog() {
  const res = await fetch('backend-engine.php?action=list');
  const data = await res.json();
  catalog = data.channels || [];
  networks = data.networks.files || [];
  renderNetworks();
  applyRegionAutoSelect();
  applyUrlChannel();
  renderGrid();
  watchHistory = loadHistory();
  renderContinueWatching();
}

// --- Networks sidebar ---
function renderNetworks() {
  const list = document.getElementById('networkList');
  list.innerHTML = '';
  networks.forEach(file => {
    const li = document.createElement('li');
    li.className = 'network-item';
    li.dataset.network = file;
    li.innerHTML = `<span>${file.replace('.json','')}</span>`;
    li.addEventListener('click', () => {
      document.querySelectorAll('.network-item').forEach(el => el.classList.remove('active'));
      li.classList.add('active');
      filterByNetwork(file);
    });
    list.appendChild(li);
  });
}

function filterByNetwork(file) {
  filteredChannels = catalog.filter(ch => (ch.network_file === file) || (ch.network === file));
  renderGrid();
}

// --- Region tabs + GeoIP ---
async function detectRegionByGeoIP() {
  try {
    const res = await fetch('http://ip-api.com/json/?fields=countryCode');
    const data = await res.json();
    const cc = (data.countryCode || '').toUpperCase();
    if (cc === 'NZ') return 'nz';
    if (cc === 'GB' || cc === 'UK') return 'uk';
    if (cc === 'US') return 'us';
  } catch (e) {}
  return null;
}

async function applyRegionAutoSelect() {
  const region = await detectRegionByGeoIP();
  if (!region) return;
  const tab = document.querySelector(`.region-tab[data-region="${region}"]`);
  if (tab) {
    setRegion(region);
    tab.classList.add('active');
  }
}

function setRegion(region) {
  currentRegion = region;
  filteredChannels = catalog.filter(ch => getRegionFromChannel(ch) === region);
  renderGrid();
}

document.getElementById('regionTabs').addEventListener('click', e => {
  const btn = e.target.closest('.region-tab');
  if (!btn) return;
  document.querySelectorAll('.region-tab').forEach(el => el.classList.remove('active'));
  btn.classList.add('active');
  setRegion(btn.dataset.region);
});

// --- Search via backend ---
let searchTimeout = null;
document.getElementById('searchInput').addEventListener('input', e => {
  const q = e.target.value.trim();
  if (searchTimeout) clearTimeout(searchTimeout);
  searchTimeout = setTimeout(() => doSearch(q), 250);
});

async function doSearch(q) {
  if (!q) {
    filteredChannels = currentRegion
      ? catalog.filter(ch => getRegionFromChannel(ch) === currentRegion)
      : catalog;
    renderGrid();
    return;
  }
  const res = await fetch('backend-engine.php?action=search&q=' + encodeURIComponent(q));
  const data = await res.json();
  filteredChannels = data.results || [];
  renderGrid();
}

// --- Channel grid + Continue Watching ---
function renderGrid() {
  const grid = document.getElementById('channelGrid');
  grid.innerHTML = '';
  const list = filteredChannels.length ? filteredChannels : catalog;
  list.forEach(ch => {
    const card = document.createElement('div');
    card.className = 'channel-card';
    card.dataset.id = ch.id;
    const logoUrl = getLogoUrl(ch);
    card.innerHTML = `
      <div class="channel-logo">
        ${logoUrl ? `<img src="${logoUrl}" alt="${ch.name}">` : `<span>${ch.name}</span>`}
      </div>
      <div class="channel-name">${ch.name}</div>
      <div class="channel-meta">${(ch.category || '').toUpperCase()}</div>
    `;
    card.addEventListener('click', () => playChannel(ch));
    grid.appendChild(card);
  });
  highlightActiveCard();
}

function renderContinueWatching() {
  const row = document.getElementById('continueRow');
  const grid = document.getElementById('continueGrid');
  grid.innerHTML = '';
  if (!watchHistory.length) {
    row.style.display = 'none';
    return;
  }
  watchHistory.forEach(id => {
    const ch = getChannelById(id);
    if (!ch) return;
    const card = document.createElement('div');
    card.className = 'channel-card';
    card.dataset.id = ch.id;
    const logoUrl = getLogoUrl(ch);
    card.innerHTML = `
      <div class="channel-logo">
        ${logoUrl ? `<img src="${logoUrl}" alt="${ch.name}">` : `<span>${ch.name}</span>`}
      </div>
      <div class="channel-name">${ch.name}</div>
      <div class="channel-meta">Last watched</div>
    `;
    card.addEventListener('click', () => playChannel(ch));
    grid.appendChild(card);
  });
  row.style.display = 'block';
}

// --- Player + EPG + URL routing + MediaSession ---
const player = document.getElementById('player');
const playerTitle = document.getElementById('playerTitle');
const playerSubtitle = document.getElementById('playerSubtitle');
const epgList = document.getElementById('epgList');
const channelDetails = document.getElementById('channelDetails');

async function playChannel(ch) {
  currentChannel = ch;
  player.src = ch.url;
  player.play().catch(() => {});
  playerTitle.textContent = ch.name;
  playerSubtitle.textContent = ch.category || '';
  addToHistory(ch.id);
  updateUrlForChannel(ch);
  highlightActiveCard();
  fetchEpgForChannel(ch);
  setupMediaSession(ch);
}

function highlightActiveCard() {
  document.querySelectorAll('.channel-card').forEach(card => {
    card.classList.toggle('active', currentChannel && card.dataset.id === currentChannel.id);
  });
}

async function fetchEpgForChannel(ch) {
  epgList.innerHTML = 'Loading...';
  const region = getRegionFromChannel(ch) || 'nz';
  const res = await fetch('backend-engine.php?action=epg&channel=' + encodeURIComponent(ch.id) + '&country=' + encodeURIComponent(region));
  const data = await res.json();
  const programs = data.programs || [];
  epgList.innerHTML = '';
  const now = Date.now();
  programs.forEach(p => {
    const start = new Date(p.start).getTime();
    const stop = new Date(p.stop).getTime();
    const isCurrent = now >= start && now <= stop;
    const item = document.createElement('div');
    item.className = 'epg-item' + (isCurrent ? ' current' : '');
    item.innerHTML = `
      <div>${p.title}</div>
      <div class="epg-time">${new Date(p.start).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})} - ${new Date(p.stop).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})}</div>
      ${p.desc ? `<div class="epg-desc">${p.desc}</div>` : ''}
    `;
    epgList.appendChild(item);
  });
  channelDetails.innerHTML = `
    <div>${ch.name}</div>
    <div class="channel-meta">${(ch.category || '').toUpperCase()} • ${ch.id}</div>
  `;
}

function updateUrlForChannel(ch) {
  const url = new URL(window.location.href);
  url.searchParams.set('channel', ch.id);
  history.replaceState({}, '', url.toString());
}

function applyUrlChannel() {
  const url = new URL(window.location.href);
  const id = url.searchParams.get('channel');
  if (!id) return;
  const ch = getChannelById(id);
  if (ch) playChannel(ch);
}

function setupMediaSession(ch) {
  if (!('mediaSession' in navigator)) return;
  navigator.mediaSession.metadata = new MediaMetadata({
    title: ch.name,
    artist: ch.category || '',
    album: 'Live TV',
    artwork: [
      { src: getLogoUrl(ch), sizes: '256x256', type: 'image/png' }
    ]
  });
  navigator.mediaSession.setActionHandler('play', () => player.play());
  navigator.mediaSession.setActionHandler('pause', () => player.pause());
  navigator.mediaSession.setActionHandler('previoustrack', () => stepChannel(-1));
  navigator.mediaSession.setActionHandler('nexttrack', () => stepChannel(1));
}

function stepChannel(delta) {
  const list = filteredChannels.length ? filteredChannels : catalog;
  if (!currentChannel || !list.length) return;
  const idx = list.findIndex(ch => ch.id === currentChannel.id);
  if (idx === -1) return;
  const next = list[(idx + delta + list.length) % list.length];
  playChannel(next);
}

// --- PiP, Share, Cast (stub) ---
document.getElementById('pipBtn').addEventListener('click', async () => {
  if (!document.pictureInPictureEnabled) return;
  if (document.pictureInPictureElement) {
    document.exitPictureInPicture();
  } else {
    try {
      await player.requestPictureInPicture();
    } catch (e) {}
  }
});

document.getElementById('shareBtn').addEventListener('click', async () => {
  if (!navigator.share || !currentChannel) return;
  const url = new URL(window.location.href);
  url.searchParams.set('channel', currentChannel.id);
  try {
    await navigator.share({
      title: currentChannel.name,
      text: 'Watch this channel',
      url: url.toString()
    });
  } catch (e) {}
});

// Cast: you’d load the Cast SDK and wire this button
document.getElementById('castBtn').addEventListener('click', () => {
  alert('Cast integration stub — wire Google Cast SDK here.');
});

// --- Keyboard shortcuts + modal ---
const shortcutModal = document.getElementById('shortcutModal');
function openShortcutModal() {
  shortcutModal.classList.add('open');
}
function closeShortcutModal() {
  shortcutModal.classList.remove('open');
}
shortcutModal.addEventListener('click', e => {
  if (e.target === shortcutModal) closeShortcutModal();
});
document.addEventListener('keydown', e => {
  if (e.key === '?') {
    e.preventDefault();
    openShortcutModal();
  } else if (e.key === 'Escape') {
    closeShortcutModal();
  } else if (e.key === ' ') {
    if (document.activeElement === document.getElementById('searchInput')) return;
    e.preventDefault();
    if (player.paused) player.play(); else player.pause();
  } else if (e.key === 'ArrowRight') {
    stepChannel(1);
  } else if (e.key === 'ArrowLeft') {
    stepChannel(-1);
  } else if (e.key.toLowerCase() === 'p') {
    document.getElementById('pipBtn').click();
  } else if (e.key.toLowerCase() === 'm') {
    player.muted = !player.muted;
  }
});

// --- Mobile drawer ---
const sidebar = document.getElementById('sidebar');
const drawerToggle = document.getElementById('drawerToggle');
drawerToggle.addEventListener('click', () => {
  sidebar.classList.toggle('open');
});

// --- Service worker registration ---
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('service-worker.js').catch(() => {});
}

// --- Init ---
fetchCatalog();
</script>
</body>
</html>