/* ============================================================
   The Carnation — Share & Quote Card Studio
   Renders striking, downloadable social cards (cover + quotes)
   for any story, drawn on a canvas in the publication's style.
   ============================================================ */
(function () {
  const RED = "#b21e36", REDINK = "#8c1428", INK = "#15110c", PAPER = "#f4efe3",
        PAPER2 = "#ece6d8", CREAM = "#fbf8f0", GREEN = "#2f6b41", GREENDK = "#234d30",
        MUTE = "#6f675b", MUTE_D = "#a9a093";

  const FORMATS = [
    { k: "square",   w: 1080, h: 1080, label: "Square" },
    { k: "portrait", w: 1080, h: 1350, label: "Story" },
    { k: "wide",     w: 1200, h: 630,  label: "Link" },
  ];

  let fontsReady = null;
  function ensureFonts() {
    if (fontsReady) return fontsReady;
    const loads = [
      '700 80px Newsreader', '600 80px Newsreader', 'italic 600 60px Newsreader',
      '400 120px UnifrakturMaguntia', '600 24px "Libre Franklin"', '700 24px "Libre Franklin"',
      '500 20px "IBM Plex Mono"',
    ].map((f) => (document.fonts.load ? document.fonts.load(f).catch(() => {}) : null));
    fontsReady = Promise.all(loads).then(() => (document.fonts.ready || Promise.resolve())).catch(() => {});
    return fontsReady;
  }

  /* ---- carnation bloom, drawn on canvas ---- */
  function drawBloom(ctx, cx, cy, scale, stem) {
    ctx.save();
    ctx.translate(cx, cy);
    ctx.scale(scale, scale);
    ctx.lineJoin = "round";
    if (stem) {
      ctx.strokeStyle = GREEN; ctx.lineWidth = 4.5; ctx.lineCap = "round";
      ctx.beginPath(); ctx.moveTo(0, 33); ctx.bezierCurveTo(2, 53, 8, 71, 22, 95); ctx.stroke();
      ctx.fillStyle = GREEN; ctx.strokeStyle = GREENDK; ctx.lineWidth = 1.2;
      ctx.beginPath(); ctx.moveTo(3, 55); ctx.bezierCurveTo(-13, 48, -25, 52, -32, 65);
      ctx.bezierCurveTo(-15, 70, -2, 65, 4, 56); ctx.closePath(); ctx.fill(); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(8, 73); ctx.bezierCurveTo(24, 66, 37, 71, 43, 84);
      ctx.bezierCurveTo(26, 88, 13, 83, 7, 74); ctx.closePath(); ctx.fill(); ctx.stroke();
    }
    const rings = [[11, 23, 10, 0], [8, 14, 10, 0.4], [5, 7, 9, 0.2]];
    ctx.strokeStyle = REDINK; ctx.lineWidth = 1.6; ctx.fillStyle = RED;
    rings.forEach(([n, d, r, off]) => {
      for (let i = 0; i < n; i++) {
        const a = off + 2 * Math.PI * i / n;
        ctx.beginPath(); ctx.arc(d * Math.cos(a), d * Math.sin(a), r, 0, 7); ctx.fill(); ctx.stroke();
      }
    });
    ctx.beginPath(); ctx.arc(0, 0, 9, 0, 7); ctx.fill(); ctx.stroke();
    ctx.restore();
  }

  /* ---- text helpers ---- */
  function wrapLines(ctx, text, maxW) {
    const words = (text || "").split(/\s+/);
    const lines = []; let line = "";
    for (const w of words) {
      const test = line ? line + " " + w : w;
      if (ctx.measureText(test).width > maxW && line) { lines.push(line); line = w; }
      else line = test;
    }
    if (line) lines.push(line);
    return lines;
  }
  // shrink font until wrapped text fits height; returns {size, lines, lh}
  function fitText(ctx, text, maxW, maxH, fontTpl, start, min, lhRatio) {
    let size = start;
    while (size > min) {
      ctx.font = fontTpl.replace("%S", size);
      const lines = wrapLines(ctx, text, maxW);
      const lh = size * (lhRatio || 1.08);
      if (lines.length * lh <= maxH) return { size, lines, lh };
      size -= 2;
    }
    ctx.font = fontTpl.replace("%S", min);
    return { size: min, lines: wrapLines(ctx, text, maxW), lh: min * (lhRatio || 1.08) };
  }
  function kicker(ctx, text, x, y, size, color) {
    ctx.font = '600 ' + size + 'px "IBM Plex Mono"';
    ctx.fillStyle = color; ctx.textAlign = "left"; ctx.textBaseline = "alphabetic";
    const ls = size * 0.18; let cx = x;
    const up = (text || "").toUpperCase();
    for (const ch of up) { ctx.fillText(ch, cx, y); cx += ctx.measureText(ch).width + ls; }
    return cx - ls;
  }

  /* ---- COVER (story) card ---- */
  function drawCover(ctx, W, H, d) {
    const wide = W > H;
    ctx.fillStyle = PAPER; ctx.fillRect(0, 0, W, H);
    // subtle dotted halftone wash
    ctx.fillStyle = "rgba(21,17,12,0.035)";
    const step = Math.round(W / 46);
    for (let yy = step; yy < H; yy += step) for (let xx = step; xx < W; xx += step) { ctx.beginPath(); ctx.arc(xx, yy, 1.4, 0, 7); ctx.fill(); }
    const m = Math.round(W * 0.062);
    // double border
    ctx.strokeStyle = INK; ctx.lineWidth = Math.max(2, W * 0.004);
    ctx.strokeRect(m, m, W - 2 * m, H - 2 * m);
    ctx.lineWidth = Math.max(1, W * 0.0015);
    ctx.strokeRect(m + W * 0.014, m + W * 0.014, W - 2 * (m + W * 0.014), H - 2 * (m + W * 0.014));

    const pad = m + W * 0.05;
    const innerW = W - 2 * pad;

    // masthead label
    ctx.textAlign = "center"; ctx.fillStyle = INK;
    ctx.font = '400 ' + Math.round(W * (wide ? 0.052 : 0.066)) + 'px UnifrakturMaguntia';
    ctx.textBaseline = "alphabetic";
    const mastY = m + W * (wide ? 0.085 : 0.115);
    ctx.fillText("The Carnation", W / 2, mastY);
    // rule under masthead
    ctx.strokeStyle = INK; ctx.lineWidth = 1.5;
    ctx.beginPath(); ctx.moveTo(pad, mastY + W * 0.022); ctx.lineTo(W - pad, mastY + W * 0.022); ctx.stroke();
    // tiny issue line
    kickerCentered(ctx, "Local Record · Alliance, Ohio", W / 2, mastY + W * 0.052, Math.round(W * 0.019), MUTE);

    // category kicker
    const kY = mastY + W * (wide ? 0.10 : 0.16);
    kicker(ctx, d.kicker || "The Carnation", pad, kY, Math.round(W * (wide ? 0.026 : 0.03)), RED);

    // headline (auto-fit)
    const headTop = kY + W * 0.03;
    const headBottom = H - m - W * (wide ? 0.12 : 0.165);
    const fit = fitText(ctx, d.title, innerW, headBottom - headTop,
      '600 %Spx Newsreader', Math.round(W * (wide ? 0.075 : 0.092)), Math.round(W * 0.04), 1.04);
    ctx.font = '600 ' + fit.size + 'px Newsreader';
    ctx.fillStyle = INK; ctx.textAlign = "left"; ctx.textBaseline = "top";
    let ty = headTop;
    // vertically center the headline block in its zone
    const blockH = fit.lines.length * fit.lh;
    ty = headTop + Math.max(0, ((headBottom - headTop) - blockH) / 2) * 0.5;
    fit.lines.forEach((ln) => { ctx.fillText(ln, pad, ty); ty += fit.lh; });

    // dek (optional, under headline if room)
    if (d.sub && ty < headBottom - W * 0.06) {
      ctx.font = 'italic 500 ' + Math.round(W * 0.026) + 'px Newsreader';
      ctx.fillStyle = MUTE;
      const dl = wrapLines(ctx, d.sub, innerW).slice(0, 2);
      ty += W * 0.018;
      dl.forEach((ln) => { ctx.fillText(ln, pad, ty); ty += W * 0.026 * 1.3; });
    }

    // footer: bloom + byline
    const footY = H - m - W * 0.052;
    ctx.strokeStyle = INK; ctx.lineWidth = 1.5;
    ctx.beginPath(); ctx.moveTo(pad, footY - W * 0.03); ctx.lineTo(W - pad, footY - W * 0.03); ctx.stroke();
    drawBloom(ctx, pad + W * 0.022, footY - W * 0.004, W * 0.00085, true);
    ctx.textAlign = "left"; ctx.textBaseline = "middle";
    ctx.font = '600 ' + Math.round(W * 0.0205) + 'px "Libre Franklin"'; ctx.fillStyle = INK;
    ctx.fillText(d.byline || "carnationpost.com", pad + W * 0.055, footY);
    ctx.font = '500 ' + Math.round(W * 0.018) + 'px "IBM Plex Mono"'; ctx.fillStyle = MUTE;
    ctx.textAlign = "right"; ctx.textBaseline = "middle";
    ctx.fillText((d.meta || "ALLIANCE, OHIO").toUpperCase(), W - pad, footY);
  }
  function ctxRightReset(ctx) { return ctx; }
  function kickerCentered(ctx, text, cx, y, size, color) {
    ctx.font = '500 ' + size + 'px "IBM Plex Mono"'; ctx.fillStyle = color;
    ctx.textAlign = "center"; ctx.textBaseline = "alphabetic";
    const ls = size * 0.16; const up = (text || "").toUpperCase();
    let total = 0; for (const ch of up) total += ctx.measureText(ch).width + ls; total -= ls;
    let x = cx - total / 2; ctx.textAlign = "left";
    for (const ch of up) { ctx.fillText(ch, x, y); x += ctx.measureText(ch).width + ls; }
  }

  /* ---- QUOTE card ---- */
  function drawQuote(ctx, W, H, d) {
    const wide = W > H;
    ctx.fillStyle = INK; ctx.fillRect(0, 0, W, H);
    // faint bloom watermark, large, bottom-right
    ctx.globalAlpha = 0.07; drawBloom(ctx, W * 0.86, H * 0.84, W * 0.0036, false); ctx.globalAlpha = 1;
    const m = Math.round(W * 0.062);
    ctx.strokeStyle = "rgba(244,239,227,0.28)"; ctx.lineWidth = 1.5;
    ctx.strokeRect(m, m, W - 2 * m, H - 2 * m);
    const pad = m + W * 0.045;
    const innerW = W - 2 * pad;

    // top label
    kicker(ctx, "The Carnation · Open to the city", pad, m + W * 0.075, Math.round(W * 0.02), "#d8b2b6");

    // giant opening quote
    ctx.fillStyle = RED; ctx.textAlign = "left"; ctx.textBaseline = "alphabetic";
    ctx.font = '400 ' + Math.round(W * 0.26) + 'px UnifrakturMaguntia';
    ctx.fillText("\u201C", pad - W * 0.012, m + W * (wide ? 0.30 : 0.30));

    // quote text, auto-fit, centered block
    const qTop = m + W * (wide ? 0.18 : 0.27);
    const qBottom = H - m - W * 0.13;
    const fit = fitText(ctx, d.text, innerW, qBottom - qTop,
      'italic 600 %Spx Newsreader', Math.round(W * (wide ? 0.06 : 0.072)), Math.round(W * 0.032), 1.16);
    ctx.font = 'italic 600 ' + fit.size + 'px Newsreader';
    ctx.fillStyle = CREAM; ctx.textAlign = "left"; ctx.textBaseline = "top";
    let ty = qTop + Math.max(0, ((qBottom - qTop) - fit.lines.length * fit.lh) / 2) * 0.6;
    fit.lines.forEach((ln) => { ctx.fillText(ln, pad, ty); ty += fit.lh; });

    // attribution
    const aY = H - m - W * 0.062;
    ctx.strokeStyle = "rgba(244,239,227,0.28)"; ctx.lineWidth = 1.5;
    ctx.beginPath(); ctx.moveTo(pad, aY - W * 0.028); ctx.lineTo(W - pad, aY - W * 0.028); ctx.stroke();
    drawBloom(ctx, pad + W * 0.02, aY + W * 0.002, W * 0.0008, true);
    ctx.textAlign = "left"; ctx.textBaseline = "middle";
    ctx.font = '600 ' + Math.round(W * 0.021) + 'px "Libre Franklin"'; ctx.fillStyle = CREAM;
    const attr = d.attribution || "The Carnation";
    ctx.fillText(attr, pad + W * 0.05, aY - W * 0.008);
    ctx.font = '500 ' + Math.round(W * 0.0165) + 'px "IBM Plex Mono"'; ctx.fillStyle = "#d8b2b6";
    ctx.fillText((d.meta || "ALLIANCE, OHIO").toUpperCase(), pad + W * 0.05, aY + W * 0.018);
  }

  function render(canvas, fmt, card, data) {
    const ctx = canvas.getContext("2d");
    canvas.width = fmt.w; canvas.height = fmt.h;
    ctx.clearRect(0, 0, fmt.w, fmt.h);
    if (card.kind === "quote") drawQuote(ctx, fmt.w, fmt.h, { text: card.text, attribution: data.attribution, meta: data.meta });
    else drawCover(ctx, fmt.w, fmt.h, data);
  }

  /* ---- React modal ---- */
  function CardStudio({ article, onClose }) {
    const canvasRef = React.useRef(null);
    const [ready, setReady] = React.useState(false);
    const [fmtK, setFmtK] = React.useState("square");
    const [cardIdx, setCardIdx] = React.useState(0);
    const [copied, setCopied] = React.useState(false);

    const pulls = (article.body || []).filter((b) => b && b.pull).map((b) => b.pull);
    const cards = [{ kind: "cover", label: "Cover" }];
    pulls.forEach((q, i) => cards.push({ kind: "quote", label: "Quote " + (i + 1), text: q }));
    if (!pulls.length && article.dek) cards.push({ kind: "quote", label: "Quote", text: article.dek });

    const fmt = FORMATS.find((f) => f.k === fmtK) || FORMATS[0];
    const data = {
      kicker: article.category, title: article.title, sub: article.dek,
      byline: "carnationpost.com", meta: article.dateline || "Alliance, Ohio",
      attribution: "The Carnation · " + article.title,
    };

    React.useEffect(() => { ensureFonts().then(() => setReady(true)); }, []);
    React.useEffect(() => {
      if (!ready || !canvasRef.current) return;
      render(canvasRef.current, fmt, cards[cardIdx] || cards[0], data);
    }, [ready, fmtK, cardIdx]);

    React.useEffect(() => {
      const onKey = (e) => { if (e.key === "Escape") onClose(); };
      document.body.style.overflow = "hidden";
      window.addEventListener("keydown", onKey);
      return () => { document.body.style.overflow = ""; window.removeEventListener("keydown", onKey); };
    }, []);

    const download = () => {
      const c = canvasRef.current; if (!c) return;
      c.toBlob((blob) => {
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url; a.download = "the-carnation-" + article.slug + "-" + (cards[cardIdx].kind === "quote" ? "quote" + cardIdx : "cover") + ".png";
        document.body.appendChild(a); a.click(); a.remove();
        setTimeout(() => URL.revokeObjectURL(url), 1000);
      }, "image/png");
    };

    const shareUrl = (window.postUrl ? window.postUrl("article", article.slug) : location.href);
    const shareTitle = "The Carnation — " + article.title;
    const copyLink = async () => { try { await navigator.clipboard.writeText(shareUrl); setCopied(true); setTimeout(() => setCopied(false), 1800); } catch (e) {} };
    const nativeShare = async () => {
      const c = canvasRef.current;
      try {
        const blob = await new Promise((res) => c.toBlob(res, "image/png"));
        const file = new File([blob], "the-carnation-" + article.slug + ".png", { type: "image/png" });
        if (navigator.canShare && navigator.canShare({ files: [file] })) {
          await navigator.share({ files: [file], title: shareTitle, text: article.dek || "" });
          return;
        }
      } catch (e) {}
      try { if (navigator.share) { await navigator.share({ title: shareTitle, text: article.dek || "", url: shareUrl }); return; } } catch (e) {}
      copyLink();
    };

    const ov = { position: "fixed", inset: 0, zIndex: 4000, background: "rgba(21,17,12,0.72)", backdropFilter: "blur(3px)", display: "flex", alignItems: "center", justifyContent: "center", padding: "24px" };
    const panel = { background: PAPER, width: "min(960px, 96vw)", maxHeight: "92vh", overflow: "auto", borderRadius: "3px", boxShadow: "0 40px 90px -30px rgba(0,0,0,.6)", display: "grid", gridTemplateColumns: "minmax(0,1fr) 280px" };
    const previewWrap = { background: PAPER2, padding: "26px", display: "flex", alignItems: "center", justifyContent: "center" };
    const controls = { padding: "26px 24px", borderLeft: "1px solid rgba(21,17,12,.12)", display: "flex", flexDirection: "column", gap: "18px" };
    const lab = { fontFamily: "var(--mono)", fontSize: ".62rem", letterSpacing: ".16em", textTransform: "uppercase", color: MUTE, marginBottom: "9px", display: "block" };
    const seg = { display: "flex", gap: "6px", flexWrap: "wrap" };
    const chip = (on) => ({ fontFamily: "var(--mono)", fontSize: ".66rem", letterSpacing: ".08em", textTransform: "uppercase", padding: "8px 12px", borderRadius: "2px", cursor: "pointer", border: "1px solid " + (on ? INK : "rgba(21,17,12,.2)"), background: on ? INK : "transparent", color: on ? PAPER : INK });

    return ReactDOM.createPortal(React.createElement("div", { style: ov, onMouseDown: (e) => { if (e.target === e.currentTarget) onClose(); } },
      React.createElement("div", { style: panel },
        React.createElement("div", { style: previewWrap },
          React.createElement("canvas", { ref: canvasRef, style: { maxWidth: "100%", maxHeight: "62vh", width: fmt.w >= fmt.h ? "100%" : "auto", height: fmt.h > fmt.w ? "62vh" : "auto", boxShadow: "0 14px 36px -16px rgba(0,0,0,.5)", borderRadius: "2px", background: PAPER } })
        ),
        React.createElement("div", { style: controls },
          React.createElement("div", null,
            React.createElement("div", { style: { fontFamily: "var(--black-letter)", fontSize: "1.5rem", lineHeight: 1 } }, "Share this story"),
            React.createElement("p", { style: { fontFamily: "var(--serif)", fontSize: ".92rem", color: MUTE, margin: "8px 0 0", lineHeight: 1.45 } }, "Send it as a Carnation card, or share the link.")
          ),
          React.createElement("div", null,
            React.createElement("span", { style: lab }, "Card"),
            React.createElement("div", { style: seg }, cards.map((c, i) =>
              React.createElement("button", { key: i, style: chip(i === cardIdx), onClick: () => setCardIdx(i) }, c.label)))
          ),
          React.createElement("div", null,
            React.createElement("span", { style: lab }, "Format"),
            React.createElement("div", { style: seg }, FORMATS.map((f) =>
              React.createElement("button", { key: f.k, style: chip(f.k === fmtK), onClick: () => setFmtK(f.k) }, f.label)))
          ),
          React.createElement("div", { style: { marginTop: "auto", display: "flex", flexDirection: "column", gap: "10px" } },
            React.createElement("button", { className: "btn btn--red", onClick: nativeShare, style: { justifyContent: "center" } }, "Share \u2192"),
            React.createElement("p", { style: { fontFamily: "var(--mono)", fontSize: ".55rem", letterSpacing: ".1em", textTransform: "uppercase", color: MUTE, margin: "-4px 0 2px", textAlign: "center" } }, "To Instagram, TikTok, Messages & more"),
            React.createElement("div", { style: { display: "flex", gap: "8px" } },
              React.createElement("button", { className: "btn btn--line", onClick: download, style: { justifyContent: "center", flex: 1 } }, "Download"),
              React.createElement("button", { className: "btn btn--line", onClick: copyLink, style: { justifyContent: "center", flex: 1 } }, copied ? "Copied" : "Copy link")
            ),
            React.createElement("div", { style: { display: "flex", gap: "9px", alignItems: "center", marginTop: "2px" } },
              React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: ".56rem", letterSpacing: ".14em", textTransform: "uppercase", color: MUTE, marginRight: "2px" } }, "Or"),
              [["X", "https://twitter.com/intent/tweet?url=" + encodeURIComponent(shareUrl) + "&text=" + encodeURIComponent(shareTitle)],
               ["f", "https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(shareUrl)],
               ["in", "https://www.linkedin.com/sharing/share-offsite/?url=" + encodeURIComponent(shareUrl)],
               ["\u2709", "mailto:?subject=" + encodeURIComponent(shareTitle) + "&body=" + encodeURIComponent(shareUrl)]].map(function (s) {
                return React.createElement("a", { key: s[0], href: s[1], target: s[0] === "\u2709" ? undefined : "_blank", rel: "noopener",
                  style: { width: 32, height: 32, borderRadius: "50%", border: "1px solid rgba(21,17,12,.22)", display: "inline-flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--sans)", fontWeight: 700, fontSize: ".82rem", color: INK, textDecoration: "none" } }, s[0]);
              })
            ),
            React.createElement("button", { className: "btn btn--line", onClick: onClose, style: { justifyContent: "center" } }, "Close")
          )
        )
      )
    ), document.body);
  }

  window.CardStudio = CardStudio;
})();
