// components/legal-renderer.jsx
// Renders long-form legal pages (Privacy Policy, Terms of Service) from the
// structured data in content/legal-pages.js. Shared by privacy.html + terms.html.
//
// Exports to window: LegalPage, renderInline.

// ── Inline formatter ─────────────────────────────────────────────────────────
// Parses **bold**, [label](url), and `code` into React nodes. We do this by
// walking the string once and emitting fragments. Order matters: links are
// tokenized first (so URLs can contain ** without breaking), then bold, then
// code. This is intentionally not a full markdown parser — only the subset
// that appears in our legal copy.
function renderInline(text, keyPrefix) {
  if (typeof text !== "string" || text.length === 0) return text;
  // Tokenize links → placeholders, so subsequent bold/code passes don't eat
  // anything inside link targets or labels.
  const links = [];
  let s = text.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, href) => {
    links.push({ label, href });
    return `\u0000L${links.length - 1}\u0000`;
  });

  // Bold pass: **...** (non-greedy, no nested **).
  // Split on bold tokens.
  const parts = [];
  let cursor = 0;
  const boldRe = /\*\*([^*]+)\*\*/g;
  let m;
  while ((m = boldRe.exec(s)) !== null) {
    if (m.index > cursor) parts.push({ kind: "txt", value: s.slice(cursor, m.index) });
    parts.push({ kind: "bold", value: m[1] });
    cursor = m.index + m[0].length;
  }
  if (cursor < s.length) parts.push({ kind: "txt", value: s.slice(cursor) });

  // Now expand each part: replace link/code placeholders inside txt + bold.
  function expand(str, keyBase) {
    // Code spans
    const out = [];
    const codeRe = /`([^`]+)`/g;
    let last = 0;
    let mm;
    let idx = 0;
    while ((mm = codeRe.exec(str)) !== null) {
      if (mm.index > last) out.push(...expandLinks(str.slice(last, mm.index), keyBase + "_" + idx + "t"));
      out.push(<code key={keyBase + "_" + idx + "c"} className="legal-code">{mm[1]}</code>);
      idx++;
      last = mm.index + mm[0].length;
    }
    if (last < str.length) out.push(...expandLinks(str.slice(last), keyBase + "_" + idx + "t"));
    return out;
  }

  function expandLinks(str, keyBase) {
    const out = [];
    const re = /\u0000L(\d+)\u0000/g;
    let last = 0;
    let mm;
    let idx = 0;
    while ((mm = re.exec(str)) !== null) {
      if (mm.index > last) out.push(str.slice(last, mm.index));
      const link = links[parseInt(mm[1], 10)];
      const isExternal = /^https?:\/\//i.test(link.href);
      const isMailto = /^mailto:/i.test(link.href);
      const linkProps = isExternal
        ? { target: "_blank", rel: "noopener noreferrer" }
        : {};
      out.push(
        <a
          key={keyBase + "_l" + idx}
          href={link.href}
          className={isMailto ? "legal-link legal-link--mail" : "legal-link"}
          {...linkProps}
        >
          {link.label}
        </a>
      );
      idx++;
      last = mm.index + mm[0].length;
    }
    if (last < str.length) out.push(str.slice(last));
    return out;
  }

  const nodes = [];
  parts.forEach((p, i) => {
    const key = (keyPrefix || "k") + "_" + i;
    if (p.kind === "bold") {
      nodes.push(<strong key={key}>{expand(p.value, key)}</strong>);
    } else {
      nodes.push(...expand(p.value, key));
    }
  });
  return nodes;
}

// ── Block renderers ──────────────────────────────────────────────────────────
function Block({ block, kp }) {
  switch (block.type) {
    case "p":
      return <p className="legal-p">{renderInline(block.text, kp)}</p>;
    case "h3":
      return (
        <h3 id={block.id} className="legal-h3">
          {renderInline(block.text, kp)}
        </h3>
      );
    case "list":
      return (
        <ul className="legal-list">
          {block.items.map((it, i) => (
            <li key={i} className="legal-list-item">
              {renderInline(it, kp + "_" + i)}
            </li>
          ))}
        </ul>
      );
    case "table":
      return (
        <div className="legal-table-wrap">
          <table className="legal-table">
            <thead>
              <tr>
                {block.headers.map((h, i) => (
                  <th key={i} scope="col">{renderInline(h, kp + "_h" + i)}</th>
                ))}
              </tr>
            </thead>
            <tbody>
              {block.rows.map((row, ri) => (
                <tr key={ri}>
                  {row.map((cell, ci) => (
                    <td key={ci}>{renderInline(cell, kp + "_r" + ri + "c" + ci)}</td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      );
    case "legalese":
      return <p className="legal-legalese">{renderInline(block.text, kp)}</p>;
    case "warning":
      return <p className="legal-warning">{renderInline(block.text, kp)}</p>;
    default:
      return null;
  }
}

// ── Sticky TOC (desktop ≥ 1100px) ────────────────────────────────────────────
function StickyTOC({ sections, activeId }) {
  return (
    <nav className="legal-toc" aria-label="Sections">
      <div className="legal-toc-label">Contents</div>
      <ul className="legal-toc-list">
        {sections.map((s) => (
          <li key={s.id} className="legal-toc-item">
            <a
              href={"#" + s.id}
              className={
                "legal-toc-link" + (activeId === s.id ? " legal-toc-link--active" : "")
              }
            >
              {s.heading}
            </a>
          </li>
        ))}
      </ul>
    </nav>
  );
}

// ── Main page ────────────────────────────────────────────────────────────────
function LegalPage({ pageKey }) {
  const C = window.COPY;
  const data = C.placeholderPages[pageKey];
  const [modalSource, setModalSource] = React.useState(null);
  const [activeId, setActiveId] = React.useState(
    data.sections && data.sections.length > 0 ? data.sections[0].id : null
  );

  // Observe section headings to highlight the current TOC entry.
  React.useEffect(() => {
    if (!data.sections) return;
    const opts = { rootMargin: "-30% 0px -60% 0px", threshold: 0 };
    const handler = (entries) => {
      // Pick the topmost visible heading.
      const visible = entries
        .filter((e) => e.isIntersecting)
        .map((e) => e.target.id);
      if (visible.length > 0) setActiveId(visible[0]);
    };
    const io = new IntersectionObserver(handler, opts);
    data.sections.forEach((s) => {
      const el = document.getElementById(s.id);
      if (el) io.observe(el);
    });
    return () => io.disconnect();
  }, [data]);

  return (
    <>
      <SiteHeader onIntent={(s) => setModalSource(s)} isLaunched={C.isLaunched} />
      <BackLink />
      <main className="placeholder-page-main section-dark legal-page-main">
        <div className="legal-layout">
          <StickyTOC sections={data.sections || []} activeId={activeId} />
          <article className="legal-article">
            <header className="legal-header">
              <h1 className="placeholder-h1 legal-h1">{data.title}</h1>
              <dl className="legal-dates">
                {data.effectiveDate && data.lastUpdated && data.effectiveDate === data.lastUpdated ? (
                  <>
                    <dt>Effective + last updated</dt>
                    <dd>{data.effectiveDate}</dd>
                  </>
                ) : (
                  <>
                    {data.effectiveDate && (
                      <>
                        <dt>Effective date</dt>
                        <dd>{data.effectiveDate}</dd>
                      </>
                    )}
                    {data.lastUpdated && (
                      <>
                        <dt>Last updated</dt>
                        <dd>{data.lastUpdated}</dd>
                      </>
                    )}
                  </>
                )}
              </dl>
              {data.intro && (
                <p className="legal-intro">{renderInline(data.intro, "intro")}</p>
              )}
              {data.introBold && (
                <p className="legal-intro legal-intro--bold">
                  <strong>{renderInline(data.introBold, "introB")}</strong>
                </p>
              )}
            </header>
            {(data.sections || []).map((s, idx) => (
              <section key={s.id} className="legal-section" id={s.id}>
                <h2 className="legal-h2">{s.heading}</h2>
                {(s.blocks || []).map((b, bi) => (
                  <Block key={bi} block={b} kp={"s" + idx + "b" + bi} />
                ))}
              </section>
            ))}
          </article>
        </div>
      </main>
      <SiteFooter />
      {modalSource && !C.isLaunched && (
        <DownloadIntentModal source={modalSource} onClose={() => setModalSource(null)} />
      )}
      <CookieBanner />
    </>
  );
}

// Expose to window so privacy.html / terms.html can mount it.
window.LegalPage = LegalPage;
window.renderInline = renderInline;
