import { useEffect, useId, useRef } from "react";
import { createPortal } from "react-dom";
import type { ReactNode } from "react";
import {
  hasOpenDialog,
  isTopDialog,
  popDialog,
  pushDialog,
} from "./dialogStack";

interface DrawerProps {
  open: boolean;
  title: ReactNode;
  /** Accessible name when `title` is not plain text. */
  ariaLabel?: string;
  /** Optional secondary line under the title (status, id). */
  subtitle?: ReactNode;
  onClose: () => void;
  /** Sticky footer slot for actions. */
  footer?: ReactNode;
  children: ReactNode;
}

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

/**
 * Right-anchored side panel for read and inspect flows (machine detail and
 * history) where a modal would over-interrupt. Shares the dialog a11y contract:
 * Tab focus is trapped, the rest of the page is inert, Escape closes, and focus
 * returns to the trigger on close.
 */
export function Drawer({
  open,
  title,
  ariaLabel,
  subtitle,
  onClose,
  footer,
  children,
}: DrawerProps) {
  const panelRef = useRef<HTMLDivElement>(null);
  const lastFocused = useRef<HTMLElement | null>(null);
  const titleId = useId();

  useEffect(() => {
    if (!open) return;
    const panel = panelRef.current;
    lastFocused.current = document.activeElement as HTMLElement | null;
    const token = pushDialog();

    const root = document.getElementById("root");
    root?.setAttribute("inert", "");

    const first = panel?.querySelector<HTMLElement>(FOCUSABLE);
    (first ?? panel)?.focus();

    function onKey(e: KeyboardEvent) {
      if (!isTopDialog(token)) return;
      if (e.key === "Escape") {
        e.stopPropagation();
        onClose();
        return;
      }
      if (e.key !== "Tab" || !panel) return;
      const items = Array.from(
        panel.querySelectorAll<HTMLElement>(FOCUSABLE),
      ).filter((el) => el.offsetParent !== null || el === document.activeElement);
      if (items.length === 0) {
        e.preventDefault();
        panel.focus();
        return;
      }
      const firstEl = items[0];
      const lastEl = items[items.length - 1];
      const active = document.activeElement as HTMLElement;
      if (e.shiftKey && (active === firstEl || active === panel)) {
        e.preventDefault();
        lastEl.focus();
      } else if (!e.shiftKey && active === lastEl) {
        e.preventDefault();
        firstEl.focus();
      }
    }
    document.addEventListener("keydown", onKey, true);

    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";

    return () => {
      document.removeEventListener("keydown", onKey, true);
      document.body.style.overflow = prevOverflow;
      popDialog(token);
      if (!hasOpenDialog()) root?.removeAttribute("inert");
      lastFocused.current?.focus?.();
    };
  }, [open, onClose]);

  if (!open) return null;

  return createPortal(
    <div
      className="drawer__scrim"
      onMouseDown={(e) => {
        if (e.target === e.currentTarget) onClose();
      }}
    >
      <aside
        ref={panelRef}
        className="drawer"
        role="dialog"
        aria-modal="true"
        aria-label={ariaLabel}
        aria-labelledby={ariaLabel ? undefined : titleId}
        tabIndex={-1}
      >
        <header className="drawer__head">
          <div className="drawer__titles">
            <h2 className="drawer__title" id={titleId}>
              {title}
            </h2>
            {subtitle && <div className="drawer__subtitle">{subtitle}</div>}
          </div>
          <button
            type="button"
            className="iconbtn"
            onClick={onClose}
            aria-label="Close panel"
          >
            <svg
              width="16"
              height="16"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="2"
              strokeLinecap="round"
              aria-hidden="true"
            >
              <path d="M6 6l12 12M18 6 6 18" />
            </svg>
          </button>
        </header>
        <div className="drawer__body">{children}</div>
        {footer && <footer className="drawer__footer">{footer}</footer>}
      </aside>
    </div>,
    document.body,
  );
}
