const FOCUSABLE_SELECTOR = [
  "a[href]",
  "area[href]",
  "button:not([disabled])",
  "input:not([disabled]):not([type=\"hidden\"])",
  "select:not([disabled])",
  "textarea:not([disabled])",
  "details > summary:first-of-type",
  "iframe",
  "object",
  "embed",
  "[contenteditable]:not([contenteditable=\"false\"])",
  "[tabindex]:not([tabindex=\"-1\"])"
].join(",");

export type DialogKeyboardEvent = Pick<KeyboardEvent, "key" | "shiftKey" | "preventDefault">;

function elementIsAvailable(element: HTMLElement): boolean {
  if (element.tabIndex < 0 || element.hasAttribute("disabled")) return false;
  if (element.closest('[hidden], [inert], [aria-hidden="true"]')) return false;
  if (typeof window === "undefined") return true;
  try {
    const style = window.getComputedStyle(element);
    return style.display !== "none" && style.visibility !== "hidden";
  } catch {
    return true;
  }
}

function focusWithoutScrolling(element: HTMLElement): void {
  try {
    element.focus({ preventScroll: true });
  } catch {
    element.focus();
  }
}

export function dialogFocusableElements(panel: HTMLElement): HTMLElement[] {
  return Array.from(panel.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(elementIsAvailable);
}

export function focusDialogOnOpen(panel: HTMLElement, activeElement: Element | null): HTMLElement {
  if (activeElement && panel.contains(activeElement)) return activeElement as HTMLElement;
  const focusable = dialogFocusableElements(panel);
  const requested = panel.querySelector<HTMLElement>("[autofocus]");
  const target = requested && focusable.includes(requested) ? requested : (focusable[0] ?? panel);
  focusWithoutScrolling(target);
  return target;
}

export function trapDialogFocus(
  panel: HTMLElement,
  event: DialogKeyboardEvent,
  activeElement: Element | null
): boolean {
  if (event.key !== "Tab") return false;

  const focusable = dialogFocusableElements(panel);
  let target: HTMLElement | null = null;

  if (focusable.length === 0) {
    target = panel;
  } else {
    const activeIndex = activeElement ? focusable.indexOf(activeElement as HTMLElement) : -1;
    if (activeIndex < 0) {
      target = event.shiftKey ? focusable[focusable.length - 1] : focusable[0];
    } else if (event.shiftKey && activeIndex === 0) {
      target = focusable[focusable.length - 1];
    } else if (!event.shiftKey && activeIndex === focusable.length - 1) {
      target = focusable[0];
    }
  }

  if (!target) return false;
  event.preventDefault();
  focusWithoutScrolling(target);
  return true;
}

export function handleDialogKeyDown(
  panel: HTMLElement,
  event: DialogKeyboardEvent,
  activeElement: Element | null,
  canClose: boolean,
  onClose?: () => void
): boolean {
  if (event.key === "Tab") return trapDialogFocus(panel, event, activeElement);
  if (event.key !== "Escape" || !canClose) return false;
  onClose?.();
  return true;
}

export function restoreDialogFocus(element: HTMLElement | null): boolean {
  if (!element || element.isConnected === false) return false;
  focusWithoutScrolling(element);
  return true;
}

export function shouldCloseDialogOnBackdrop(
  target: EventTarget | null,
  currentTarget: EventTarget | null,
  closeOnBackdrop: boolean,
  canClose: boolean
): boolean {
  return closeOnBackdrop && canClose && target === currentTarget;
}
