/* A dropdown of grouped choices — the switcher for "which thing am I looking
 * at" when the things have structure (pages → directions, boards → items).
 *
 * The trigger says where you are AND that there are alternatives (a count
 * chip), because a control that looks like a label gets read as one: the
 * first version of easel's option switcher was two tiny chevrons around a
 * name, and a client could not tell there was a second concept at all.
 *
 * Presentational: groups and items in, a callback out. Escape and a click
 * outside close it; the current item is marked. */

import { useEffect, useRef, useState, type ReactNode } from "react";

export type MenuItem = {
  id: string | number;
  label: string;
  /** Small secondary text under the label (a concept tag, a slug). */
  meta?: string;
  /** Trailing badge(s): a count, "chosen", "draft". */
  badges?: { label: string; tone?: string }[];
  active?: boolean;
  disabled?: boolean;
};

export type MenuGroup = {
  id: string | number;
  label: string;
  /** Right-aligned note on the group row ("2 directions", "draft"). */
  note?: string;
  items: MenuItem[];
};

export function Menu({
  trigger, groups, onSelect, footer, ariaLabel, dataTour,
}: {
  /** The trigger's content — usually "where you are" + a count chip. */
  trigger: ReactNode;
  groups: MenuGroup[];
  onSelect: (id: MenuItem["id"]) => void;
  /** An action row at the bottom ("← Back to the board"). */
  footer?: ReactNode;
  ariaLabel?: string;
  dataTour?: string;
}) {
  const [open, setOpen] = useState(false);
  const wrap = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (!open) return;
    const away = (e: MouseEvent) => {
      if (wrap.current && !wrap.current.contains(e.target as Node)) setOpen(false);
    };
    const key = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(false); };
    document.addEventListener("mousedown", away);
    document.addEventListener("keydown", key);
    return () => {
      document.removeEventListener("mousedown", away);
      document.removeEventListener("keydown", key);
    };
  }, [open]);

  return (
    <div className="cu-menu" ref={wrap}>
      <button type="button" className="cu-menu-trigger" aria-haspopup="menu"
              aria-expanded={open} aria-label={ariaLabel} data-tour={dataTour}
              onClick={() => setOpen((v) => !v)}>
        {trigger}
        <svg className="cu-menu-caret" width="12" height="12" viewBox="0 0 24 24"
             fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round"
             strokeLinejoin="round" aria-hidden="true">
          <path d="m6 9 6 6 6-6" />
        </svg>
      </button>

      {open && (
        <div className="cu-menu-pop" role="menu">
          {groups.map((g) => (
            <div key={g.id} className="cu-menu-group">
              <div className="cu-menu-group-row">
                <span className="cu-menu-group-label">{g.label}</span>
                {g.note && <span className="cu-menu-group-note">{g.note}</span>}
              </div>
              {g.items.map((it) => (
                <button key={it.id} type="button" role="menuitemradio"
                        aria-checked={!!it.active} disabled={it.disabled}
                        className={`cu-menu-item ${it.active ? "is-active" : ""}`}
                        onClick={() => { setOpen(false); onSelect(it.id); }}>
                  <span className="cu-menu-check" aria-hidden="true">
                    {it.active ? "✓" : ""}
                  </span>
                  <span className="cu-menu-main">
                    <span className="cu-menu-label">{it.label}</span>
                    {it.meta && <span className="cu-menu-meta">{it.meta}</span>}
                  </span>
                  {it.badges && it.badges.length > 0 && (
                    <span className="cu-menu-badges">
                      {it.badges.map((b, i) => (
                        <span key={i} className="cu-menu-badge"
                              style={b.tone
                                ? ({ ["--chip-tone" as string]: b.tone } as React.CSSProperties)
                                : undefined}>
                          {b.label}
                        </span>
                      ))}
                    </span>
                  )}
                </button>
              ))}
              {g.items.length === 0 && (
                <span className="cu-menu-empty">Nothing here yet.</span>
              )}
            </div>
          ))}
          {footer && <div className="cu-menu-foot">{footer}</div>}
        </div>
      )}
    </div>
  );
}

/** The trigger's "N of M" chip — tells you alternatives exist without words. */
export function CountChip({ n, of }: { n: number; of: number }) {
  return <span className="cu-menu-count">{n} of {of}</span>;
}
