// J Renee Studios — Journal post (article) renderer.
// Reads the slug from the URL (/journal/<slug>/), pulls display meta from
// window.J_POSTS (defined in journal-sections.jsx) and the article body from
// window.J_POST_CONTENT (generated from _data/journal-posts.json at build time).

const { useState: jpUseState, useEffect: jpUseEffect, useMemo: jpUseMemo } = React;

function jpGetSlug() {
  const parts = window.location.pathname.split("/").filter(Boolean);
  const i = parts.indexOf("journal");
  if (i >= 0 && parts[i + 1]) return parts[i + 1];
  return parts.length ? parts[parts.length - 1] : "";
}

// Minimal inline formatter: [text](url) links, **bold**, and *italic*.
function jpInline(text) {
  if (text == null) return null;
  const out = [];
  const re = /\[([^\]]+)\]\(([^)]+)\)|\*\*([^*]+)\*\*|\*([^*]+)\*/g;
  let last = 0;
  let key = 0;
  let m;
  while ((m = re.exec(text)) !== null) {
    if (m.index > last) out.push(text.slice(last, m.index));
    if (m[1] != null) {
      const href = m[2];
      // Only allow safe link schemes; anything else renders as plain text.
      const safe = /^(\/|#|https?:\/\/|mailto:|tel:)/i.test(href);
      const external = /^https?:\/\//i.test(href);
      if (safe) {
        out.push(
          <a key={key++} href={href}
            {...(external ? { target: "_blank", rel: "noopener noreferrer" } : {})}
            style={{ color: J_GOLD, textDecoration: "underline", textUnderlineOffset: "3px" }}>
            {m[1]}
          </a>,
        );
      } else {
        out.push(m[1]);
      }
    } else if (m[3] != null) {
      out.push(<strong key={key++} style={{ fontWeight: 400 }}>{m[3]}</strong>);
    } else {
      out.push(<em key={key++} style={{ fontStyle: "italic" }}>{m[4]}</em>);
    }
    last = re.lastIndex;
  }
  if (last < text.length) out.push(text.slice(last));
  return out;
}

function jpReadingTime(body) {
  const words = (body || []).reduce((n, b) => {
    if (b.text) return n + b.text.split(/\s+/).length;
    if (b.items) return n + b.items.join(" ").split(/\s+/).length;
    return n;
  }, 0);
  return Math.max(1, Math.round(words / 200));
}

function JPostBlock({ block }) {
  const pStyle = {
    fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 17,
    lineHeight: 1.85, color: J_INK, margin: "0 0 28px",
  };
  switch (block.type) {
    case "lead":
      return (
        <p style={{ ...pStyle, fontSize: 21, lineHeight: 1.7, color: "#2A2A2A", marginBottom: 40 }}>
          {jpInline(block.text)}
        </p>
      );
    case "p":
      return <p style={pStyle}>{jpInline(block.text)}</p>;
    case "h2":
      return (
        <h2 style={{
          fontFamily: "Gloock, serif", fontWeight: 400, fontSize: 30, lineHeight: 1.25,
          color: J_INK, margin: "56px 0 22px", letterSpacing: "0.01em",
        }}>{block.text}</h2>
      );
    case "h3":
      return (
        <h3 style={{
          fontFamily: "Gloock, serif", fontWeight: 400, fontSize: 22, lineHeight: 1.3,
          color: J_INK, margin: "40px 0 16px",
        }}>{block.text}</h3>
      );
    case "quote":
      return (
        <blockquote style={{
          margin: "44px 0", padding: "8px 0 8px 32px",
          borderLeft: `2px solid ${J_GOLD}`,
          fontFamily: "Gloock, serif", fontWeight: 400, fontSize: 24, lineHeight: 1.5,
          fontStyle: "italic", color: J_INK,
        }}>{block.text}</blockquote>
      );
    case "list":
      return (
        <ul style={{ margin: "0 0 32px", padding: 0, listStyle: "none", display: "grid", gap: 16 }}>
          {(block.items || []).map((it, i) => (
            <li key={i} style={{
              fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 17,
              lineHeight: 1.7, color: J_INK, paddingLeft: 26, position: "relative",
            }}>
              <span style={{ position: "absolute", left: 0, top: 0, color: J_GOLD }}>—</span>
              {jpInline(it)}
            </li>
          ))}
        </ul>
      );
    case "image":
      return (
        <figure style={{ margin: "44px 0" }}>
          <img src={block.src} alt={block.alt || block.caption || ""} loading="lazy"
            style={{ width: "100%", display: "block" }} />
          {block.caption ? (
            <figcaption style={{
              fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 12.5,
              letterSpacing: "0.04em", color: J_GREY, marginTop: 12, textAlign: "center",
            }}>{block.caption}</figcaption>
          ) : null}
        </figure>
      );
    default:
      return null;
  }
}

function JPostMissing() {
  return (
    <div>
      <JHeader scrolled={true} />
      <section style={{ maxWidth: 720, margin: "0 auto", padding: "180px 32px 160px", textAlign: "center" }}>
        <JEyebrow style={{ marginBottom: 24 }}>Journal</JEyebrow>
        <h1 style={{ fontFamily: "Gloock, serif", fontWeight: 400, fontSize: 38, lineHeight: 1.2, margin: "0 0 24px" }}>
          This story is coming soon
        </h1>
        <p style={{ fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 16, lineHeight: 1.8, color: J_GREY, marginBottom: 40 }}>
          This journal entry hasn't been published yet. In the meantime, explore the rest of the journal.
        </p>
        <JBtn href="/journal/" variant="gold">Back to the Journal</JBtn>
      </section>
      <JFooter />
    </div>
  );
}

function JPostApp() {
  const slug = jpUseMemo(() => jpGetSlug(), []);
  const content = (window.J_POST_CONTENT || {})[slug] || null;
  // Prefer the rich card entry (J_POSTS) when present, but fall back to the
  // generated content meta so a post renders from JSON alone.
  const meta = jpUseMemo(
    () =>
      (window.J_POSTS || []).find((p) => p.slug === slug) ||
      (content && content.meta) ||
      null,
    [slug, content],
  );

  const [scrolled, setScrolled] = jpUseState(false);
  jpUseEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 80);
    window.addEventListener("scroll", onScroll, { passive: true });
    return () => window.removeEventListener("scroll", onScroll);
  }, []);

  jpUseEffect(() => {
    const els = document.querySelectorAll(".reveal");
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) e.target.classList.add("in"); });
    }, { threshold: 0.12 });
    els.forEach((el) => io.observe(el));
    return () => io.disconnect();
  }, [content]);

  if (!content || !meta) return <JPostMissing />;

  const body = content.body || [];
  const minutes = jpReadingTime(body);
  const heroImages = ((content.meta && content.meta.heroImages) || meta.heroImages || []).filter(Boolean);
  // The post's own cover comes from its JSON entry (content.meta.image) so it can
  // differ from the card thumbnail (meta.image, from the J_POSTS card entry).
  const coverImage = (content.meta && content.meta.image) || meta.image || "";

  const written = window.J_POST_CONTENT || {};
  const related = (window.J_POSTS || [])
    .filter((p) => p.slug !== slug && written[p.slug])
    .sort((a, b) => {
      const am = a.city === meta.city ? 0 : 1;
      const bm = b.city === meta.city ? 0 : 1;
      return am - bm;
    })
    .slice(0, 3);

  const metaLine = [meta.category, meta.city && meta.city !== "General" ? meta.city : null, meta.date]
    .filter(Boolean)
    .join("  ·  ");

  return (
    <div>
      <JHeader scrolled={scrolled} />

      {/* Hero */}
      <article>
        <header className="jp-hero" style={{
          maxWidth: 820, margin: "0 auto", padding: "140px 32px 56px", textAlign: "center",
        }}>
          <div style={{
            display: "flex", alignItems: "center", justifyContent: "center", gap: 16, marginBottom: 28,
          }}>
            <a href="/journal/" style={{
              fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 11,
              letterSpacing: "0.32em", textTransform: "uppercase", color: J_GOLD, textDecoration: "none",
            }}>Journal</a>
            <JGoldRule width={28} />
            <span style={{
              fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 11,
              letterSpacing: "0.32em", textTransform: "uppercase", color: J_GREY,
            }}>{minutes} min read</span>
          </div>

          <h1 style={{
            fontFamily: "Gloock, serif", fontWeight: 400,
            fontSize: "clamp(32px, 5vw, 52px)", lineHeight: 1.16, letterSpacing: "0.005em",
            color: J_INK, margin: "0 0 26px",
          }}>{meta.title}</h1>

          <div style={{
            fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 12.5,
            letterSpacing: "0.18em", textTransform: "uppercase", color: J_GREY,
          }}>{metaLine}</div>
        </header>

        {/* Cover */}
        {heroImages.length >= 2 ? (
          <div style={{ maxWidth: 1100, margin: "0 auto 72px", padding: "0 32px" }}>
            <div style={{
              display: "grid",
              gridTemplateColumns: `repeat(${heroImages.length}, 1fr)`,
              gap: "clamp(8px, 1.6vw, 18px)",
            }}>
              {heroImages.map((src, i) => (
                <img key={i} src={src} alt={`${meta.title} — ${i + 1}`} loading={i === 0 ? "eager" : "lazy"}
                  style={{ width: "100%", aspectRatio: "2 / 3", objectFit: "cover", display: "block" }} />
              ))}
            </div>
          </div>
        ) : coverImage ? (
          <div style={{ maxWidth: 1100, margin: "0 auto 72px", padding: "0 32px" }}>
            <img src={coverImage} alt={meta.title} style={{
              width: "100%", aspectRatio: "3 / 2", objectFit: "cover", display: "block",
            }} />
          </div>
        ) : null}

        {/* Body */}
        <div className="jp-body article-body" style={{ maxWidth: 720, margin: "0 auto", padding: "0 32px 112px" }}>
          {body.map((block, i) => <JPostBlock key={i} block={block} />)}

          {/* Byline */}
          <div style={{
            marginTop: 56, paddingTop: 36, borderTop: "1px solid rgba(26,26,26,0.12)",
            display: "flex", alignItems: "center", gap: 18,
          }}>
            <div>
              <div style={{
                fontFamily: "Poppins, sans-serif", fontWeight: 300, fontSize: 10.5,
                letterSpacing: "0.3em", textTransform: "uppercase", color: J_GOLD, marginBottom: 6,
              }}>Written by</div>
              <div style={{ fontFamily: "Gloock, serif", fontWeight: 400, fontSize: 19, color: J_INK }}>
                J. Renée Johnson
              </div>
            </div>
            <div style={{ marginLeft: "auto" }}>
              <JBtn href="/journal/" variant="outline-ink">Back to the Journal</JBtn>
            </div>
          </div>
        </div>
      </article>

      {/* Related */}
      {related.length ? (
        <section style={{ background: J_BEIGE, padding: "96px 48px" }}>
          <div style={{ maxWidth: 1280, margin: "0 auto" }}>
            <div style={{ textAlign: "center", marginBottom: 56 }}>
              <JEyebrow style={{ marginBottom: 14 }}>Keep Reading</JEyebrow>
              <h2 style={{ fontFamily: "Gloock, serif", fontWeight: 400, fontSize: 30, margin: 0 }}>
                More from the Journal
              </h2>
            </div>
            <div className="j-grid-3" style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: "64px 44px" }}>
              {related.map((p) => <JPostCard key={p.slug} post={p} />)}
            </div>
          </div>
        </section>
      ) : null}

      {/* Subscribe form hidden until GoHighLevel is connected — re-enable when the webhook is live. */}
      {/* <div className="reveal"><JSubscribe /></div> */}
      <div className="reveal"><JFinalCTA /></div>
      <JFooter />
    </div>
  );
}

Object.assign(window, { JPostApp });

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