/* The Pulse — Custom Section engine.
   A fully flexible, block-based section the user can add as many times as
   they like, reorder among the fixed sections, and fill with any mix of
   content blocks. Exposes:
     window.PulseCustomSection  — preview renderer  <CustomSection d num />
     window.PulseCustomEditor   — editor panel body  <CustomEditor sectionKey content setContent onDelete />
     window.pulseMakeCustom()   — factory for a new blank custom section
     window.PULSE_BLOCK_KINDS   — metadata for the "add block" menu
   Self-contained: does not depend on editor.jsx internals. */
(function () {
  const { useState, useRef } = React;
  const I = window.PulseIcons;

  /* ---------- ids + factories ---------- */
  function uid(p) { return (p || "b_") + Math.random().toString(36).slice(2, 8); }

  function blankBlock(kind) {
    switch (kind) {
      case "heading":   return { id: uid(), kind, text: "Section heading", sub: "" };
      case "paragraph": return { id: uid(), kind, text: "Write your text here. Press Enter twice for a new paragraph." };
      case "image":     return { id: uid(), kind, url: "", size: "full", align: "full", caption: "", rounded: true };
      case "gallery":   return { id: uid(), kind, images: [], caption: "" };
      case "stats":     return { id: uid(), kind, items: [{ value: "100+", label: "Label" }, { value: "12", label: "Label" }] };
      case "quote":     return { id: uid(), kind, text: "A memorable quote goes here.", by: "" };
      case "list":      return { id: uid(), kind, items: ["First point", "Second point"] };
      case "button":    return { id: uid(), kind, text: "Learn more", url: "https://", align: "left" };
      default:          return { id: uid(), kind: "paragraph", text: "" };
    }
  }

  const BLOCK_KINDS = [
    { kind: "heading",   name: "Heading",   ic: "List" },
    { kind: "paragraph", name: "Text",      ic: "Mic" },
    { kind: "image",     name: "Image",     ic: "Image" },
    { kind: "gallery",   name: "Gallery",   ic: "Copy" },
    { kind: "stats",     name: "Stat tiles",ic: "Sparkle" },
    { kind: "quote",     name: "Quote",     ic: "Star" },
    { kind: "list",      name: "List",      ic: "List" },
    { kind: "button",    name: "Button",    ic: "Arrow" }
  ];

  const ACCENTS = [
    { c: "#00778B", n: "Teal" }, { c: "#00B7BD", n: "Turquoise" }, { c: "#004860", n: "Navy" },
    { c: "#8C30F5", n: "Purple" }, { c: "#FF6A14", n: "Orange" }, { c: "#1f8a5b", n: "Green" }
  ];

  function makeCustom() {
    return {
      type: "custom",
      enabled: true,
      label: "Custom Section",
      accent: "#00778B",
      blocks: [
        blankBlock("heading"),
        blankBlock("paragraph")
      ]
    };
  }

  /* ================= PREVIEW RENDERER ================= */
  function CKicker({ num, title, accent }) {
    return (
      <div className="pm-kicker cst-kicker">
        {num && <span className="num" style={{ color: accent }}>{num}</span>}
        <span className="ttl" style={{ color: accent }}>{title}</span>
        <span className="rule" style={{ background: accent, opacity: .25 }} />
      </div>
    );
  }

  function Block({ b, accent }) {
    switch (b.kind) {
      case "heading":
        return (
          <div className="cst-heading">
            <h3 className="cst-h">{b.text}</h3>
            {b.sub && <p className="cst-sub">{b.sub}</p>}
          </div>
        );
      case "paragraph":
        return <p className="cst-para">{b.text}</p>;
      case "image": {
        if (!b.url) return null;
        const cls = "cst-img size-" + (b.size || "full") + " align-" + (b.align || "full") +
          (b.rounded === false ? " square" : " rounded");
        return (
          <figure className="cst-fig">
            <img className={cls} src={b.url} alt="" />
            {b.caption && <figcaption className="cst-cap">{b.caption}</figcaption>}
          </figure>
        );
      }
      case "gallery": {
        const imgs = (b.images || []).filter(Boolean);
        if (!imgs.length) return null;
        const cols = imgs.length === 1 ? 1 : (imgs.length === 2 || imgs.length === 4 ? 2 : 3);
        return (
          <figure className="cst-fig">
            <div className="cst-gallery" style={{ gridTemplateColumns: "repeat(" + cols + ",1fr)" }}>
              {imgs.map((src, i) => <img key={i} src={src} alt="" />)}
            </div>
            {b.caption && <figcaption className="cst-cap">{b.caption}</figcaption>}
          </figure>
        );
      }
      case "stats": {
        const items = (b.items || []).filter((s) => s.value || s.label);
        if (!items.length) return null;
        return (
          <div className="cst-stats">
            {items.map((s, i) => (
              <div className="cst-stat" key={i}>
                <div className="v" style={{ color: accent }}>{s.value}</div>
                <div className="l">{s.label}</div>
              </div>
            ))}
          </div>
        );
      }
      case "quote":
        return (
          <blockquote className="cst-quote" style={{ borderColor: accent }}>
            <p>“{b.text}”</p>
            {b.by && <cite style={{ color: accent }}>— {b.by}</cite>}
          </blockquote>
        );
      case "list": {
        const items = (b.items || []).filter(Boolean);
        if (!items.length) return null;
        return (
          <ul className="cst-list">
            {items.map((t, i) => (
              <li key={i}><span className="bullet" style={{ background: accent }} />{t}</li>
            ))}
          </ul>
        );
      }
      case "button":
        if (!b.text) return null;
        return (
          <div className={"cst-btn-wrap align-" + (b.align || "left")}>
            <a className="cst-btn" href={b.url || "#"} style={{ background: accent }}>{b.text}</a>
          </div>
        );
      default:
        return null;
    }
  }

  function CustomSection({ d, num }) {
    const accent = d.accent || "#00778B";
    return (
      <div className="pm-sec pm-custom">
        <CKicker num={num} title={d.label || "Custom Section"} accent={accent} />
        {(d.blocks || []).map((b) => <Block key={b.id} b={b} accent={accent} />)}
      </div>
    );
  }

  /* ================= EDITOR ================= */
  // image resize → dataURL (kept in-file so custom.jsx is self-contained)
  function fileToDataURL(file, maxW, cb) {
    const reader = new FileReader();
    reader.onload = (e) => {
      const img = new Image();
      img.onload = () => {
        const scale = Math.min(1, maxW / img.width);
        const w = Math.max(1, Math.round(img.width * scale));
        const h = Math.max(1, Math.round(img.height * scale));
        const cv = document.createElement("canvas");
        cv.width = w; cv.height = h;
        const ctx = cv.getContext("2d");
        ctx.fillStyle = "#ffffff"; ctx.fillRect(0, 0, w, h);
        ctx.drawImage(img, 0, 0, w, h);
        cb(cv.toDataURL("image/jpeg", 0.82));
      };
      img.onerror = () => cb(null);
      img.src = e.target.result;
    };
    reader.readAsDataURL(file);
  }

  function CField({ label, val, set, area, rows, ph }) {
    return (
      <div className="fld">
        {label && <label>{label}</label>}
        {area
          ? <textarea value={val || ""} placeholder={ph || ""} onChange={(e) => set(e.target.value)} style={{ minHeight: (rows || 3) * 22 }} />
          : <input type="text" value={val || ""} placeholder={ph || ""} onChange={(e) => set(e.target.value)} />}
      </div>
    );
  }

  function CSeg({ label, value, set, opts }) {
    return (
      <div className="fld">
        {label && <label>{label}</label>}
        <div className="seg">
          {opts.map((o) => (
            <button key={o.id} className={"seg-btn" + (value === o.id ? " on" : "")} onClick={() => set(o.id)}>{o.name}</button>
          ))}
        </div>
      </div>
    );
  }

  function CImage({ label, hint, value, set, maxW }) {
    const ref = useRef(null);
    const [busy, setBusy] = useState(false);
    const pick = (e) => {
      const f = e.target.files && e.target.files[0];
      if (!f) return;
      setBusy(true);
      window.pulseProcessImage(f, maxW || 1100).then((url) => { setBusy(false); if (url) set(url); });
      e.target.value = "";
    };
    return (
      <div className="fld">
        {label && <label>{label}</label>}
        <input ref={ref} type="file" accept="image/*" onChange={pick} style={{ display: "none" }} />
        {value ? (
          <div className="img-has">
            <img src={value} alt="" className="img-thumb" />
            <div className="img-acts">
              <button className="img-btn" onClick={() => ref.current && ref.current.click()}><I.Upload size={13} /> Replace</button>
              <button className="img-btn danger" onClick={() => set("")}><I.Trash size={13} /> Remove</button>
            </div>
          </div>
        ) : (
          <button className="img-drop" onClick={() => ref.current && ref.current.click()} disabled={busy}>
            <I.Image size={18} /><span>{busy ? "Adding…" : "Upload image"}</span>{hint && <em>{hint}</em>}
          </button>
        )}
      </div>
    );
  }

  // gallery multi-image adder
  function CGallery({ images, set }) {
    const ref = useRef(null);
    const [busy, setBusy] = useState(false);
    const add = (e) => {
      const files = [...(e.target.files || [])];
      if (!files.length) return;
      setBusy(true);
      Promise.all(files.map((f) => window.pulseProcessImage(f, 900))).then((urls) => {
        setBusy(false);
        set([...(images || []), ...urls.filter(Boolean)]);
      });
      e.target.value = "";
    };
    return (
      <div className="fld">
        <label>Gallery images</label>
        <input ref={ref} type="file" accept="image/*" multiple onChange={add} style={{ display: "none" }} />
        {(images || []).length > 0 && (
          <div className="gal-grid">
            {images.map((src, i) => (
              <div className="gal-thumb" key={i}>
                <img src={src} alt="" />
                <button onClick={() => set(images.filter((_, j) => j !== i))}>×</button>
              </div>
            ))}
          </div>
        )}
        <button className="add-btn" onClick={() => ref.current && ref.current.click()} disabled={busy} style={{ marginTop: 8 }}>
          <I.Plus size={14} /> {busy ? "Adding…" : "Add image(s)"}
        </button>
      </div>
    );
  }

  function StatRows({ items, set }) {
    return (
      <div className="fld">
        <label>Stat tiles</label>
        {(items || []).map((it, i) => (
          <div className="frow" key={i} style={{ gridTemplateColumns: "90px 1fr 28px", alignItems: "center", marginBottom: 8 }}>
            <input value={it.value || ""} placeholder="100+" onChange={(e) => set(items.map((x, j) => j === i ? { ...x, value: e.target.value } : x))} />
            <input value={it.label || ""} placeholder="Label" onChange={(e) => set(items.map((x, j) => j === i ? { ...x, label: e.target.value } : x))} />
            <button className="mini-x" onClick={() => set(items.filter((_, j) => j !== i))}>×</button>
          </div>
        ))}
        <button className="add-btn" onClick={() => set([...(items || []), { value: "", label: "" }])}><I.Plus size={14} /> Add tile</button>
      </div>
    );
  }

  function ListRows({ items, set }) {
    return (
      <div className="fld">
        <label>List items</label>
        {(items || []).map((it, i) => (
          <div className="frow" key={i} style={{ gridTemplateColumns: "1fr 28px", alignItems: "center", marginBottom: 8 }}>
            <input value={it} placeholder="List item" onChange={(e) => set(items.map((x, j) => j === i ? e.target.value : x))} />
            <button className="mini-x" onClick={() => set(items.filter((_, j) => j !== i))}>×</button>
          </div>
        ))}
        <button className="add-btn" onClick={() => set([...(items || []), ""])}><I.Plus size={14} /> Add item</button>
      </div>
    );
  }

  function BlockEditor({ b, patch }) {
    switch (b.kind) {
      case "heading":
        return (
          <React.Fragment>
            <CField label="Heading" val={b.text} set={(v) => patch({ text: v })} />
            <CField label="Subheading (optional)" val={b.sub} set={(v) => patch({ sub: v })} />
          </React.Fragment>
        );
      case "paragraph":
        return <CField label="Text" val={b.text} set={(v) => patch({ text: v })} area rows={5} ph="Blank line between paragraphs." />;
      case "image":
        return (
          <React.Fragment>
            <CImage label="Image" value={b.url} set={(v) => patch({ url: v })} maxW={1200} />
            <CSeg label="Size" value={b.size || "full"} set={(v) => patch({ size: v })}
                  opts={[{ id: "small", name: "Small" }, { id: "medium", name: "Medium" }, { id: "full", name: "Full" }]} />
            <CSeg label="Placement" value={b.align || "full"} set={(v) => patch({ align: v })}
                  opts={[{ id: "left", name: "Left" }, { id: "center", name: "Center" }, { id: "right", name: "Right" }, { id: "full", name: "Full width" }]} />
            <CField label="Caption (optional)" val={b.caption} set={(v) => patch({ caption: v })} />
            <CSeg label="Corners" value={b.rounded === false ? "square" : "rounded"} set={(v) => patch({ rounded: v === "rounded" })}
                  opts={[{ id: "rounded", name: "Rounded" }, { id: "square", name: "Square" }]} />
          </React.Fragment>
        );
      case "gallery":
        return (
          <React.Fragment>
            <CGallery images={b.images} set={(v) => patch({ images: v })} />
            <CField label="Caption (optional)" val={b.caption} set={(v) => patch({ caption: v })} />
          </React.Fragment>
        );
      case "stats":
        return <StatRows items={b.items} set={(v) => patch({ items: v })} />;
      case "quote":
        return (
          <React.Fragment>
            <CField label="Quote" val={b.text} set={(v) => patch({ text: v })} area rows={3} />
            <CField label="Attribution (optional)" val={b.by} set={(v) => patch({ by: v })} />
          </React.Fragment>
        );
      case "list":
        return <ListRows items={b.items} set={(v) => patch({ items: v })} />;
      case "button":
        return (
          <React.Fragment>
            <CField label="Button label" val={b.text} set={(v) => patch({ text: v })} />
            <CField label="Link URL" val={b.url} set={(v) => patch({ url: v })} ph="https://" />
            <CSeg label="Alignment" value={b.align || "left"} set={(v) => patch({ align: v })}
                  opts={[{ id: "left", name: "Left" }, { id: "center", name: "Center" }, { id: "right", name: "Right" }]} />
          </React.Fragment>
        );
      default:
        return null;
    }
  }

  const KIND_NAME = { heading: "Heading", paragraph: "Text", image: "Image", gallery: "Gallery", stats: "Stat tiles", quote: "Quote", list: "List", button: "Button" };

  function CustomEditor({ sectionKey, content, setContent, onDelete }) {
    const d = content[sectionKey] || {};
    const [addOpen, setAddOpen] = useState(false);
    const setField = (k) => (v) => setContent((p) => ({ ...p, [sectionKey]: { ...p[sectionKey], [k]: v } }));
    const setBlocks = (arr) => setContent((p) => ({ ...p, [sectionKey]: { ...p[sectionKey], blocks: arr } }));
    const blocks = d.blocks || [];

    const patchBlock = (id, partial) => setBlocks(blocks.map((b) => b.id === id ? { ...b, ...partial } : b));
    const removeBlock = (id) => setBlocks(blocks.filter((b) => b.id !== id));
    const moveBlock = (id, dir) => {
      const i = blocks.indexOf(blocks.find((b) => b.id === id));
      const j = i + dir;
      if (i < 0 || j < 0 || j >= blocks.length) return;
      const arr = blocks.slice();
      arr.splice(j, 0, arr.splice(i, 1)[0]);
      setBlocks(arr);
    };
    const addBlock = (kind) => { setBlocks([...blocks, blankBlock(kind)]); setAddOpen(false); };

    return (
      <div className="cst-editor">
        <CField label="Section title" val={d.label} set={setField("label")} ph="Custom Section" />

        <div className="fld">
          <label>Accent color</label>
          <div className="accent-row">
            {ACCENTS.map((a) => (
              <button key={a.c} className={"accent-sw" + ((d.accent || "#00778B") === a.c ? " on" : "")}
                      title={a.n} style={{ background: a.c }} onClick={() => setField("accent")(a.c)} />
            ))}
          </div>
        </div>

        <div className="blk-list">
          {blocks.map((b, i) => (
            <div className="blk" key={b.id}>
              <div className="blk-head">
                <span className="blk-kind">{KIND_NAME[b.kind] || b.kind}</span>
                <div className="blk-tools">
                  <button disabled={i === 0} onClick={() => moveBlock(b.id, -1)} title="Move up"><span className="mv-up"><I.ChevDown size={13} /></span></button>
                  <button disabled={i === blocks.length - 1} onClick={() => moveBlock(b.id, 1)} title="Move down"><I.ChevDown size={13} /></button>
                  <button className="danger" onClick={() => removeBlock(b.id)} title="Remove block"><I.Trash size={13} /></button>
                </div>
              </div>
              <div className="blk-body">
                <BlockEditor b={b} patch={(partial) => patchBlock(b.id, partial)} />
              </div>
            </div>
          ))}
        </div>

        <div className="blk-add-wrap">
          <button className="add-btn" onClick={() => setAddOpen(!addOpen)}>
            <I.Plus size={14} /> Add content block
          </button>
          {addOpen && (
            <div className="blk-menu">
              {BLOCK_KINDS.map((k) => {
                const Ic = I[k.ic] || I.Sparkle;
                return (
                  <button key={k.kind} onClick={() => addBlock(k.kind)}>
                    <Ic size={15} /> {k.name}
                  </button>
                );
              })}
            </div>
          )}
        </div>

        <button className="cst-del" onClick={onDelete}>
          <I.Trash size={14} /> Delete this section
        </button>
      </div>
    );
  }

  window.PulseCustomSection = CustomSection;
  window.PulseCustomEditor = CustomEditor;
  window.pulseMakeCustom = makeCustom;
  window.PULSE_BLOCK_KINDS = BLOCK_KINDS;
})();
