// gallery.jsx — collection gallery: toolbar, facet filters, grid/list results,
// search-within, sort, active-filter chips, and loading/empty/error states.

const { useState, useEffect, useMemo, useRef } = React;

function facetOptions(docs, pick) {
  const m = new Map();
  for (const d of docs) for (const o of pick(d)) {
    if (!o || !o.code) continue;
    const e = m.get(o.code) || { code: o.code, label: o.label, count: 0 };
    e.count++; m.set(o.code, e);
  }
  return [...m.values()].sort((a, b) => b.count - a.count || a.label.localeCompare(b.label));
}

function Gallery({ collectionId, index, onOpenDoc, query, onQuery }) {
  const collection = (index.collections || []).find((c) => c.id === collectionId) || { id: collectionId, label: collectionId };
  const docs = useMemo(() => (index.documents || []).filter((d) => d.collection === collectionId), [index, collectionId]);

  const [view, setView] = useState(() => localStorage.getItem("ukdocs.view") || "grid");
  const [sort, setSort] = useState("updated");
  const [domains, setDomains] = useState([]);
  const [statuses, setStatuses] = useState([]);
  const [classes, setClasses] = useState([]);
  const [q, setQ] = useState(query || "");
  const [sheet, setSheet] = useState(false);
  useEffect(() => { setQ(query || ""); }, [query]);
  useEffect(() => { localStorage.setItem("ukdocs.view", view); }, [view]);
  useEffect(() => { setDomains([]); setStatuses([]); setClasses([]); }, [collectionId]);

  const domainOpts = useMemo(() => facetOptions(docs, (d) => d.domains.length ? [d.domains[0]] : []), [docs]);
  const statusOpts = useMemo(() => facetOptions(docs, (d) => [{ code: d.statusStage, label: d.status || d.statusStage }]), [docs]);
  const classOpts = useMemo(() => facetOptions(docs, (d) => d.classificationPath[0] ? [{ code: d.classificationPath[0], label: d.classificationPath[0] }] : []), [docs]);

  const filtered = useMemo(() => {
    const qq = q.trim().toLowerCase();
    let out = docs.filter((d) => {
      if (domains.length && !(d.domains[0] && domains.includes(d.domains[0].code))) return false;
      if (statuses.length && !statuses.includes(d.statusStage)) return false;
      if (classes.length && !(d.classificationPath[0] && classes.includes(d.classificationPath[0]))) return false;
      if (qq && !(d.searchText || "").includes(qq)) return false;
      return true;
    });
    const byDate = (a, b) => String(b.lastUpdated || "").localeCompare(String(a.lastUpdated || ""));
    if (sort === "updated") out = out.sort(byDate);
    else if (sort === "title") out = out.sort((a, b) => a.title.localeCompare(b.title));
    else if (sort === "version") out = out.sort((a, b) => String(b.version || "").localeCompare(String(a.version || "")));
    else if (sort === "status") out = out.sort((a, b) => a.statusStage.localeCompare(b.statusStage) || byDate(a, b));
    return out;
  }, [docs, domains, statuses, classes, q, sort]);

  const toggle = (setter, list) => (code) => setter(list.includes(code) ? list.filter((x) => x !== code) : [...list, code]);
  const clearAll = () => { setDomains([]); setStatuses([]); setClasses([]); setQ(""); onQuery && onQuery(""); };
  const activeCount = domains.length + statuses.length + classes.length + (q ? 1 : 0);

  const filtersBody = (
    <React.Fragment>
      <FilterGroup label="Domain" options={domainOpts} selected={domains} onToggle={toggle(setDomains, domains)} />
      <FilterGroup label="Status" options={statusOpts} selected={statuses} onToggle={toggle(setStatuses, statuses)} />
      <FilterGroup label="Classification" options={classOpts} selected={classes} onToggle={toggle(setClasses, classes)} />
    </React.Fragment>
  );

  return (
    <React.Fragment>
      <div className="gtoolbar">
        <h1 className="gtoolbar__title">{collection.label}<span className="gtoolbar__count">{filtered.length} / {docs.length}</span></h1>
        <div className="gtoolbar__spacer" />
        <label className="gtoolbar__search">
          <I.Search />
          <input type="search" value={q} placeholder={"Search " + collection.label.toLowerCase()} aria-label={"Search " + collection.label}
                 onChange={(e) => { setQ(e.target.value); onQuery && onQuery(e.target.value); }} />
        </label>
        <select className="select" value={sort} onChange={(e) => setSort(e.target.value)} aria-label="Sort">
          <option value="updated">Last updated</option>
          <option value="title">Title</option>
          <option value="version">Version</option>
          <option value="status">Status</option>
        </select>
        <Segmented ariaLabel="View" value={view} onChange={setView}
          options={[{ value: "grid", icon: <I.Grid />, title: "Grid" }, { value: "list", icon: <I.List />, title: "List" }]} />
        <button className="btn btn--sm gfilterbtn" onClick={() => setSheet(true)} aria-label="Filters">
          <I.Filter /> Filters{activeCount ? " (" + activeCount + ")" : ""}
        </button>
      </div>

      <div className="glayout">
        <aside className="filters" aria-label="Filters">
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "var(--uk-space-16)" }}>
            <span className="filters__label">Filters</span>
            {activeCount > 0 && <button className="btn btn--ghost btn--sm" onClick={clearAll}>Clear</button>}
          </div>
          {filtersBody}
        </aside>

        <div className="results">
          {activeCount > 0 && (
            <div className="activefilters">
              {domains.map((c) => <button key={"d" + c} className="chip" onClick={() => toggle(setDomains, domains)(c)}>{(domainOpts.find((o) => o.code === c) || {}).label || c} <I.Close /></button>)}
              {statuses.map((c) => <button key={"s" + c} className="chip" onClick={() => toggle(setStatuses, statuses)(c)}>{c} <I.Close /></button>)}
              {classes.map((c) => <button key={"c" + c} className="chip" onClick={() => toggle(setClasses, classes)(c)}>{c} <I.Close /></button>)}
              <button className="btn btn--ghost btn--sm" onClick={clearAll}>Clear all</button>
            </div>
          )}

          {filtered.length === 0
            ? <EmptyState title="No documents match" msg="Try removing a filter or changing your search." action={activeCount ? <button className="btn btn--sm" onClick={clearAll}>Clear filters</button> : null} />
            : view === "grid"
              ? <div className="cardgrid">{filtered.map((d) => <DocCard key={d.id} doc={d} onOpen={onOpenDoc} />)}</div>
              : <div className="rowlist">{filtered.map((d) => <DocRow key={d.id} doc={d} onOpen={onOpenDoc} />)}</div>}
        </div>
      </div>

      {sheet && (
        <React.Fragment>
          <button className="scrim" aria-label="Close filters" onClick={() => setSheet(false)} />
          <nav className="drawer" aria-label="Filters" style={{ left: "auto", right: 0 }}>
            <div className="drawer__head"><span className="mono muted" style={{ fontSize: "11px" }}>FILTERS</span><button className="iconbtn" onClick={() => setSheet(false)} aria-label="Close"><I.Close /></button></div>
            {activeCount > 0 && <button className="btn btn--ghost btn--sm" onClick={clearAll} style={{ marginBottom: "12px" }}>Clear all</button>}
            {filtersBody}
          </nav>
        </React.Fragment>
      )}
    </React.Fragment>
  );
}

window.Gallery = Gallery;
