const {
  useState: useStateDis,
  useEffect: useEffectDis,
  useRef: useRefDis,
} = React;

// ── helpers ────────────────────────────────────────────────────────────────────

function genSectionKey(title) {
  return title.toLowerCase().replace(/\s+/g, "_").replace(/[^a-z0-9_]/g, "");
}

const MODE_LABELS = {
  auto_general: "Newest overall",
  auto_category: "Newest in category",
  manual: "Hand-picked",
  recently_viewed: "Recently viewed (per user)",
};

// ── shared bits (mirrors page-categories.jsx conventions) ─────────────────────

const DisModal = ({ title, onClose, children, width = 420 }) => (
  <div
    style={{
      position: "fixed", inset: 0, zIndex: 100,
      background: "rgba(0,0,0,0.35)", display: "flex",
      alignItems: "center", justifyContent: "center",
    }}
    onClick={e => { if (e.target === e.currentTarget) onClose(); }}
  >
    <div
      className="panel"
      style={{ width, maxHeight: "90vh", overflow: "auto", padding: 24 }}
    >
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 18 }}>
        <span style={{ fontWeight: 600, fontSize: 14 }}>{title}</span>
        <button className="btn ghost" onClick={onClose} style={{ height: 24, padding: "0 8px" }}>✕</button>
      </div>
      {children}
    </div>
  </div>
);

const DisFormField = ({ label, hint, children }) => (
  <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
    <label style={{ fontSize: 11, fontWeight: 500, color: "var(--ink-2)", textTransform: "uppercase", letterSpacing: "0.06em", fontFamily: "var(--font-mono)" }}>
      {label}
    </label>
    {children}
    {hint && <span style={{ fontSize: 11, color: "var(--ink-3)" }}>{hint}</span>}
  </div>
);

const disInputStyle = {
  padding: "7px 10px", fontSize: 13, borderRadius: 5,
  border: "1px solid var(--hairline)", background: "var(--surface-2)",
  color: "var(--ink)", outline: "none", fontFamily: "var(--font-sans)", width: "100%",
};

// ── SectionModal: create / edit a home feed section ───────────────────────────

const SectionModal = ({ initial, categories, nextOrder, onSave, onClose }) => {
  const sb = window.supabaseClient;
  const I = window.Icons;

  const [title, setTitle] = useStateDis(initial?.title || "");
  const [sectionKey, setSectionKey] = useStateDis(initial?.section_key || "");
  const [mode, setMode] = useStateDis(initial?.mode || "auto_general");
  const [categorySlug, setCategorySlug] = useStateDis(initial?.category_slug || (categories[0]?.slug ?? ""));
  const [productLimit, setProductLimit] = useStateDis(initial?.product_limit ?? 8);
  const [minCount, setMinCount] = useStateDis(initial?.min_count ?? 4);
  const [isFaves, setIsFaves] = useStateDis(initial?.is_faves ?? false);
  const [isActive, setIsActive] = useStateDis(initial?.is_active ?? true);
  const [saving, setSaving] = useStateDis(false);
  const [err, setErr] = useStateDis(null);

  // Product picker state — only relevant when mode === "manual". Picks are
  // held locally and only persisted to home_feed_section_items when the
  // whole modal is saved, so creating a brand-new section and picking its
  // products is one motion instead of "save, then reopen to manage picks".
  const [pickedProducts, setPickedProducts] = useStateDis([]); // [{id, name, images}]
  const [pickedLoading, setPickedLoading] = useStateDis(!!initial && initial.mode === "manual");
  const [query, setQuery] = useStateDis("");
  const [results, setResults] = useStateDis([]);
  const [searching, setSearching] = useStateDis(false);

  useEffectDis(() => {
    if (!initial || initial.mode !== "manual") return;
    sb.from("home_feed_section_items")
      .select("position, products(id, name, images, status)")
      .eq("section_id", initial.id)
      .order("position", { ascending: true })
      .then(({ data, error }) => {
        if (!error && data) setPickedProducts(data.filter(r => r.products).map(r => r.products));
        setPickedLoading(false);
      });
  }, [initial?.id]);

  useEffectDis(() => {
    const q = query.trim();
    if (!q || mode !== "manual") { setResults([]); return; }
    setSearching(true);
    const handle = setTimeout(async () => {
      const { data } = await sb
        .from("products")
        .select("id, name, images, status")
        .eq("status", "active")
        .ilike("name", `%${q}%`)
        .limit(15);
      setResults(data || []);
      setSearching(false);
    }, 300);
    return () => clearTimeout(handle);
  }, [query, mode]);

  const pickedIds = new Set(pickedProducts.map(p => p.id));
  const addPicked = (product) => {
    if (pickedIds.has(product.id)) return;
    setPickedProducts(prev => [...prev, product]);
  };
  const removePicked = (productId) => {
    setPickedProducts(prev => prev.filter(p => p.id !== productId));
  };
  const movePicked = (index, dir) => {
    const other = index + dir;
    if (other < 0 || other >= pickedProducts.length) return;
    const next = [...pickedProducts];
    [next[index], next[other]] = [next[other], next[index]];
    setPickedProducts(next);
  };

  const handleTitleChange = (v) => {
    setTitle(v);
    if (!initial) setSectionKey(genSectionKey(v));
  };

  const handleSubmit = async () => {
    if (!title.trim() || !sectionKey.trim()) { setErr("Title and key are required."); return; }
    if (mode === "auto_category" && !categorySlug) { setErr("Pick a category for this mode."); return; }
    if (mode === "manual" && pickedProducts.length === 0) { setErr("Pick at least one product."); return; }
    setSaving(true);
    setErr(null);
    try {
      await onSave({
        section_key: sectionKey.trim(),
        title: title.trim(),
        mode,
        category_slug: mode === "auto_category" ? categorySlug : null,
        product_limit: Number(productLimit) || 8,
        min_count: Number(minCount) || 4,
        is_faves: isFaves,
        is_active: isActive,
        ...(initial ? {} : { display_order: nextOrder }),
      }, mode === "manual" ? pickedProducts.map(p => p.id) : null);
      onClose();
    } catch (e) {
      setErr(e.message);
    } finally {
      setSaving(false);
    }
  };

  return (
    <DisModal title={initial ? "Edit section" : "New section"} onClose={onClose} width={mode === "manual" ? 520 : 420}>
      <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
        <DisFormField label="Title" hint={'What shoppers see above the row, e.g. "Our Faves"'}>
          <input style={disInputStyle} value={title} onChange={e => handleTitleChange(e.target.value)} placeholder="e.g. Dashain Specials" />
        </DisFormField>
        <DisFormField label="Section key" hint="Stable id — safe to leave as-is once created">
          <input style={{ ...disInputStyle, fontFamily: "var(--font-mono)", fontSize: 12 }} value={sectionKey} onChange={e => setSectionKey(e.target.value)} />
        </DisFormField>
        <DisFormField label="Content source">
          <select style={disInputStyle} value={mode} onChange={e => setMode(e.target.value)}>
            <option value="auto_general">Newest overall (auto)</option>
            <option value="auto_category">Newest in a category (auto)</option>
            <option value="manual">Hand-picked products</option>
            <option value="recently_viewed">Recently viewed by shopper</option>
          </select>
          <span style={{ fontSize: 11, color: "var(--ink-3)" }}>
            Auto modes are diversified across stores automatically — one seller's upload batch can't fill the row.
          </span>
        </DisFormField>
        {mode === "auto_category" && (
          <DisFormField label="Category">
            <select style={disInputStyle} value={categorySlug} onChange={e => setCategorySlug(e.target.value)}>
              {categories.map(c => <option key={c.slug} value={c.slug}>{c.name}</option>)}
            </select>
          </DisFormField>
        )}

        {mode === "manual" && (
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, border: "1px solid var(--hairline)", borderRadius: 6, padding: "7px 10px", background: "var(--surface-2)" }}>
              <I.search size={13} style={{ color: "var(--ink-3)", flexShrink: 0 }} />
              <input
                style={{ flex: 1, border: "none", outline: "none", background: "transparent", fontSize: 13, color: "var(--ink)" }}
                placeholder="Search products to add…"
                value={query}
                onChange={e => setQuery(e.target.value)}
              />
              {query && <I.x size={13} style={{ color: "var(--ink-3)", cursor: "pointer" }} onClick={() => setQuery("")} />}
            </div>

            {query && (
              <div style={{ maxHeight: 160, overflow: "auto", border: "1px solid var(--hairline)", borderRadius: 6 }}>
                {searching ? (
                  <div style={{ padding: 14, fontSize: 12, color: "var(--ink-3)", textAlign: "center" }}>Searching…</div>
                ) : results.length === 0 ? (
                  <div style={{ padding: 14, fontSize: 12, color: "var(--ink-3)", textAlign: "center" }}>No matches</div>
                ) : results.map(p => {
                  const added = pickedIds.has(p.id);
                  return (
                    <div key={p.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "7px 10px", borderBottom: "1px solid var(--hairline)" }}>
                      <div style={{ width: 28, height: 28, borderRadius: 4, overflow: "hidden", background: "var(--surface-3)", flexShrink: 0 }}>
                        {p.images?.[0] && <img src={p.images[0]} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />}
                      </div>
                      <div style={{ flex: 1, minWidth: 0, fontSize: 12.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.name}</div>
                      <button
                        className="btn ghost"
                        style={{ height: 22, padding: "0 8px", fontSize: 11 }}
                        disabled={added}
                        onClick={() => addPicked(p)}
                      >
                        {added ? "Added" : "Add"}
                      </button>
                    </div>
                  );
                })}
              </div>
            )}

            <div>
              <div style={{ fontSize: 11, fontWeight: 500, color: "var(--ink-2)", textTransform: "uppercase", letterSpacing: "0.06em", fontFamily: "var(--font-mono)", marginBottom: 8 }}>
                Picked ({pickedProducts.length})
              </div>
              {pickedLoading ? (
                <div style={{ padding: 14, fontSize: 12, color: "var(--ink-3)", textAlign: "center" }}>Loading…</div>
              ) : pickedProducts.length === 0 ? (
                <div style={{ padding: 14, fontSize: 12, color: "var(--ink-3)", textAlign: "center", border: "1px dashed var(--hairline)", borderRadius: 6 }}>
                  Nothing picked yet — search above to add products.
                </div>
              ) : (
                <div style={{ display: "flex", flexDirection: "column", gap: 6, maxHeight: 220, overflow: "auto" }}>
                  {pickedProducts.map((p, i) => (
                    <div key={p.id} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 8px", border: "1px solid var(--hairline)", borderRadius: 6 }}>
                      <div style={{ display: "flex", flexDirection: "column", gap: 1 }}>
                        <button className="btn ghost" style={{ height: 16, width: 20, padding: 0, display: "grid", placeItems: "center" }} disabled={i === 0} onClick={() => movePicked(i, -1)}><I.arrowUp size={9} /></button>
                        <button className="btn ghost" style={{ height: 16, width: 20, padding: 0, display: "grid", placeItems: "center" }} disabled={i === pickedProducts.length - 1} onClick={() => movePicked(i, 1)}><I.arrowDn size={9} /></button>
                      </div>
                      <div style={{ width: 28, height: 28, borderRadius: 4, overflow: "hidden", background: "var(--surface-3)", flexShrink: 0 }}>
                        {p.images?.[0] && <img src={p.images[0]} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />}
                      </div>
                      <div style={{ flex: 1, minWidth: 0, fontSize: 12.5, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>{p.name}</div>
                      <button
                        className="btn ghost"
                        style={{ height: 22, width: 22, padding: 0, display: "grid", placeItems: "center", color: "var(--neg)" }}
                        onClick={() => removePicked(p.id)}
                      ><I.trash size={10} /></button>
                    </div>
                  ))}
                </div>
              )}
            </div>
          </div>
        )}

        <div style={{ display: "flex", gap: 12 }}>
          <DisFormField label="Product limit">
            <input style={{ ...disInputStyle, width: 90 }} type="number" min="1" max="40" value={productLimit} onChange={e => setProductLimit(e.target.value)} />
          </DisFormField>
          <DisFormField label="Min to show" hint="Hidden if fewer are available">
            <input style={{ ...disInputStyle, width: 90 }} type="number" min="1" value={minCount} onChange={e => setMinCount(e.target.value)} />
          </DisFormField>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <input type="checkbox" id="ds-faves" checked={isFaves} onChange={e => setIsFaves(e.target.checked)} />
          <label htmlFor="ds-faves" style={{ fontSize: 13, cursor: "pointer" }}>
            Use the "Our Faves" collage card style instead of the standard grid
          </label>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <input type="checkbox" id="ds-active" checked={isActive} onChange={e => setIsActive(e.target.checked)} />
          <label htmlFor="ds-active" style={{ fontSize: 13, cursor: "pointer" }}>Active</label>
        </div>
        {err && <div style={{ fontSize: 12, color: "var(--neg)", background: "var(--neg-soft)", padding: "8px 10px", borderRadius: 5 }}>{err}</div>}
        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button className="btn ghost" onClick={onClose}>Cancel</button>
          <button className="btn primary" onClick={handleSubmit} disabled={saving}>{saving ? "Saving…" : "Save"}</button>
        </div>
      </div>
    </DisModal>
  );
};

// ── DiscoveryPage ───────────────────────────────────────────────────────────────

const DiscoveryPage = () => {
  const I = window.Icons;
  const sb = window.supabaseClient;

  const [sections, setSections] = useStateDis([]);
  const [categories, setCategories] = useStateDis([]);
  const [loading, setLoading] = useStateDis(true);

  const [sectionModal, setSectionModal] = useStateDis(null); // null | "new" | row
  const [deleteTarget, setDeleteTarget] = useStateDis(null);

  const fetchSections = async () => {
    const { data, error } = await sb.from("home_feed_sections").select("*").order("display_order");
    if (!error && data) setSections(data);
    setLoading(false);
  };

  useEffectDis(() => {
    if (!sb) return;
    fetchSections();
    sb.from("store_main_categories").select("slug, name").eq("is_active", true).order("display_order")
      .then(({ data }) => { if (data) setCategories(data); });
  }, []);

  const swapOrder = async (editingId, oldOrder, newOrder) => {
    if (oldOrder === newOrder) return;
    const conflict = sections.find(s => s.id !== editingId && s.display_order === newOrder);
    if (!conflict) return;
    const { error } = await sb.from("home_feed_sections").update({ display_order: oldOrder }).eq("id", conflict.id);
    if (error) throw new Error(error.message || error.error || JSON.stringify(error));
  };

  const moveSection = async (index, dir) => {
    const other = index + dir;
    if (other < 0 || other >= sections.length) return;
    const a = sections[index], b = sections[other];
    await Promise.all([
      sb.from("home_feed_sections").update({ display_order: b.display_order }).eq("id", a.id),
      sb.from("home_feed_sections").update({ display_order: a.display_order }).eq("id", b.id),
    ]);
    await fetchSections();
  };

  // pickedProductIds is non-null only for mode === "manual" — when present,
  // home_feed_section_items is fully replaced with this list (in order) so
  // the section row and its hand-picked products save as one atomic-feeling
  // action from the single modal instead of two separate steps.
  const saveSection = async (payload, pickedProductIds) => {
    let sectionId = sectionModal?.id;
    if (sectionId) {
      const { error } = await sb.from("home_feed_sections").update(payload).eq("id", sectionId);
      if (error) throw new Error(error.message || error.error || JSON.stringify(error));
    } else {
      const { data, error } = await sb.from("home_feed_sections").insert(payload).select("id").single();
      if (error) throw new Error(error.message || error.error || JSON.stringify(error));
      sectionId = data.id;
    }

    if (pickedProductIds) {
      const { error: delErr } = await sb.from("home_feed_section_items").delete().eq("section_id", sectionId);
      if (delErr) throw new Error(delErr.message || delErr.error || JSON.stringify(delErr));
      if (pickedProductIds.length > 0) {
        const rows = pickedProductIds.map((product_id, i) => ({ section_id: sectionId, product_id, position: i }));
        const { error: insErr } = await sb.from("home_feed_section_items").insert(rows);
        if (insErr) throw new Error(insErr.message || insErr.error || JSON.stringify(insErr));
      }
    }

    await fetchSections();
  };

  const toggleActive = async (section) => {
    const { error } = await sb.from("home_feed_sections").update({ is_active: !section.is_active }).eq("id", section.id);
    if (!error) setSections(ss => ss.map(s => s.id === section.id ? { ...s, is_active: !s.is_active } : s));
  };

  const handleDelete = async () => {
    if (!deleteTarget) return;
    await sb.from("home_feed_sections").delete().eq("id", deleteTarget.id);
    setDeleteTarget(null);
    await fetchSections();
  };

  const nextOrder = sections.length > 0 ? Math.max(...sections.map(s => s.display_order)) + 1 : 0;

  return (
    <div className="page" data-screen-label="Discovery">
      <div className="page-h">
        <div>
          <div className="ts">{loading ? "Loading…" : `${sections.length} sections · ${sections.filter(s => s.is_active).length} active`}</div>
          <h1>Home Feed Sections</h1>
        </div>
        <div className="acts">
          <button className="btn primary" onClick={() => setSectionModal("new")}>
            <I.plus size={12} /> New section
          </button>
        </div>
      </div>

      <div className="panel">
        <div className="panel-h">
          <span>Sections</span>
          <span className="meta">"Made just for you" rows on the home feed</span>
        </div>
        {loading ? (
          <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>Loading…</div>
        ) : sections.length === 0 ? (
          <div style={{ padding: 24, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>No sections yet</div>
        ) : (
          <div className="t-wrap">
            <table className="t">
              <thead>
                <tr>
                  <th style={{ width: 50 }}></th>
                  <th>Title</th>
                  <th>Source</th>
                  <th style={{ textAlign: "center" }}>Limit</th>
                  <th style={{ textAlign: "center" }}>Active</th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                {sections.map((s, i) => (
                  <tr key={s.id}>
                    <td>
                      <div style={{ display: "flex", flexDirection: "column", gap: 1 }}>
                        <button className="btn ghost" style={{ height: 16, width: 20, padding: 0, display: "grid", placeItems: "center" }} disabled={i === 0} onClick={() => moveSection(i, -1)}><I.arrowUp size={9} /></button>
                        <button className="btn ghost" style={{ height: 16, width: 20, padding: 0, display: "grid", placeItems: "center" }} disabled={i === sections.length - 1} onClick={() => moveSection(i, 1)}><I.arrowDn size={9} /></button>
                      </div>
                    </td>
                    <td>
                      <div style={{ fontWeight: 500, fontSize: 12.5 }}>{s.title}</div>
                      <div style={{ fontSize: 10.5, color: "var(--ink-3)", fontFamily: "var(--font-mono)" }}>{s.section_key}{s.is_faves ? " · faves style" : ""}</div>
                    </td>
                    <td>
                      <span className="chip" style={{ fontSize: 11 }}>
                        {MODE_LABELS[s.mode] || s.mode}
                        {s.mode === "auto_category" && s.category_slug ? ` · ${s.category_slug}` : ""}
                      </span>
                    </td>
                    <td style={{ textAlign: "center" }}><span className="num">{s.product_limit}</span></td>
                    <td style={{ textAlign: "center" }}>
                      <span
                        className={`chip dot ${s.is_active ? "pos" : "warn"}`}
                        style={{ cursor: "pointer", fontSize: 10 }}
                        onClick={() => toggleActive(s)}
                      >
                        {s.is_active ? "on" : "off"}
                      </span>
                    </td>
                    <td>
                      <div style={{ display: "flex", gap: 4, justifyContent: "flex-end" }}>
                        <button
                          className="btn ghost"
                          style={{ height: 22, width: 22, padding: 0, display: "grid", placeItems: "center" }}
                          onClick={() => setSectionModal(s)}
                        ><I.edit size={10} /></button>
                        <button
                          className="btn ghost"
                          style={{ height: 22, width: 22, padding: 0, display: "grid", placeItems: "center", color: "var(--neg)" }}
                          onClick={() => setDeleteTarget(s)}
                        ><I.trash size={10} /></button>
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>

      {sectionModal && (
        <SectionModal
          initial={sectionModal === "new" ? null : sectionModal}
          categories={categories}
          nextOrder={nextOrder}
          onSave={saveSection}
          onClose={() => setSectionModal(null)}
        />
      )}

      {deleteTarget && (
        <DisModal title="Confirm delete" onClose={() => setDeleteTarget(null)}>
          <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
            <div style={{ fontSize: 13, color: "var(--ink-2)" }}>
              Delete <strong>{deleteTarget.title}</strong>? This removes it from the home feed
              {deleteTarget.mode === "manual" && " along with its hand-picked product list"}. This cannot be undone.
            </div>
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
              <button className="btn ghost" onClick={() => setDeleteTarget(null)}>Cancel</button>
              <button
                className="btn"
                style={{ background: "var(--neg)", color: "#fff", borderColor: "var(--neg)" }}
                onClick={handleDelete}
              >Delete</button>
            </div>
          </div>
        </DisModal>
      )}
    </div>
  );
};

window.DiscoveryPage = DiscoveryPage;
