// Concepts.jsx — storefront concept (formerly "series") presentation.
// ConceptsView = the index of all concepts; ConceptPage = one editorial page
// (name + description + image gallery). Concept data comes from meta.series:
// [{ name, logo, description, images }].

function ConceptsView({ concepts, onOpen, info }) {
  const ec = React.useContext(window.EditCtx);
  const editing = ec && ec.edit;
  const list = (concepts || []).filter((c) => c && c.name);

  // Edit mode: live drag-reorder (order held by name; null = follow the data).
  const [order, setOrder] = React.useState(null);
  React.useEffect(() => { setOrder(null); }, [concepts]);
  const names = list.map((c) => c.name);
  const shown = (editing && order)
    ? order.map((n) => list.find((c) => c.name === n)).filter(Boolean)
    : list;

  const dragName = React.useRef(null);
  const moved = React.useRef(false);
  const workRef = React.useRef(null);
  const [dragVisual, setDragVisual] = React.useState(null);
  const isFileDrag = (e) => e.dataTransfer && Array.from(e.dataTransfer.types || []).includes("Files");

  const startDrag = (name) => (e) => {
    dragName.current = name; moved.current = false; workRef.current = names.slice();
    setDragVisual(name);
    if (e.dataTransfer) { e.dataTransfer.effectAllowed = "move"; try { e.dataTransfer.setData("text/plain", name); } catch (err) {} }
  };
  const overDrag = (name) => (e) => {
    if (isFileDrag(e)) { e.preventDefault(); return; }   // a dragged file → let it drop (logo upload), don't reorder
    if (dragName.current == null) return;
    e.preventDefault();
    const d = dragName.current; if (d === name) return;
    const arr = workRef.current || names.slice();
    const from = arr.indexOf(d), to = arr.indexOf(name);
    if (from < 0 || to < 0 || from === to) return;
    workRef.current = window.sbMove(arr, from, to); moved.current = true; setOrder(workRef.current);
  };
  const endDrag = () => {
    if (moved.current && workRef.current) {
      const seq = workRef.current;
      const reordered = seq.map((n) => (concepts || []).find((c) => c && c.name === n)).filter(Boolean);
      const rest = (concepts || []).filter((c) => !c || !c.name || !seq.includes(c.name));
      ec.saveSeries([...reordered, ...rest]);
    }
    dragName.current = null; moved.current = false; workRef.current = null; setDragVisual(null);
  };
  // Drop an SVG (or image) file anywhere on a card → set that concept's logo.
  const dropLogo = (name) => (e) => {
    if (isFileDrag(e) && e.dataTransfer.files && e.dataTransfer.files.length) {
      e.preventDefault(); e.stopPropagation();
      ec.upload(e.dataTransfer.files[0], (path) => ec.saveConcept(name, { logo: path }));
    }
  };

  return (
    <section className="concepts-index" data-screen-label="05 Concepts">
      <div className="page-head" style={{ borderBottom: "none", marginBottom: 32, paddingBottom: 0 }}>
        <div>
          <h1>concepts.</h1>
          <div className="lead">{info.season}</div>
        </div>
        <div className="meta">
          {String(list.length).padStart(2, "0")} CONCEPTS
          {editing && <><br /><span style={{ color: "var(--fg-3)" }}>drag to reorder · drop an svg to set a logo</span></>}
        </div>
      </div>

      {list.length === 0 ? (
        <div style={{ padding: "96px 0", textAlign: "center", color: "var(--fg-3)" }}>
          <div className="t-meta">no concepts yet.</div>
        </div>
      ) : (
        <div className="concepts-grid">
          {shown.map((c) => (
            <a key={c.name}
              className={"concept-card" + (editing ? " concept-card-edit" : "") + (dragVisual === c.name ? " is-dragging" : "")}
              draggable={editing}
              onDragStart={editing ? startDrag(c.name) : undefined}
              onDragOver={editing ? overDrag(c.name) : undefined}
              onDrop={editing ? dropLogo(c.name) : undefined}
              onDragEnd={editing ? endDrag : undefined}
              onClick={() => { if (!dragVisual) onOpen(c.name); }}>
              <div className="concept-card-media"
                {...window.dropProps(ec, (path) => ec.saveConcept(c.name, { logo: path }))}>
                {c.images && c.images[0]
                  ? <img className="concept-card-cover" src={c.images[0]} alt="" draggable={false} />
                  : c.logo
                    ? <img className="concept-card-logo" src={c.logo} alt="" draggable={false} />
                    : <span className="concept-card-none">◯</span>}
                {editing && (
                  <window.EditableImage title="⤓ logo · svg"
                    onPick={(path) => ec.saveConcept(c.name, { logo: path })} />
                )}
              </div>
              <div className="concept-card-foot">
                {c.logo && <img className="concept-card-foot-logo" src={c.logo} alt="" draggable={false} />}
                <span className="concept-card-name">{c.name.toLowerCase()}</span>
                <span className="concept-card-arrow">{editing ? "⠿" : "⟶"}</span>
              </div>
            </a>
          ))}
        </div>
      )}
    </section>
  );
}

// ── concept canvases — the lookbook's freeform canvas editor, borrowed. Each
// block lives on the series entry (concept.blocks: [{id, els, bg, height,
// heightM, hidden}]) and renders through window.CanvasBlock via a pseudo-look
// + an EditCtx adapter that reroutes look-saves into saveConcept. While a
// block is selected in edit mode, the lookbook's CanvasInspector floats
// beside the page, so building here feels exactly like the book.
function ConceptCanvases({ concept }) {
  const ec = React.useContext(window.EditCtx);
  const editing = ec && ec.edit;
  const saved = concept.blocks || [];
  const [live, setLive] = React.useState(null);   // uncommitted preview overlay
  const blocks = live || saved;
  const savedKey = JSON.stringify(saved);
  React.useEffect(() => { setLive(null); }, [savedKey]);
  const [selId, setSelId] = React.useState(null);

  // pseudo-look shape CanvasBlock/CanvasInspector expect ↔ stored block
  const toLook = (b) => ({
    id: b.id, kind: "canvas", hidden: !!b.hidden,
    blockMeta: { els: b.els || [], bg: b.bg || null },
    imgHeight: b.height == null ? null : b.height,
    imgHeightMobile: b.heightM == null ? null : b.heightM,
  });
  const applyPatch = (b, patch) => {
    const nb = { ...b };
    if (patch.blockMeta) { nb.els = patch.blockMeta.els || []; nb.bg = patch.blockMeta.bg || null; }
    if ("imgHeight" in patch) nb.height = patch.imgHeight;
    if ("imgHeightMobile" in patch) nb.heightM = patch.imgHeightMobile;
    if ("hidden" in patch) nb.hidden = patch.hidden;
    return nb;
  };
  const patchBlocks = (id, patch) => blocks.map((b) => (b.id === id ? applyPatch(b, patch) : b));
  const commit = (next) => { setLive(next); ec.saveConcept(concept.name, { blocks: next }); };
  const newId = () => "cb" + Date.now().toString(36) + Math.floor(Math.random() * 1e4).toString(36);

  const ctx = editing ? {
    ...ec,
    selectedLookId: selId,
    selectLook: setSelId,
    saveLook: (id, patch) => commit(patchBlocks(id, patch)),
    previewLook: (id, patch) => setLive(patchBlocks(id, patch)),
    duplicateLook: (id) => {
      const src = blocks.find((b) => b.id === id);
      if (src) commit([...blocks, { ...JSON.parse(JSON.stringify(src)), id: newId() }]);
    },
    deleteLook: (id) => { if (selId === id) setSelId(null); commit(blocks.filter((b) => b.id !== id)); },
  } : ec;

  const move = (i, dir) => { const j = i + dir; if (j >= 0 && j < blocks.length) commit(window.sbMove(blocks, i, j)); };
  const shown = editing ? blocks : blocks.filter((b) => !b.hidden);
  const selBlock = editing && !ec.preview ? blocks.find((b) => b.id === selId) : null;
  if (!shown.length && !(editing && !ec.preview)) return null;

  return (
    <window.EditCtx.Provider value={ctx}>
      <div className="concept-canvases">
        {shown.map((b, i) => (
          <div className="concept-canvas" key={b.id}>
            {editing && !ec.preview && blocks.length > 1 && (
              <div className="cc-move">
                <button title="move section up" onClick={() => move(i, -1)}>↑</button>
                <button title="move section down" onClick={() => move(i, +1)}>↓</button>
              </div>
            )}
            <window.CanvasBlock look={toLook(b)} />
          </div>
        ))}
        {editing && !ec.preview && (
          <button type="button" className="cc-add"
            onClick={() => commit([...blocks, { id: newId(), els: [], bg: null, height: null, heightM: null, hidden: false }])}>
            ✦ ＋ canvas section
          </button>
        )}
      </div>
      {selBlock && ReactDOM.createPortal(
        /* portalled to <body>: inside .view-anim its animation makes a stacking
           context that paints UNDER the order drawer/rail */
        <div className="cc-insp" onClick={(e) => e.stopPropagation()}>
          <div className="cc-insp-head">
            <span>✦ CANVAS</span>
            <button title="close" onClick={() => setSelId(null)}>×</button>
          </div>
          <window.CanvasInspector key={selBlock.id} look={toLook(selBlock)} device={ec.device || "desktop"}
            onPatch={(id, patch) => commit(patchBlocks(id, patch))}
            onPreview={(id, patch) => setLive(patchBlocks(id, patch))}
            onUpload={ec.upload} />
        </div>,
        document.body
      )}
    </window.EditCtx.Provider>
  );
}

// Every product of a concept, ordered by the concept's saved skuOrder (ids;
// unknown ids sink to the end in collection order). Shared by the concept page
// and the PDP concept section.
function sbConceptProducts(collection, concept) {
  if (!concept) return [];
  const list = (collection || []).filter(
    (p) => String(p.series || "").toLowerCase() === String(concept.name).toLowerCase());
  const o = concept.skuOrder || [];
  const at = (id) => { const i = o.indexOf(id); return i === -1 ? Infinity : i; };
  return list.map((p, k) => [p, k])
    .sort((a, b) => (at(a[0].id) - at(b[0].id)) || (a[1] - b[1])).map(([p]) => p);
}

// Small product thumbnails of one concept. `editing` + `onReorder` turn on
// drag-to-reorder (same pattern as the WORN grid). `bare` = thumbnails only
// (no name/colourway), centred — side-scrolls on phones (the PDP variant).
function ConceptProducts({ products, currentId, onOpenSku, editing, onReorder, bare }) {
  const dragIdx = React.useRef(null);
  if (!products.length) return null;
  return (
    <div className={"cp-prods" + (bare ? " is-bare" : "")}>
      {products.map((p, i) => (
        <button key={p.id} type="button"
          className={"cp-prod" + (p.id === currentId ? " is-current" : "")}
          title={p.name.toLowerCase() + (p.colorway && p.colorway.name ? " · " + p.colorway.name : "")
            + (editing ? " · drag to reorder" : "")}
          onClick={() => { if (p.id !== currentId && onOpenSku) onOpenSku(p); }}
          draggable={!!editing}
          onDragStart={(e) => { dragIdx.current = i; e.dataTransfer.effectAllowed = "move"; }}
          onDragOver={(e) => { if (editing && dragIdx.current != null) e.preventDefault(); }}
          onDrop={(e) => {
            if (!editing || dragIdx.current == null) return;
            e.preventDefault(); e.stopPropagation();
            onReorder(window.sbMove(products, dragIdx.current, i));
            dragIdx.current = null;
          }}
          onDragEnd={() => { dragIdx.current = null; }}>
          <span className="cp-prod-thumb" style={{ background: p.bg }} />
          {!bare && <span className="cp-prod-name">{p.name.toLowerCase()}</span>}
          {!bare && p.colorway && p.colorway.name && <span className="cp-prod-cw">{p.colorway.name}</span>}
        </button>
      ))}
    </div>
  );
}

function ConceptPage({ concept, onBack, collection, onOpenSku }) {
  const ec = React.useContext(window.EditCtx);
  if (!concept) {
    return (
      <section className="concept-page">
        <button className="concept-back" onClick={onBack}>← concepts</button>
        <div style={{ padding: "96px 0", color: "var(--fg-3)" }} className="t-meta">concept not found.</div>
      </section>
    );
  }
  const imgs = (concept.images || []).filter(Boolean);
  const paras = (concept.description || "").split(/\n\s*\n/).map((p) => p.trim()).filter(Boolean);
  const prods = sbConceptProducts(collection, concept);
  const setImageAt = (i, path) => {
    const next = [...(concept.images || [])];
    next[i] = path;
    ec.saveConcept(concept.name, { images: next.filter(Boolean).slice(0, 12) });
  };
  return (
    <section className="concept-page" data-screen-label="05 Concept">
      <button className="concept-back" onClick={onBack}>← concepts</button>
      <header className="concept-head">
        {concept.logo && <img className="concept-head-logo" src={concept.logo} alt="" />}
        <h1>{concept.name.toLowerCase()}</h1>
      </header>
      {ec.edit ? (
        <div className="concept-desc">
          <window.EditableText tag="p" multiline value={concept.description || ""}
            placeholder="describe this concept · blank line starts a new paragraph"
            onSave={(v) => ec.saveConcept(concept.name, { description: v })} />
        </div>
      ) : (paras.length > 0 && (
        <div className="concept-desc">
          {paras.map((p, i) => <p key={i}>{p}</p>)}
        </div>
      ))}
      <ConceptCanvases concept={concept} />
      {(imgs.length > 0 || ec.edit) && (
        <div className="concept-gallery">
          {imgs.map((src, i) => (
            <div className="concept-gallery-item" key={i}>
              <img src={src} alt="" />
              <window.EditableImage title="⤓ replace" onPick={(path) => setImageAt(i, path)} />
            </div>
          ))}
          {ec.edit && imgs.length < 12 && (
            <div className="concept-gallery-item concept-gallery-add">
              <window.EditableImage title="＋ add image" onPick={(path) => setImageAt(imgs.length, path)} />
            </div>
          )}
        </div>
      )}
      {!ec.edit && !paras.length && !imgs.length && (
        <div className="t-meta" style={{ color: "var(--fg-3)", marginTop: 32 }}>
          this concept has no description or images yet.
        </div>
      )}
      {prods.length > 0 && (
        <div className="concept-pieces">
          <div className="pdp-details-h">
            PIECES · {String(prods.length).padStart(2, "0")}
            {ec.edit && <span style={{ color: "var(--fg-3)" }}>  ·  drag to reorder</span>}
          </div>
          <ConceptProducts products={prods} onOpenSku={onOpenSku}
            editing={ec.edit}
            onReorder={(arr) => ec.saveConcept(concept.name, { skuOrder: arr.map((p) => p.id) })} />
        </div>
      )}
    </section>
  );
}

window.ConceptsView = ConceptsView;
window.ConceptPage = ConceptPage;
window.ConceptProducts = ConceptProducts;
window.sbConceptProducts = sbConceptProducts;
