/* global React, ReactDOM, RuggedNote, CrashCoin, BleedingCandle, CopeWojak, InflationPig, PrinterDemon, DoomerWojak, BrainletWojak, ChadWojak, NpcWojak */

const MASCOTS = [
  { id: "rugged-note", name: "The Rugged Note", tagline: "rp 1.000.000, rugged with prejudice", Component: () => <RuggedNote/> },
  { id: "crash-coin", name: "The Crash Coin", tagline: "embossed cope. legal tender.", Component: () => <CrashCoin/> },
  { id: "bleeding-candle", name: "The Bleeding Candle", tagline: "down-only, with feelings", Component: () => <BleedingCandle/> },
  { id: "cope-wojak", name: "The Cope Wojak", tagline: "dollar-sign tears, cope-grip pose", Component: () => <CopeWojak/> },
  { id: "doomer-wojak", name: "Doomer Wojak", tagline: "hoodie + cig + endless cope", Component: () => <DoomerWojak/> },
  { id: "brainlet-wojak", name: "Brainlet Wojak", tagline: "buy high, sell low, $$ eyes", Component: () => <BrainletWojak/> },
  { id: "chad-wojak", name: "Chad Wojak", tagline: "still holding. crying inside.", Component: () => <ChadWojak/> },
  { id: "npc-wojak", name: "NPC Wojak", tagline: "inflation is transitory.", Component: () => <NpcWojak/> },
  { id: "inflation-pig", name: "The Inflation Pig", tagline: "savings down, snout angry", Component: () => <InflationPig/> },
  { id: "printer-demon", name: "The Printer Demon", tagline: "BRRR victims welcome", Component: () => <PrinterDemon/> },
];

function serializeSvg(svgEl) {
  const clone = svgEl.cloneNode(true);
  clone.setAttribute("xmlns", "http://www.w3.org/2000/svg");
  clone.setAttribute("width", "1024");
  clone.setAttribute("height", "1024");
  const fontImport = document.createElementNS("http://www.w3.org/2000/svg", "style");
  fontImport.textContent = `@import url("https://fonts.googleapis.com/css2?family=Archivo+Black&family=IBM+Plex+Sans:wght@400;700;800&family=IBM+Plex+Mono:wght@400;700&display=swap");`;
  clone.insertBefore(fontImport, clone.firstChild);
  return new XMLSerializer().serializeToString(clone);
}

function triggerDownload(blob, filename) {
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1500);
}

function downloadSvg(svgEl, filename) {
  const xml = serializeSvg(svgEl);
  triggerDownload(new Blob([xml], { type: "image/svg+xml;charset=utf-8" }), filename);
}

async function downloadPng(svgEl, filename, size = 1024) {
  if (document.fonts && document.fonts.ready) {
    try { await document.fonts.ready; } catch (e) {}
  }
  const xml = serializeSvg(svgEl);
  const svgBlob = new Blob([xml], { type: "image/svg+xml;charset=utf-8" });
  const url = URL.createObjectURL(svgBlob);
  try {
    const img = new Image();
    img.crossOrigin = "anonymous";
    await new Promise((resolve, reject) => {
      img.onload = resolve;
      img.onerror = (e) => reject(e);
      img.src = url;
    });
    const canvas = document.createElement("canvas");
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0, size, size);
    await new Promise((resolve) => {
      canvas.toBlob((blob) => {
        if (blob) triggerDownload(blob, filename);
        resolve();
      }, "image/png");
    });
  } finally {
    setTimeout(() => URL.revokeObjectURL(url), 1500);
  }
}

function MascotCard({ mascot, onExpand }) {
  const svgRef = React.useRef(null);
  const [busy, setBusy] = React.useState(null);

  async function handleDownload(kind) {
    const svgEl = svgRef.current?.querySelector("svg");
    if (!svgEl) return;
    setBusy(kind);
    try {
      if (kind === "png") await downloadPng(svgEl, `rugpiah-${mascot.id}.png`, 1024);
      else if (kind === "png-2x") await downloadPng(svgEl, `rugpiah-${mascot.id}@2x.png`, 2048);
      else downloadSvg(svgEl, `rugpiah-${mascot.id}.svg`);
    } catch (e) {
      console.error(e);
    } finally {
      setBusy(null);
    }
  }

  const Comp = mascot.Component;

  return (
    <article className="mascot-card">
      <div className="mascot-preview" ref={svgRef} onClick={() => onExpand(mascot)}>
        <Comp/>
        <div className="zoom-hint">click to enlarge ⤢</div>
      </div>
      <div className="mascot-meta">
        <div className="mascot-id">{mascot.id}</div>
        <h3 className="mascot-name">{mascot.name}</h3>
        <p className="mascot-tag">{mascot.tagline}</p>
      </div>
      <div className="mascot-actions">
        <button type="button" className="dl dl-primary" onClick={() => handleDownload("png")} disabled={busy !== null}>
          {busy === "png" ? "rendering…" : "↓ PNG · 1024"}
        </button>
        <button type="button" className="dl" onClick={() => handleDownload("png-2x")} disabled={busy !== null}>
          {busy === "png-2x" ? "…" : "PNG · 2048"}
        </button>
        <button type="button" className="dl" onClick={() => handleDownload("svg")} disabled={busy !== null}>
          ↓ SVG
        </button>
      </div>
    </article>
  );
}

function MascotModal({ mascot, onClose }) {
  const svgRef = React.useRef(null);
  const [busy, setBusy] = React.useState(null);

  React.useEffect(() => {
    function onKey(e) {
      if (e.key === "Escape") onClose();
    }
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [onClose]);

  if (!mascot) return null;
  const Comp = mascot.Component;

  async function handleDownload(kind) {
    const svgEl = svgRef.current?.querySelector("svg");
    if (!svgEl) return;
    setBusy(kind);
    try {
      if (kind === "png") await downloadPng(svgEl, `rugpiah-${mascot.id}.png`, 1024);
      else if (kind === "png-2x") await downloadPng(svgEl, `rugpiah-${mascot.id}@2x.png`, 2048);
      else downloadSvg(svgEl, `rugpiah-${mascot.id}.svg`);
    } finally {
      setBusy(null);
    }
  }

  return (
    <div className="modal-shade" onClick={onClose}>
      <div className="modal-box" onClick={(e) => e.stopPropagation()}>
        <button className="modal-close" type="button" onClick={onClose} aria-label="close">×</button>
        <div className="modal-svg" ref={svgRef}>
          <Comp/>
        </div>
        <div className="modal-meta">
          <div className="mascot-id">{mascot.id}</div>
          <h2 className="modal-name">{mascot.name}</h2>
          <p className="mascot-tag">{mascot.tagline}</p>
          <div className="mascot-actions">
            <button type="button" className="dl dl-primary" onClick={() => handleDownload("png")} disabled={busy !== null}>
              {busy === "png" ? "rendering…" : "↓ PNG · 1024"}
            </button>
            <button type="button" className="dl" onClick={() => handleDownload("png-2x")} disabled={busy !== null}>
              {busy === "png-2x" ? "…" : "PNG · 2048"}
            </button>
            <button type="button" className="dl" onClick={() => handleDownload("svg")} disabled={busy !== null}>
              ↓ SVG
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

function App() {
  const [open, setOpen] = React.useState(null);

  return (
    <React.Fragment>
      <header className="gallery-head">
        <a className="back-link" href="/" target="_top" rel="noreferrer">← back to rugpiah.meme</a>
        <h1 className="gallery-title">
          RUGPIAH <span className="crash">mascot</span> gallery.
        </h1>
        <p className="gallery-sub">
          Ten PFP-ready candidates — banknotes, wojaks, coins, candles, and beyond.
          Pick one, smash download. Each comes in 1024 PNG, 2048 PNG (for cropping
          headroom), and the raw SVG.
        </p>
        <div className="gallery-meta">
          <span className="chip">{MASCOTS.length} variants</span>
          <span className="chip">1:1 square · PFP-ready</span>
          <span className="chip">PNG + SVG</span>
        </div>
      </header>

      <main className="gallery">
        {MASCOTS.map((m) => (
          <MascotCard key={m.id} mascot={m} onExpand={setOpen}/>
        ))}
      </main>

      <footer className="gallery-foot">
        all mascots are CSS+SVG · vector · scale to any size.
        if you want a custom variant (eg. doge×rupiah, pepe×rupiah, your face on a banknote), ask in chat.
      </footer>

      <MascotModal mascot={open} onClose={() => setOpen(null)}/>
    </React.Fragment>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App/>);
