import { useEffect, useRef, useState } from "react";
import mpegts from "mpegts.js";

interface Props {
  live: boolean;
  streamKey: string;
}

const MAX_RETRIES = 8;

export default function Player({ live, streamKey }: Props) {
  const videoRef = useRef<HTMLVideoElement>(null);
  const playerRef = useRef<mpegts.Player | null>(null);
  const retryTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const stallTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const retryCountRef = useRef(0);
  const lastProgressRef = useRef(0);
  const [playing, setPlaying] = useState(false);

  useEffect(() => {
    const video = videoRef.current;
    if (!video) return;

    const clearTimers = () => {
      if (retryTimerRef.current) {
        clearTimeout(retryTimerRef.current);
        retryTimerRef.current = null;
      }
      if (stallTimerRef.current) {
        clearInterval(stallTimerRef.current);
        stallTimerRef.current = null;
      }
    };

    const destroyPlayer = () => {
      if (playerRef.current) {
        try { playerRef.current.pause(); } catch { /* noop */ }
        try { playerRef.current.unload(); } catch { /* noop */ }
        try { playerRef.current.detachMediaElement(); } catch { /* noop */ }
        try { playerRef.current.destroy(); } catch { /* noop */ }
        playerRef.current = null;
      }
    };

    // Tear down when offline
    if (!live) {
      clearTimers();
      destroyPlayer();
      try { video.removeAttribute("src"); video.load(); } catch { /* noop */ }
      setPlaying(false);
      return;
    }

    if (!mpegts.isSupported()) {
      setPlaying(false);
      return;
    }

    const src = `${window.location.origin}/ts?v=${encodeURIComponent(streamKey)}`;

    const scheduleRetry = () => {
      if (retryCountRef.current >= MAX_RETRIES) {
        setPlaying(false);
        return;
      }
      retryCountRef.current++;
      const delay = Math.min(2000 * retryCountRef.current, 10000);
      setPlaying(false);
      retryTimerRef.current = setTimeout(start, delay);
    };

    const startStallWatchdog = () => {
      if (stallTimerRef.current) clearInterval(stallTimerRef.current);
      lastProgressRef.current = Date.now();
      const bump = () => { lastProgressRef.current = Date.now(); };
      video.addEventListener("timeupdate", bump);
      video.addEventListener("progress", bump);
      stallTimerRef.current = setInterval(() => {
        if (Date.now() - lastProgressRef.current > 30000) {
          lastProgressRef.current = Date.now();
          start();
        }
      }, 5000);
    };



    function start() {
      destroyPlayer();
      // Config mirrors webplayer.online (proven on this exact bursty upstream):
      // a deep 30-90s live buffer absorbs the upstream's multi-second delivery
      // gaps, while gentle 1.1x catch-up keeps latency bounded.
      const player = mpegts.createPlayer(
        { type: "mpegts", isLive: true, url: src },
        {
          enableWorker: true,
          enableStashBuffer: true,
          stashInitialSize: 8 * 1024 * 1024,
          liveSync: true,
          liveSyncMaxLatency: 60,
          liveSyncTargetLatency: 45,
          liveSyncPlaybackRate: 1.1,
          liveBufferLatencyChasing: true,
          liveBufferLatencyMaxLatency: 90,
          liveBufferLatencyMinRemain: 30,
          autoCleanupSourceBuffer: true,
          autoCleanupMaxBackwardDuration: 120,
          autoCleanupMinBackwardDuration: 90,
          fixAudioTimestampGap: true,
          lazyLoad: false,
        }
      );
      playerRef.current = player;
      player.attachMediaElement(video!);

      player.on(mpegts.Events.ERROR, () => {
        scheduleRetry();
      });
      player.on(mpegts.Events.LOADING_COMPLETE, () => {
        scheduleRetry();
      });
      player.on(mpegts.Events.MEDIA_INFO, () => {
        setPlaying(true);
      });

      player.load();
      video!.play().catch(() => { /* autoplay handled via muted attribute */ });
      startStallWatchdog();
    }

    retryCountRef.current = 0;
    start();

    return () => {
      clearTimers();
      destroyPlayer();
      setPlaying(false);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [live, streamKey]);

  return (
    <div className="player-container">
      <video ref={videoRef} className="player-video" controls playsInline autoPlay muted />
      {!playing && <div className="player-offline">Stream Offline</div>}
    </div>
  );
}
