import { useEffect, useMemo, useRef, useState } from "react";

// Searchable, grouped construct picker. A flat dropdown stops working past
// ~15 options; the library is at 99 and growing. Researchers either know the
// scale ("GAD-7") or the family ("empathy"), so search matches name, category,
// and questionnaire, results group by category, and the last 5 used constructs
// stay on top (researchers re-run the same scales constantly).
// Keyboard: ArrowUp/Down move, Enter selects, Escape closes.

const RECENT_KEY = "ccr_recent_constructs";
const RECENT_MAX = 5;

function readRecent() {
  try {
    return JSON.parse(localStorage.getItem(RECENT_KEY) || "[]");
  } catch {
    return [];
  }
}

export function rememberRecent(id) {
  const next = [id, ...readRecent().filter((x) => x !== id)].slice(0, RECENT_MAX);
  try {
    localStorage.setItem(RECENT_KEY, JSON.stringify(next));
  } catch {
    /* storage unavailable: recents simply don't persist */
  }
}

// Multi-construct runs: `selectedIds` is the ordered selection, `onToggle(id)`
// adds/removes one. Picking closes the panel (same feel as the old
// single-select); the Workspace shows the selection as removable chips.
export default function ConstructPicker({ constructs, selectedIds, onToggle }) {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState("");
  const [active, setActive] = useState(0);
  const rootRef = useRef(null);
  const inputRef = useRef(null);
  const listRef = useRef(null);

  const selected = new Set(selectedIds);

  const groups = useMemo(() => {
    const q = query.trim().toLowerCase();
    const match = (c) =>
      !q ||
      c.name.toLowerCase().includes(q) ||
      (c.category || "").toLowerCase().includes(q);
    const filtered = constructs.filter(match);

    const out = [];
    const used = new Set();

    const recentIds = readRecent();
    const recent = recentIds
      .map((id) => filtered.find((c) => c.id === id))
      .filter(Boolean);
    if (recent.length) {
      out.push(["Recently used", recent]);
      recent.forEach((c) => used.add(c.id));
    }

    const custom = filtered.filter((c) => !c.is_seed && !used.has(c.id));
    if (custom.length) {
      out.push(["My custom constructs", custom]);
      custom.forEach((c) => used.add(c.id));
    }

    const byCategory = new Map();
    for (const c of filtered) {
      if (used.has(c.id)) continue;
      const cat = c.category || "Other";
      if (!byCategory.has(cat)) byCategory.set(cat, []);
      byCategory.get(cat).push(c);
    }
    for (const cat of [...byCategory.keys()].sort((a, b) => a.localeCompare(b))) {
      out.push([cat, byCategory.get(cat).sort((a, b) => a.name.localeCompare(b.name))]);
    }
    return out;
  }, [constructs, query]);

  const flat = useMemo(() => groups.flatMap(([, items]) => items), [groups]);

  useEffect(() => setActive(0), [query, open]);

  // Close on outside click.
  useEffect(() => {
    if (!open) return undefined;
    const onDown = (e) => {
      if (rootRef.current && !rootRef.current.contains(e.target)) setOpen(false);
    };
    document.addEventListener("mousedown", onDown);
    return () => document.removeEventListener("mousedown", onDown);
  }, [open]);

  // Keep the active option scrolled into view.
  useEffect(() => {
    const el = listRef.current?.querySelector('[data-active="true"]');
    el?.scrollIntoView({ block: "nearest" });
  }, [active, open]);

  function choose(c) {
    onToggle(c.id);
    if (!selected.has(c.id)) rememberRecent(c.id);
    setOpen(false);
    setQuery("");
  }

  function onKeyDown(e) {
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setActive((a) => Math.min(a + 1, flat.length - 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setActive((a) => Math.max(a - 1, 0));
    } else if (e.key === "Enter") {
      e.preventDefault();
      if (flat[active]) choose(flat[active]);
    } else if (e.key === "Escape") {
      setOpen(false);
    }
  }

  let index = -1; // running index across groups for keyboard highlight

  return (
    <div className="picker" ref={rootRef}>
      {!open ? (
        <button
          type="button"
          className="picker-display"
          aria-haspopup="listbox"
          aria-expanded="false"
          onClick={() => {
            setOpen(true);
            setTimeout(() => inputRef.current?.focus(), 0);
          }}
        >
          {selected.size > 0 ? (
            <span>
              + Add another construct ({selected.size} selected)
            </span>
          ) : (
            <span className="muted">
              Select one or more constructs ({constructs.length} in library)
            </span>
          )}
          <span className="picker-caret" aria-hidden="true">▾</span>
        </button>
      ) : (
        <>
          <input
            ref={inputRef}
            type="text"
            role="combobox"
            aria-expanded="true"
            aria-autocomplete="list"
            className="picker-search"
            placeholder="Search by scale, construct, or category (e.g. empathy, GAD-7)"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            onKeyDown={onKeyDown}
          />
          <div className="picker-panel" role="listbox" ref={listRef}>
            {flat.length === 0 && (
              <p className="small muted picker-empty">
                No constructs match "{query}". Try a scale abbreviation or use + Custom construct.
              </p>
            )}
            {groups.map(([label, items]) => (
              <div key={label}>
                <div className="picker-group">{label}</div>
                {items.map((c) => {
                  index += 1;
                  const isActive = index === active;
                  const isSelected = selected.has(c.id);
                  return (
                    <div
                      key={c.id}
                      role="option"
                      aria-selected={isSelected}
                      data-active={isActive || undefined}
                      className={
                        "picker-option" +
                        (isActive ? " active" : "") +
                        (isSelected ? " selected" : "")
                      }
                      onMouseDown={(e) => {
                        e.preventDefault();
                        choose(c);
                      }}
                    >
                      <span className="picker-name">
                        {isSelected ? "✓ " : ""}
                        {c.name}
                      </span>
                      <span className="picker-meta">
                        {c.category ? `${c.category} · ` : ""}
                        {c.items.length} item{c.items.length === 1 ? "" : "s"}
                        {c.ai_generated
                          ? " · AI-generated · not validated"
                          : c.verification_status !== "verified"
                            ? " · unverified"
                            : ""}
                        {isSelected ? " · click to remove" : ""}
                      </span>
                    </div>
                  );
                })}
              </div>
            ))}
          </div>
        </>
      )}
    </div>
  );
}
