<?php
require_once __DIR__ . '/functions.php';

$matchId  = $_GET['m'] ?? '';
$serverId = $_GET['s'] ?? '';

$pageError = null;
$match = null;
$server = null;

if ($matchId === '' || $serverId === '') {
    $pageError = 'ম্যাচ অথবা সার্ভার আইডি দেওয়া হয়নি।';
} else {
    $data    = fetchMatches();
    $matches = $data['matches'] ?? [];
    $match   = findMatch($matches, $matchId);

    if (!$match) {
        $pageError = 'এই ম্যাচটি খুঁজে পাওয়া যায়নি।';
    } else {
        $server = findServer($match, $serverId);
        if (!$server) {
            $pageError = 'এই সার্ভারটি খুঁজে পাওয়া যায়নি।';
        } else {
            // canonical slug URL — upstream id দিয়ে এলে slug URL-এ redirect
            $canonMatchSlug  = computeMatchSlug($matches, $match);
            $canonServerSlug = computeServerSlug($match, $server);
            if ($canonMatchSlug !== '' && $canonServerSlug !== '' &&
                ($matchId !== $canonMatchSlug || $serverId !== $canonServerSlug)) {
                $qs = 'm=' . rawurlencode($canonMatchSlug) . '&s=' . rawurlencode($canonServerSlug);
                header('Location: ' . basename($_SERVER['SCRIPT_NAME']) . '?' . $qs, true, 302);
                exit;
            }
        }
    }
}

$streamUrl = $server['url'] ?? '';
$drm       = $server['drm'] ?? null;
$drmKeyRaw = $server['drmKey'] ?? null;
$headers   = $server['headers'] ?? [];
$matchTitle = $match['title'] ?? '';
$serverName = $server['name'] ?? '';
$pageTitle  = trim($matchTitle . ($serverName ? ' - ' . $serverName : ''));
if ($pageTitle === '') $pageTitle = SITE_NAME;
?>
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<!-- v5 fix: no-referrer যাতে Akamai/PLDT edge referrer চেকে 403 না দেয় -->
<meta name="referrer" content="no-referrer">
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title><?= h($pageTitle) ?> — <?= h(SITE_NAME) ?></title>
<link rel="stylesheet" href="assets/controls.css">
<style>
  html,body{margin:0;padding:0;width:100%;height:100%;background:#000;overflow:hidden;}
  #player-root{position:fixed;inset:0;width:100vw;height:100vh;background:#000;}
  video{width:100%;height:100%;background:#000;object-fit:fill;}
  video.fit-mode {object-fit:contain;}
  video.fill-mode{object-fit:fill;}
  video.zoom-mode{object-fit:cover;}
  #fitBtn{position:absolute;right:12px;bottom:70px;z-index:2147483000;background:rgba(0,0,0,.6);color:#fff;border:1px solid rgba(255,255,255,.3);padding:6px 12px;border-radius:6px;font:600 12px system-ui,-apple-system,sans-serif;cursor:pointer;user-select:none;}
  #fitBtn:hover{background:rgba(0,0,0,.85);}
  #watermark{position:absolute;top:12px;right:12px;width:70px;opacity:.85;pointer-events:none;z-index:2147483647;filter:drop-shadow(0 2px 8px rgba(0,0,0,.5));}
  #loading-overlay,#error-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;z-index:2147483000;background:rgba(0,0,0,.55);}
  #error-overlay{background:rgba(0,0,0,.85);display:none;}
  .spinner{width:44px;height:44px;border-radius:50%;border:4px solid rgba(255,255,255,.25);border-top-color:#ff3d5a;animation:spin 0.9s linear infinite;}
  @keyframes spin{to{transform:rotate(360deg);}}
  #error-overlay p{color:#fff;font-size:14px;max-width:320px;text-align:center;margin:16px 0;}
  #error-overlay svg{color:#ff3d5a;}
  .btn-row{display:flex;gap:12px;}
  .ov-btn{display:flex;align-items:center;gap:6px;cursor:pointer;background:#1b2030;border:1px solid #2a3145;color:#fff;padding:9px 16px;border-radius:8px;font-size:13px;font-family:inherit;}
  .ov-btn:hover{background:#252c42;}
  .ov-btn.primary{background:#ff3d5a;border-color:#ff3d5a;}
  .ov-btn.primary:hover{background:#e63350;}
  #fatal{position:fixed;inset:0;background:#000;color:#fff;display:flex;align-items:center;justify-content:center;flex-direction:column;text-align:center;padding:20px;font-family:'Segoe UI',Roboto,Arial,sans-serif;}
  #fatal a{color:#ff3d5a;text-decoration:none;margin-top:14px;font-size:14px;}
</style>
</head>
<body>

<?php if ($pageError): ?>

  <div id="fatal">
    <div class="spinner" style="border-top-color:#5a6178;animation:none;opacity:.5;"></div>
    <p style="max-width:340px;font-size:14px;margin-top:16px;"><?= h($pageError) ?></p>
    <a href="index.php">← হোমপেজে ফিরে যান</a>
  </div>

<?php else: ?>

  <div id="player-root" data-shaka-player>
    <img id="watermark" src="<?= h(WATERMARK_URL) ?>" alt="">
    <video id="video" class="fill-mode" autoplay muted playsinline preload="auto" poster="<?= h(PLAYER_POSTER) ?>"></video>
    <button id="fitBtn" type="button" title="Fit / Fill / Zoom">⛶ Fill</button>

    <div id="loading-overlay"><div class="spinner"></div></div>

    <div id="error-overlay">
      <svg width="46" height="46" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
        <circle cx="12" cy="12" r="10"></circle>
        <line x1="12" y1="8" x2="12" y2="12"></line>
        <line x1="12" y1="16" x2="12.01" y2="16"></line>
      </svg>
      <p id="error-msg">স্ট্রিম চালু করা যায়নি।</p>
      <div class="btn-row">
        <button class="ov-btn primary" id="retry-btn">⟳ আবার চেষ্টা করুন</button>
        <button class="ov-btn" id="back-btn">← ফিরে যান</button>
      </div>
    </div>
  </div>

  <script src="assets/shaka-player.ui.js" onerror="document.getElementById('loading-overlay').style.display='none';document.getElementById('error-overlay').style.display='flex';document.getElementById('error-msg').textContent='assets/shaka-player.ui.js ফাইলটি খুঁজে পাওয়া যায়নি।';"></script>
  <script>
  (function () {
    "use strict";

    var STREAM_URL   = <?= json_encode($streamUrl) ?>;
    var DRM_INFO     = <?= json_encode($drm) ?>;
    var DRM_KEY_RAW  = <?= json_encode($drmKeyRaw) ?>;
    var HEADERS      = <?= json_encode($headers) ?>;
    var BACK_URL     = 'index.php';

    var video      = document.getElementById('video');
    var container  = document.getElementById('player-root');
    var loadingOv  = document.getElementById('loading-overlay');
    var errorOv    = document.getElementById('error-overlay');
    var errorMsgEl = document.getElementById('error-msg');
    var retryBtn   = document.getElementById('retry-btn');
    var backBtn    = document.getElementById('back-btn');

    var player = null, ui = null, driftInterval = null, retry1003 = 0;

    retryBtn.addEventListener('click', initPlayer);
    backBtn.addEventListener('click', function () {
      if (document.referrer) window.history.back(); else window.location.href = BACK_URL;
    });

    function showLoading(s){ loadingOv.style.display = s ? 'flex' : 'none'; }
    function showError(m){ errorMsgEl.textContent = m || 'স্ট্রিম চালু করা যায়নি।'; errorOv.style.display='flex'; showLoading(false); }
    function hideError(){ errorOv.style.display='none'; }

    function jumpToLiveEdge(){
      if (video.seekable && video.seekable.length > 0) {
        var e = video.seekable.end(0);
        video.currentTime = Math.max(0, e - 0.5);
      }
    }

    function normalizeKeyToken(value){
      if (value == null) return '';
      var s = String(value).trim().replace(/^['"]|['"]$/g, '').replace(/^0x/i, '').replace(/-/g, '').toLowerCase();
      if (/^[0-9a-f]{32}$/.test(s)) return s;
      try {
        var b64 = String(value).trim().replace(/-/g, '+').replace(/_/g, '/');
        while (b64.length % 4) b64 += '=';
        var bin = atob(b64);
        if (bin.length === 16) {
          var hex = '';
          for (var i = 0; i < bin.length; i++) hex += ('0' + bin.charCodeAt(i).toString(16)).slice(-2);
          return hex;
        }
      } catch(e){}
      return '';
    }

    function addClearKey(out, kid, key){
      var k = normalizeKeyToken(kid);
      var v = normalizeKeyToken(key);
      if (k && v) out[k] = v;
    }

    function normalizeClearKeyMap(input){
      var out = {};
      if (!input) return null;
      if (typeof input === 'string') return parseClearKeyValue(input);
      if (Array.isArray(input)) {
        input.forEach(function(item){
          var keys = normalizeClearKeyMap(item);
          if (keys) Object.keys(keys).forEach(function(k){ out[k] = keys[k]; });
        });
      } else if (typeof input === 'object') {
        if (input.clearKeys) {
          var ck = normalizeClearKeyMap(input.clearKeys);
          if (ck) Object.keys(ck).forEach(function(k){ out[k] = ck[k]; });
        }
        if (Array.isArray(input.keys)) {
          input.keys.forEach(function(jwk){ addClearKey(out, jwk && jwk.kid, jwk && jwk.k); });
        }
        addClearKey(out, input.keyId || input.kid, input.key || input.k);
        Object.keys(input).forEach(function(k){ addClearKey(out, k, input[k]); });
      }
      return Object.keys(out).length ? out : null;
    }

    function parseClearKeyValue(raw){
      if (!raw) return null;
      if (typeof raw === 'object') return normalizeClearKeyMap(raw);
      var s = String(raw).trim();
      if (!s) return null;
      try { if (/%[0-9a-f]{2}/i.test(s)) s = decodeURIComponent(s); } catch(e){}
      try {
        if (s[0] === '{' || s[0] === '[') {
          var parsed = JSON.parse(s);
          var keys = normalizeClearKeyMap(parsed);
          if (keys) return keys;
        }
      } catch(e){}
      var out = {};
      s.split(/[\n,]+/).forEach(function(pair){
        pair = pair.trim();
        if (!pair) return;
        var pos = pair.indexOf(':');
        if (pos === -1) pos = pair.indexOf('=');
        if (pos === -1) return;
        addClearKey(out, pair.slice(0, pos), pair.slice(pos + 1));
      });
      return Object.keys(out).length ? out : null;
    }

    function parseInlineUrlDrm(rawUrl){
      if (!rawUrl || rawUrl.indexOf('|') === -1) return null;
      var parts = rawUrl.split('|');
      try {
        var params = new URLSearchParams(parts.slice(1).join('|'));
        var scheme = String(params.get('drmScheme') || params.get('drmType') || '').toLowerCase();
        var license = params.get('drmLicense') || params.get('license') || params.get('clearkey') || '';
        var keys = parseClearKeyValue(license);
        if ((scheme.indexOf('clearkey') !== -1 || keys) && keys) {
          return { url: parts[0].trim(), clearKeys: keys };
        }
      } catch(e){}
      return { url: parts[0].trim(), clearKeys: null };
    }

    function resolveClearKeys(){
      var keys = normalizeClearKeyMap(DRM_INFO);
      if (keys) return keys;
      keys = parseClearKeyValue(DRM_KEY_RAW);
      if (keys) return keys;
      var inline = parseInlineUrlDrm(STREAM_URL);
      if (inline && inline.clearKeys) return inline.clearKeys;
      return null;
    }

    function resolvePlaybackUrl(){
      if (STREAM_URL && STREAM_URL.indexOf('|') !== -1) return STREAM_URL.split('|')[0].trim();
      return STREAM_URL;
    }

    function buildDrmConfig(){
      var ck = resolveClearKeys();
      var cfg = { retryParameters: { maxAttempts: 5, baseDelay: 1000 } };
      if (ck) {
        // ClearKey থাকলে Widevine/PlayReady বাদ দিয়ে browser-কে org.w3.clearkey-তেই রাখি
        cfg.clearKeys = ck;
        cfg.preferredKeySystems = ['org.w3.clearkey'];
        cfg.advanced = {
          'org.w3.clearkey': {
            distinctiveIdentifierRequired: false,
            persistentStateRequired: false,
            videoRobustness: '',
            audioRobustness: ''
          }
        };
      }
      return cfg;
    }

    function forceClearKeyDashManifest(mpdText){
      // Amazon/Willow টাইপ MPD-তে Widevine/PlayReady tag থাকলে Shaka ভুল key-system ধরতে পারে।
      // সেগুলো বাদ দিয়ে cenc default_KID রেখে ClearKey scheme tag যোগ করা হচ্ছে।
      mpdText = mpdText
        .replace(/<ContentProtection\b(?=[^>]*schemeIdUri=["']urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed["'])[\s\S]*?<\/ContentProtection>\s*/gi, '')
        .replace(/<ContentProtection\b(?=[^>]*schemeIdUri=["']urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed["'])[^>]*\/?>\s*/gi, '')
        .replace(/<ContentProtection\b(?=[^>]*schemeIdUri=["']urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95["'])[\s\S]*?<\/ContentProtection>\s*/gi, '')
        .replace(/<ContentProtection\b(?=[^>]*schemeIdUri=["']urn:uuid:9a04f079-9840-4286-ab92-e65be0885f95["'])[^>]*\/?>\s*/gi, '');

      if (mpdText.indexOf('e2719d58-a985-b3c9-781a-b030af78d30e') === -1) {
        mpdText = mpdText.replace(
          /(<ContentProtection\b(?=[^>]*schemeIdUri=["']urn:mpeg:dash:mp4protection:2011["'])[^>]*\/?>)/gi,
          '$1\n        <ContentProtection schemeIdUri="urn:uuid:e2719d58-a985-b3c9-781a-b030af78d30e" value="ClearKey"/>'
        );
      }
      return mpdText;
    }

    function describeShakaError(err){
      if (err && typeof err.code !== 'undefined')
        return 'Shaka Error ' + err.code + ' (category ' + err.category + '): ' + (err.message || '');
      return (err && err.message) ? err.message : String(err);
    }

    async function initPlayer(){
      hideError(); showLoading(true);
      if (player) { try { await player.destroy(); } catch(e){} player = null; }
      if (ui) { try { await ui.destroy(); } catch(e){} ui = null; }

      // v9 fix: previous stream frame/buffer clear — নাহলে নতুন load-এর আগে পুরনো stream flash করে
      try {
        video.pause();
        video.removeAttribute('src');
        while (video.firstChild) video.removeChild(video.firstChild);
        video.load();
        video.currentTime = 0;
      } catch(e){}
      retry1003 = 0;

      if (!window.shaka || !shaka.Player) {
        showError('Shaka Player লাইব্রেরি লোড হয়নি।'); return;
      }
      if (!shaka.Player.isBrowserSupported()) {
        showError('এই ব্রাউজার সাপোর্টেড না।'); return;
      }

      try {
        player = new shaka.Player();
        await player.attach(video);

        ui = new shaka.ui.Overlay(player, container, video);
        ui.configure({
          controlPanelElements: ['play_pause','time_and_duration','mute','volume','spacer','language','captions','picture_in_picture','quality','fullscreen'],
          seekBarColors: { base:'rgba(255,255,255,0.3)', buffered:'rgba(255,255,255,0.5)', played:'#ff3d5a' }
        });

        // v8: stream type detect (HLS vs DASH vs MP4)
        var playbackUrl = resolvePlaybackUrl();
        var urlLower = (playbackUrl || '').toLowerCase().split('?')[0];
        var isHls  = urlLower.indexOf('.m3u8') !== -1;
        var isDash = urlLower.indexOf('.mpd')  !== -1;

        var playbackSearch = '';
        try { playbackSearch = new URL(playbackUrl, window.location.href).search; } catch(e) {}

        player.getNetworkingEngine().registerResponseFilter(function (type, response) {
          // DASH+ClearKey stream-এ Widevine/PlayReady ContentProtection থাকলে Chrome wrong key-system try করে fail করে।
          if (isDash && type === shaka.net.NetworkingEngine.RequestType.MANIFEST && resolveClearKeys()) {
            try {
              var mpdText = new TextDecoder().decode(response.data);
              if (mpdText.indexOf('ContentProtection') !== -1) {
                response.data = new TextEncoder().encode(forceClearKeyDashManifest(mpdText));
              }
            } catch(e) { console.warn('DRM manifest filter failed', e); }
          }
        });
        player.configure(Object.assign({
          streaming: {
            bufferingGoal: 30,
            rebufferingGoal: 2,
            bufferBehind: 30,
            stallEnabled: true,
            stallThreshold: 1,
            stallSkip: 0.1,
            lowLatencyMode: false,
            useNativeHlsOnSafari: true,
            retryParameters: {
              timeout: 30000, stallTimeout: 5000, connectionTimeout: 10000,
              maxAttempts: 5, baseDelay: 1000, backoffFactor: 2, fuzzFactor: 0.5
            }
          },
          manifest: {
            dash: { ignoreMinBufferTime: true, autoCorrectDrift: true },
            hls:  { ignoreTextStreamFailures: true, ignoreImageStreamFailures: true },
            retryParameters: { timeout: 30000, maxAttempts: 5, baseDelay: 1000, backoffFactor: 2 }
          },
          drm: buildDrmConfig()
        }, {}));

        player.addEventListener('error', function (event) {
          var er = event.detail;
          console.error('Shaka error:', er);
          // v10 fix: ভিডিও চললে (segment ফেইল হলেও) error overlay দেখানো হবে না
          var isPlaying = video && !video.paused && !video.ended && video.readyState >= 2;
          if (isPlaying && er && (er.category === 1 || er.category === 3)) {
            // network/media segment error but playback continues — silently ignore
            return;
          }
          if (er && er.code === 1003 && retry1003 < 2) {
            retry1003++;
            setTimeout(initPlayer, 1500);
            return;
          }
          if (isPlaying) return; // অন্য error-ও, কিন্তু চললে overlay দেখাব না
          showError('প্লেব্যাক এরর: ' + describeShakaError(er));
        });


        await player.load(resolvePlaybackUrl());

        video.muted = true;
        try { await video.play(); video.muted = false; }
        catch(e){ video.muted = true; try { await video.play(); } catch(e2){} }

        retry1003 = 0;
        showLoading(false);
      } catch (err) {
        console.error('Init error:', err);
        // v8: Shaka fail হলে native <video> fallback (m3u8/mp4/webm সরাসরি play)
        if (!resolveClearKeys()) {
          try {
            if (player) { await player.destroy(); player = null; }
            video.src = playbackUrl;
            video.load();
            await video.play();
            showLoading(false);
            return;
          } catch(e2){ console.warn('Native fallback failed', e2); }
        }
        showError('স্ট্রিম লোড করা যায়নি: ' + describeShakaError(err));
      }
    }

    video.addEventListener('play', function(){
      if (video.seekable && video.seekable.length > 0) {
        var behind = video.seekable.end(0) - video.currentTime;
        if (behind > 30) jumpToLiveEdge();
      }
    });

    driftInterval = setInterval(function(){
      if (!video.paused && video.seekable && video.seekable.length > 0) {
        var behind = video.seekable.end(0) - video.currentTime;
        if (behind > 30) jumpToLiveEdge();
      }
    }, 15000);

    window.addEventListener('beforeunload', function(){
      clearInterval(driftInterval);
      if (ui) ui.destroy().catch(function(){});
      if (player) player.destroy().catch(function(){});
    });

    // v9 fix: browser back/forward cache থেকে ফিরলে পুরনো player state দেখাবে — force reinit
    window.addEventListener('pageshow', function(ev){
      if (ev.persisted) { try { initPlayer(); } catch(e){} }
    });
    document.addEventListener('DOMContentLoaded', initPlayer);
    if (document.readyState !== 'loading') initPlayer();
    // v7: Fit / Fill / Zoom toggle (default = Fill / stretch)
    (function(){
      var btn = document.getElementById('fitBtn');
      if (!btn) return;
      var modes = [
        { cls:'fill-mode', label:'⛶ Fill' },
        { cls:'fit-mode',  label:'⛶ Fit'  },
        { cls:'zoom-mode', label:'⛶ Zoom' }
      ];
      var i = 0;
      try {
        var saved = parseInt(localStorage.getItem('eplay_fit_mode')||'0',10);
        if (!isNaN(saved) && saved>=0 && saved<modes.length) i = saved;
      } catch(e){}
      function apply(){
        video.classList.remove('fit-mode','fill-mode','zoom-mode');
        video.classList.add(modes[i].cls);
        btn.textContent = modes[i].label;
        try { localStorage.setItem('eplay_fit_mode', String(i)); } catch(e){}
      }
      apply();
      btn.addEventListener('click', function(ev){ ev.stopPropagation(); i=(i+1)%modes.length; apply(); });
      var lastTap = 0;
      video.addEventListener('touchend', function(e){
        var now = Date.now();
        if (now - lastTap < 300) { i=(i+1)%modes.length; apply(); e.preventDefault(); }
        lastTap = now;
      });
    })();
  })();
  </script>

<?php endif; ?>

</body>
</html>
