import { forwardRef, useEffect, useRef } from "react";
import Hls from "hls.js";

interface VideoPlayerProps {
  src?: string;
  poster?: string;
  className?: string;
  /** Seconds into the current item to seek on load (broadcast sync). */
  initialOffset?: number;
  onStreamError?: () => void;
}

const VideoPlayer = forwardRef<HTMLVideoElement, VideoPlayerProps>(
  ({ src, poster, className, initialOffset = 0, onStreamError }, ref) => {
    const internalRef = useRef<HTMLVideoElement | null>(null);
    const hlsRef = useRef<Hls | null>(null);

    const setRef = (el: HTMLVideoElement | null) => {
      internalRef.current = el;
      if (typeof ref === "function") ref(el);
      else if (ref) ref.current = el;
    };

    useEffect(() => {
      const video = internalRef.current;
      if (!video || !src) return;

      hlsRef.current?.destroy();
      hlsRef.current = null;

      const isHls = src.includes(".m3u8");

      if (isHls && Hls.isSupported()) {
        const hls = new Hls({
          startPosition: initialOffset > 0 ? initialOffset : -1,
          maxMaxBufferLength: 30,
        });
        hlsRef.current = hls;

        hls.on(Hls.Events.MANIFEST_PARSED, () => {
          video.play().catch(() => {});
        });

        hls.on(Hls.Events.ERROR, (_event, data) => {
          if (data.fatal) onStreamError?.();
        });

        hls.loadSource(src);
        hls.attachMedia(video);
      } else if (isHls && video.canPlayType("application/vnd.apple.mpegurl")) {
        // Native HLS (Safari)
        video.src = src;
        video.addEventListener(
          "loadedmetadata",
          () => {
            if (initialOffset > 0) video.currentTime = initialOffset;
            video.play().catch(() => {});
          },
          { once: true },
        );
      } else {
        // Plain MP4 fallback
        video.src = src;
        video.load();
        video.play().catch(() => {});
      }

      return () => {
        hlsRef.current?.destroy();
        hlsRef.current = null;
      };
      // initialOffset intentionally excluded: only seek when src changes (new slot/mount)
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [src]);

    return (
      <div className={`relative h-full w-full bg-black ${className ?? ""}`}>
        <video
          ref={setRef}
          poster={poster}
          playsInline
          onError={onStreamError}
          className="h-full w-full object-contain"
        />
      </div>
    );
  },
);

VideoPlayer.displayName = "VideoPlayer";

export { VideoPlayer };
export type { VideoPlayerProps };
