// app.jsx — momoGood Release notes app
const { useState, useEffect, useMemo, useRef } = React;

// ─── Tiny helpers ────────────────────────────────────────────
const fmtDate = (iso) => {
  const d = new Date(iso + "T12:00:00");
  return d.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
};
const fmtMonth = (iso) => {
  const d = new Date(iso + "T12:00:00");
  return d.toLocaleDateString("en-US", { month: "long", year: "numeric" }).toUpperCase();
};
const dayNum = (iso) => new Date(iso + "T12:00:00").getDate();
const monShort = (iso) =>
  new Date(iso + "T12:00:00").toLocaleDateString("en-US", { month: "short" }).toUpperCase();

const productById = (id) => window.PRODUCTS.find((p) => p.id === id);
const productMeta = (rel) => {
  const p = window.PRODUCTS.find((x) => x.id === rel.product);
  if (p) return { label: p.label, sublabel: p.sublabel, dot: p.dot };
  // Platform / unknown
  return { label: rel.productLabel || "Platform", sublabel: null, dot: "#2D2C3E" };
};

// ─── Hash router ─────────────────────────────────────────────
function useHashRoute() {
  // On pre-rendered release pages, __RELEASE_ID__ is set before the app loads.
  // Use it to initialize the route so React shows the correct release immediately.
  const initial = window.__RELEASE_ID__
    ? `#/r/${window.__RELEASE_ID__}`
    : (window.location.hash || "#/");
  const [hash, setHash] = useState(initial);
  useEffect(() => {
    const onHash = () => setHash(window.location.hash || "#/");
    window.addEventListener("hashchange", onHash);
    return () => window.removeEventListener("hashchange", onHash);
  }, []);
  return hash;
}

// ─── Icons (inline SVG, Lucide-ish stroke) ──────────────────
const Icon = ({ name, size = 16, stroke = 1.5 }) => {
  const s = size;
  const sw = stroke;
  const common = {
    width: s, height: s, viewBox: "0 0 24 24",
    fill: "none", stroke: "currentColor",
    strokeWidth: sw, strokeLinecap: "round", strokeLinejoin: "round",
  };
  switch (name) {
    case "search":
      return (<svg {...common}><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>);
    case "arrow-right":
      return (<svg {...common}><path d="M5 12h14"/><path d="m13 6 6 6-6 6"/></svg>);
    case "arrow-left":
      return (<svg {...common}><path d="M19 12H5"/><path d="m11 18-6-6 6-6"/></svg>);
    case "list":
      return (<svg {...common}><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>);
    case "grid":
      return (<svg {...common}><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>);
    case "doc":
      return (<svg {...common}><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>);
    case "link":
      return (<svg {...common}><path d="M10 13a5 5 0 0 0 7.07 0l3-3a5 5 0 0 0-7.07-7.07l-1.5 1.5"/><path d="M14 11a5 5 0 0 0-7.07 0l-3 3a5 5 0 0 0 7.07 7.07l1.5-1.5"/></svg>);
    case "share":
      return (<svg {...common}><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.6" y1="13.5" x2="15.4" y2="17.5"/><line x1="15.4" y1="6.5" x2="8.6" y2="10.5"/></svg>);
    default: return null;
  }
};

// ─── Pills ───────────────────────────────────────────────────
function ProductPill({ rel }) {
  const m = productMeta(rel);
  return (
    <span className="pill pill--product">
      <span className="pill__dot" style={{ background: m.dot }}/>
      {m.label}
    </span>
  );
}
function TagPill({ tag }) {
  const c = window.TAG_COLORS[tag] || { bg: "#F1EEE3", fg: "#6B6B6B" };
  return (
    <span className="pill pill--tag" style={{ background: c.bg, color: c.fg }}>
      {tag}
    </span>
  );
}
function VersionPill({ v }) {
  return <span className="pill--version">{v}</span>;
}

// ─── Top bar ─────────────────────────────────────────────────
function TopBar({ onOpenSearch }) {
  return (
    <header className="topbar">
      <div className="topbar__left">
        <a href="/" style={{ display: "inline-flex" }}>
          <img src="assets/logo/wordmark-nightsky.svg" alt="momoGood" height="22"
               style={{ display: "block", height: 22, width: "auto" }} />
        </a>
        <span className="topbar__divider"/>
        <span className="topbar__crumb">Release notes</span>
      </div>
      <div className="topbar__center">
        <button className="search" onClick={onOpenSearch} aria-label="Search updates">
          <span className="search__icon"><Icon name="search" size={15}/></span>
          <span className="search__placeholder">Search updates</span>
          <span className="search__kbd">⌘K</span>
        </button>
      </div>
      <div className="topbar__right"/>
    </header>
  );
}

// ─── Hero ────────────────────────────────────────────────────
function Hero() {
  return (
    <section className="hero">
      <p className="hero__eyebrow">Release notes</p>
      <h1 className="hero__title">
        What's <em>new</em> at momoGood.
      </h1>
      <p className="hero__lede">
        Every update across Giving, Events, and Texting — written for the people who use them.
        New features, improvements, and the occasional fix, all in one place.
      </p>
    </section>
  );
}

// ─── Featured release ────────────────────────────────────────
function Featured({ rel }) {
  const illust = rel.illustration ? `assets/illustrations/${rel.illustration}.png` : null;
  return (
    <a className="featured" href={`/releases/${rel.id}/`}>
      <div className="featured__body">
        <div className="featured__meta">
          <ProductPill rel={rel}/>
          {rel.tags.map((t) => <TagPill key={t} tag={t}/>)}
          <span className="metadate">{fmtDate(rel.date)}</span>
          <span className="metasep">·</span>
          <VersionPill v={rel.version}/>
        </div>
        <h2 className="featured__title">{rel.title}</h2>
        <p className="featured__summary">{rel.summary}</p>
        <span className="featured__cta">
          Read the full release <Icon name="arrow-right" size={14}/>
        </span>
      </div>
      <div className="featured__art">
        <div className="featured__art-card">
          {illust && <img src={illust} alt=""/>}
        </div>
      </div>
    </a>
  );
}

// ─── Filter chips ────────────────────────────────────────────
function FilterChips({ value, onChange }) {
  return (
    <div className="chips">
      {window.PRODUCTS.map((p) => (
        <button
          key={p.id}
          className={`chip ${value === p.id ? "is-active" : ""}`}
          onClick={() => onChange(p.id)}
        >
          {p.dot && <span className="chip__dot" style={{ background: p.dot }}/>}
          <span>{p.label}</span>
          {p.sublabel && <span className="chip__sub">({p.sublabel})</span>}
        </button>
      ))}
    </div>
  );
}

// ─── Timeline view ───────────────────────────────────────────
function Timeline({ items }) {
  // Group by month
  const groups = useMemo(() => {
    const out = [];
    let currentKey = null;
    for (const r of items) {
      const key = fmtMonth(r.date);
      if (key !== currentKey) {
        out.push({ month: key, items: [] });
        currentKey = key;
      }
      out[out.length - 1].items.push(r);
    }
    return out;
  }, [items]);

  if (!items.length) {
    return (
      <div style={{ padding: "60px 0", textAlign: "center", color: "var(--color-fg-muted)" }}>
        No releases match this filter.
      </div>
    );
  }

  return (
    <div className="timeline">
      {groups.map((g) => (
        <div key={g.month}>
          <div className="timeline__month">{g.month}</div>
          {g.items.map((r) => (
            <a className="entry" href={`/releases/${r.id}/`} key={r.id}>
              <div className="entry__date">
                <div className="entry__day">{dayNum(r.date)}</div>
                <span className="entry__mon">{monShort(r.date)}</span>
              </div>
              <div className="entry__main">
                <div className="entry__meta">
                  <ProductPill rel={r}/>
                  {r.tags.map((t) => <TagPill key={t} tag={t}/>)}
                  <VersionPill v={r.version}/>
                </div>
                <h3 className="entry__title">{r.title}</h3>
                <p className="entry__summary">{r.summary}</p>
              </div>
              <div className="entry__arrow">
                <Icon name="arrow-right" size={18}/>
              </div>
            </a>
          ))}
        </div>
      ))}
    </div>
  );
}

// ─── Grid view ───────────────────────────────────────────────
function GridView({ items }) {
  if (!items.length) {
    return (
      <div style={{ padding: "60px 0", textAlign: "center", color: "var(--color-fg-muted)" }}>
        No releases match this filter.
      </div>
    );
  }
  return (
    <div className="grid">
      {items.map((r) => (
        <a className="gcard" href={`/releases/${r.id}/`} key={r.id}>
          <div className="gcard__meta">
            <ProductPill rel={r}/>
            {r.tags.slice(0, 2).map((t) => <TagPill key={t} tag={t}/>)}
          </div>
          <h3 className="gcard__title">{r.title}</h3>
          <p className="gcard__summary">{r.summary}</p>
          <div className="gcard__foot">
            {fmtDate(r.date)} · {r.version}
          </div>
        </a>
      ))}
    </div>
  );
}

// ─── Section: Recent updates ─────────────────────────────────
function RecentUpdates({ defaultView }) {
  const [view, setView] = useState(defaultView || "timeline");
  useEffect(() => { if (defaultView) setView(defaultView); }, [defaultView]);
  const [filter, setFilter] = useState("all");

  const items = useMemo(() => {
    const all = window.RELEASES.filter((r) => r.id !== window.RELEASES[0].id);
    if (filter === "all") return all;
    return all.filter((r) => r.product === filter);
  }, [filter]);

  return (
    <section style={{ marginTop: 16 }}>
      <div className="section-head">
        <h2 className="section-head__title">Recent updates</h2>
        <div className="section-head__right">
          <div className="viewtoggle">
            <button
              className={`viewtoggle__btn ${view === "timeline" ? "is-active" : ""}`}
              onClick={() => setView("timeline")}>
              <Icon name="list" size={14}/> Timeline
            </button>
            <button
              className={`viewtoggle__btn ${view === "grid" ? "is-active" : ""}`}
              onClick={() => setView("grid")}>
              <Icon name="grid" size={14}/> Grid
            </button>
          </div>
          <a className="browseall" href="#/all">
            Browse all <Icon name="arrow-right" size={14}/>
          </a>
        </div>
      </div>
      <FilterChips value={filter} onChange={setFilter}/>
      {view === "timeline"
        ? <Timeline items={items}/>
        : <GridView items={items}/>}
    </section>
  );
}

// ─── Detail page ─────────────────────────────────────────────
function ReleaseDetail({ rel }) {
  const m = productMeta(rel);
  const tldr = rel.body && rel.body.length ? rel.summary : null;

  return (
    <article className="detail">
      <a className="detail__back" href="#/" >
        <Icon name="arrow-left" size={14}/> Back to {m.label}
      </a>
      <div className="detail__meta">
        <ProductPill rel={rel}/>
        {rel.tags.map((t) => <TagPill key={t} tag={t}/>)}
        <span className="metadate">{fmtDate(rel.date)}</span>
        <span className="metasep">·</span>
        <VersionPill v={rel.version}/>
      </div>
      <h1 className="detail__title">{rel.title}</h1>

      {tldr && (
        <div className="tldr">
          <span className="tldr__label">TL;DR</span>
          <p className="tldr__text">{tldr}</p>
        </div>
      )}

      <div className="detail__body">
        {(rel.body || []).map((b, i) => {
          if (b.kind === "p") return <p key={i}>{b.text}</p>;
          if (b.kind === "h") return <h2 key={i}>{b.text}</h2>;
          if (b.kind === "ul")
            return (
              <ul key={i}>
                {b.items.map((it, j) => <li key={j}>{it}</li>)}
              </ul>
            );
          if (b.kind === "callout")
            return (
              <div key={i} className={`callout ${b.tone === "warn" ? "callout--warn" : ""}`}>
                {b.text}
              </div>
            );
          if (b.kind === "img")
            return (
              <figure key={i} className="shot">
                <img src={b.src} alt={b.alt || ""} loading="lazy"/>
                {b.caption && <figcaption>{b.caption}</figcaption>}
              </figure>
            );
          if (b.kind === "link")
            return (
              <a key={i} className="bodylink" href={b.href} target="_blank" rel="noopener noreferrer">
                {b.text}
              </a>
            );
          return null;
        })}

        <div className="helpdocs">
          <div className="helpdocs__label">Related help docs</div>
          <ul className="helpdocs__list">
            <li><a href="#"><Icon name="doc" size={13}/> Reading your impact receipts</a></li>
            <li><a href="#"><Icon name="doc" size={13}/> Why some receipts are blank</a></li>
          </ul>
        </div>

        <div className="share">
          <span>Share this release —</span>
          <button className="share__btn"><Icon name="link" size={13}/> Copy permalink</button>
          <button className="share__btn"><Icon name="share" size={13}/> Share</button>
        </div>
      </div>
    </article>
  );
}

// ─── Search modal (⌘K) ───────────────────────────────────────
function SearchModal({ onClose }) {
  const [q, setQ] = useState("");
  const [active, setActive] = useState(0);
  const inputRef = useRef(null);
  useEffect(() => { inputRef.current && inputRef.current.focus(); }, []);

  const results = useMemo(() => {
    const needle = q.trim().toLowerCase();
    const list = window.RELEASES;
    if (!needle) return list.slice(0, 8);
    return list.filter((r) =>
      r.title.toLowerCase().includes(needle) ||
      r.summary.toLowerCase().includes(needle) ||
      (r.productLabel || "").toLowerCase().includes(needle) ||
      r.tags.some((t) => t.toLowerCase().includes(needle))
    );
  }, [q]);

  useEffect(() => { setActive(0); }, [q]);

  const onKey = (e) => {
    if (e.key === "Escape") { onClose(); }
    else if (e.key === "ArrowDown") { e.preventDefault(); setActive((a) => Math.min(results.length - 1, a + 1)); }
    else if (e.key === "ArrowUp") { e.preventDefault(); setActive((a) => Math.max(0, a - 1)); }
    else if (e.key === "Enter" && results[active]) {
      window.location.href = `/releases/${results[active].id}/`;
      onClose();
    }
  };

  return (
    <div className="searchmodal__bg" onClick={onClose}>
      <div className="searchmodal" onClick={(e) => e.stopPropagation()}>
        <div className="searchmodal__input">
          <span style={{ color: "var(--color-fg-muted)" }}><Icon name="search" size={16}/></span>
          <input
            ref={inputRef}
            value={q}
            onChange={(e) => setQ(e.target.value)}
            onKeyDown={onKey}
            placeholder="Search releases, features, fixes…"
          />
          <span className="search__kbd">esc</span>
        </div>
        <div className="searchmodal__results">
          {!results.length && (
            <div className="searchmodal__empty">No matches for "{q}"</div>
          )}
          {results.map((r, i) => (
            <a
              key={r.id}
              className={`searchmodal__result ${i === active ? "is-active" : ""}`}
              href={`/releases/${r.id}/`}
              onClick={() => onClose()}
              onMouseEnter={() => setActive(i)}
            >
              <p className="searchmodal__result-title">{r.title}</p>
              <span className="searchmodal__result-meta">
                {productMeta(r).label} · {fmtDate(r.date)} · {r.version}
              </span>
            </a>
          ))}
        </div>
      </div>
    </div>
  );
}

// ─── App root ────────────────────────────────────────────────
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "defaultView": "timeline",
  "showFeatured": true,
  "heroLayout": "title-first"
}/*EDITMODE-END*/;

function App() {
  const hash = useHashRoute();
  const [searchOpen, setSearchOpen] = useState(hash === "#/search");
  const tweaks = (typeof useTweaks === "function") ? useTweaks(TWEAK_DEFAULTS) : [TWEAK_DEFAULTS, () => {}];
  const [t, setT] = tweaks;

  // Open search on hash route
  useEffect(() => {
    if (hash === "#/search") setSearchOpen(true);
  }, [hash]);

  const closeSearch = () => {
    setSearchOpen(false);
    if (window.location.hash === "#/search") {
      history.replaceState(null, "", "#/");
    }
  };

  // Resolve route
  const route = (() => {
    if (hash.startsWith("#/r/")) {
      const id = hash.slice(4);
      const rel = window.RELEASES.find((r) => r.id === id);
      if (rel) return { kind: "detail", rel };
    }
    return { kind: "home" };
  })();

  const featured = window.RELEASES[0];

  return (
    <div className="app">
      <TopBar onOpenSearch={() => setSearchOpen(true)}/>
      {route.kind === "home" && (
        <main className="shell">
          <Hero/>
          {t.showFeatured && <Featured rel={featured}/>}
          <RecentUpdates defaultView={t.defaultView}/>
        </main>
      )}
      {route.kind === "detail" && <ReleaseDetail rel={route.rel}/>}

      {searchOpen && <SearchModal onClose={closeSearch}/>}

      {typeof TweaksPanel === "function" && (
        <TweaksPanel title="Tweaks">
          <TweakSection title="Defaults">
            <TweakRadio
              label="Default list view"
              value={t.defaultView}
              options={[
                { value: "timeline", label: "Timeline" },
                { value: "grid", label: "Grid" },
              ]}
              onChange={(v) => setT("defaultView", v)}
            />
            <TweakToggle
              label="Show featured release"
              value={t.showFeatured}
              onChange={(v) => setT("showFeatured", v)}
            />
          </TweakSection>
        </TweaksPanel>
      )}
    </div>
  );
}

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