/* Per-customer artwork library — a ~70% fullscreen modal opened from an order/draft.
   Folders + tags + search + CRUD (rename/move/delete/embroidery) over the SAME
   /api/assets store the customer's headless gang-sheet builder reads, plus a bridge
   to add library artwork onto the order as production artwork (and back). Light theme,
   reuses .modal-overlay / .btn / Icon. Registered before views-orders.jsx. */

function LibFmtWhen(iso) {
  if (!iso) return "";
  const d = new Date(iso); if (isNaN(d)) return "";
  const now = new Date(), diff = (now - d) / 1000;
  if (diff < 60) return "just now";
  if (diff < 3600) return Math.floor(diff / 60) + "m ago";
  if (diff < 86400) return Math.floor(diff / 3600) + "h ago";
  if (diff < 86400 * 7) return Math.floor(diff / 86400) + "d ago";
  return d.toLocaleDateString(undefined, { day: "numeric", month: "short", year: "numeric" });
}

// Folder picker (matches the "Move artwork" reference). value=null → All artworks.
function LibMoveModal({ folders, current, name, onPick, onClose }) {
  const [pick, setPick] = useState(current || null);
  return (
    <div className="modal-overlay" style={{ zIndex: 1200 }} onClick={onClose}>
      <div className="modal" style={{ maxWidth: 520 }} onClick={e => e.stopPropagation()}>
        <div className="modal__head"><h3>Move artwork</h3><button className="icon-btn" onClick={onClose}><Icon name="x" /></button></div>
        <div className="modal__body">
          <div className="kick" style={{ marginBottom: 12 }}>Choose a folder for <b>{name}</b>.</div>
          <div className="lib-pick">
            <div className={"lib-pick__row" + (pick == null ? " is-sel" : "")} onClick={() => setPick(null)}>
              <Icon name="image" /><span>All artworks</span>{current == null && <span className="dim" style={{ marginLeft: "auto", fontSize: 12 }}>(current)</span>}
            </div>
            {folders.map(f => (
              <div key={f.id} className={"lib-pick__row" + (pick === f.id ? " is-sel" : "")} onClick={() => setPick(f.id)}>
                <Icon name="box" /><span>{f.name}</span>{current === f.id && <span className="dim" style={{ marginLeft: "auto", fontSize: 12 }}>(current)</span>}
              </div>
            ))}
          </div>
        </div>
        <div className="modal__foot" style={{ justifyContent: "flex-end", gap: 8 }}>
          <button className="btn btn--ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn--primary" disabled={pick === current} onClick={() => onPick(pick)}>Move here</button>
        </div>
      </div>
    </div>
  );
}

// Shopify-style tag editor popover: current tags as removable chips, a search/add box,
// and the whole library's tag vocabulary (frequently-used first) as toggle checkboxes.
// Changes apply live via onChange. `ranked` = [{tag,count}] across all assets.
function LibTagEditor({ asset, ranked, onChange, onClose, pos }) {
  const [tags, setTags] = useState(asset.tags || []);
  const [q, setQ] = useState("");
  const inFor = (t) => tags.includes(t);
  const apply = (next) => { setTags(next); onChange(next); };
  const toggle = (t) => apply(inFor(t) ? tags.filter(x => x !== t) : [...tags, t]);
  const addNew = () => { const t = q.trim(); if (t && !inFor(t)) apply([...tags, t]); setQ(""); };
  const ql = q.trim().toLowerCase();
  const all = ranked.map(r => r.tag);
  const matches = all.filter(t => t.toLowerCase().includes(ql));
  const exact = all.some(t => t.toLowerCase() === ql);
  const freq = ranked.slice(0, 6).map(r => r.tag);
  const rest = all.filter(t => !freq.includes(t));
  const Row = (t) => (
    <label key={t} className="lib-te__row"><input type="checkbox" checked={inFor(t)} onChange={() => toggle(t)} /> <span>{t}</span></label>
  );
  return (
    <div className="lib-te" style={{ top: pos.top, left: pos.left }} onClick={e => e.stopPropagation()}>
      <div className="lib-te__chips">
        {tags.length ? tags.map(t => <span key={t} className="lib-tag">{t}<button title="Remove" onClick={() => toggle(t)}>×</button></span>)
          : <span className="dim" style={{ fontSize: 12 }}>No tags yet</span>}
      </div>
      <div className="lib-te__search"><Icon name="search" /><input autoFocus placeholder="Search or add tags" value={q}
        onChange={e => setQ(e.target.value)} onKeyDown={e => { if (e.key === "Enter") { e.preventDefault(); addNew(); } }} /></div>
      <div className="lib-te__list">
        {ql && !exact && <button className="lib-te__add" onClick={addNew}><Icon name="plus" /> Add “{q.trim()}”</button>}
        {ql
          ? (matches.length ? matches.map(Row) : (!q.trim() ? null : <div className="lib-te__empty">No matching tags.</div>))
          : (all.length === 0 ? <div className="lib-te__empty">No tags in the library yet — type to add one.</div>
            : <>
                {freq.length > 0 && <div className="lib-te__h">Frequently used</div>}
                {freq.map(Row)}
                {rest.length > 0 && <div className="lib-te__h">Other tags</div>}
                {rest.map(Row)}
              </>)}
      </div>
      <div className="lib-te__foot"><button className="btn btn--primary btn--sm" onClick={onClose}>Done</button></div>
    </div>
  );
}

// Centered ~60% preview panel — click an artwork's image to open. The backdrop click
// stops propagation so it closes ONLY the preview, not the library modal underneath.
function LibPreviewModal({ asset, ranked, onRename, onTags, onClose }) {
  const [dark, setDark] = useState(false);   // toggle bg so white OR dark art stays visible
  const [name, setName] = useState(asset.name || "");
  const [tags, setTags] = useState(asset.tags || []);
  const [newTag, setNewTag] = useState("");
  useEffect(() => { setName(asset.name || ""); }, [asset.name]);   // reflect server-normalised name
  useEffect(() => { setTags(asset.tags || []); }, [asset.tags]);
  const close = (e) => { if (e) e.stopPropagation(); onClose(); };
  const saveName = () => { const v = name.trim(); if (v && v !== (asset.name || "")) onRename(v); };
  const setTagList = (next) => { setTags(next); onTags(next); };
  const addTag = () => { const t = newTag.trim(); if (t && !tags.includes(t)) setTagList([...tags, t]); setNewTag(""); };
  return (
    <div className="lib-lightbox" onClick={close}>
      <div className="lib-lightbox__panel" onClick={e => e.stopPropagation()}>
        <button className="lib-lightbox__x" title="Close" onClick={close}><Icon name="x" /></button>
        <div className={"lib-lightbox__stage" + (dark ? " is-dark" : "")}><img src={asset.url} alt={asset.name || ""} /></div>
        <div className="lib-lightbox__edit">
          <div className="lib-lightbox__row">
            <input className="lib-lightbox__name-in" value={name} onChange={e => setName(e.target.value)} onBlur={saveName}
              onKeyDown={e => { if (e.key === "Enter") { e.preventDefault(); e.currentTarget.blur(); } }} placeholder="Artwork name" title="Rename (spaces become dashes, extension kept)" />
            <button className="btn btn--ghost btn--sm" onClick={() => setDark(d => !d)} title="Switch preview background">{dark ? "Light bg" : "Dark bg"}</button>
            <a className="btn btn--ghost btn--sm" href={asset.url} download target="_blank" rel="noopener"><Icon name="download" /> Download</a>
          </div>
          <div className="lib-lightbox__tags">
            {tags.map(t => <span key={t} className="lib-tag">{t}<button title="Remove" onClick={() => setTagList(tags.filter(x => x !== t))}>×</button></span>)}
            <input className="lib-lightbox__tag-in" list="lib-tag-suggest" value={newTag} onChange={e => setNewTag(e.target.value)}
              onKeyDown={e => { if (e.key === "Enter") { e.preventDefault(); addTag(); } }} placeholder="+ add tag" />
            <datalist id="lib-tag-suggest">{(ranked || []).map(r => <option key={r.tag} value={r.tag} />)}</datalist>
          </div>
        </div>
      </div>
    </div>
  );
}

function CustomerLibraryModal({ customerId, customerName, owner, onClose, onAssigned }) {
  const cid = customerId;
  const [data, setData] = useState(null);        // { assets, folders }
  const [err, setErr] = useState("");
  const [folder, setFolder] = useState("all");   // "all" | "none" | folderId
  const [q, setQ] = useState("");
  const [sort, setSort] = useState("new");       // new | old | name
  const [sel, setSel] = useState(() => new Set());
  const [busy, setBusy] = useState("");          // status text while working
  const [menuFor, setMenuFor] = useState(null);  // assetId whose … menu is open
  const [menuPos, setMenuPos] = useState(null);  // {top,right} for the floating … menu
  const [moveFor, setMoveFor] = useState(null);  // asset being moved
  const [preview, setPreview] = useState(null);  // asset shown in the big lightbox
  const [tagFor, setTagFor] = useState(null);    // assetId whose tag editor is open
  const [tagPos, setTagPos] = useState(null);    // {top,left} for the tag editor
  const fileRef = useRef(null);
  // Open the … menu as a fixed dropdown anchored to its button (never clipped by the
  // card/grid), flipping up when it would run past the bottom of the screen.
  const openMenu = (a) => (e) => {
    e.stopPropagation();
    if (menuFor === a.id) { setMenuFor(null); return; }
    const r = e.currentTarget.getBoundingClientRect();
    const H = 252;
    const top = (r.bottom + H > window.innerHeight - 10) ? Math.max(10, r.top - H) : r.bottom + 4;
    setMenuPos({ top, right: Math.max(10, window.innerWidth - r.right) });
    setMenuFor(a.id);
  };

  const reload = () => DTF.customerLibrary(cid).then(d => { setData(d); setErr(""); }).catch(e => setErr(e.message || "Couldn't load library"));
  useEffect(() => { reload(); }, [cid]);
  useEffect(() => {
    const onKey = e => { if (e.key === "Escape") { if (preview) setPreview(null); else if (tagFor) setTagFor(null); else if (moveFor) setMoveFor(null); else if (menuFor) setMenuFor(null); else onClose(); } };
    window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey);
  }, [moveFor, menuFor, preview, tagFor]);

  const assets = (data && data.assets) || [];
  const folders = (data && data.folders) || [];
  const folderName = id => { const f = folders.find(x => x.id === id); return f ? f.name : null; };
  const countIn = id => assets.filter(a => a.folderId === id).length;
  // Shared tag vocabulary across the whole customer library, ranked by frequency.
  const tagCounts = {};
  assets.forEach(a => (a.tags || []).forEach(t => { tagCounts[t] = (tagCounts[t] || 0) + 1; }));
  const allTagsRanked = Object.entries(tagCounts).sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([tag, count]) => ({ tag, count }));

  const view = assets
    .filter(a => folder === "all" ? true : folder === "none" ? !a.folderId : a.folderId === folder)
    .filter(a => {
      const s = q.trim().toLowerCase(); if (!s) return true;
      return (a.name || "").toLowerCase().includes(s) || (a.tags || []).some(t => t.toLowerCase().includes(s));
    })
    .sort((a, b) => sort === "name" ? String(a.name || "").localeCompare(String(b.name || ""))
      : sort === "old" ? String(a.createdAt).localeCompare(String(b.createdAt))
      : String(b.createdAt).localeCompare(String(a.createdAt)));

  const toggleSel = id => setSel(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });

  async function guard(status, fn) {
    setBusy(status); setErr("");
    try { await fn(); await reload(); }
    catch (e) { setErr(e.message || "Action failed"); }
    finally { setBusy(""); setMenuFor(null); }
  }

  const onUpload = async (e) => {
    const files = [...(e.target.files || [])]; e.target.value = "";
    if (!files.length) return;
    await guard("Uploading…", async () => {
      const fid = (folder === "all" || folder === "none") ? null : folder;
      for (const f of files) await DTF.libUpload(cid, f, fid);
    });
  };
  const newFolder = () => { const n = prompt("New folder name"); if (n && n.trim()) guard("Creating folder…", () => DTF.libCreateFolder(cid, n.trim())); };
  const renameFolder = (f) => { const n = prompt("Rename folder", f.name); if (n && n.trim() && n.trim() !== f.name) guard("Renaming…", () => DTF.libRenameFolder(cid, f.id, n.trim())); };
  const delFolder = (f) => { if (confirm(`Delete folder “${f.name}”? Its artwork is kept (moved to All artworks).`)) guard("Deleting folder…", async () => { await DTF.libDeleteFolder(cid, f.id); if (folder === f.id) setFolder("all"); }); };

  const rename = (a) => { const n = prompt("Rename artwork", a.name || ""); if (n != null && n.trim() && n.trim() !== a.name) guard("Renaming…", () => DTF.libUpdateAsset(cid, a.id, { name: n.trim() })); };
  const move = (a) => { setMenuFor(null); setMoveFor(a); };
  const doMove = (a, folderId) => { setMoveFor(null); guard("Moving…", () => DTF.libUpdateAsset(cid, a.id, { folderId: folderId })); };
  const embroider = (a) => guard("Converting to embroidery… (this can take ~30s)", () => DTF.libEmbroider(cid, a.id));
  const del = (a) => { if (confirm(`Delete “${a.name || "artwork"}” from the library? This can't be undone.`)) guard("Deleting…", () => DTF.libDeleteAsset(cid, a.id)); };
  // Live tag edits: patch local data (no full-reload flash) so the tag editor, the card
  // chips, and the shared tag vocabulary all update instantly.
  const applyTags = async (assetId, next) => {
    setData(d => d ? { ...d, assets: d.assets.map(a => a.id === assetId ? { ...a, tags: next } : a) } : d);
    setPreview(p => (p && p.id === assetId) ? { ...p, tags: next } : p);
    try { await DTF.libUpdateAsset(cid, assetId, { tags: next }); }
    catch (e) { setErr(e.message || "Couldn't save tags"); reload(); }
  };
  // Rename via the server (spaces→dashes, extension kept) then reflect the normalised name.
  const renameAsset = async (assetId, nm) => {
    try {
      const up = await DTF.libUpdateAsset(cid, assetId, { name: nm });
      const newName = (up && up.name) || nm;
      setData(d => d ? { ...d, assets: d.assets.map(a => a.id === assetId ? { ...a, name: newName } : a) } : d);
      setPreview(p => (p && p.id === assetId) ? { ...p, name: newName } : p);
    } catch (e) { setErr(e.message || "Couldn't rename"); }
  };
  const removeTag = (a, tag) => applyTags(a.id, (a.tags || []).filter(t => t !== tag));
  const openTagEditor = (a) => (e) => {
    e.stopPropagation();
    const r = e.currentTarget.getBoundingClientRect();
    const W = 268, H = 344;
    const left = Math.max(10, Math.min(r.left, window.innerWidth - W - 10));
    const top = (r.bottom + H > window.innerHeight - 10) ? Math.max(10, r.top - H) : r.bottom + 6;
    setTagPos({ top, left }); setTagFor(a.id);
  };

  async function addSelectedToOrder() {
    if (!owner || !sel.size) return;
    setBusy("Adding to order…"); setErr("");
    try {
      let files = null;
      for (const id of sel) files = await DTF.libAddToOrder(owner, cid, id);
      if (onAssigned) onAssigned(files || []);
      onClose();
    } catch (e) { setErr(e.message || "Couldn't add to order"); setBusy(""); }
  }

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal lib" onClick={e => e.stopPropagation()}>
        <div className="modal__head">
          <div style={{ display: "flex", alignItems: "center", gap: 10, minWidth: 0 }}>
            <Icon name="image" /><h3 style={{ margin: 0 }}>Artwork library</h3>
            {customerName && <span className="badge badge--mint">{customerName}</span>}
          </div>
          <button className="icon-btn" onClick={onClose}><Icon name="x" /></button>
        </div>

        <div className="lib__body">
          {/* Folders sidebar */}
          <aside className="lib__side">
            <div className={"lib__folder" + (folder === "all" ? " is-sel" : "")} onClick={() => setFolder("all")}>
              <Icon name="image" /><span>All artworks</span><span className="lib__n">{assets.length}</span>
            </div>
            <div className={"lib__folder" + (folder === "none" ? " is-sel" : "")} onClick={() => setFolder("none")}>
              <Icon name="box" /><span>Ungrouped</span><span className="lib__n">{assets.filter(a => !a.folderId).length}</span>
            </div>
            <div className="lib__side-h">Folders</div>
            {folders.map(f => (
              <div key={f.id} className={"lib__folder" + (folder === f.id ? " is-sel" : "")} onClick={() => setFolder(f.id)}>
                <Icon name="box" /><span className="lib__fname">{f.name}</span><span className="lib__n">{countIn(f.id)}</span>
                <span className="lib__fx">
                  <button className="icon-btn icon-btn--xs" title="Rename" onClick={e => { e.stopPropagation(); renameFolder(f); }}><Icon name="spark" /></button>
                  <button className="icon-btn icon-btn--xs" title="Delete" onClick={e => { e.stopPropagation(); delFolder(f); }}><Icon name="x" /></button>
                </span>
              </div>
            ))}
            <button className="btn btn--ghost btn--sm" style={{ marginTop: 8 }} onClick={newFolder}><Icon name="plus" /> New folder</button>
          </aside>

          {/* Main */}
          <section className="lib__main">
            <div className="lib__bar">
              <div className="lib__search"><Icon name="search" /><input placeholder="Search artwork and tags…" value={q} onChange={e => setQ(e.target.value)} /></div>
              <select className="lib__sort" value={sort} onChange={e => setSort(e.target.value)}>
                <option value="new">Newest</option><option value="old">Oldest</option><option value="name">Name A–Z</option>
              </select>
              <button className="btn btn--primary btn--sm" disabled={!!busy} onClick={() => fileRef.current && fileRef.current.click()}><Icon name="plus" /> Add</button>
              <input ref={fileRef} type="file" accept="image/*,application/pdf" multiple style={{ display: "none" }} onChange={onUpload} />
            </div>

            {err && <div className="lib__err">{err}</div>}
            {busy && <div className="lib__busy"><span className="spin spin--dark" /> {busy}</div>}

            {!data ? <div className="empty" style={{ padding: 40 }}>Loading…</div>
              : view.length === 0 ? <div className="empty" style={{ padding: 40 }}>{q ? "No artwork matches your search." : "No artwork here yet — use Add to upload."}</div>
              : (
                <div className="lib__grid">
                  {view.map(a => (
                    <div key={a.id} className={"lib-card" + (sel.has(a.id) ? " is-sel" : "")}>
                      <div className="lib-card__thumb" onClick={() => setPreview(a)} title="Click to preview">
                        <input type="checkbox" className="lib-card__ck" checked={sel.has(a.id)} onChange={() => toggleSel(a.id)} onClick={e => e.stopPropagation()} title="Select" />
                        <img src={a.url} loading="lazy" alt="" />
                        <button className="lib-card__more" onClick={openMenu(a)}><Icon name="dots" /></button>
                        {menuFor === a.id && menuPos && (
                          <div className="lib-menu" style={{ top: menuPos.top, right: menuPos.right }} onClick={e => e.stopPropagation()}>
                            <button onClick={() => rename(a)}><Icon name="spark" /> Rename</button>
                            <button onClick={() => move(a)}><Icon name="box" /> Move to folder</button>
                            <button onClick={() => embroider(a)}><Icon name="scissors" /> Convert to embroidery</button>
                            <a href={a.url} target="_blank" rel="noopener" download onClick={() => setMenuFor(null)}><Icon name="download" /> Download</a>
                            <button className="is-danger" onClick={() => del(a)}><Icon name="x" /> Delete</button>
                          </div>
                        )}
                      </div>
                      <div className="lib-card__name" title={a.name || ""}>{a.name || "Untitled"}</div>
                      <div className="lib-card__meta">
                        <span>{LibFmtWhen(a.createdAt)}</span>
                        {a.folderId && <span className="dim"> · {folderName(a.folderId)}</span>}
                      </div>
                      <div className="lib-card__tags">
                        {(a.tags || []).map(t => (
                          <span key={t} className="lib-tag">{t}<button onClick={() => removeTag(a, t)}>×</button></span>
                        ))}
                        <button className="lib-tag lib-tag--add" onClick={openTagEditor(a)}><Icon name="tag" /> tag</button>
                      </div>
                    </div>
                  ))}
                </div>
              )}
          </section>
        </div>

        <div className="modal__foot" style={{ justifyContent: "space-between" }}>
          <div className="dim" style={{ fontSize: 13 }}>{sel.size ? `${sel.size} selected` : `${assets.length} in library`}</div>
          <div style={{ display: "flex", gap: 8 }}>
            {sel.size > 0 && <button className="btn btn--ghost" onClick={() => setSel(new Set())}>Clear</button>}
            {owner
              ? <button className="btn btn--primary" disabled={!sel.size || !!busy} onClick={addSelectedToOrder}><Icon name="plus" /> Add {sel.size || ""} to order</button>
              : <button className="btn btn--primary" onClick={onClose}>Done</button>}
          </div>
        </div>
      </div>

      {menuFor && <div className="lib-menu-scrim" onClick={() => setMenuFor(null)} />}
      {tagFor && tagPos && (() => { const ta = assets.find(a => a.id === tagFor); return ta ? (<>
        <div className="lib-menu-scrim" onClick={() => setTagFor(null)} />
        <LibTagEditor key={tagFor} asset={ta} ranked={allTagsRanked} pos={tagPos} onChange={(next) => applyTags(tagFor, next)} onClose={() => setTagFor(null)} />
      </>) : null; })()}
      {moveFor && <LibMoveModal folders={folders} current={moveFor.folderId || null} name={moveFor.name || "artwork"} onPick={(fid) => doMove(moveFor, fid)} onClose={() => setMoveFor(null)} />}
      {preview && <LibPreviewModal asset={preview} ranked={allTagsRanked} onRename={(n) => renameAsset(preview.id, n)} onTags={(t) => applyTags(preview.id, t)} onClose={() => setPreview(null)} />}
    </div>
  );
}
window.CustomerLibraryModal = CustomerLibraryModal;
