import React from "react";
import { useAnchoredPosition, portalToBody } from "../overlays/Popover.jsx";

const CHEVRONS = (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m7 15 5 5 5-5" /><path d="m7 9 5-5 5 5" /></svg>
);

/**
 * The listbox is an overlay, so it leaves the flow.
 *
 * A container that scrolls on one axis clips both, and a Select is most often
 * used inside exactly those containers — a dialog panel, a table cell, a side
 * rail. Rendered absolutely inside the field, its popup is cut off by the first
 * of them. So it portals to the document and positions in viewport coordinates
 * with the same helper Popover, Menu and Tooltip use: it flips above the trigger
 * when there is no room below, clamps to the viewport, and repositions on scroll
 * and resize rather than closing.
 *
 * Two consequences worth knowing. The popup takes the trigger's measured width
 * rather than `min-width: 100%`, because a fixed element has no percentage
 * parent to resolve against. And the outside-click test has to know about the
 * portalled panel, or the mousedown that closes the popup would land before the
 * click that picks an option.
 */
export function Select({ items = [], value, defaultValue, onValueChange, placeholder = "Select…", size = "default", disabled, invalid, className = "", id }) {
  const [open, setOpen] = React.useState(false);
  const [internal, setInternal] = React.useState(defaultValue);
  const [width, setWidth] = React.useState(null);
  const ref = React.useRef(null);
  const panelRef = React.useRef(null);
  const val = value !== undefined ? value : internal;
  const selected = items.find((i) => i.value === val);
  const pos = useAnchoredPosition(open, ref, panelRef, "bottom", "start");
  React.useLayoutEffect(() => {
    if (open && ref.current) setWidth(ref.current.getBoundingClientRect().width);
  }, [open]);
  React.useEffect(() => {
    if (!open) return undefined;
    const away = (e) => {
      const inField = ref.current && ref.current.contains(e.target);
      const inPanel = panelRef.current && panelRef.current.contains(e.target);
      if (!inField && !inPanel) setOpen(false);
    };
    const key = (e) => { if (e.key === "Escape") setOpen(false); };
    document.addEventListener("mousedown", away);
    document.addEventListener("keydown", key);
    return () => { document.removeEventListener("mousedown", away); document.removeEventListener("keydown", key); };
  }, [open]);
  const pick = (v) => { if (value === undefined) setInternal(v); if (onValueChange) onValueChange(v); setOpen(false); };
  const cls = ["o-select", size !== "default" ? "o-select--" + size : "", className].filter(Boolean).join(" ");
  return (
    <span ref={ref} style={{ position: "relative", display: "inline-block", width: "100%" }}>
      <button type="button" id={id} className={cls} data-slot="select-trigger" disabled={disabled} aria-invalid={invalid || undefined}
        aria-haspopup="listbox" aria-expanded={open} onClick={() => setOpen(!open)}>
        <span className={["o-select__value", selected ? "" : "o-select__placeholder"].filter(Boolean).join(" ")}>{selected ? selected.label : placeholder}</span>
        {CHEVRONS}
      </button>
      {open ? portalToBody(
        <div ref={panelRef} className="o-popup" data-slot="select-popup" role="listbox"
          style={{ position: "fixed", top: pos.top, left: pos.left, zIndex: 70, minWidth: width || "auto" }}>
          <div className="o-menu o-scroll" style={{ maxHeight: "16rem" }}>
            {items.map((item) => (
              <div key={item.value} role="option" aria-selected={item.value === val} className="o-menu__item" data-slot="select-item"
                style={{ display: "grid", gridTemplateColumns: "1rem 1fr", paddingInlineEnd: "var(--space-4)" }} onClick={() => pick(item.value)}>
                <span className="o-menu__check">{item.value === val ? <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M5.252 12.7 10.2 18.63 18.748 5.37" /></svg> : null}</span>
                <span>{item.label}</span>
              </div>
            ))}
          </div>
        </div>
      ) : null}
    </span>
  );
}
