import React, { useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';

const FOCUSABLE = 'button:not(:disabled), [href], input:not(:disabled), [tabindex]:not([tabindex="-1"])';

export function ConfirmationPopup({
  open,
  id,
  kicker,
  title,
  description,
  cancelLabel,
  confirmLabel,
  busy = false,
  onCancel,
  onConfirm,
}) {
  const overlayRef = useRef(null);
  const dialogRef = useRef(null);
  const cancelRef = useRef(null);
  const busyRef = useRef(busy);
  const onCancelRef = useRef(onCancel);
  busyRef.current = busy;
  onCancelRef.current = onCancel;

  useEffect(() => {
    if (!open) return undefined;
    const previousFocus = document.activeElement;
    const background = [...(overlayRef.current?.parentElement?.children || [])]
      .filter((element) => !element.classList.contains('client-confirmation-popup'))
      .map((element) => [element, element.inert]);
    background.forEach(([element]) => { element.inert = true; });
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    const frame = requestAnimationFrame(() => cancelRef.current?.focus());
    const onKeyDown = (event) => {
      if (event.key === 'Escape' && !busyRef.current) {
        event.preventDefault();
        onCancelRef.current();
        return;
      }
      if (event.key !== 'Tab') return;
      const controls = [...(dialogRef.current?.querySelectorAll(FOCUSABLE) || [])];
      if (!controls.length) return;
      const first = controls[0];
      const last = controls.at(-1);
      if (!dialogRef.current?.contains(document.activeElement)) {
        event.preventDefault();
        first.focus();
      } else if (event.shiftKey && document.activeElement === first) {
        event.preventDefault();
        last.focus();
      } else if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault();
        first.focus();
      }
    };
    document.addEventListener('keydown', onKeyDown);
    return () => {
      cancelAnimationFrame(frame);
      document.removeEventListener('keydown', onKeyDown);
      background.forEach(([element, inert]) => { element.inert = inert; });
      document.body.style.overflow = previousOverflow;
      requestAnimationFrame(() => previousFocus?.focus?.());
    };
  }, [open]);

  return createPortal(
    <div
      ref={overlayRef}
      className={`client-confirmation-popup${open ? ' is-open' : ''}`}
      aria-hidden={!open}
      inert={!open ? true : undefined}
      onPointerDown={(event) => {
        if (event.target === event.currentTarget && !busy) onCancel();
      }}
    >
      <section
        ref={dialogRef}
        className="client-confirmation-dialog"
        role="alertdialog"
        aria-modal="true"
        aria-labelledby={`${id}-title`}
        aria-describedby={`${id}-description`}
        aria-busy={busy}
      >
        {kicker && <span className="client-confirmation-kicker">{kicker}</span>}
        <h2 id={`${id}-title`}>{title}</h2>
        <p id={`${id}-description`}>{description}</p>
        <div className="client-confirmation-actions">
          <button ref={cancelRef} type="button" disabled={busy} onClick={onCancel}>{cancelLabel}</button>
          <button className="is-danger" type="button" disabled={busy} onClick={onConfirm}>{confirmLabel}</button>
        </div>
      </section>
    </div>,
    document.querySelector('.app.client-app') || document.body,
  );
}
