/* admin.jsx — the content panel at /admin.

   The panel builds itself from window.ADMIN_SCHEMA (schema.js): every group,
   section and field you see here is described there. Nothing in this file knows
   about the site's own structure, so adding an editable field never means
   touching this file.

   Talks to Supabase directly (auth + RLS) and saves through saveContent(). */

const { useState: useAdminState, useEffect: useAdminEffect, useRef: useAdminRef } = React;

function aClone(x){ return JSON.parse(JSON.stringify(x)); }

/* ─────────── path helpers (immutable get/set on the draft) ─────────── */
function getAt(obj, path){
  if (!path) return obj;
  return String(path).split(".").reduce(function (node, k) { return node == null ? node : node[k]; }, obj);
}
function setAt(obj, path, value){
  if (!path) return value;
  const parts = String(path).split(".");
  const out = Array.isArray(obj) ? obj.slice() : Object.assign({}, obj);
  let node = out;
  for (let i = 0; i < parts.length - 1; i++){
    const k = parts[i];
    const child = node[k];
    node[k] = Array.isArray(child) ? child.slice() : Object.assign({}, child || {});
    node = node[k];
  }
  node[parts[parts.length - 1]] = value;
  return out;
}
function fieldPath(section, key){ return section.path ? section.path + "." + key : key; }

/* ─────────── tiny style helpers ─────────── */
function inputStyle(palette){
  return { width:"100%", padding:"11px 13px", border:`1px solid ${palette.line}`, borderRadius:8,
    background: palette.bg, color: palette.ink, fontSize:14.5, fontFamily:"inherit", lineHeight:1.5 };
}
function miniBtn(palette){
  return { padding:"7px 11px", border:`1px solid ${palette.line}`, borderRadius:7, background: palette.bg,
    color: palette.ink, fontSize:12.5, fontWeight:600, cursor:"pointer" };
}
function addBtn(palette){
  return { padding:"13px 18px", border:`1px dashed ${palette.accent}`, borderRadius:9, background:"transparent",
    color: palette.accent, fontSize:14.5, fontWeight:700, cursor:"pointer", width:"100%", marginTop:6 };
}
function solidBtn(palette){
  return { padding:"11px 22px", border:0, borderRadius:8, background: palette.accent, color: palette.bg,
    fontSize:14, fontWeight:700, cursor:"pointer" };
}

/* ═══════════════ media picker ═══════════════ */
/* one shared gallery of everything already uploaded + the pictures that ship
   with the site, so a picture can be re-used without hunting for the file */
function MediaPicker({ palette, kind, onPick, onClose }){
  const [items, setItems] = useAdminState(null);
  const [busy, setBusy] = useAdminState(false);
  const [err, setErr] = useAdminState("");

  useAdminEffect(() => {
    let live = true;
    window.listMedia().then((list) => { if (live) setItems(list); }).catch(() => live && setItems([]));
    return () => { live = false; };
  }, []);

  const upload = (e) => {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    setBusy(true); setErr("");
    window.uploadMedia(f, kind === "video" ? "uploads" : "site")
      .then((url) => { onPick(url); onClose(); })
      .catch((ex) => setErr(ex.message || "שגיאת העלאה"))
      .finally(() => { setBusy(false); e.target.value = ""; });
  };

  const isVideo = (u) => /\.(mp4|webm|mov|m4v)(\?|$)/i.test(u || "");
  const uploaded = (items || []).filter((m) => (kind === "video" ? isVideo(m.url) : !isVideo(m.url)));
  const builtin = kind === "video" ? [] : (window.BUILTIN_MEDIA || []);

  const tile = (url, name, key) => (
    <button key={key} type="button" onClick={() => { onPick(url); onClose(); }}
      title={name}
      style={{ padding:0, border:`1px solid ${palette.line}`, borderRadius:8, overflow:"hidden", background: palette.bg, cursor:"pointer", textAlign:"start" }}>
      {kind === "video"
        ? <div style={{ height:92, display:"grid", placeItems:"center", fontSize:26, background: palette.surface }}>🎬</div>
        : <img src={url} alt="" style={{ width:"100%", height:92, objectFit:"cover", display:"block", background: palette.surface }}/>}
      <div style={{ padding:"6px 8px", fontSize:11, color: palette.ink2, whiteSpace:"nowrap", overflow:"hidden", textOverflow:"ellipsis", direction:"ltr" }}>{name}</div>
    </button>
  );

  return (
    <div onClick={onClose} style={{ position:"fixed", inset:0, zIndex:100, background:"rgba(20,16,12,.55)", display:"grid", placeItems:"center", padding:18 }}>
      <div onClick={(e)=>e.stopPropagation()} style={{ width:"100%", maxWidth:760, maxHeight:"84vh", overflow:"auto", background: palette.bg, border:`1px solid ${palette.line}`, borderRadius:12, padding:"22px 24px" }}>
        <div style={{ display:"flex", justifyContent:"space-between", alignItems:"center", gap:14, marginBottom:16 }}>
          <div className="display" style={{ fontSize:20, fontWeight:700 }}>{kind === "video" ? "בחירת סרטון" : "בחירת תמונה"}</div>
          <button type="button" onClick={onClose} style={miniBtn(palette)}>סגירה</button>
        </div>

        <label style={{ ...solidBtn(palette), display:"inline-block", marginBottom:18 }}>
          {busy ? "מעלה…" : (kind === "video" ? "העלאת סרטון מהמחשב" : "העלאת תמונה מהמחשב")}
          <input type="file" accept={kind === "video" ? "video/*" : "image/*"} onChange={upload} disabled={busy} style={{ display:"none" }}/>
        </label>
        {err && <div style={{ color:"#c0392b", fontSize:13, marginBottom:12 }}>{err}</div>}

        {items === null && <div style={{ color: palette.ink2, fontSize:14 }}>טוען את הגלריה…</div>}

        {items !== null && uploaded.length > 0 && (
          <>
            <div style={{ fontSize:12.5, fontWeight:700, color: palette.ink2, margin:"0 0 10px" }}>קבצים שהעליתם</div>
            <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(120px, 1fr))", gap:10, marginBottom:20 }}>
              {uploaded.map((m, i) => tile(m.url, m.name, "u" + i))}
            </div>
          </>
        )}

        {builtin.length > 0 && (
          <>
            <div style={{ fontSize:12.5, fontWeight:700, color: palette.ink2, margin:"0 0 10px" }}>תמונות שמגיעות עם האתר</div>
            <div style={{ display:"grid", gridTemplateColumns:"repeat(auto-fill, minmax(120px, 1fr))", gap:10 }}>
              {builtin.map((u, i) => tile(u, u.split("/").pop(), "b" + i))}
            </div>
          </>
        )}

        {items !== null && !uploaded.length && !builtin.length && (
          <div style={{ color: palette.ink2, fontSize:14 }}>עדיין לא הועלו קבצים. אפשר להעלות קובץ מהמחשב בכפתור למעלה.</div>
        )}
      </div>
    </div>
  );
}

/* ═══════════════ field renderers ═══════════════ */
function FieldShell({ palette, label, hint, children, id }){
  return (
    <div style={{ marginBottom:16 }} data-field-id={id}>
      <div style={{ fontSize:13, color: palette.ink, marginBottom: hint ? 3 : 6, fontWeight:700 }}>{label}</div>
      {hint && <div style={{ fontSize:12, color: palette.ink2, marginBottom:7, lineHeight:1.55 }}>{hint}</div>}
      {children}
    </div>
  );
}

function MediaInput({ palette, field, value, onChange }){
  const [picking, setPicking] = useAdminState(false);
  const [busy, setBusy] = useAdminState(false);
  const [err, setErr] = useAdminState("");
  const kind = field.type === "video" ? "video" : "image";
  const preview = kind === "image" && value ? (window.productImageSrc ? window.productImageSrc(value) : value) : null;

  const quickUpload = (e) => {
    const f = e.target.files && e.target.files[0];
    if (!f) return;
    setBusy(true); setErr("");
    window.uploadMedia(f, kind === "video" ? "uploads" : "site")
      .then(onChange).catch((ex) => setErr(ex.message || "שגיאת העלאה"))
      .finally(() => { setBusy(false); e.target.value = ""; });
  };

  return (
    <>
      <div style={{ display:"flex", gap:10, alignItems:"center", flexWrap:"wrap" }}>
        <div style={{ width:58, height:58, borderRadius:8, border:`1px solid ${palette.line}`, background: palette.surface, display:"grid", placeItems:"center", overflow:"hidden", flexShrink:0 }}>
          {preview ? <img src={preview} alt="" style={{ width:"100%", height:"100%", objectFit:"cover" }}/>
            : <span style={{ fontSize:20, opacity:.5 }}>{kind === "video" ? "🎬" : "🖼"}</span>}
        </div>
        <button type="button" onClick={()=>setPicking(true)} style={{ ...solidBtn(palette), padding:"10px 18px" }}>
          {kind === "video" ? "בחירת סרטון" : "בחירת תמונה"}
        </button>
        <label style={{ ...miniBtn(palette), padding:"10px 14px" }}>
          {busy ? "מעלה…" : "העלאה מהירה"}
          <input type="file" accept={kind === "video" ? "video/*" : "image/*"} onChange={quickUpload} disabled={busy} style={{ display:"none" }}/>
        </label>
        {value && <button type="button" onClick={()=>onChange("")} style={{ ...miniBtn(palette), color:"#c0392b", borderColor:"#e0b4ad" }}>הסרה</button>}
      </div>
      <input value={value == null ? "" : value} onChange={(e)=>onChange(e.target.value)} dir="ltr" placeholder="או הדביקו כאן כתובת קובץ"
        style={{ ...inputStyle(palette), marginTop:8, fontSize:12.5, padding:"8px 11px", color: palette.ink2 }}/>
      {err && <div style={{ color:"#c0392b", fontSize:12, marginTop:5 }}>{err}</div>}
      {picking && <MediaPicker palette={palette} kind={kind} onPick={onChange} onClose={()=>setPicking(false)}/>}
    </>
  );
}

function Toggle({ palette, value, onChange }){
  const on = value !== false;
  return (
    <button type="button" onClick={()=>onChange(!on)}
      style={{ display:"inline-flex", alignItems:"center", gap:10, background:"transparent", border:0, cursor:"pointer", padding:0 }}>
      <span style={{ width:46, height:26, borderRadius:999, background: on ? palette.accent : palette.line, position:"relative", transition:"background .2s" }}>
        <span style={{ position:"absolute", top:3, insetInlineStart: on ? 23 : 3, width:20, height:20, borderRadius:999, background:"#fff", transition:"inset-inline-start .2s", boxShadow:"0 1px 3px rgba(0,0,0,.25)" }}/>
      </span>
      <span style={{ fontSize:13.5, fontWeight:700, color: on ? palette.accent : palette.ink2 }}>{on ? "פעיל" : "כבוי"}</span>
    </button>
  );
}

function Field({ palette, field, value, onChange, idPrefix }){
  const id = (idPrefix || "") + field.k;
  const base = inputStyle(palette);

  if (field.type === "list") {
    return <ListEditor palette={palette} field={field} list={Array.isArray(value) ? value : []} onChange={onChange} idPrefix={idPrefix}/>;
  }

  let control;
  switch (field.type) {
    case "textarea":
      control = <textarea value={value == null ? "" : value} rows={field.rows || 3} dir={field.dir}
        onChange={(e)=>onChange(e.target.value)} style={{ ...base, resize:"vertical" }}/>;
      break;
    case "lines":
      control = <textarea value={Array.isArray(value) ? value.join("\n") : (value || "")} rows={field.rows || 4} dir={field.dir}
        onChange={(e)=>onChange(e.target.value.split("\n").map((s)=>s.replace(/\s+$/,"")))}
        style={{ ...base, resize:"vertical", lineHeight:1.7 }}/>;
      break;
    case "tags":
      control = <input value={Array.isArray(value) ? value.join(", ") : (value || "")} dir={field.dir}
        onChange={(e)=>onChange(e.target.value.split(",").map((s)=>s.trim()).filter(Boolean))} style={base}/>;
      break;
    case "number":
      control = <input type="number" step="0.01" value={value == null ? "" : value} dir="ltr"
        onChange={(e)=>onChange(e.target.value === "" ? "" : Number(e.target.value))} style={base}/>;
      break;
    case "toggle":
      control = <Toggle palette={palette} value={value} onChange={onChange}/>;
      break;
    case "select":
      control = (
        <select value={value == null ? "" : value} onChange={(e)=>onChange(e.target.value)} style={base}>
          {(field.options || []).map((o)=><option key={o.value} value={o.value}>{o.label}</option>)}
        </select>
      );
      break;
    case "image":
    case "video":
      control = <MediaInput palette={palette} field={field} value={value} onChange={onChange}/>;
      break;
    case "link":
      control = (
        <>
          <input value={value == null ? "" : value} dir="ltr" list="site-paths" onChange={(e)=>onChange(e.target.value)} style={base}/>
          {value && /^\//.test(value) && (
            <a href={value} target="_blank" rel="noopener" style={{ fontSize:12, color: palette.accent, fontWeight:700, marginTop:5, display:"inline-block" }}>
              בדיקת הקישור ↗
            </a>
          )}
        </>
      );
      break;
    default:
      control = <input type="text" value={value == null ? "" : value} dir={field.dir}
        onChange={(e)=>onChange(e.target.value)} style={base}/>;
  }

  return <FieldShell palette={palette} label={field.label} hint={field.hint} id={id}>{control}</FieldShell>;
}

/* ═══════════════ repeatable list editor ═══════════════ */
function ListEditor({ palette, field, list, onChange, idPrefix }){
  const meta = field.item || {};
  const [open, setOpen] = useAdminState(field.startOpen ? -1 : -1);

  const set = (i, key, v) => { const next = aClone(list); next[i] = Object.assign({}, next[i], { [key]: v }); onChange(next); };
  const move = (i, d) => {
    const j = i + d; if (j < 0 || j >= list.length) return;
    const next = aClone(list); const t = next[i]; next[i] = next[j]; next[j] = t;
    onChange(next); setOpen(open === i ? j : open === j ? i : open);
  };
  const remove = (i) => {
    const name = (list[i] && list[i][meta.titleKey]) || "הפריט";
    if (!window.confirm("למחוק את " + name + "? אי אפשר לבטל אחרי שמירה.")) return;
    const next = aClone(list); next.splice(i, 1); onChange(next); setOpen(-1);
  };
  const duplicate = (i) => {
    const next = aClone(list);
    const copy = aClone(next[i]);
    if (copy.id) copy.id = "p" + Date.now();
    if (copy.slug) copy.slug = copy.slug + "-copy";
    if (copy[meta.titleKey]) copy[meta.titleKey] = copy[meta.titleKey] + " (עותק)";
    next.splice(i + 1, 0, copy); onChange(next); setOpen(i + 1);
  };
  const add = () => {
    const blank = aClone(meta.blank || {});
    if (blank.id) blank.id = "p" + Date.now();
    if (blank.slug) blank.slug = blank.slug + "-" + Date.now();
    onChange([...aClone(list), blank]); setOpen(list.length);
  };

  return (
    <div style={{ marginBottom:16 }}>
      <div style={{ display:"flex", alignItems:"baseline", justifyContent:"space-between", gap:12, marginBottom:8 }}>
        <div style={{ fontSize:13, color: palette.ink, fontWeight:700 }}>{field.label}</div>
        <div style={{ fontSize:12, color: palette.ink2 }}>{list.length} פריטים</div>
      </div>
      {field.hint && <div style={{ fontSize:12, color: palette.ink2, marginBottom:9, lineHeight:1.55 }}>{field.hint}</div>}

      {list.map((item, i) => {
        const isOpen = open === i;
        const thumb = meta.thumbKey ? window.productImageSrc(item[meta.thumbKey]) : null;
        const sub = meta.meta ? meta.meta(item) : (meta.subKey ? String(item[meta.subKey] || "").slice(0, 70) : "");
        return (
          <div key={i} style={{ border:`1px solid ${isOpen ? palette.accent : palette.line}`, borderRadius:9, marginBottom:9, background: isOpen ? palette.surface : palette.bg, overflow:"hidden" }}>
            <div style={{ display:"flex", alignItems:"center", gap:10, padding:"10px 12px" }}>
              <button type="button" onClick={()=>setOpen(isOpen ? -1 : i)}
                style={{ flex:1, display:"flex", alignItems:"center", gap:11, background:"transparent", border:0, cursor:"pointer", textAlign:"start", color: palette.ink, minWidth:0, padding:0 }}>
                <span style={{ color: palette.accent, fontSize:12, transform: isOpen ? "rotate(90deg)" : "none", transition:"transform .2s" }}>▶</span>
                {meta.thumbKey && (
                  thumb ? <img src={thumb} alt="" style={{ width:38, height:38, objectFit:"cover", borderRadius:6, border:`1px solid ${palette.line}`, flexShrink:0 }}/>
                        : <span style={{ width:38, height:38, borderRadius:6, border:`1px solid ${palette.line}`, display:"grid", placeItems:"center", flexShrink:0, opacity:.5 }}>🖼</span>
                )}
                <span style={{ minWidth:0 }}>
                  <span className="display" style={{ display:"block", fontSize:15, fontWeight:700, whiteSpace:"nowrap", overflow:"hidden", textOverflow:"ellipsis" }}>
                    {item[meta.titleKey] || meta.newLabel || "פריט"}
                  </span>
                  {sub && <span style={{ display:"block", fontSize:12, color: palette.ink2, marginTop:2, whiteSpace:"nowrap", overflow:"hidden", textOverflow:"ellipsis" }}>{sub}</span>}
                </span>
              </button>
              <div style={{ display:"flex", gap:5, flexShrink:0 }}>
                <button type="button" title="העברה למעלה" onClick={()=>move(i,-1)} disabled={i===0} style={{ ...miniBtn(palette), opacity: i===0 ? .35 : 1 }}>↑</button>
                <button type="button" title="העברה למטה" onClick={()=>move(i,1)} disabled={i===list.length-1} style={{ ...miniBtn(palette), opacity: i===list.length-1 ? .35 : 1 }}>↓</button>
              </div>
            </div>
            {isOpen && (
              <div style={{ padding:"14px 16px 16px", borderTop:`1px solid ${palette.line}` }}>
                {(meta.fields || []).map((f) => (
                  <Field key={f.k} palette={palette} field={f} idPrefix={(idPrefix||"") + field.k + "-" + i + "-"}
                    value={item[f.k]} onChange={(v)=>set(i, f.k, v)}/>
                ))}
                <div style={{ display:"flex", gap:8, flexWrap:"wrap", marginTop:6, paddingTop:12, borderTop:`1px solid ${palette.line}` }}>
                  {meta.linkKey && item[meta.linkKey] && (
                    <a href={(meta.linkPrefix || "") + item[meta.linkKey]} target="_blank" rel="noopener" style={{ ...miniBtn(palette), color: palette.accent, textDecoration:"none" }}>
                      צפייה בעמוד ↗
                    </a>
                  )}
                  <button type="button" onClick={()=>duplicate(i)} style={miniBtn(palette)}>שכפול</button>
                  <button type="button" onClick={()=>remove(i)} style={{ ...miniBtn(palette), color:"#c0392b", borderColor:"#e0b4ad" }}>מחיקה</button>
                </div>
              </div>
            )}
          </div>
        );
      })}
      <button type="button" onClick={add} style={addBtn(palette)}>+ הוספת {meta.newLabel || "פריט"}</button>
    </div>
  );
}

/* ═══════════════ one section card ═══════════════ */
function SectionCard({ palette, section, draft, setDraft, open, onToggle, highlight }){
  const restore = () => {
    if (!window.confirm("להחזיר את ״" + section.label + "״ לתוכן המקורי? השינויים שלכם בקטע הזה יימחקו.")) return;
    setDraft((d) => {
      let next = d;
      if (section.flat) {
        section.fields.forEach((f) => {
          const def = window.__defaultAt(f.k);
          if (def !== undefined) next = setAt(next, f.k, def);
        });
      } else {
        const def = window.__defaultAt(section.path);
        if (def !== undefined) next = setAt(next, section.path, def);
      }
      return next;
    });
  };

  return (
    <section id={"sec-" + section.id}
      style={{ border:`1px solid ${highlight ? palette.accent : palette.line}`, borderRadius:12, marginBottom:14,
        background: palette.bg, overflow:"hidden", boxShadow: highlight ? `0 0 0 3px ${palette.accent}22` : "none" }}>
      <button type="button" onClick={onToggle}
        style={{ width:"100%", display:"flex", alignItems:"center", gap:12, padding:"16px 18px", background: open ? palette.surface : "transparent",
          border:0, borderBottom: open ? `1px solid ${palette.line}` : "none", cursor:"pointer", textAlign:"start", color: palette.ink }}>
        <span style={{ color: palette.accent, fontSize:13, transform: open ? "rotate(90deg)" : "none", transition:"transform .2s", flexShrink:0 }}>▶</span>
        <span style={{ flex:1, minWidth:0 }}>
          <span className="display" style={{ display:"block", fontSize:17.5, fontWeight:700 }}>{section.label}</span>
          {section.where && !open && (
            <span style={{ display:"block", fontSize:12.5, color: palette.ink2, marginTop:3, overflow:"hidden", textOverflow:"ellipsis", whiteSpace:"nowrap" }}>{section.where}</span>
          )}
        </span>
      </button>

      {open && (
        <div style={{ padding:"18px 20px 20px" }}>
          {section.where && (
            <div style={{ background: palette.surface, borderInlineStart:`3px solid ${palette.accent}`, borderRadius:8, padding:"12px 14px", marginBottom:18, fontSize:13, lineHeight:1.65, color: palette.ink2 }}>
              <strong style={{ color: palette.accent }}>איפה זה מופיע: </strong>{section.where}
            </div>
          )}
          {section.fields.map((f) => (
            <Field key={f.k} palette={palette} field={f} idPrefix={section.id + "-"}
              value={getAt(draft, fieldPath(section, f.k))}
              onChange={(v)=>setDraft((d)=>setAt(d, fieldPath(section, f.k), v))}/>
          ))}
          <div style={{ display:"flex", gap:10, flexWrap:"wrap", marginTop:6, paddingTop:14, borderTop:`1px solid ${palette.line}` }}>
            {section.view && (
              <a href={section.view} target="_blank" rel="noopener" style={{ ...miniBtn(palette), color: palette.accent, textDecoration:"none" }}>
                צפייה בעמוד ↗
              </a>
            )}
            <button type="button" onClick={restore} style={miniBtn(palette)}>החזרה לתוכן המקורי</button>
          </div>
        </div>
      )}
    </section>
  );
}

/* ═══════════════ search across every field label ═══════════════ */
function buildSearchIndex(){
  const out = [];
  (window.ADMIN_SCHEMA || []).forEach((group) => {
    group.sections.forEach((section) => {
      out.push({ group, section, label: section.label, kind: "section", text: (section.label + " " + (section.where || "")) });
      (section.fields || []).forEach((f) => {
        out.push({ group, section, label: f.label, kind: "field", text: f.label + " " + (f.hint || "") });
        if (f.type === "list" && f.item) {
          (f.item.fields || []).forEach((sf) => {
            out.push({ group, section, label: f.label + " › " + sf.label, kind: "field", text: sf.label + " " + (sf.hint || "") });
          });
        }
      });
    });
  });
  return out;
}

/* ═══════════════ dashboard ═══════════════ */
function AdminDashboard({ palette, onLogout }){
  const schema = window.ADMIN_SCHEMA || [];
  const [draft, setDraft] = useAdminState(() => aClone(window.__currentContentDoc()));
  const [groupId, setGroupId] = useAdminState(schema.length ? schema[0].id : "");
  const [openSection, setOpenSection] = useAdminState(schema.length && schema[0].sections.length ? schema[0].sections[0].id : "");
  const [status, setStatus] = useAdminState("");
  const [saving, setSaving] = useAdminState(false);
  const [dirty, setDirty] = useAdminState(false);
  const [query, setQuery] = useAdminState("");
  const [navOpen, setNavOpen] = useAdminState(false);
  const [highlight, setHighlight] = useAdminState("");
  const index = useAdminRef(null);
  if (!index.current) index.current = buildSearchIndex();

  const group = schema.find((g) => g.id === groupId) || schema[0];

  // every change marks the draft dirty; the browser warns before leaving
  const editDraft = (fn) => { setDraft(fn); setDirty(true); setStatus(""); };

  useAdminEffect(() => {
    const warn = (e) => { if (dirty) { e.preventDefault(); e.returnValue = ""; } };
    window.addEventListener("beforeunload", warn);
    return () => window.removeEventListener("beforeunload", warn);
  }, [dirty]);

  const save = () => {
    setSaving(true); setStatus("");
    window.saveContent(aClone(draft))
      .then(() => { setStatus("נשמר ופורסם באתר ✓"); setDirty(false); })
      .catch((ex) => setStatus("שגיאה בשמירה: " + (ex.message || "")))
      .finally(() => setSaving(false));
  };

  // Ctrl/Cmd+S saves too
  useAdminEffect(() => {
    const onKey = (e) => {
      if ((e.ctrlKey || e.metaKey) && String(e.key).toLowerCase() === "s") { e.preventDefault(); if (dirty && !saving) save(); }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  });

  const reset = () => {
    if (!window.confirm("לבטל את כל השינויים שלא נשמרו?")) return;
    setDraft(aClone(window.__currentContentDoc())); setDirty(false); setStatus("השינויים בוטלו");
  };

  const jumpTo = (entry) => {
    setGroupId(entry.group.id);
    setOpenSection(entry.section.id);
    setQuery("");
    setNavOpen(false);
    setHighlight(entry.section.id);
    setTimeout(() => {
      const el = document.getElementById("sec-" + entry.section.id);
      if (el) el.scrollIntoView({ behavior:"smooth", block:"start" });
      setTimeout(() => setHighlight(""), 2200);
    }, 60);
  };

  const q = query.trim();
  const results = q.length > 1
    ? index.current.filter((e) => e.text.indexOf(q) !== -1).slice(0, 14)
    : [];

  const navItem = (g) => (
    <button key={g.id} type="button"
      onClick={() => { setGroupId(g.id); setOpenSection(g.sections.length ? g.sections[0].id : ""); setNavOpen(false); window.scrollTo({ top:0, behavior:"smooth" }); }}
      style={{ display:"flex", alignItems:"center", gap:10, width:"100%", textAlign:"start", padding:"12px 14px", borderRadius:9,
        border:0, cursor:"pointer", marginBottom:4, fontSize:14.5, fontWeight:700,
        background: g.id === groupId ? palette.ink : "transparent", color: g.id === groupId ? palette.bg : palette.ink }}>
      <span style={{ fontSize:17 }}>{g.icon}</span>{g.label}
    </button>
  );

  return (
    <div style={{ minHeight:"100vh", background: palette.surface }}>
      {/* site paths for the link autocomplete */}
      <datalist id="site-paths">
        {["/", "/book", "/about", "/products", "/bat-mitzvah", "/workshops", "/group", "/sample", "/faq", "/contact", "/blog", "/terms", "/privacy", "/shipping", "/refund", "/accessibility"].map((p) => <option key={p} value={p}/>)}
      </datalist>

      {/* top bar */}
      <div style={{ position:"sticky", top:0, zIndex:20, background: palette.bg, borderBottom:`1px solid ${palette.line}`, padding:"11px 18px" }}>
        <div style={{ display:"flex", alignItems:"center", justifyContent:"space-between", gap:12, flexWrap:"wrap", maxWidth:1240, margin:"0 auto" }}>
          <div style={{ display:"flex", alignItems:"center", gap:10 }}>
            <button type="button" className="adm-burger" onClick={()=>setNavOpen((o)=>!o)} style={{ ...miniBtn(palette), display:"none", fontSize:16, padding:"8px 12px" }}>☰</button>
            <div className="display" style={{ fontSize:18, fontWeight:700 }}>ניהול תוכן האתר</div>
            {dirty
              ? <span style={{ fontSize:12, color: palette.bg, fontWeight:700, background: palette.accent, padding:"4px 11px", borderRadius:999 }}>יש שינויים שלא נשמרו</span>
              : <span style={{ fontSize:12, color: palette.ink2 }}>הכול שמור</span>}
          </div>
          <div style={{ display:"flex", alignItems:"center", gap:9, flexWrap:"wrap" }}>
            {status && <span style={{ fontSize:13, fontWeight:700, color: status.indexOf("שגיאה") === 0 ? "#c0392b" : palette.accent }}>{status}</span>}
            <a href="/" target="_blank" rel="noopener" style={{ ...miniBtn(palette), textDecoration:"none", padding:"9px 14px" }}>צפייה באתר ↗</a>
            <button type="button" onClick={reset} disabled={!dirty} style={{ ...miniBtn(palette), padding:"9px 14px", opacity: dirty ? 1 : .45, cursor: dirty ? "pointer" : "default" }}>ביטול שינויים</button>
            <button type="button" onClick={save} disabled={saving || !dirty}
              style={{ ...solidBtn(palette), opacity: (saving || !dirty) ? .55 : 1, cursor: (saving || !dirty) ? "default" : "pointer" }}>
              {saving ? "שומר…" : "שמירה ופרסום"}
            </button>
            <button type="button" onClick={onLogout} style={{ fontSize:13, color: palette.ink2, border:0, background:"transparent", cursor:"pointer" }}>יציאה</button>
          </div>
        </div>
      </div>

      <div className="adm-body" style={{ maxWidth:1240, margin:"0 auto", padding:"20px 18px 90px", display:"grid", gridTemplateColumns:"250px 1fr", gap:24, alignItems:"start" }}>
        {/* sidebar */}
        <aside className={"adm-nav" + (navOpen ? " open" : "")} style={{ position:"sticky", top:74, background: palette.bg, border:`1px solid ${palette.line}`, borderRadius:12, padding:"14px 12px" }}>
          <div style={{ position:"relative", marginBottom:12 }}>
            <input value={query} onChange={(e)=>setQuery(e.target.value)} placeholder="חיפוש… (למשל: מחיר, טלפון)"
              style={{ ...inputStyle(palette), fontSize:13.5, padding:"10px 12px" }}/>
            {results.length > 0 && (
              <div style={{ position:"absolute", insetInlineStart:0, insetInlineEnd:0, top:"calc(100% + 6px)", zIndex:30,
                background: palette.bg, border:`1px solid ${palette.line}`, borderRadius:9, boxShadow:"0 18px 40px -18px rgba(0,0,0,.35)", maxHeight:340, overflow:"auto" }}>
                {results.map((e, i) => (
                  <button key={i} type="button" onClick={()=>jumpTo(e)}
                    style={{ display:"block", width:"100%", textAlign:"start", padding:"9px 12px", background:"transparent", border:0, borderBottom:`1px solid ${palette.line}`, cursor:"pointer", color: palette.ink }}>
                    <div style={{ fontSize:13.5, fontWeight:700 }}>{e.label}</div>
                    <div style={{ fontSize:11.5, color: palette.ink2, marginTop:2 }}>{e.group.icon} {e.group.label} › {e.section.label}</div>
                  </button>
                ))}
              </div>
            )}
          </div>
          {schema.map(navItem)}
        </aside>

        {/* sections */}
        <main style={{ minWidth:0 }}>
          {group && (
            <>
              <div style={{ marginBottom:16 }}>
                <h1 className="display" style={{ fontSize:26, fontWeight:700, margin:"0 0 6px" }}>{group.icon} {group.label}</h1>
                {group.blurb && <p style={{ fontSize:14, color: palette.ink2, lineHeight:1.65, margin:0, maxWidth:"70ch" }}>{group.blurb}</p>}
              </div>
              {group.sections.map((section) => (
                <SectionCard key={section.id} palette={palette} section={section} draft={draft} setDraft={editDraft}
                  open={openSection === section.id} highlight={highlight === section.id}
                  onToggle={()=>setOpenSection(openSection === section.id ? "" : section.id)}/>
              ))}
            </>
          )}
          <div style={{ marginTop:22, padding:"16px 18px", background: palette.bg, border:`1px solid ${palette.line}`, borderRadius:12, fontSize:13.5, color: palette.ink2, lineHeight:1.7 }}>
            שינויים נשמרים רק אחרי לחיצה על <strong style={{ color: palette.ink }}>שמירה ופרסום</strong> (או Ctrl+S). מיד אחרי השמירה הם עולים לאתר החי.
          </div>
        </main>
      </div>

      {/* mobile save bar */}
      {dirty && (
        <div className="adm-savebar" style={{ position:"fixed", insetInlineStart:0, insetInlineEnd:0, bottom:0, zIndex:25, display:"none",
          background: palette.bg, borderTop:`1px solid ${palette.line}`, padding:"10px 16px calc(10px + env(safe-area-inset-bottom, 0px))", gap:10, alignItems:"center" }}>
          <span style={{ flex:1, fontSize:13, fontWeight:700, color: palette.accent }}>יש שינויים שלא נשמרו</span>
          <button type="button" onClick={save} disabled={saving} style={solidBtn(palette)}>{saving ? "שומר…" : "שמירה ופרסום"}</button>
        </div>
      )}

      <style>{`
        @media (max-width: 900px){
          .adm-body{ grid-template-columns: 1fr !important; }
          .adm-nav{ position: static !important; display: none; }
          .adm-nav.open{ display: block; }
          .adm-burger{ display: inline-block !important; }
          .adm-savebar{ display: flex !important; }
        }
      `}</style>
    </div>
  );
}

/* ═══════════════ login ═══════════════ */
/* a failed sign-in has very different causes — say which one, instead of
   blaming the password when the project itself is unreachable */
function authErrorMessage(err){
  const msg = String((err && err.message) || "");
  const status = err && err.status;
  if (!status || /fetch|network|failed to fetch|load failed|abort/i.test(msg)) {
    return "אין חיבור לשרת התוכן (Supabase). הפרויקט כנראה כבוי או שהכתובת בקובץ index.html אינה נכונה.";
  }
  if (/email not confirmed/i.test(msg)) return "המשתמש קיים אך האימייל לא אושר. אשרו אותו ב‑Supabase → Authentication → Users.";
  if (status === 400 || status === 401) return "אימייל או סיסמה שגויים.";
  if (status === 422) return "כתובת האימייל אינה תקינה.";
  if (status === 429) return "יותר מדי ניסיונות התחברות. נסו שוב בעוד כמה דקות.";
  return "שגיאה בהתחברות: " + (msg || status);
}

function AdminLogin({ palette, onLoggedIn }){
  const [email, setEmail] = useAdminState("");
  const [pw, setPw] = useAdminState("");
  const [err, setErr] = useAdminState("");
  const [detail, setDetail] = useAdminState("");
  const [busy, setBusy] = useAdminState(false);
  const fail = (ex) => { setErr(authErrorMessage(ex)); setDetail(String((ex && ex.message) || "")); setBusy(false); };
  const submit = (e) => {
    e.preventDefault(); setBusy(true); setErr(""); setDetail("");
    window.adminAuth.signIn(email.trim(), pw).then((res) => {
      if (res.error) { fail(res.error); return; }
      onLoggedIn(res.data.session);
    }).catch(fail);
  };
  return (
    <div style={{ minHeight:"100vh", display:"grid", placeItems:"center", padding:24 }}>
      <form onSubmit={submit} style={{ width:"100%", maxWidth:380, background: palette.surface, border:`1px solid ${palette.line}`, borderRadius:12, padding:"34px 30px" }}>
        <div className="display" style={{ fontSize:24, fontWeight:700, marginBottom:6 }}>ניהול תוכן</div>
        <div style={{ fontSize:13.5, color: palette.ink2, marginBottom:22 }}>מנהיגות מלידה · כניסת מנהל</div>
        <FieldShell palette={palette} label="אימייל">
          <input type="email" value={email} onChange={(e)=>setEmail(e.target.value)} dir="ltr" style={inputStyle(palette)}/>
        </FieldShell>
        <FieldShell palette={palette} label="סיסמה">
          <input type="password" value={pw} onChange={(e)=>setPw(e.target.value)} dir="ltr" style={inputStyle(palette)}/>
        </FieldShell>
        {err && (
          <div style={{ margin:"4px 0 12px" }}>
            <div style={{ color:"#c0392b", fontSize:13, lineHeight:1.6 }}>{err}</div>
            {detail && <div dir="ltr" style={{ color: palette.ink2, fontSize:11, marginTop:4, fontFamily:"ui-monospace,monospace" }}>{detail}</div>}
          </div>
        )}
        <button type="submit" disabled={busy} style={{ width:"100%", padding:"13px", border:0, borderRadius:8, background: palette.ink, color: palette.bg, fontSize:14, fontWeight:600, cursor:"pointer", marginTop:6 }}>
          {busy ? "מתחבר…" : "כניסה"}
        </button>
        <a href="/" style={{ display:"block", textAlign:"center", marginTop:16, fontSize:13, color: palette.ink2 }}>← חזרה לאתר</a>
      </form>
    </div>
  );
}

function AdminSetupNotice({ palette }){
  return (
    <div style={{ minHeight:"100vh", display:"grid", placeItems:"center", padding:24 }}>
      <div style={{ maxWidth:560, background: palette.surface, border:`1px solid ${palette.line}`, borderRadius:12, padding:"32px 30px" }}>
        <div className="display" style={{ fontSize:24, fontWeight:700, marginBottom:10 }}>פאנל הניהול כמעט מוכן</div>
        <p style={{ color: palette.ink2, lineHeight:1.7, fontSize:14.5 }}>
          כדי להפעיל את הפאנל יש לחבר את האתר ל‑Supabase: ליצור פרויקט, להריץ את
          <code style={{ background: palette.bg, padding:"1px 6px", borderRadius:4, margin:"0 4px" }}>supabase-setup.sql</code>,
          ולמלא את כתובת הפרויקט וה‑anon key ב‑<code>window.SUPABASE_CONFIG</code> שבקובץ <code>index.html</code>.
        </p>
        <a href="/" style={{ display:"inline-block", marginTop:14, fontSize:13.5, color: palette.accent, fontWeight:700 }}>← חזרה לאתר</a>
      </div>
    </div>
  );
}

/* shown when the configured Supabase project answers nothing — a login form
   here would fail forever and look like a wrong password */
function AdminConnectionNotice({ palette, health, onRetry }){
  const code = { background: palette.bg, padding:"1px 6px", borderRadius:4, fontFamily:"ui-monospace,monospace", fontSize:12.5, direction:"ltr", display:"inline-block" };
  const badKey = health.reason === "badkey";
  return (
    <div style={{ minHeight:"100vh", display:"grid", placeItems:"center", padding:24 }}>
      <div style={{ maxWidth:600, background: palette.surface, border:`1px solid ${palette.line}`, borderInlineStart:`3px solid #c0392b`, borderRadius:12, padding:"32px 30px" }}>
        <div className="display" style={{ fontSize:24, fontWeight:700, marginBottom:10 }}>
          {badKey ? "המפתח של Supabase אינו תקף" : "אין חיבור לשרת התוכן"}
        </div>
        <p style={{ color: palette.ink2, lineHeight:1.75, fontSize:14.5, margin:"0 0 14px" }}>
          {badKey
            ? "הפרויקט עונה אך דוחה את המפתח (anon key). יש להעתיק מפתח עדכני מ‑Project Settings → API."
            : "הכתובת המוגדרת לפאנל אינה מגיבה — הפרויקט כבוי, נמחק, או שהכתובת שגויה. כל עוד זה המצב, אי אפשר להתחבר וגם לא לשמור תוכן."}
        </p>
        <div style={{ fontSize:13.5, color: palette.ink, marginBottom:16 }}>
          הכתובת המוגדרת: <span style={code}>{health.url || "—"}</span>
          {health.status ? <span style={{ color: palette.ink2 }}> · סטטוס {health.status}</span> : null}
        </div>
        <div style={{ fontSize:13.5, color: palette.ink2, lineHeight:1.9 }}>
          <div style={{ fontWeight:700, color: palette.ink, marginBottom:4 }}>מה לעשות</div>
          1. להיכנס ל‑<a href="https://supabase.com/dashboard" target="_blank" rel="noopener" style={{ color: palette.accent, fontWeight:700 }}>supabase.com/dashboard</a> ולבדוק אם הפרויקט קיים ופעיל (Paused → Restore).<br/>
          2. אם הוא נמחק — ליצור פרויקט חדש ולהריץ בו את <span style={code}>supabase-setup.sql</span>.<br/>
          3. להעתיק Project URL ו‑anon key ל‑<span style={code}>window.SUPABASE_CONFIG</span> שבקובץ <span style={code}>index.html</span>, ולפרסם מחדש.<br/>
          4. ליצור משתמש מנהל: Authentication → Users → Add user.
        </div>
        <div style={{ display:"flex", gap:10, alignItems:"center", marginTop:22 }}>
          <button type="button" onClick={onRetry} style={{ padding:"10px 20px", border:0, borderRadius:8, background: palette.ink, color: palette.bg, fontSize:13.5, fontWeight:700, cursor:"pointer" }}>בדיקה מחדש</button>
          <a href="/" style={{ fontSize:13.5, color: palette.ink2 }}>← חזרה לאתר</a>
        </div>
        {health.detail && <div dir="ltr" style={{ color: palette.ink2, fontSize:11, marginTop:14, fontFamily:"ui-monospace,monospace" }}>{health.detail}</div>}
      </div>
    </div>
  );
}

/* ─────────── root ─────────── */
function AdminApp({ palette }){
  const [session, setSession] = useAdminState(null);
  const [ready, setReady] = useAdminState(false);
  const [health, setHealth] = useAdminState(null);
  const [probe, setProbe] = useAdminState(0);
  const [loaded, setLoaded] = useAdminState(false);

  useAdminEffect(() => {
    if (!window.isSupabaseConfigured || !window.isSupabaseConfigured()) { setReady(true); return; }
    let live = true;
    setReady(false);
    window.supabaseHealth().then((h) => {
      if (!live) return;
      setHealth(h);
      if (!h.ok) { setReady(true); return; }
      // pull the saved content first, so the editor never starts from stale defaults
      window.loadContent().finally(() => {
        if (!live) return;
        setLoaded(true);
        window.adminAuth.getSession().then((res) => {
          if (!live) return;
          setSession(res && res.data ? res.data.session : null);
          setReady(true);
        }).catch(() => live && setReady(true));
      });
    });
    return () => { live = false; };
  }, [probe]);

  if (!window.isSupabaseConfigured || !window.isSupabaseConfigured()) return <AdminSetupNotice palette={palette}/>;
  if (!ready) return <div style={{ minHeight:"100vh", display:"grid", placeItems:"center", color: palette.ink2 }}>טוען…</div>;
  if (health && !health.ok) return <AdminConnectionNotice palette={palette} health={health} onRetry={()=>setProbe((n)=>n+1)}/>;
  if (!session) return <AdminLogin palette={palette} onLoggedIn={setSession}/>;

  const logout = () => { window.adminAuth.signOut().finally(() => setSession(null)); };
  return <AdminDashboard key={loaded ? "loaded" : "fresh"} palette={palette} onLogout={logout}/>;
}

Object.assign(window, { AdminApp });
