/**
 * useFocusRestore — captures the currently-focused norigin key on
 * mount and restores it when the component unmounts (or when
 * `active` toggles false).
 *
 * Usage (inside a modal / dropdown / overlay):
 *
 *   useFocusRestore(open, ["home-header-add", "tv-back-button"]);
 *
 * When `active` becomes true (e.g. modal opens), the hook records
 * the previously-focused element. When `active` becomes false (or
 * the component unmounts), it walks the candidate list — starting
 * with the previously-focused key — and calls `setFocus()` on the
 * first one that still exists. This prevents the "focus dead after
 * dismiss" bug that froze the entire app on TV remotes.
 */
import { useEffect, useRef } from "react";
import {
  getCurrentFocusKey,
  doesFocusableExist,
  setFocus,
} from "@noriginmedia/norigin-spatial-navigation";

export function useFocusRestore(
  active: boolean,
  /**
   * Ordered list of fallback focus keys to try if the previously
   * focused element no longer exists. The hook tries the captured
   * "before-open" key first, then walks this list.
   */
  fallbackKeys: string[] = [],
): void {
  const capturedKey = useRef<string | null>(null);

  // Capture the focused element JUST BEFORE the overlay claims focus.
  useEffect(() => {
    if (active) {
      try {
        const key = getCurrentFocusKey();
        if (key) capturedKey.current = key;
      } catch {
        /* spatial-nav not ready */
      }
    }
  }, [active]);

  // Restore focus when the overlay closes (active flips false) or
  // unmounts.
  useEffect(() => {
    if (active) return;
    // Defer restoration so React has time to unmount the overlay's
    // own focusables — otherwise we'd race the destruction and
    // land back on the same dead key.
    const t = window.setTimeout(() => {
      const candidates = [
        capturedKey.current ?? "",
        ...fallbackKeys,
      ].filter(Boolean);
      for (const key of candidates) {
        try {
          if (doesFocusableExist(key)) {
            setFocus(key);
            return;
          }
        } catch {
          /* try next */
        }
      }
      // Last-resort: try the candidates anyway (doesFocusableExist
      // can return false during layout shifts even when the node
      // actually exists).
      for (const key of candidates) {
        try {
          setFocus(key);
          return;
        } catch {
          /* try next */
        }
      }
    }, 80);
    return () => window.clearTimeout(t);
  }, [active, fallbackKeys]);

  // Unmount-time safety net. If the parent yanks us out of the
  // tree without setting `active=false` first, we still restore.
  useEffect(() => {
    return () => {
      window.setTimeout(() => {
        const candidates = [
          capturedKey.current ?? "",
          ...fallbackKeys,
        ].filter(Boolean);
        for (const key of candidates) {
          try {
            if (doesFocusableExist(key)) {
              setFocus(key);
              return;
            }
          } catch {
            /* ignore */
          }
        }
      }, 80);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
}
