import { useEffect } from "react";
import {
  useFocusable,
  FocusContext,
  setFocus as spatialSetFocus,
} from "@noriginmedia/norigin-spatial-navigation";
import { cn } from "@/lib/utils";

export type FocusableSectionProps = {
  /** Unique key — keeps focus state stable across renders. */
  focusKey?: string;
  className?: string;
  /** When true, arrow keys will not leave this section (used for modals). */
  trap?: boolean;
  /**
   * When true, the section grabs focus on mount (so its first focusable
   * child becomes the active element). This is what makes remote arrow
   * keys work IMMEDIATELY when a page opens — without it the user has
   * to click once before the keys do anything.
   */
  autoFocus?: boolean;
  children: React.ReactNode;
  /** Pass-through for data-testid / aria-label etc. */
  as?: keyof JSX.IntrinsicElements;
} & Omit<React.HTMLAttributes<HTMLElement>, "children">;

/**
 * A "focus area" wrapper. Establishes a FocusContext so that every
 * focusable child is indexed under a single parent — makes arrow
 * navigation inside grids / rows predictable and isolates one row
 * from leaking into a neighbour.
 */
export const FocusableSection = ({
  focusKey,
  className,
  trap,
  autoFocus,
  children,
  as: Tag = "div",
  ...rest
}: FocusableSectionProps) => {
  // ───────────────────────────────────────────────────────────────────
  // CROSS-SECTION NAVIGATION (v1.4.4 fix)
  // ───────────────────────────────────────────────────────────────────
  // We mark the section ITSELF as focusable so norigin can pick it as
  // a navigation target when arrow keys leave one section and need to
  // enter another (e.g. ArrowUp from a category card → header section
  // → first header button). The section never visibly "owns" focus —
  // `getNextFocusKey()` (see norigin-core/SpatialNavigation.js)
  // automatically forwards focus to the section's last-focused or
  // closest child because we keep `trackChildren` + `saveLastFocusedChild`
  // enabled. Without `focusable: true` here, ArrowUp/Down from a card
  // would find NO valid candidate above (only siblings inside the same
  // section are considered, and the parent recursion still requires
  // siblings to be `focusable: true`).
  const { ref, focusKey: currentKey } = useFocusable({
    focusKey,
    focusable: true,
    trackChildren: true,
    isFocusBoundary: !!trap,
    saveLastFocusedChild: true,
  });

  // Grant initial focus to the section — robust multi-pass version.
  //
  // PROBLEM (pre-v1.4.4): A single setTimeout(80ms) call to setFocus
  // often fired BEFORE the child FocusableButton / FocusableTile
  // components had registered themselves with norigin via their own
  // useEffect. The library then had no children to route focus into
  // and silently no-op'd — leaving the page with ZERO focused
  // elements; the focus-watchdog then raw-focused whatever
  // interactive node it found first (typically the language selector
  // top-right), desynchronising browser focus from norigin's
  // internal state. Arrow keys stopped responding.
  //
  // FIX (v1.4.4): Retry up to 4 times with backoff (60ms, 200ms,
  // 500ms, 1000ms) until focus actually lands inside this section's
  // DOM subtree.
  useEffect(() => {
    if (!autoFocus || !currentKey) return;
    let cancelled = false;
    const attempts = [60, 200, 500, 1000];
    const timers: number[] = [];
    attempts.forEach((delay) => {
      timers.push(
        window.setTimeout(() => {
          if (cancelled) return;
          // Already inside us? bail out — no more retries needed.
          const root = ref.current as HTMLElement | null;
          if (root && root.contains(document.activeElement)) return;
          try {
            spatialSetFocus(currentKey);
          } catch {
            /* spatial-nav not yet ready — next pass will retry */
          }
        }, delay),
      );
    });
    return () => {
      cancelled = true;
      timers.forEach(window.clearTimeout);
    };
  }, [autoFocus, currentKey, ref]);

  const Element = Tag as React.ElementType;

  return (
    <FocusContext.Provider value={currentKey}>
      <Element ref={ref} className={cn(className)} {...rest}>
        {children}
      </Element>
    </FocusContext.Provider>
  );
};
