// MostlyRender — shared primitives: brand marks, icons, the live render card,
// and the payload / code-snippet generators that power the signature widget.
const F = window.ForgeDesignSystem_e40d74;

/* ───────────────────────── Icons (Lucide geometry, stroke 2, round caps) ── */
const ICONS = {
  arrow: "M5 12h14M13 5l7 7-7 7",
  check: "M20 6 9 17l-5-5",
  bolt: "M13 2 3 14h7l-1 8 10-12h-7z",
  layers: "M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 18l9 5 9-5",
  code: "M16 18l6-6-6-6 M8 6l-6 6 6 6",
  image: "M3 3h18v18H3z M3 15l5-5 4 4 3-3 6 6 M8.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3",
  gauge: "M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4 M13.4 12.6 19 7 M4 18a8 8 0 1 1 16 0",
  plug: "M9 2v6 M15 2v6 M6 8h12v3a6 6 0 0 1-12 0z M12 17v5",
  grid: "M3 3h7v7H3z M14 3h7v7h-7z M14 14h7v7h-7z M3 14h7v7H3z",
  play: "M6 4l14 8-14 8z",
  copy: "M9 9h11v11H9z M5 15H4V4h11v1",
  refresh: "M3 12a9 9 0 0 1 15-6.7L21 8 M21 3v5h-5 M21 12a9 9 0 0 1-15 6.7L3 16 M3 21v-5h5",
  chart: "M3 3v18h18 M7 14l4-4 3 3 5-6",
  book: "M4 19.5A2.5 2.5 0 0 1 6.5 17H20 M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z",
  cog: "M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6 M19.4 15a1.6 1.6 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.6 1.6 0 0 0-2.7 1.1V21a2 2 0 1 1-4 0v-.1A1.6 1.6 0 0 0 7 19.4l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1A1.6 1.6 0 0 0 4.6 14H4a2 2 0 1 1 0-4h.1A1.6 1.6 0 0 0 5.6 7L5.5 7a2 2 0 1 1 2.8-2.8l.1.1a1.6 1.6 0 0 0 1.8.3H10a1.6 1.6 0 0 0 1-1.5V4a2 2 0 1 1 4 0v.1a1.6 1.6 0 0 0 2.7 1.1l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.6 1.6 0 0 0-.3 1.8V10a1.6 1.6 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.6 1.6 0 0 0-1.5 1z",
  card: "M2 5h20v14H2z M2 10h20",
  bell: "M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9 M10.3 21a1.9 1.9 0 0 0 3.4 0",
  search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16 M21 21l-4.3-4.3",
  moon: "M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8z",
  sun: "M12 17a5 5 0 1 0 0-10 5 5 0 0 0 0 10 M12 1v2 M12 21v2 M4.2 4.2l1.4 1.4 M18.4 18.4l1.4 1.4 M1 12h2 M21 12h2 M4.2 19.8l1.4-1.4 M18.4 5.6l1.4-1.4",
  plus: "M12 5v14M5 12h14",
  x: "M18 6 6 18M6 6l12 12",
  film: "M2 3h20v18H2z M7 3v18 M17 3v18 M2 8h5 M17 8h5 M2 16h5 M17 16h5",
  file: "M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z M14 2v6h6",
  type: "M4 7V5h16v2 M9 19h6 M12 5v14",
  dollar: "M12 1v22 M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6",
  external: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6 M15 3h6v6 M10 14 21 3",
  zap: "M13 2 3 14h7l-1 8 10-12h-7z",
  globe: "M12 2a10 10 0 1 0 0 20 10 10 0 0 0 0-20 M2 12h20 M12 2a15 15 0 0 1 0 20 15 15 0 0 1 0-20",
  shield: "M12 2 4 6v6c0 5 3.5 8 8 10 4.5-2 8-5 8-10V6z",
  lock: "M5 11h14v10H5z M8 11V7a4 4 0 0 1 8 0v4",
  hash: "M4 9h16 M4 15h16 M10 3 8 21 M16 3l-2 18",
  clock: "M12 22a10 10 0 1 0 0-20 10 10 0 0 0 0 20 M12 6v6l4 2",
  sparkle: "M12 3l1.9 5.1L19 10l-5.1 1.9L12 17l-1.9-5.1L5 10l5.1-1.9z",
};
const Icon = ({ d, size = 18, sw = 1.8, style }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
    strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" style={style}>
    {(ICONS[d] || d).split(" M").map((p, i) => <path key={i} d={(i ? "M" : "") + p} />)}
  </svg>
);

/* ───────────────────────── Logo language ────────────────────────────────
   MostlyRender mark: rounded tile + two overlapping frames (one template →
   many renders) + the signature tiny dot, lower-right.                      */
const RenderMark = ({ s = 28, animate = false }) => (
  <svg width={s} height={s} viewBox="0 0 100 100" aria-hidden="true">
    <rect x="3" y="3" width="94" height="94" rx="27" fill="var(--accent)" />
    {/* Layers glyph — a template stack (one design, many outputs) */}
    <path d="M50 24 L74 38 L50 52 L26 38 Z" fill="none" stroke="#fff" strokeWidth="5" strokeLinejoin="round" />
    <path d="M26 50 L50 64 L74 50" fill="none" stroke="#fff" strokeWidth="5" strokeLinecap="round" strokeLinejoin="round" />
    {/* THE tiny dot */}
    <circle cx="76" cy="76" r="4.2" fill="#fff" className={animate ? "logo-dot" : undefined} />
  </svg>
);
const MTMark = ({ s = 16 }) => (
  <svg width={s} height={s} viewBox="0 0 100 100" aria-hidden="true">
    <rect x="3" y="3" width="94" height="94" rx="27" fill="var(--fg)" />
    <circle cx="74" cy="74" r="4.4" fill="var(--bg-elev)" />
  </svg>
);
const Wordmark = ({ size = 19, weight = 600 }) => (
  <span style={{ fontFamily: "var(--font-display)", fontWeight: weight, fontSize: size, letterSpacing: "-0.03em", color: "var(--fg)" }}>
    Mostly<span style={{ color: "var(--accent)" }}>Render</span>
  </span>
);

/* ───────────────────────── The live render: an OG / social card ──────────
   Beautiful, text-driven, theme-able. This is what the API "renders".       */
const RENDER_THEMES = {
  dusk:   { name: "Indigo dusk", bg: "linear-gradient(135deg,#23204a 0%,#3b2f73 48%,#5b5bd6 100%)", ink: "#ffffff", sub: "rgba(255,255,255,0.74)", chip: "rgba(255,255,255,0.16)", accent: "#c4bbff", mesh: true },
  aurora: { name: "Aurora", bg: "linear-gradient(120deg,#0c4a6e 0%,#0e7490 40%,#5b5bd6 100%)", ink: "#ffffff", sub: "rgba(255,255,255,0.76)", chip: "rgba(255,255,255,0.16)", accent: "#9ff0e6", mesh: true },
  bone:   { name: "Bone", bg: "#f5f5f7", ink: "#1d1d1f", sub: "#6e6e73", chip: "rgba(0,0,0,0.05)", accent: "#5b5bd6", mesh: false },
  ink:    { name: "Mono ink", bg: "#0a0a1a", ink: "#ffffff", sub: "rgba(255,255,255,0.6)", chip: "rgba(255,255,255,0.10)", accent: "#8a7cf0", mesh: false },
};

function RenderCard({ data, w = 560, cap = true }) {
  const t = RENDER_THEMES[data.theme] || RENDER_THEMES.dusk;
  const cq = (px) => (px / 12).toFixed(3) + "cqw"; // 1200px design grid → 100cqw, so the card scales to its container
  return (
    <div style={{
      width: w, maxWidth: cap ? "100%" : "none", aspectRatio: "1200 / 630", containerType: "inline-size",
      borderRadius: cq(17), overflow: "hidden", position: "relative",
      background: t.bg, color: t.ink, boxShadow: "0 1px 3px rgba(10,10,26,.10), 0 18px 48px rgba(10,10,26,.16)",
    }}>
      {t.mesh && (
        <div style={{ position: "absolute", inset: 0, opacity: 0.6, pointerEvents: "none",
          background: "radial-gradient(60% 80% at 82% 18%, rgba(255,255,255,.22), transparent 60%), radial-gradient(50% 70% at 12% 96%, rgba(0,0,0,.28), transparent 55%)" }} />
      )}
      <div style={{ position: "absolute", inset: 0, padding: cq(64), display: "flex", flexDirection: "column", boxSizing: "border-box" }}>
        <div style={{ display: "flex", alignItems: "center", gap: cq(14) }}>
          <div style={{ width: cq(44), height: cq(44) }}><RenderMark s="100%" /></div>
          <span style={{ fontWeight: 600, fontSize: cq(26), letterSpacing: "-0.02em" }}>
            {data.brand || "MostlyRender"}
          </span>
          <span style={{ marginLeft: "auto", fontSize: cq(22), fontWeight: 600, color: t.accent,
            background: t.chip, padding: `${cq(10)} ${cq(20)}`, borderRadius: 999 }}>
            {data.badge || "Changelog"}
          </span>
        </div>
        <div style={{ marginTop: "auto" }}>
          <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: cq(78), lineHeight: 1.02,
            letterSpacing: "-0.035em", textWrap: "balance", maxWidth: "16em" }}>
            {data.title || "Your title here"}
          </div>
          <div style={{ marginTop: cq(26), fontSize: cq(31), lineHeight: 1.32, color: t.sub, maxWidth: "30em", fontWeight: 450 }}>
            {data.subtitle || "A subtitle that explains the thing."}
          </div>
          <div style={{ marginTop: cq(40), display: "flex", alignItems: "center", gap: cq(16) }}>
            <div style={{ width: cq(56), height: cq(56), borderRadius: 999, background: t.accent,
              display: "grid", placeItems: "center", color: t.theme === "bone" ? "#fff" : "#1d1d1f", fontWeight: 700, fontSize: cq(24),
              fontFamily: "var(--font-display)" }}>
              {(data.author || "AR").split(" ").map((x) => x[0]).join("").slice(0, 2).toUpperCase()}
            </div>
            <div style={{ lineHeight: 1.3, whiteSpace: "nowrap" }}>
              <div style={{ fontWeight: 600, fontSize: cq(25) }}>{data.author || "Ada Render"}</div>
              <div style={{ fontSize: cq(21), color: t.sub }}>{data.role || "Engineering"}</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ───────────────────────── Payload + code generators ─────────────────────
   The "layer name IS the API parameter" idea: every editable field maps to a
   modifications key, and the same object drives cURL / Node / Python.        */
function buildModifications(data) {
  // Only emit keys that map to real template layers (flat, name-keyed) — the engine
  // overrides layers BY NAME, so invented keys (author.name/theme) silently no-op.
  if (data && data.modifications) return data.modifications;
  const out = {};
  ["title", "subtitle", "badge"].forEach((k) => { if (data && data[k] != null) out[k] = data[k]; });
  return out;
}
function payloadObject(data) {
  return { templateId: (data && (data.templateId || data.template)) || "tpl_xxx", modifications: buildModifications(data) };
}
const API_KEY = "mr_test_YOUR_KEY"; // placeholder for snippets; real keys come from the dashboard

function jsonLines(obj, indent = 0) {
  // returns array of {text, depth} — simple stable pretty printer for our shapes
  const pad = "  ".repeat(indent);
  const out = [];
  const entries = Object.entries(obj);
  entries.forEach(([k, v], i) => {
    const comma = i < entries.length - 1 ? "," : "";
    if (v && typeof v === "object" && !Array.isArray(v)) {
      out.push(`${pad}"${k}": {`);
      out.push(...jsonLines(v, indent + 1));
      out.push(`${pad}}${comma}`);
    } else {
      out.push(`${pad}"${k}": ${JSON.stringify(v)}${comma}`);
    }
  });
  return out;
}

function codeSnippet(lang, data, opts = {}) {
  const apiUrl = opts.apiUrl || "https://api.mostlyrender.com";
  const key = opts.apiKey || API_KEY;
  const body = payloadObject(data);
  // Honest: a real Bearer POST to /v1/renders (the deployed renderApi endpoint).
  if (lang === "curl") {
    return `curl ${apiUrl}/v1/renders \\
  -H "Authorization: Bearer ${key}" \\
  -H "Content-Type: application/json" \\
  -d '${JSON.stringify(body)}'`;
  }
  if (lang === "node") {
    return `const res = await fetch("${apiUrl}/v1/renders", {
  method: "POST",
  headers: { Authorization: "Bearer ${key}", "Content-Type": "application/json" },
  body: JSON.stringify(${JSON.stringify(body, null, 2).replace(/\n/g, "\n  ")}),
});
const { url } = await res.json();
console.log(url);`;
  }
  // python
  return `import requests
res = requests.post(
    "${apiUrl}/v1/renders",
    headers={"Authorization": "Bearer ${key}"},
    json=${JSON.stringify(body, null, 4).replace(/\n/g, "\n    ")},
)
print(res.json()["url"])`;
}

/* ── async + error helpers (used by every wired screen) ── */
function useAsync(fn, deps) {
  const { useState, useEffect, useCallback } = React;
  const [st, setSt] = useState({ data: null, loading: true, error: null });
  const run = useCallback(() => {
    let alive = true;
    setSt((s) => ({ ...s, loading: true, error: null }));
    Promise.resolve().then(fn).then(
      (data) => alive && setSt({ data, loading: false, error: null }),
      (error) => alive && setSt({ data: null, loading: false, error }),
    );
    return () => { alive = false; };
  }, deps || []); // eslint-disable-line react-hooks/exhaustive-deps
  useEffect(run, [run]);
  return { data: st.data, loading: st.loading, error: st.error, reload: run };
}
function errMsg(e) {
  const code = (e && (e.code || (e.details && e.details.code))) || "";
  if (/unauthenticated/.test(code)) return "Please sign in to continue.";
  if (/resource-exhausted/.test(code)) return "You've hit your free render quota — upgrade to keep rendering.";
  if (/permission-denied/.test(code)) return "You don't have access to that.";
  if (/not-found/.test(code)) return "Not found.";
  return (e && e.message) || "Something went wrong.";
}
const Spinner = ({ size = 18 }) => (
  <span style={{ width: size, height: size, display: "inline-block", border: "2px solid var(--border)", borderTopColor: "var(--accent)", borderRadius: "50%", animation: "mrspin .7s linear infinite", verticalAlign: "middle" }} />
);
const ErrorCard = ({ error, onRetry }) => (
  <div style={{ border: "1px solid var(--border)", borderRadius: "var(--radius)", padding: "18px 20px", background: "var(--bg-elev)" }}>
    <div style={{ fontWeight: 600, color: "var(--fg)" }}>Couldn't load</div>
    <div style={{ fontSize: 13, marginTop: 4, color: "var(--fg-muted)" }}>{errMsg(error)}</div>
    {onRetry && <button className="forge-btn forge-btn--secondary" style={{ marginTop: 12 }} onClick={onRetry}>Try again</button>}
  </div>
);

/* tiny syntax tint for the dark code panel */
function highlight(code, lang) {
  // escape
  let s = code.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  // strings
  s = s.replace(/(&quot;|")(?:[^"\\]|\\.)*\1|'(?:[^'\\]|\\.)*'/g, (m) => `<span class="tok-str">${m}</span>`);
  s = s.replace(/(?:&quot;)(?:[^&]|&(?!quot;))*(?:&quot;)/g, (m) => `<span class="tok-str">${m}</span>`);
  // keywords
  s = s.replace(/\b(import|from|const|await|new|print|def|return)\b/g, '<span class="tok-kw">$1</span>');
  // comments (// and #)
  s = s.replace(/(\/\/[^\n]*)/g, '<span class="tok-com">$1</span>');
  s = s.replace(/(#[^\n]*)/g, '<span class="tok-com">$1</span>');
  // numbers
  s = s.replace(/\b(\d[\d,]*\.?\d*)\b/g, '<span class="tok-num">$1</span>');
  return s;
}

// Mount helper for the per-page boot files: hydrate prerendered HTML in production,
// plain createRoot in dev / app pages. Replaces the prototype's mount.jsx + TweaksPanel.
function mrBoot(node) {
  const el = document.getElementById("mr-app");
  if (!el) return;
  if (el.firstElementChild) ReactDOM.hydrateRoot(el, node);
  else ReactDOM.createRoot(el).render(node);
}

Object.assign(window, {
  MR_F: F, Icon, ICONS, RenderMark, MTMark, Wordmark,
  RenderCard, RENDER_THEMES, buildModifications, payloadObject, codeSnippet, highlight, API_KEY,
  useAsync, errMsg, Spinner, ErrorCard, mrBoot,
});
