import React from 'react';

export function useDismissiblePopover(
  open: boolean,
  onOpenChange: (open: boolean) => void,
  triggerRef: React.RefObject<HTMLElement | null>,
  panelRef: React.RefObject<HTMLElement | null>,
): void {
  React.useEffect(() => {
    if (!open) return;
    const onPointerDown = (event: PointerEvent) => {
      const target = event.target as Node | null;
      if (!target) return;
      if (triggerRef.current?.contains(target) || panelRef.current?.contains(target)) return;
      onOpenChange(false);
    };
    const onKeyDown = (event: KeyboardEvent) => {
      if (event.key !== 'Escape') return;
      event.preventDefault();
      onOpenChange(false);
      triggerRef.current?.focus();
    };
    document.addEventListener('pointerdown', onPointerDown);
    document.addEventListener('keydown', onKeyDown);
    return () => {
      document.removeEventListener('pointerdown', onPointerDown);
      document.removeEventListener('keydown', onKeyDown);
    };
  }, [onOpenChange, open, panelRef, triggerRef]);
}

export function DismissibleDetails({
  children,
  className,
}: {
  children: React.ReactNode;
  className?: string;
}) {
  const [open, setOpen] = React.useState(false);
  const rootRef = React.useRef<HTMLDetailsElement>(null);
  const summaryRef = React.useRef<HTMLElement | null>(null);
  const panelRef = rootRef as React.RefObject<HTMLElement | null>;

  React.useEffect(() => {
    summaryRef.current = rootRef.current?.querySelector<HTMLElement>(':scope > summary') ?? null;
  }, []);
  useDismissiblePopover(open, setOpen, summaryRef, panelRef);

  return (
    <details
      ref={rootRef}
      className={className}
      open={open}
      onToggle={(event) => setOpen(event.currentTarget.open)}
      onClickCapture={(event) => {
        const target = event.target as HTMLElement;
        const summary = target.closest('summary');
        if (summary && rootRef.current?.firstElementChild === summary) return;
        if (target.closest('button,a')) queueMicrotask(() => setOpen(false));
      }}
    >
      {children}
    </details>
  );
}
