// EntryPage.jsx — generic long-form content renderer driven by content/entries.json.
//
// Route:  #/entry/<slug>
//
// Each entry in entries.json is rendered as a Palantir-style document page:
//   breadcrumb + doc# → kicker/lede → hero image + caption → meta strip →
//   block-based body → related entries → CTA.
//
// Supported block types (in entry.blocks[]):
//   { type: "paragraph",   text }
//   { type: "heading",     text }
//   { type: "pullquote",   text, attribution? }
//   { type: "list",        items: [string, …] }
//   { type: "image",       src, alt?, caption? }
//   { type: "video",       src, poster?, webm? }
//   { type: "stats",       items: [{ n, u?, lbl }] }
//   { type: "spacer" }
//   { type: "html",        html }    // raw HTML, for escape hatches only

const { useState: useES, useEffect: useEE } = React;

// in-memory cache so we don't re-fetch the feed on every nav
let __entriesCache = null;
let __entriesPromise = null;

function loadEntries() {
  if (__entriesCache) return Promise.resolve(__entriesCache);
  if (__entriesPromise) return __entriesPromise;
  __entriesPromise = fetch("content/entries.json")
    .then((r) => {
      if (!r.ok) throw new Error("Failed to load entries.json: " + r.status);
      return r.json();
    })
    .then((data) => {
      __entriesCache = (data && data.entries) || [];
      return __entriesCache;
    });
  return __entriesPromise;
}

// expose so other components (NewsBlock, Capabilities) can show titles/dates
// without each fetching independently.
window.LuliusContent = {
  load: loadEntries,
  byKind: (kind) => loadEntries().then((es) => es.filter((e) => e.kind === kind)),
  bySlug: (slug) => loadEntries().then((es) => es.find((e) => e.slug === slug)),
};

// ───────────────────────── block renderers ─────────────────────────

function Block({ b }) {
  switch (b.type) {
    case "paragraph":
      return <p style={{ fontSize: 17, lineHeight: 1.65, margin: "0 0 22px", color: "var(--paper)" }}>{b.text}</p>;

    case "heading":
      return <h3 className="h2" style={{ fontSize: "clamp(24px, 2.6vw, 34px)", margin: "48px 0 18px" }}>{b.text}</h3>;

    case "pullquote":
      return (
        <blockquote style={{
          margin: "40px 0",
          padding: "32px 36px",
          borderLeft: "2px solid var(--accent)",
          background: "var(--ink-2)",
        }}>
          <p className="pull" style={{ fontSize: "clamp(22px, 2.4vw, 30px)", margin: 0 }}>{b.text}</p>
          {b.attribution && (
            <div className="eyebrow mute" style={{ marginTop: 18 }}>— {b.attribution}</div>
          )}
        </blockquote>
      );

    case "list":
      return (
        <ul style={{ listStyle: "none", padding: 0, margin: "8px 0 26px", display: "flex", flexDirection: "column", gap: 12 }}>
          {b.items.map((it, i) => (
            <li key={i} style={{ display: "flex", gap: 14, alignItems: "baseline", fontSize: 16, lineHeight: 1.55 }}>
              <span style={{ color: "var(--accent)", fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: ".14em", flexShrink: 0, paddingTop: 2 }}>
                {String(i + 1).padStart(2, "0")}
              </span>
              <span>{it}</span>
            </li>
          ))}
        </ul>
      );

    case "image":
      return (
        <figure style={{ margin: "40px 0" }}>
          <div style={{ border: "1px solid var(--line)", aspectRatio: "16/9", background: "#0A0A0A" }}>
            <MediaImg src={b.src} alt={b.alt || ""} />
          </div>
          {b.caption && (
            <figcaption className="eyebrow mute" style={{ marginTop: 12 }}>FIG · {b.caption}</figcaption>
          )}
        </figure>
      );

    case "video":
      return (
        <figure style={{ margin: "40px 0" }}>
          <div style={{ border: "1px solid var(--line)", aspectRatio: "16/9", background: "#0A0A0A" }}>
            <VideoBg src={b.src} webm={b.webm} poster={b.poster} />
          </div>
          {b.caption && (
            <figcaption className="eyebrow mute" style={{ marginTop: 12 }}>VID · {b.caption}</figcaption>
          )}
        </figure>
      );

    case "stats":
      return (
        <div style={{
          display: "grid",
          gridTemplateColumns: `repeat(${Math.min(b.items.length, 4)}, 1fr)`,
          gap: 28, margin: "32px 0 40px",
        }}>
          {b.items.map((s, i) => (
            <div key={i} className="stat">
              <div className="n">{s.n}{s.u && <span className="u">{s.u}</span>}</div>
              <div className="lbl">{s.lbl}</div>
            </div>
          ))}
        </div>
      );

    case "spacer":
      return <div style={{ height: 24 }} />;

    case "html":
      return <div dangerouslySetInnerHTML={{ __html: b.html }} />;

    default:
      return null;
  }
}

// ───────────────────────── related card ─────────────────────────

// Hero media renderer — switches between MediaImg and MediaFrame based on file
// extension. .html (and .htm) heroes are embedded via the sandboxed iframe
// component so self-contained HTML assets work as drop-in replacements for
// static images. baseWidth/baseHeight let an entry declare its embedded
// content's natural canvas size (e.g. a 2280×720 wide-format diagram) so the
// iframe viewport matches and nothing gets cropped at the edges.
function HeroMedia({ src, alt, position, baseWidth, baseHeight }) {
  const isHtml = /\.html?($|\?|#)/i.test(src);
  if (isHtml) {
    return <MediaFrame src={src} title={alt} baseWidth={baseWidth} baseHeight={baseHeight} />;
  }
  return <MediaImg src={src} alt={alt} position={position} />;
}

function RelatedCard({ entry, onNavigate }) {
  return (
    <a href={`#/entry/${entry.slug}`}
      onClick={(e) => { e.preventDefault(); onNavigate(`/entry/${entry.slug}`); }}
      style={{
        display: "flex", flexDirection: "column",
        border: "1px solid var(--line)",
        background: "var(--ink-2)",
        padding: 24,
        gap: 16,
        transition: "border-color .25s ease, transform .25s ease",
        textDecoration: "none",
        color: "inherit",
      }}
      onMouseEnter={(e) => { e.currentTarget.style.borderColor = "var(--accent)"; }}
      onMouseLeave={(e) => { e.currentTarget.style.borderColor = "var(--line)"; }}
    >
      <div style={{ display: "flex", justifyContent: "space-between", gap: 12 }}>
        <span className="eyebrow accent-text">{entry.tag}</span>
        <span className="eyebrow mute tabular">{entry.dateLabel}</span>
      </div>
      <div className="h3" style={{ margin: 0, fontSize: 19 }}>{entry.title}</div>
      <div className="mute" style={{ fontSize: 14, lineHeight: 1.5, marginTop: "auto" }}>{entry.subtitle || entry.lede}</div>
      <div style={{ fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: ".14em", color: "var(--accent)" }}>Read entry →</div>
    </a>
  );
}

// ───────────────────────── main page ─────────────────────────

function EntryPage({ slug, onNavigate }) {
  const [entry, setEntry] = useES(undefined); // undefined = loading, null = not found
  const [all,   setAll]   = useES([]);

  useEE(() => {
    let dead = false;
    loadEntries().then((entries) => {
      if (dead) return;
      setAll(entries);
      const e = entries.find((x) => x.slug === slug);
      setEntry(e || null);
    }).catch(() => { if (!dead) setEntry(null); });
    return () => { dead = true; };
  }, [slug]);

  // loading
  if (entry === undefined) {
    return (
      <main style={{ padding: "180px 0" }}>
        <div className="wrap">
          <div className="eyebrow mute"><span className="dot"></span>LOADING ENTRY</div>
        </div>
      </main>
    );
  }

  // not found
  if (entry === null) {
    return (
      <main style={{ padding: "180px 0" }}>
        <div className="wrap">
          <div className="eyebrow accent-text" style={{ marginBottom: 16 }}>ERR · 404 · entry/{slug}</div>
          <h1 className="display">Entry not on file.</h1>
          <p className="lede mute" style={{ marginTop: 24 }}>
            That slug doesn't map to a record in <code style={{ fontFamily: "var(--f-mono)", color: "var(--paper)" }}>content/entries.json</code>.
          </p>
          <a href="#/" onClick={(e) => { e.preventDefault(); onNavigate("/"); }} className="btn" style={{ marginTop: 32 }}>
            Return to index <span className="arrow">→</span>
          </a>
        </div>
      </main>
    );
  }

  const related = (entry.related || [])
    .map((s) => all.find((e) => e.slug === s))
    .filter(Boolean);

  return (
    <main>
      {/* breadcrumb */}
      <div style={{ paddingTop: 100 }}>
        <div className="wrap" style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "24px var(--pad-x)" }}>
          <div className="crumb">
            <a href="#/" onClick={(e) => { e.preventDefault(); onNavigate("/"); }}>Index</a>
            <span className="sep">/</span>
            <span>{entry.kind === "capability" ? "Capabilities" : "Dispatch"}</span>
            <span className="sep">/</span>
            <span className="curr">{entry.title}</span>
          </div>
          {entry.doc && <div className="eyebrow mute tabular">DOC · {entry.doc}</div>}
        </div>
      </div>

      {/* kicker + hero — layout depends on entry.heroLayout */}
      {(() => {
        const layout = entry.heroLayout || (entry.hero ? "cinematic" : "none");

        // Shared kicker pieces, reused across layouts
        const eyebrows = (
          <div style={{ display: "flex", gap: 16, alignItems: "center", marginBottom: 28, flexWrap: "wrap" }}>
            <span className="eyebrow"><span className="dot"></span>{entry.tag}</span>
            <span className="eyebrow mute tabular">{entry.dateLabel}</span>
          </div>
        );
        const titleEl = (
          <h1 className="display" style={{ fontSize: "clamp(40px, 7vw, 104px)", marginBottom: 28 }}>
            {entry.title}
          </h1>
        );
        const subtitleEl = entry.subtitle ? (
          <p className="lede" style={{ fontSize: "clamp(18px, 1.6vw, 24px)", maxWidth: "60ch", marginBottom: 0 }}>
            {entry.subtitle}
          </p>
        ) : null;

        // ── Profile: 2-col grid, image lives beside the title block ──
        if (layout === "profile" && entry.hero) {
          return (
            <section style={{ padding: "40px 0 80px", borderBottom: "1px solid var(--line)" }}>
              <div className="wrap profile-grid" style={{ display: "grid", gridTemplateColumns: "1.4fr 1fr", gap: 60, alignItems: "end" }}>
                <div>
                  {eyebrows}
                  <h1 className="display" style={{ fontSize: "clamp(36px, 5.8vw, 54px)", marginBottom: 24 }}>
                    {entry.title}
                  </h1>
                  {subtitleEl}
                </div>
                <figure style={{ margin: 0 }}>
                  <div style={{
                    aspectRatio: entry.heroAspect || "4 / 5",
                    background: "#0A0A0A",
                    border: "1px solid var(--line)",
                    position: "relative",
                  }}>
                    <HeroMedia src={entry.hero} alt={entry.title} position={entry.heroPosition || "50% 25%"} baseWidth={entry.heroBaseWidth} baseHeight={entry.heroBaseHeight} />
                  </div>
                  {entry.heroCaption && (
                    <figcaption className="eyebrow mute" style={{ marginTop: 12 }}>FIG · {entry.heroCaption}</figcaption>
                  )}
                </figure>
              </div>
              <style>{`
                @media (max-width: 880px) {
                  .profile-grid { grid-template-columns: 1fr !important; gap: 32px !important; }
                }
              `}</style>
            </section>
          );
        }

        // ── Feature: kicker, then a contained 16:9 image inside .wrap ──
        if (layout === "feature" && entry.hero) {
          return (
            <>
              <section style={{ padding: "40px 0 60px" }}>
                <div className="wrap">
                  {eyebrows}
                  {titleEl}
                  {subtitleEl}
                </div>
              </section>
              <section style={{ borderBottom: "1px solid var(--line)" }}>
                <div className="wrap">
                  <figure style={{
                    margin: 0,
                    aspectRatio: entry.heroAspect || "16 / 9",
                    background: "#0A0A0A",
                    border: "1px solid var(--line)",
                    position: "relative",
                  }}>
                    <HeroMedia src={entry.hero} alt={entry.title} position={entry.heroPosition || "50% 50%"} baseWidth={entry.heroBaseWidth} baseHeight={entry.heroBaseHeight} />
                  </figure>
                  {entry.heroCaption && (
                    <div className="eyebrow mute" style={{ padding: "16px 0 0" }}>FIG · {entry.heroCaption}</div>
                  )}
                </div>
              </section>
            </>
          );
        }

        // ── Cinematic (default): full-bleed 21:9 hero below the kicker ──
        if (layout === "cinematic" && entry.hero) {
          return (
            <>
              <section style={{ padding: "40px 0 80px", borderBottom: "1px solid var(--line)" }}>
                <div className="wrap">
                  {eyebrows}
                  {titleEl}
                  {subtitleEl}
                </div>
              </section>
              <section style={{ borderBottom: "1px solid var(--line)" }}>
                <div style={{ position: "relative", aspectRatio: entry.heroAspect || "21 / 9", background: "#0A0A0A" }}>
                  <HeroMedia src={entry.hero} alt={entry.title} position={entry.heroPosition || "50% 50%"} baseWidth={entry.heroBaseWidth} baseHeight={entry.heroBaseHeight} />
                </div>
                {entry.heroCaption && (
                  <div className="wrap" style={{ padding: "16px var(--pad-x)", borderBottom: "1px solid var(--line)" }}>
                    <div className="eyebrow mute">FIG · {entry.heroCaption}</div>
                  </div>
                )}
              </section>
            </>
          );
        }

        // ── None / no image: just the kicker ──
        return (
          <section style={{ padding: "40px 0 80px", borderBottom: "1px solid var(--line)" }}>
            <div className="wrap">
              {eyebrows}
              {titleEl}
              {subtitleEl}
            </div>
          </section>
        );
      })()}

      {/* meta strip */}
      {entry.meta && entry.meta.length > 0 && (
        <section style={{ borderBottom: "1px solid var(--line)" }}>
          <div className="wrap" style={{
            display: "grid",
            gridTemplateColumns: `repeat(${Math.min(entry.meta.length, 4)}, 1fr)`,
            gap: 0,
          }} className="entry-meta">
            {entry.meta.map(([k, v], i) => (
              <div key={i} style={{
                padding: "24px var(--pad-x)",
                borderRight: i < entry.meta.length - 1 ? "1px solid var(--line)" : "none",
              }}>
                <div className="eyebrow mute" style={{ marginBottom: 8 }}>{k}</div>
                <div className="h3" style={{ margin: 0, fontSize: 18 }}>{v}</div>
              </div>
            ))}
          </div>
        </section>
      )}

      {/* body */}
      <section className="section">
        <div className="wrap entry-body" style={{ display: "grid", gridTemplateColumns: "1fr 2.4fr", gap: 60 }}>
          <aside style={{ position: "sticky", top: 100, alignSelf: "start" }} className="entry-aside">
            <div className="eyebrow mute" style={{ marginBottom: 12 }}>LEDE</div>
            <p className="lede" style={{ fontSize: 16 }}>{entry.lede}</p>

            {entry.links && entry.links.length > 0 && (
              <div style={{ marginTop: 32, paddingTop: 24, borderTop: "1px solid var(--line)" }}>
                <div className="eyebrow mute" style={{ marginBottom: 14 }}>ACTIONS</div>
                <div style={{ display: "flex", flexDirection: "column", gap: 10, alignItems: "flex-start" }}>
                  {entry.links.map((l, i) => (
                    <a key={i}
                      href={l.href}
                      target={l.external ? "_blank" : undefined}
                      rel={l.external ? "noopener" : undefined}
                      onClick={(e) => {
                        if (!l.external && l.href.startsWith("#")) {
                          e.preventDefault();
                          onNavigate(l.href.replace(/^#/, ""));
                        }
                      }}
                      className="btn compact"
                      style={{ background: i === 0 ? "var(--paper)" : "transparent", color: i === 0 ? "var(--ink)" : "var(--paper)", border: "1px solid var(--paper)" }}
                    >
                      {l.label} <span className="arrow">{l.external ? "↗" : "→"}</span>
                    </a>
                  ))}
                </div>
              </div>
            )}
          </aside>

          <article style={{ maxWidth: 720 }}>
            {(entry.blocks || []).map((b, i) => <Block key={i} b={b} />)}
          </article>
        </div>
      </section>

      {/* related */}
      {related.length > 0 && (
        <section className="section" style={{ background: "var(--ink-2)", borderTop: "1px solid var(--line)", borderBottom: "1px solid var(--line)" }}>
          <div className="wrap">
            <div className="idx" style={{ marginBottom: 32 }}><span className="num">→</span> Related</div>
            <div style={{ display: "grid", gridTemplateColumns: `repeat(${Math.min(related.length, 3)}, 1fr)`, gap: 16 }} className="rel-grid">
              {related.map((r) => <RelatedCard key={r.slug} entry={r} onNavigate={onNavigate} />)}
            </div>
          </div>
        </section>
      )}

      <ContactCTA onNavigate={onNavigate} />

      <style>{`
        @media (max-width: 880px) {
          .entry-body { grid-template-columns: 1fr !important; gap: 32px !important; }
          .entry-aside { position: static !important; }
          .entry-meta { grid-template-columns: 1fr 1fr !important; }
          .entry-meta > div { border-right: none !important; border-bottom: 1px solid var(--line) !important; padding: 16px var(--pad-x) !important; }
          .rel-grid { grid-template-columns: 1fr !important; }
        }
      `}</style>
    </main>
  );
}

window.EntryPage = EntryPage;
