// BookHubPage — one canonical page per Bible book (the "missing middle").
// Shows: intro-derived themes + structure, the clickable pericope spine,
// early-church highlights aggregated from the trust ledger, and the door
// into the continuous Plain-reading edition. Data: /api/book/{abbr}.
(function () {
  const CSS = `
  .bhp { max-width: 1060px; margin: 0 auto; padding: 26px 34px 80px; }
  .bhp-top { display:flex; align-items:center; gap:12px; margin-bottom:18px; }
  .bhp-back { border:1px solid var(--line,#d8d3c8); background:#fff; border-radius:999px;
    padding:7px 16px; cursor:pointer; font:inherit; }
  .bhp-eyebrow { letter-spacing:.14em; font-size:11px; font-weight:700;
    color:var(--accent,#a33b2e); text-transform:uppercase; margin-bottom:6px; }
  .bhp-eyebrow .crumb { background:none; border:none; padding:0; font:inherit;
    color:inherit; letter-spacing:inherit; text-transform:inherit; cursor:pointer;
    text-decoration:underline; text-underline-offset:3px; }
  .bhp-eyebrow .crumb:hover { opacity:.75; }
  .bhp h1 { font-family: var(--serif, Georgia, serif); font-size:clamp(30px, 8vw, 44px); margin:0 0 10px; }
  .bhp-pills { display:flex; flex-wrap:wrap; gap:8px; margin:10px 0 8px; }
  .bhp-pill { border:1px solid var(--line,#ddd6c9); border-radius:999px; padding:4px 12px;
    font-size:12.5px; background:#faf8f2; }
  .bhp-pill.cta { background:var(--ink,#123); color:#fff; border-color:var(--ink,#123);
    cursor:pointer; font-weight:600; }
  .bhp-pill.cta:hover { opacity:.9; }
  .bhp-grid { display:grid; grid-template-columns: 1.5fr 1fr; gap:28px; margin-top:26px; }
  @media (max-width: 900px) { .bhp-grid { grid-template-columns: 1fr; } }
  .bhp h2 { font-family: var(--serif, Georgia, serif); font-size:21px; margin:26px 0 10px; }
  .bhp-md { line-height:1.62; font-size:15.5px; }
  .bhp-md h3 { font-size:16px; margin:16px 0 4px; }
  .bhp-md p { margin:8px 0; }
  .bhp-md ul { padding-left:20px; }
  .bhp-more { background:none; border:none; color:var(--accent,#a33b2e); cursor:pointer;
    font:inherit; padding:0; margin-top:6px; }
  .bhp-chapter { margin:14px 0 4px; font-weight:700; font-size:13px; color:#6d675c;
    letter-spacing:.06em; }
  .bhp-peris { display:flex; flex-direction:column; gap:6px; }
  .bhp-peri { display:flex; align-items:baseline; gap:10px; width:100%; text-align:left;
    border:1px solid var(--line,#e4ddd0); background:#fff; border-radius:10px;
    padding:9px 13px; cursor:pointer; font:inherit; }
  .bhp-peri:hover { border-color:var(--ink,#123); }
  .bhp-peri .ref { font-size:12px; color:#8a8375; white-space:nowrap; min-width:74px; }
  .bhp-peri .t { font-weight:600; }
  .bhp-peri .t.untitled { font-weight:400; color:#6d675c; font-style:italic; }
  .bhp-hl { border:1px solid var(--line,#e4ddd0); border-left:3px solid var(--accent,#a33b2e);
    background:#fff; border-radius:10px; padding:11px 14px; margin-bottom:9px; cursor:pointer;
    width:100%; text-align:left; font:inherit; }
  .bhp-hl:hover { border-color:var(--ink,#123); }
  .bhp-hl .who { font-weight:700; }
  .bhp-hl .what { font-size:13px; color:#6d675c; margin-top:2px; }
  .bhp-hl .tier { float:right; font-size:11px; border-radius:999px; padding:2px 8px;
    background:#e8f2ec; color:#1e6b46; font-weight:700; }
  .bhp-hl .tier.ol { background:#123; color:#ffd; }
  .bhp-note { font-size:13px; color:#8a8375; margin-top:8px; }
  .bhp-load { padding:60px 0; text-align:center; color:#8a8375; }
  .bhp-glance { border:1px solid var(--line,#e0d9ca); border-radius:14px; background:#fff;
    padding:18px 22px; margin-top:22px; }
  .bhp-glance-head { letter-spacing:.13em; font-size:11px; font-weight:700;
    color:var(--accent,#a33b2e); text-transform:uppercase; margin-bottom:12px;
    display:inline-block; padding:2px 8px; border-radius:4px;
    background:linear-gradient(transparent 45%, rgba(163,59,46,.13) 45%); }
  .bhp-facts { display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
    gap:12px 22px; margin-bottom:14px; }
  .bhp-fact .k { font-size:10.5px; letter-spacing:.1em; text-transform:uppercase;
    color:#8a8375; margin-bottom:2px; }
  .bhp-fact .v { font-size:14px; line-height:1.45; }
  .bhp-takes { margin:10px 0 4px; padding-left:0; list-style:none; }
  .bhp-takes li { margin:6px 0; font-size:14.5px; line-height:1.5; padding-left:24px; position:relative; }
  .bhp-takes li::before { content:"✓"; position:absolute; left:2px; top:0;
    color:var(--accent,#a33b2e); font-weight:700; }
  .bhp-nv { border-left:3px solid var(--accent,#a33b2e); background:#faf8f2;
    border-radius:0 10px 10px 0; padding:10px 14px; margin:10px 0; cursor:pointer;
    width:100%; text-align:left; font:inherit; border-top:none; border-right:none; border-bottom:none; }
  .bhp-nv:hover { background:#f4efe4; }
  .bhp-nv .q { font-family:var(--serif,Georgia,serif); font-size:15.5px; line-height:1.55; }
  .bhp-nv .r { font-size:12px; color:#8a8375; margin-top:4px; }
  .bhp-sig { display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
  .bhp-sig button { border:1px solid var(--line,#ddd6c9); background:#fff; border-radius:999px;
    padding:5px 13px; font:inherit; font-size:12.5px; cursor:pointer; }
  .bhp-sig button:hover { border-color:var(--ink,#123); }
  `;

  function inlineMd(s) {
    return String(s)
      .replace(/\[\[([^\]|]*\|)?([^\]]+)\]\]/g, '$2')
      .replace(/\*\*([^*]+)\*\*/g, '<b>$1</b>')
      .replace(/\*([^*]+)\*/g, '<i>$1</i>')
      .replace(/`([^`]+)`/g, '<code>$1</code>');
  }
  // tiny md → html for intro slices (headings, lists, paragraphs)
  function mdSliceHtml(md) {
    const out = [];
    let list = null;
    const flush = () => { if (list) { out.push('<ul>' + list.join('') + '</ul>'); list = null; } };
    for (const raw of md.split('\n')) {
      const l = raw.trim();
      if (!l) { flush(); continue; }
      if (l.startsWith('####')) { flush(); out.push('<h4>' + inlineMd(l.replace(/^#+\s*/, '')) + '</h4>'); }
      else if (l.startsWith('###')) { flush(); out.push('<h3>' + inlineMd(l.replace(/^#+\s*/, '')) + '</h3>'); }
      else if (l.startsWith('##')) { flush(); out.push('<h3>' + inlineMd(l.replace(/^#+\s*/, '')) + '</h3>'); }
      else if (/^[-*]\s+/.test(l)) { (list = list || []).push('<li>' + inlineMd(l.replace(/^[-*]\s+/, '')) + '</li>'); }
      else if (l.startsWith('|') || l.startsWith('---')) { continue; }
      else { flush(); out.push('<p>' + inlineMd(l) + '</p>'); }
    }
    flush();
    return out.join('');
  }
  // split the intro essay into its ## sections (headings vary per book)
  function introSections(md) {
    const out = [];
    const re = /^##\s+(.+)$/gm;
    let m, prev = null;
    while ((m = re.exec(md))) {
      if (prev) out.push({ h: prev.h, body: md.slice(prev.end, m.index).trim() });
      prev = { h: m[1].replace(/^\d+\.\s*/, '').trim(), end: m.index + m[0].length };
    }
    if (prev) out.push({ h: prev.h, body: md.slice(prev.end).trim() });
    return out.filter(s => s.body);
  }
  const AUTHOR_NAMES = {
    irenaeus: 'Irenaeus of Lyons', tertullian: 'Tertullian', origen: 'Origen',
    'clement-alexandria': 'Clement of Alexandria', 'clement-of-rome': 'Clement of Rome',
    cyprian: 'Cyprian of Carthage', hippolytus: 'Hippolytus', 'justin-martyr': 'Justin Martyr',
    polycarp: 'Polycarp', ignatius: 'Ignatius of Antioch', methodius: 'Methodius',
  };
  const pretty = id => AUTHOR_NAMES[id] || String(id || 'Early witness').replace(/-/g, ' ')
    .replace(/\b\w/g, c => c.toUpperCase());
  const refOf = p => (p.chapter || '') + (p.v1 ? ':' + p.v1 + (p.v2 && p.v2 !== p.v1 ? '–' + p.v2 : '') : '');

  function BookHubPage({ abbr, onClose, onOpenStudy, onOpenEdition, onOpenSource, onOpenTestament, backLabel }) {
    const [st, setSt] = React.useState({ loading: true });
    const [showIntro, setShowIntro] = React.useState(false);
    React.useEffect(() => {
      let on = true;
      setSt({ loading: true });
      window.AmosAPI.book(abbr)
        .then(d => on && setSt({ data: d }))
        .catch(e => on && setSt({ error: String(e) }));
      return () => { on = false; };
    }, [abbr]);

    if (st.loading) return <div className="bhp"><style>{CSS}</style><div className="bhp-load">Opening the book…</div></div>;
    if (st.error || !st.data) return <div className="bhp"><style>{CSS}</style>
      <button className="bhp-back" onClick={onClose}>{backLabel || '← Library'}</button>
      <div className="bhp-load">Could not load this book — the content service isn’t reachable.</div></div>;

    const d = st.data;
    const intro = d.intro && d.intro.markdown;
    const glance = d.glance;
    const allSecs = (intro ? introSections(intro) : [])
      .filter(s => !/^at a glance$/i.test(s.h));
    // drop production-metadata blocks (key: value headers, internal API notes)
    const isMetaBlock = s => /API note:|Corpus API/i.test(s.body) ||
      (s.body.split('\n').filter(l => /^\*\*[^:*]+:\*\*/.test(l.trim())).length >= 3) ||
      /^(metadata|production notes?)$/i.test(s.h);
    const secs = allSecs.filter(s => !isMetaBlock(s));
    const take = re => { const s = secs.find(s => re.test(s.h)); return s ? s.body : null; };
    const about = take(/^what it is$|^overview$/i) || (secs.length ? secs[0].body : null);
    const themes = take(/key themes|theolog|christolog/i);
    const structure = take(/structur/i);
    const shown = new Set([about, themes, structure]);
    const moreSecs = secs.filter(s => !shown.has(s.body));
    const cov = d.coverage || {};
    const byCh = {};
    d.pericopes.forEach(p => { (byCh[p.chapter] = byCh[p.chapter] || []).push(p); });
    const tiers = (d.reception && d.reception.tiers) || {};
    const strong = (tiers.ol || 0) + (tiers.verified || 0);

    return <div className="bhp">
      <style>{CSS}</style>
      <div className="bhp-top">
        <button className="bhp-back" onClick={onClose}>{backLabel || '← Library'}</button>
      </div>
      <div className="bhp-eyebrow">The Amos Project ·{' '}
        {onOpenTestament
          ? <button className="crumb" onClick={onOpenTestament}
              title="All 27 books on one screen">New Testament</button>
          : 'New Testament'}
        {' '}› {d.book_name}</div>
      <h1>{d.book_name}</h1>
      <div className="bhp-pills">
        <span className="bhp-pill">{d.pericopes.length} pericope analyses</span>
        {cov.pct != null && <span className="bhp-pill">{cov.pct}% of verses covered</span>}
        {strong > 0 && <span className="bhp-pill">{strong} verified early-church witnesses</span>}
        <button className="bhp-pill cta" onClick={() => onOpenEdition && onOpenEdition(abbr)}>
          Read the Full Analytical AI Translation →</button>
      </div>

      {glance && <div className="bhp-glance">
        <div className="bhp-glance-head">{d.book_name} at a glance</div>
        <div className="bhp-facts">
          {glance.author && <div className="bhp-fact"><div className="k">Author</div><div className="v">{glance.author}</div></div>}
          {glance.written && <div className="bhp-fact"><div className="k">Written</div><div className="v">{glance.written}</div></div>}
          {glance.setting && <div className="bhp-fact"><div className="k">Setting</div><div className="v">{glance.setting}</div></div>}
          {glance.canon && <div className="bhp-fact"><div className="k">Canon position</div><div className="v">{glance.canon}</div></div>}
        </div>
        {glance.takeaways && glance.takeaways.length > 0 &&
          <ul className="bhp-takes">{glance.takeaways.map((t, i) => <li key={i}>{t}</li>)}</ul>}
        {(glance.notable_verses || []).filter(v => v.text).map((v, i) =>
          <button key={i} className="bhp-nv" onClick={() => v.study && onOpenStudy && onOpenStudy(v.study)}
            title="In Amos's analytical translation — open the full analysis">
            <div className="q">“{v.text}”</div>
            <div className="r">{v.ref} · Amos's analytical translation, plain tier</div>
          </button>)}
        {(glance.signature || []).length > 0 && <div className="bhp-sig">
          {glance.signature.map(s =>
            <button key={s.id} onClick={() => onOpenStudy && onOpenStudy(s.id)}>
              {(s.title || (d.book_name + ' ' + s.chapter + ':' + s.v1 + (s.v2 && s.v2 !== s.v1 ? '–' + s.v2 : '')))}</button>)}
        </div>}
      </div>}

      <div className="bhp-grid">
        <div>
          {about && <React.Fragment>
            <h2>About {d.book_name}</h2>
            <div className="bhp-md" dangerouslySetInnerHTML={{ __html: mdSliceHtml(about) }} />
          </React.Fragment>}
          {themes && themes !== about && <React.Fragment>
            <h2>Themes</h2>
            <div className="bhp-md" dangerouslySetInnerHTML={{ __html: mdSliceHtml(themes) }} />
          </React.Fragment>}
          {structure && structure !== about && <React.Fragment>
            <h2>Structure</h2>
            <div className="bhp-md" dangerouslySetInnerHTML={{ __html: mdSliceHtml(structure) }} />
          </React.Fragment>}
          {moreSecs.length > 0 && <React.Fragment>
            <h2>More from the introduction</h2>
            <div className="bhp-pills">
              {moreSecs.map((s, i) =>
                <button key={i} className="bhp-pill" style={{ cursor: 'pointer' }}
                  onClick={() => setShowIntro(v => v === i ? false : i)}>
                  {s.h}{showIntro === i ? ' ▴' : ''}</button>)}
            </div>
            {showIntro !== false && moreSecs[showIntro] &&
              <div className="bhp-md" dangerouslySetInnerHTML={{ __html: mdSliceHtml(moreSecs[showIntro].body) }} />}
          </React.Fragment>}
          {intro && <button className="bhp-more"
            onClick={() => onOpenSource && onOpenSource(d.intro.path)}>
            Read the full introduction →</button>}
          {!intro && <div className="bhp-note">No introduction essay for this book yet.</div>}

          <h2>The early church on {d.book_name}</h2>
          {(d.reception.highlights || []).length === 0 &&
            <div className="bhp-note">No verified pre-Nicene citations located yet for this book.</div>}
          {(d.reception.highlights || []).map((h, i) =>
            <button key={i} className="bhp-hl" onClick={() => onOpenStudy && onOpenStudy(h.study)}
              title="Open the analysis where this witness is cited">
              <span className={'tier ' + h.tier}>{h.tier === 'ol' ? 'original language' : 'verified'}</span>
              <div className="who">{pretty(h.author_id)}</div>
              <div className="what">
                {String(h.work_slug || '').replace(/-/g, ' ')}{h.locator ? ' · ' + h.locator : ''}
                {' — on ' + d.book_name + ' ' + (h.chapter || '') + (h.v1 ? ':' + h.v1 + (h.v2 && h.v2 !== h.v1 ? '–' + h.v2 : '') : '')}
                {h.study_title ? ' (“' + h.study_title + '”)' : ''}
              </div>
            </button>)}
          {(d.reception.top_authors || []).length > 0 &&
            <div className="bhp-note">Most-cited verified voices: {d.reception.top_authors
              .filter(a => a[0]).map(a => pretty(a[0]) + ' ×' + a[1]).join(' · ')}</div>}
        </div>

        <div>
          <h2>Pericopes</h2>
          <div className="bhp-peris">
            {Object.keys(byCh).sort((a, b) => a - b).map(ch => <React.Fragment key={ch}>
              <div className="bhp-chapter">CHAPTER {ch}</div>
              {byCh[ch].map(p =>
                <button key={p.id} className="bhp-peri" onClick={() => onOpenStudy && onOpenStudy(p.id)}>
                  <span className="ref">{refOf(p)}</span>
                  <span className={'t' + (p.pericope_title ? '' : ' untitled')}>
                    {p.pericope_title || 'Analytical study'}</span>
                </button>)}
            </React.Fragment>)}
          </div>
        </div>
      </div>
    </div>;
  }
  window.BookHubPage = BookHubPage;
})();
