// Main app — hero + image-backed project cards + modal + tweaks + gold sparkle cursor

const { useState, useEffect, useMemo } = React;

// ── Firebase (initialised once; shared with admin if on same page, but these are separate files) ──
if (!firebase.apps.length) {
  firebase.initializeApp(window.APP_CONFIG.firebase);
}
const _db = firebase.firestore();

const DEFAULTS = /*EDITMODE-BEGIN*/{
  "direction": "default",
  "density": "roomy"
}/*EDITMODE-END*/;

// Legacy fallback sizes (used when a project has no cardSize set)
const SIZE_RECIPE = ["wide", "", "", "", "feature", "tall", "", "", "wide", "tall", "", "", "feature"];

function CursorSparkles() {
  useEffect(() => {
    let last = 0;
    const onMove = (e) => {
      const now = performance.now();
      if (now - last < 55) return;
      last = now;
      const el = document.createElement("div");
      el.className = "ember";
      const size = 4 + Math.random() * 5;
      el.style.width = el.style.height = size + "px";
      el.style.left = (e.clientX + (Math.random() - 0.5) * 14) + "px";
      el.style.top = (e.clientY + (Math.random() - 0.5) * 14) + "px";
      document.body.appendChild(el);
      setTimeout(() => el.remove(), 1100);
    };
    window.addEventListener("pointermove", onMove);
    return () => window.removeEventListener("pointermove", onMove);
  }, []);
  return null;
}

const STATUS_LABEL = { live: "live", wip: "wip", finished: "archived" };

// Filigree corner ornament — a small SVG swirl echoing the logo's corner motifs
function CornerSwirl({ className }) {
  return (
    <svg className={`card-corner ${className || ""}`} viewBox="0 0 30 30" aria-hidden="true">
      <path d="M 28 2 Q 20 2 16 6 Q 12 10 10 14 Q 8 18 4 20 Q 2 14 6 10 Q 10 6 16 6"
            fill="none" stroke="currentColor" strokeWidth="1.2" strokeLinecap="round"/>
      <circle cx="4" cy="20" r="1.3" fill="currentColor"/>
    </svg>
  );
}

// Placeholder screenshot — soft pastel gradient keyed to each discipline, with a tidy label.
function Placeholder({ hue, label }) {
  const bgA = `oklch(0.86 0.08 ${hue})`;
  const bgB = `oklch(0.74 0.1  ${hue + 30})`;
  return (
    <div className="placeholder-screenshot" style={{
      background: `
        radial-gradient(ellipse at 30% 30%, ${bgA} 0%, transparent 60%),
        radial-gradient(ellipse at 80% 80%, ${bgB} 0%, transparent 60%),
        linear-gradient(160deg, ${bgA}, ${bgB})`
    }}>
      <span className="placeholder-label">{label}</span>
    </div>
  );
}

function CardImage({ src, hue, label }) {
  if (!src) return <Placeholder hue={hue} label={label} />;
  return (
    <div className="card-img-wrap">
      <img src={src} className="card-img-blur" aria-hidden="true" alt="" />
      <img src={src} className="card-img-main" alt="" />
    </div>
  );
}

function ImageCarousel({ images }) {
  const [idx, setIdx] = useState(0);
  if (!images.length) return null;
  const prev = () => setIdx(i => (i - 1 + images.length) % images.length);
  const next = () => setIdx(i => (i + 1) % images.length);
  return (
    <div className="carousel">
      <img src={images[idx]} alt="" className="carousel-img" />
      {images.length > 1 && (
        <>
          <button className="carousel-btn carousel-prev" onClick={prev} aria-label="Previous">‹</button>
          <button className="carousel-btn carousel-next" onClick={next} aria-label="Next">›</button>
          <div className="carousel-dots">
            {images.map((_, i) => (
              <button key={i} className={`carousel-dot ${i === idx ? "active" : ""}`} onClick={() => setIdx(i)} aria-label={`Image ${i + 1}`} />
            ))}
          </div>
        </>
      )}
    </div>
  );
}

function Card({ p, onOpen, hidden, size, index }) {
  const hue = window.DISCIPLINES[p.disciplines?.[0]]?.hue ?? 280;
  const previewSrc = (p.images && p.images[0]) || p.image || null;
  return (
    <article
      className={`hoard-card ${size} ${hidden ? "hidden" : ""}`}
      onClick={() => onOpen(p)}
    >
      <div className="card-bg">
        <CardImage src={previewSrc} hue={hue} label={`${p.id}.png`} />
        <CornerSwirl className="tl" />
        <CornerSwirl className="tr" />
        <span className="corner-num">{String(index + 1).padStart(2, "0")}</span>
        <span className={`status status-${p.status}`}>{STATUS_LABEL[p.status]}</span>
      </div>

      <div className="card-body">
        <div className="card-tags">
          {(p.disciplines || []).map(d => (
            <span key={d} className="card-tag">{window.DISCIPLINES[d]?.label ?? d}</span>
          ))}
        </div>
        <h3 className="card-title">{p.title}</h3>
        <p className="card-subtitle">{p.subtitle}</p>
        <div className="card-links">
          {p.subdomain && <span className="link">visit <span className="arrow">↗</span></span>}
          {p.github && <span className="link">source <span className="arrow">↗</span></span>}
          {p.kofi && <span className="link">get it <span className="arrow">↗</span></span>}
          {!p.subdomain && !p.github && !p.kofi && <span className="link muted">one-of-one</span>}
          <span className="ml-auto">{p.year}</span>
        </div>
      </div>
    </article>
  );
}

function Modal({ p, onClose }) {
  useEffect(() => {
    const onKey = (e) => e.key === "Escape" && onClose();
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => { window.removeEventListener("keydown", onKey); document.body.style.overflow = ""; };
  }, [onClose]);
  if (!p) return null;
  const hue = window.DISCIPLINES[p.disciplines?.[0]]?.hue ?? 280;
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <button className="modal-close" onClick={onClose}>Close ✕</button>
        <div className="modal-hero">
          {(() => {
            const imgs = p.images?.length ? p.images : p.image ? [p.image] : [];
            return imgs.length
              ? <ImageCarousel images={imgs} />
              : <Placeholder hue={hue} label={`${p.id}.png`} />;
          })()}
        </div>
        <div className="modal-body">
          <div className="modal-meta">
            <span>{p.year}</span>
            <span className="dot">◆</span>
            <span className={`status status-${p.status}`} style={{position:"static"}}>{STATUS_LABEL[p.status]}</span>
          </div>
          <h3>{p.title}</h3>
          <p className="modal-sub">{p.subtitle}</p>
          <p className="body">{p.summary}</p>
          <div className="modal-grid">
            <div className="modal-field">
              Disciplines
              <span className="val">{(p.disciplines || []).map(d => window.DISCIPLINES[d]?.label ?? d).join(" · ")}</span>
            </div>
            <div className="modal-field">
              Made with
              <span className="val">{p.tools.join(", ")}</span>
            </div>
            {p.subdomain && (
              <div className="modal-field">
                Lives at
                <span className="val"><a href={`https://${p.subdomain}`} target="_blank" rel="noopener">{p.subdomain} ↗</a></span>
              </div>
            )}
            {p.github && (
              <div className="modal-field">
                Source
                <span className="val"><a href={p.github} target="_blank" rel="noopener">github.com ↗</a></span>
              </div>
            )}
            {p.kofi && (
              <div className="modal-field">
                Get it at
                <span className="val"><a href={p.kofi} target="_blank" rel="noopener">ko-fi.com ↗</a></span>
              </div>
            )}
            {!p.subdomain && !p.github && !p.kofi && (
              <div className="modal-field">
                A one-of-one
                <span className="val">This one lives in the physical world — no repo, no subdomain.</span>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

function TweaksPanel({ visible, sparkles, setSparkles, tagline, setTagline }) {
  if (!visible) return null;
  return (
    <div className="tweaks-panel">
      <h4>MythBehave <em>Tweaks</em></h4>
      <div className="tweak-row">
        <label>Cursor sparkles</label>
        <div className="tweak-buttons">
          <button className={`tweak-btn ${sparkles ? "active" : ""}`} onClick={() => setSparkles(true)}>on</button>
          <button className={`tweak-btn ${!sparkles ? "active" : ""}`} onClick={() => setSparkles(false)}>off</button>
        </div>
      </div>
      <div className="tweak-row">
        <label>Tagline voice</label>
        <div className="tweak-buttons">
          {["hoard", "studios", "plain"].map(t => (
            <button key={t} className={`tweak-btn ${tagline === t ? "active" : ""}`} onClick={() => setTagline(t)}>{t}</button>
          ))}
        </div>
      </div>
    </div>
  );
}

const TAGLINES = {
  hoard: <>A <strong>dragon's hoard</strong> of the things I make. Half of them live on subdomains, some live in closets and con-bins and still others are printable: all of them are too interesting to throw away.</>,
  studios: <>Welcome to <strong>MythBehave Studios</strong> — a one-person workshop where code, costume, prop, and print all share the same worktable.</>,
  plain: <>I'm <strong>Bleu</strong>. I make things — software, costumes, props, graphic design, electronics. This is where they all live together.</>,
};

function App() {
  const [projects, setProjects]   = useState([]);
  const [loadingDB, setLoadingDB] = useState(true);
  const [sparkles, setSparkles]   = useState(true);
  const [tagline, setTagline]     = useState("hoard");
  const [tweaksVisible, setTweaksVisible] = useState(false);
  const [filter, setFilter]   = useState(null);
  const [openProj, setOpenProj] = useState(null);

  // Load projects from Firestore; fall back to hardcoded data.js on error
  useEffect(() => {
    const unsub = _db.collection("projects")
      .orderBy("order", "asc")
      .onSnapshot(
        snap => { setProjects(snap.docs.map(d => ({ _fid: d.id, ...d.data() }))); setLoadingDB(false); },
        ()   => { setProjects(window.PROJECTS || []); setLoadingDB(false); }
      );
    return unsub;
  }, []);

  useEffect(() => {
    const onMsg = (e) => {
      if (e.data?.type === "__activate_edit_mode") setTweaksVisible(true);
      if (e.data?.type === "__deactivate_edit_mode") setTweaksVisible(false);
    };
    window.addEventListener("message", onMsg);
    window.parent.postMessage({ type: "__edit_mode_available" }, "*");
    return () => window.removeEventListener("message", onMsg);
  }, []);

  const counts = useMemo(() => {
    const c = { all: projects.length };
    Object.keys(window.DISCIPLINES).forEach(k => c[k] = 0);
    projects.forEach(p => (p.disciplines || []).forEach(d => c[d] = (c[d] || 0) + 1));
    return c;
  }, [projects]);

  return (
    <>
      {sparkles && <CursorSparkles />}

      <div className="page">
        <a href="https://ko-fi.com/mythbehave" target="_blank" rel="noopener" className="kofi-link">
          <span className="kofi-cup">☕</span>
          <span className="kofi-text">Support on <strong>Ko-fi</strong></span>
        </a>
        <header className="hero">
          <div className="hero-mark">
            <img src="wordmark-hd.png" alt="MythBehave Studios" className="hero-wordmark-img" />
            <img src="dragon-hd-3.png" alt="" className="floating-dragon hero-dragon"
                 style={{position:"absolute", right:"-1%", bottom:"10px", transform:"rotate(10deg)", width:"250px", opacity:1, zIndex:0}} />
          </div>
          <p className="tagline">{TAGLINES[tagline]}</p>
          <div className="byline">
            <span>Code</span><span className="sep">✦</span>
            <span>Costume</span><span className="sep">✦</span>
            <span>Graphic</span><span className="sep">✦</span>
            <span>Cosplay</span><span className="sep">✦</span>
            <span>Prop-making</span><span className="sep">✦</span>
            <span>Electronics</span>
          </div>
        </header>

        <div className="flourish">
          <span className="flourish-glyph">❦</span>
        </div>

        <div className="section-head" style={{position:"relative"}}>
          <h2>The <em>Hoard</em></h2>
          <span className="count">{projects.length} treasures · {Object.keys(window.DISCIPLINES).length} trades</span>
        </div>

        <div className="filters" style={{position:"relative"}}>
          <span className="filter-label">Sort by trade</span>
          <button className={`filter-chip ${!filter ? "active" : ""}`} onClick={() => setFilter(null)}>
            all <span className="chip-count">({counts.all})</span>
          </button>
          {Object.entries(window.DISCIPLINES).map(([k, d]) => (
            <button key={k} className={`filter-chip ${filter === k ? "active" : ""}`} onClick={() => setFilter(filter === k ? null : k)}>
              {d.label} <span className="chip-count">({counts[k]})</span>
            </button>
          ))}
          <img src="dragon-hd-1.png" alt="" className="floating-dragon"
               style={{left: "-80px", top: "-60px", transform: "rotate(-12deg)", width: "110px"}} />
        </div>

        <div className="hoard">
          {loadingDB
            ? <p style={{gridColumn:"1/-1",textAlign:"center",color:"var(--ink-dim)",fontStyle:"italic",padding:"60px 0"}}>Loading the hoard…</p>
            : projects.map((p, i) => (
              <Card
                key={p._fid || p.id}
                p={p}
                index={i}
                size={p.cardSize || SIZE_RECIPE[i] || ""}
                hidden={filter && !p.disciplines.includes(filter)}
                onOpen={setOpenProj}
              />
            ))
          }
        </div>

        <section className="about" data-screen-label="about" style={{position:"relative"}}>
          <img src="dragon-hd-2.png" alt="" className="floating-dragon"
               style={{right: "-30px", bottom: "-20px", transform: "rotate(-8deg)", width: "130px"}} />
          <h2>About <em>Bleu</em></h2>
          <div>
            <p>
              I'm a cheerful generalist. I write and develop games, programs and websites during the week; then spend
              weekends sewing scales onto bodices, tooling leather bracers,
              and coming up with new and interesting ways to use electronic components.
            </p>
            <p>
              This is the part of the internet where all of it lives in the
              same place — half subdomain, half studio. Click any card to see
              how it was made.
            </p>
            <p className="sig">— Bleu, keeper of this hoard</p>
          </div>
        </section>

        <footer>
          <span>© MMXXVI · MythBehave.com</span>
          <em>Here be dragons.</em>
          <span>bleu [at] mythbehave</span>
        </footer>
      </div>

      {openProj && <Modal p={openProj} onClose={() => setOpenProj(null)} />}

      <TweaksPanel
        visible={tweaksVisible}
        sparkles={sparkles}
        setSparkles={setSparkles}
        tagline={tagline}
        setTagline={setTagline}
      />
    </>
  );
}

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