/**
 * useFocusWatchdog — Samsung QA v1.4.4 hardened safety net.
 *
 * BEHAVIOUR (v1.4.4):
 *   • Smart TV (Tizen / webOS) → active. Polls every 500ms and listens
 *     to `focusout` so focus is never lost during async work. This is
 *     mandatory for Samsung QA: the doc reviewer rejects builds whose
 *     remote freezes when focus lands on `document.body`.
 *   • Desktop / web / mobile → DISABLED. norigin manages focus
 *     natively and any DOM-level "rescue" we add only races with the
 *     library's internal state, breaking arrow keys. Per user request
 *     (v1.4.4), no watchdog logic runs on non-TV platforms.
 *
 * `recoverFocus()` is still exported for explicit recovery points
 * (e.g. after Login API resolves). The raw-DOM fallback only fires
 * on Smart TV — desktop relies solely on norigin's `setFocus()`.
 */
import { useEffect } from "react";
import { setFocus } from "@noriginmedia/norigin-spatial-navigation";
import { isSmartTV, isTizen, isWebOS } from "@/lib/platform";

const FALLBACK_KEYS = [
  "tv-back-button",
  "login-submit",
  "login-username",
  "login-back",
  "welcome-guest-btn",
  "welcome-login-btn",
];

// CSS selector matching every "naturally focusable" interactive element.
// Used ONLY on Smart TV as a last resort. Desktop never touches this.
const RAW_FOCUSABLE_SELECTOR = [
  'input:not([disabled]):not([type="hidden"]):not([type="submit"]):not([type="button"])',
  'textarea:not([disabled])',
  'button:not([disabled])',
  '[role="button"]:not([aria-disabled="true"])',
  'a[href]',
  '[tabindex]:not([tabindex="-1"])',
].join(",");

/** Last-resort raw DOM focus. SMART TV ONLY. */
function rawFocusFirstInteractive(): boolean {
  try {
    // Prefer anything norigin already marked as focused — keeps the
    // spatial-nav tree and the browser in sync.
    const noriginFocused = document.querySelector<HTMLElement>(
      '[data-focused="true"]',
    );
    if (noriginFocused) {
      noriginFocused.focus({ preventScroll: false });
      return true;
    }
    const candidates = document.querySelectorAll<HTMLElement>(
      RAW_FOCUSABLE_SELECTOR,
    );
    for (const el of Array.from(candidates)) {
      const rect = el.getBoundingClientRect();
      if (rect.width === 0 || rect.height === 0) continue;
      const style = window.getComputedStyle(el);
      if (style.visibility === "hidden" || style.display === "none") continue;
      el.focus({ preventScroll: false });
      return true;
    }
  } catch {
    /* ignore */
  }
  return false;
}

/**
 * Best-effort focus recovery. Tries norigin `setFocus()` against the
 * provided keys, then the global fallback keys. On Smart TV ONLY,
 * falls back to a raw-DOM focus if nothing landed. On desktop /
 * mobile we trust norigin and stop after the setFocus calls.
 */
export function recoverFocus(preferred: string[] = []): void {
  const candidates = [...preferred, ...FALLBACK_KEYS];
  for (const key of candidates) {
    try {
      setFocus(key);
    } catch {
      /* try next */
    }
  }
  if (!isSmartTV()) return;
  if (typeof document !== "undefined") {
    const stillLost =
      !document.activeElement ||
      document.activeElement === document.body ||
      document.activeElement === document.documentElement;
    if (stillLost) {
      rawFocusFirstInteractive();
    }
  }
}

export function useFocusWatchdog(): void {
  useEffect(() => {
    // Desktop / web / mobile — fully disabled. norigin handles focus
    // natively and any external rescue here desyncs the spatial-nav
    // tree from the browser's `activeElement`.
    if (!isSmartTV()) return;

    let pollTimer: number | null = null;

    const checkFocus = () => {
      if (typeof document === "undefined") return;
      const active = document.activeElement;
      const lostFocus =
        !active ||
        active === document.body ||
        active === document.documentElement;
      if (lostFocus) {
        recoverFocus();
      }
    };

    const onFocusOut = () => {
      window.setTimeout(checkFocus, 0);
    };
    document.addEventListener("focusout", onFocusOut, true);
    pollTimer = window.setInterval(checkFocus, 500);

    const onPopState = () => window.setTimeout(checkFocus, 250);
    window.addEventListener("popstate", onPopState);

    return () => {
      document.removeEventListener("focusout", onFocusOut, true);
      if (pollTimer !== null) window.clearInterval(pollTimer);
      window.removeEventListener("popstate", onPopState);
    };
  }, []);
}

// Re-export platform helpers so consumers that import the watchdog
// can gate Tizen-specific UI in one import.
export { isTizen, isWebOS };
