import { useEffect, useLayoutEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import Icon from "./Icon";
import { gruppenOptionen, nachfahrenIds, pfadText } from "../groupGraph";

/**
 * Mehrfachauswahl der Obergruppen einer Gruppe.
 *
 * Bewusst KEIN Baum wie CategorySelect: eine Gruppe darf unter mehreren
 * Obergruppen hängen („Grillwurst" unter „Wurst" UND unter „Grillgut"). Ein
 * Baum müsste sie mehrfach anzeigen; eine flache, alphabetische Liste mit
 * Häkchen ist ehrlicher und deutlich weniger Code. Der volle Weg steht als
 * Titel an jeder Zeile, damit gleichnamige Äste unterscheidbar bleiben.
 *
 * Die eigene Gruppe und ihre Untergruppen sind gesperrt – sie würden einen Ring
 * erzeugen. Der Server lehnt das ohnehin ab; hier wird es vorher sichtbar.
 *
 * Das Menü hängt per Portal am <body>, damit es der horizontal scrollende
 * Tabellenrahmen nicht abschneidet (wie bei CategorySelect).
 */
export default function GroupParentSelect({
  value = [],
  onChange,
  groups = [],
  selfId = null,
  disabled = false,
}) {
  const [open, setOpen] = useState(false);
  const [pos, setPos] = useState(null);
  const [filter, setFilter] = useState("");
  const btnRef = useRef(null);
  const popRef = useRef(null);

  const gewaehlt = new Set(value || []);
  const gesperrt = selfId == null ? new Set() : new Set([selfId, ...nachfahrenIds(groups, selfId)]);
  const nameById = Object.fromEntries(groups.map((g) => [g.id, g.name]));

  // Als Baum, damit die Struktur beim Zuordnen sichtbar ist. Beim Suchen
  // flacht die Liste ab – eine Einrückung ohne ihre Eltern wäre irreführend.
  const sichtbar = filter
    ? groups
        .filter((g) => g.name.toLowerCase().includes(filter.toLowerCase()))
        .slice()
        .sort((a, b) => a.name.localeCompare(b.name, "de"))
        .map((g) => ({ id: g.id, key: `f${g.id}`, gruppe: g, tiefe: 0, label: g.name }))
    : gruppenOptionen(groups);

  const label = value?.length
    ? value.map((id) => nameById[id]).filter(Boolean).join(", ")
    : "– keine –";

  function place() {
    const r = btnRef.current?.getBoundingClientRect();
    if (r) setPos({ left: r.left, top: r.bottom + 4, width: r.width });
  }
  useLayoutEffect(() => { if (open) place(); }, [open]);

  useEffect(() => {
    if (!open) return;
    function onDoc(e) {
      if (btnRef.current?.contains(e.target)) return;
      if (popRef.current?.contains(e.target)) return;
      setOpen(false);
    }
    function onScroll(e) {
      if (popRef.current && e.target instanceof Node && popRef.current.contains(e.target)) return;
      setOpen(false);
    }
    function onResize() { setOpen(false); }
    function onKey(e) { if (e.key === "Escape") setOpen(false); }
    document.addEventListener("mousedown", onDoc);
    window.addEventListener("scroll", onScroll, true);
    window.addEventListener("resize", onResize);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", onDoc);
      window.removeEventListener("scroll", onScroll, true);
      window.removeEventListener("resize", onResize);
      document.removeEventListener("keydown", onKey);
    };
  }, [open]);

  // Bei Mehrfachauswahl bleibt das Menü offen – sonst müsste man es für jede
  // weitere Obergruppe neu aufklappen.
  function umschalten(id) {
    const neu = new Set(gewaehlt);
    if (neu.has(id)) neu.delete(id);
    else neu.add(id);
    onChange([...neu]);
  }

  return (
    <>
      <button
        type="button"
        ref={btnRef}
        className="tree-select-btn"
        disabled={disabled}
        aria-expanded={open}
        onClick={() => setOpen((o) => !o)}
      >
        <span className={value?.length ? "" : "muted"}>{label}</span>
        <Icon name="chevronRight" size={13} className={`caret ${open ? "open" : ""}`} />
      </button>

      {open && pos && createPortal(
        <div
          ref={popRef}
          className="tree-pop"
          style={{ left: pos.left, top: pos.top, minWidth: Math.max(pos.width, 240) }}
        >
          {groups.length > 8 && (
            <div className="tree-pop-line">
              <input
                autoFocus
                placeholder="Suchen…"
                value={filter}
                style={{ marginTop: 0, width: "100%" }}
                onChange={(e) => setFilter(e.target.value)}
              />
            </div>
          )}
          {sichtbar.map((o) => {
            const aus = gesperrt.has(o.id);
            const an = gewaehlt.has(o.id);
            return (
              <div key={o.key} className="tree-pop-line" style={{ paddingLeft: o.tiefe * 14 }}>
                <button
                  type="button"
                  className={`tree-pop-opt ${an ? "sel" : ""}`}
                  disabled={aus}
                  title={aus
                    ? "Würde einen Ring erzeugen (die Gruppe selbst oder eine ihrer Untergruppen)"
                    : pfadText(groups, o.id)}
                  onClick={() => umschalten(o.id)}
                >
                  <span style={{ display: "inline-block", width: 18 }}>{an ? "✓" : ""}</span>
                  {o.tiefe > 0 && <span className="muted">↳ </span>}
                  {o.gruppe.name}
                </button>
              </div>
            );
          })}
          {sichtbar.length === 0 && (
            <div className="tree-pop-line muted" style={{ padding: 6 }}>Keine Gruppe gefunden.</div>
          )}
        </div>,
        document.body,
      )}
    </>
  );
}
