import { useCallback, useEffect, useRef, useState } from "react";

/**
 * Drop-in replacement for react-full-screen's useFullScreenHandle + FullScreen component.
 *
 * Motivation: react-full-screen 1.1.1 doesn't debounce fullscreenchange events, so on
 * Windows systems with DPI scaling > 100%, the resize triggered during fullscreen entry
 * fires a fullscreenchange event that the library misinterprets as an exit, immediately
 * popping back out of fullscreen.
 *
 * This hook bypasses the library entirely and calls the native Fullscreen API directly,
 * ignoring fullscreenchange events fired within DEBOUNCE_MS of entry to absorb the
 * DPI-scaling resize blip.
 *
 * Usage — replace in BinVisualizerV2.tsx:
 *
 *   // Remove:
 *   import { FullScreen, useFullScreenHandle } from "react-full-screen";
 *   const fullScreenHandler = useFullScreenHandle();
 *   <FullScreen handle={fullScreenHandler}> ... </FullScreen>
 *
 *   // Add:
 *   import { useFullScreen } from "hooks/useFullScreen";
 *   const { fullScreenHandler, FullScreenWrapper } = useFullScreen();
 *   <FullScreenWrapper> ... </FullScreenWrapper>
 *
 *   // Everything else (fullScreenHandler.active, .enter(), .exit()) stays the same.
 */

const DEBOUNCE_MS = 500;

export interface FullScreenHandle {
  active: boolean;
  enter: () => void;
  exit: () => void;
}

export function useFullScreen(): {
  fullScreenHandler: FullScreenHandle;
  FullScreenWrapper: React.FC<{ children: React.ReactNode }>;
} {
  const [active, setActive] = useState(false);
  const containerRef = useRef<HTMLDivElement | null>(null);
  // Timestamp of the last enter() call — used to debounce spurious exit events
  const enterTimeRef = useRef<number>(0);

  const enter = useCallback(() => {
    const el = containerRef.current;
    if (!el) return;
    enterTimeRef.current = Date.now();
    if (el.requestFullscreen) {
      el.requestFullscreen().catch(() => {
        // Some browsers (e.g. iOS Safari) reject the promise — silently ignore
      });
    } else if ((el as any).webkitRequestFullscreen) {
      (el as any).webkitRequestFullscreen();
    } else if ((el as any).mozRequestFullScreen) {
      (el as any).mozRequestFullScreen();
    } else if ((el as any).msRequestFullscreen) {
      (el as any).msRequestFullscreen();
    }
  }, []);

  const exit = useCallback(() => {
    if (document.exitFullscreen) {
      document.exitFullscreen().catch(() => {});
    } else if ((document as any).webkitExitFullscreen) {
      (document as any).webkitExitFullscreen();
    } else if ((document as any).mozCancelFullScreen) {
      (document as any).mozCancelFullScreen();
    } else if ((document as any).msExitFullscreen) {
      (document as any).msExitFullscreen();
    }
  }, []);

  useEffect(() => {
    const handleChange = () => {
      const fullscreenEl =
        document.fullscreenElement ||
        (document as any).webkitFullscreenElement ||
        (document as any).mozFullScreenElement ||
        (document as any).msFullscreenElement;

      const isNowFullscreen = fullscreenEl === containerRef.current;

      // If we just called enter() and this event fires within DEBOUNCE_MS,
      // and it looks like an exit, ignore it — it's the DPI-scaling resize blip
      if (!isNowFullscreen && Date.now() - enterTimeRef.current < DEBOUNCE_MS) {
        return;
      }

      setActive(isNowFullscreen);
    };

    document.addEventListener("fullscreenchange", handleChange);
    document.addEventListener("webkitfullscreenchange", handleChange);
    document.addEventListener("mozfullscreenchange", handleChange);
    document.addEventListener("MSFullscreenChange", handleChange);

    return () => {
      document.removeEventListener("fullscreenchange", handleChange);
      document.removeEventListener("webkitfullscreenchange", handleChange);
      document.removeEventListener("mozfullscreenchange", handleChange);
      document.removeEventListener("MSFullscreenChange", handleChange);
    };
  }, []);

  const FullScreenWrapper: React.FC<{ children: React.ReactNode }> = useCallback(
    ({ children }) => (
      <div ref={containerRef} style={{ width: "100%", height: "100%" }}>
        {children}
      </div>
    ),
    []
  );

  return {
    fullScreenHandler: { active, enter, exit },
    FullScreenWrapper,
  };
}