import { useSyncExternalStore } from "react";

// The browser's Fullscreen API, WebKit included.
//
// Safari and iPadOS still ship only the prefixed spelling: no `fullscreenchange`, no
// `fullscreenElement`, no `requestFullscreen` on a plain element. Reading only the unprefixed names
// there means the page believes it is NEVER fullscreen — which silently breaks whatever the
// fullscreen state drives (an overlay that must yield, a focus reclaim, an Esc branch that would
// otherwise close the whole player instead of just leaving fullscreen).
//
// Both video surfaces (PlayerModal's YouTube embed, PlexPlayer's <video>) go through here, so the
// prefix handling lives in ONE place — the previous shape had it in neither, then in one.

type WebkitDocument = Document & {
  webkitFullscreenElement?: Element | null;
  webkitExitFullscreen?: () => void;
};
type WebkitElement = HTMLElement & { webkitRequestFullscreen?: () => void };

/** The element currently holding the fullscreen lock, or null. */
export function fullscreenElement(): Element | null {
  const d = document as WebkitDocument;
  return d.fullscreenElement ?? d.webkitFullscreenElement ?? null;
}

/** Ask for fullscreen on `el`. Errors are swallowed on purpose: a refused request (no user
 * activation, an iOS device that only fullscreens <video>) is not something a caller can fix. */
export function requestFullscreen(el: HTMLElement): void {
  const e = el as WebkitElement;
  if (e.requestFullscreen) void e.requestFullscreen().catch(() => {});
  else e.webkitRequestFullscreen?.();
}

/** Leave fullscreen, whoever holds it. */
export function exitFullscreen(): void {
  const d = document as WebkitDocument;
  if (d.exitFullscreen) void d.exitFullscreen().catch(() => {});
  else d.webkitExitFullscreen?.();
}

/** Subscribe to fullscreen transitions; returns the unsubscribe. Registers BOTH spellings — a
 * browser that supports both never fires both for the same transition, so the handler still runs
 * once. */
export function onFullscreenChange(handler: () => void): () => void {
  document.addEventListener("fullscreenchange", handler);
  document.addEventListener("webkitfullscreenchange", handler);
  return () => {
    document.removeEventListener("fullscreenchange", handler);
    document.removeEventListener("webkitfullscreenchange", handler);
  };
}

// `fullscreenElement()` returns the live DOM node, so the same element is the same reference across
// calls — a valid useSyncExternalStore snapshot without any caching of our own.
const fsSnapshot = () => fullscreenElement() as HTMLElement | null;
const fsServerSnapshot = () => null;

/** The fullscreen element as reactive state, for code that must RENDER differently while something
 *  holds the lock — chiefly the popover platform, which has to portal INTO that element (a node
 *  portaled to <body> is painted underneath the fullscreen element, i.e. invisible). Components that
 *  merely react to the transition should keep using `onFullscreenChange` directly. */
export function useFullscreenElement(): HTMLElement | null {
  return useSyncExternalStore(onFullscreenChange, fsSnapshot, fsServerSnapshot);
}
