// ════════════════════════════════════════════════════════════════
// PulsePage — «Пульс стартапов», редакционный лонгрид (веб-глубина)
// Источник: GET /api/pulse/latest (редакционный слой ПОВЕРХ Совета)
// Обратная пирамида: лид → тейкэвеи → рынок → 9 продуктов (drill-down)
// Журнальная подача: Playfair заголовки, Source Serif тело, bronze
// ════════════════════════════════════════════════════════════════

function PulsePage() {
  const [data, setData]       = React.useState(null);
  const [runs, setRuns]       = React.useState([]);   // история выпусков
  const [selTs, setSelTs]     = React.useState(null); // выбранный выпуск
  const [loading, setLoading] = React.useState(true);
  const [err, setErr]         = React.useState(null);
  const [open, setOpen]       = React.useState({});   // slug → раскрыт ли продукт

  const apiGet = (p) => (window.SDH_API ? window.SDH_API.get(p) : fetch(p).then(x => {
    if (!x.ok) throw new Error('HTTP ' + x.status); return x.json();
  }));

  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      try {
        const [latest, list] = await Promise.all([
          apiGet('/api/pulse/latest'),
          apiGet('/api/pulse/list').catch(() => []),
        ]);
        if (cancelled) return;
        setData(latest);
        setRuns(Array.isArray(list) ? list : []);
        setSelTs((latest.meta && latest.meta.pulse_ts) || null);
        setErr(null);
      } catch (e) {
        if (!cancelled) setErr(String(e.message || e));
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    load();
    return () => { cancelled = true; };
  }, []);

  // Переключение выпуска из истории
  async function selectIssue(ts) {
    if (!ts || ts === selTs) return;
    setLoading(true);
    try {
      const d = await apiGet('/api/pulse/' + ts);
      setData(d); setSelTs(ts); setOpen({}); setErr(null);
      window.scrollTo({ top: 0, behavior: 'smooth' });
    } catch (e) { setErr(String(e.message || e)); }
    finally { setLoading(false); }
  }

  const confColor = (c) => c >= 8 ? 'var(--hue-emerald)' : c >= 6 ? 'var(--hue-amber)' : 'var(--text-tertiary)';
  const confLabel = (c) => `${c}/10`;

  if (loading) return (
    <main><section className="sdh-section first"><div className="sdh-container">
      <div className="sdh-placeholder" style={{ padding: 40, textAlign: 'center' }}>готовлю выпуск…</div>
    </div></section></main>
  );

  if (err || !data) return (
    <main><section className="sdh-section first"><div className="sdh-container">
      <div className="sdh-placeholder" style={{ padding: 40 }}>
        <div style={{ fontFamily: 'var(--font-serif)', fontSize: 18, marginBottom: 8 }}>выпуск ещё не готов</div>
        <div style={{ color: 'var(--text-muted)', fontSize: 14 }}>{err || 'пульс не сгенерирован'}</div>
        <div style={{ color: 'var(--text-muted)', fontSize: 13, marginTop: 16 }}>
          запустите scripts/pulse_generate.py чтобы собрать выпуск из последнего совета.
        </div>
      </div>
    </div></section></main>
  );

  const m = data.meta || {};
  const market = data.market || {};

  return (
    <main className="pl-page">
      <section className="sdh-section first"><div className="sdh-container">

        {/* ── Шапка выпуска ── */}
        <div className="pl-masthead">
          <div className="pl-masthead-row">
            <div className="pl-eyebrow">пульс стартапов</div>
            {runs.length > 1 && (
              <select className="pl-history" value={selTs || ''}
                onChange={(e) => selectIssue(Number(e.target.value))}
                title="История выпусков">
                {runs.map((r, i) => {
                  const d = new Date(r.pulse_ts * 1000);
                  const lbl = d.toLocaleDateString('ru-RU', { day: '2-digit', month: 'short' })
                    + ' ' + d.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' });
                  return <option key={r.pulse_ts} value={r.pulse_ts}>{i === 0 ? 'свежий · ' : ''}{lbl}</option>;
                })}
              </select>
            )}
          </div>
          <div className="pl-issue">
            выпуск от {m.council_date || '—'} · корпус <span className="pl-num">{m.corpus_total || '—'}</span> стартапов
            {m.council_scope === 'full' ? ' · полный охват' : ''}
            {runs.length > 1 ? ` · всего выпусков ${runs.length}` : ''}
          </div>
        </div>

        {/* ── ЛИД (главное, обратная пирамида) ── */}
        <div className="pl-lede-wrap">
          <p className="pl-lede">{data.lede}</p>
          {data.lede_confidence != null && (
            <span className="pl-conf" style={{ color: confColor(data.lede_confidence) }}>
              уверенность {confLabel(data.lede_confidence)}
            </span>
          )}
        </div>

        {/* ── ТЕЙКЭВЕИ ── */}
        {Array.isArray(data.takeaways) && data.takeaways.length > 0 && (
          <div className="pl-takeaways">
            <div className="pl-section-label">коротко о главном</div>
            <ol className="pl-take-list">
              {data.takeaways.map((t, i) => <li key={i} className="pl-take">{t}</li>)}
            </ol>
          </div>
        )}

        {/* ── РЫНОК: тренды / кластеры / белые пятна ── */}
        <div className="pl-market">
          {[
            { key: 'trends', title: 'Макро-тренды', items: market.trends },
            { key: 'clusters', title: 'Кластеры конкуренции', items: market.clusters },
            { key: 'whitespace', title: 'Белые пятна', items: market.whitespace },
          ].map(col => (
            <div key={col.key} className="pl-mcol">
              <h3 className="pl-mcol-title">{col.title}</h3>
              {(col.items || []).map((it, i) => (
                <div key={i} className="pl-mitem">
                  <span className="pl-dot" style={{ background: confColor(it.confidence || 7) }} />
                  <span className="pl-mitem-text">{it.text}</span>
                  {it.confidence != null && <span className="pl-mitem-conf">{it.confidence}/10</span>}
                </div>
              ))}
            </div>
          ))}
        </div>

        {/* ── ПОРТФЕЛЬ: 9 продуктов, drill-down ── */}
        <div className="pl-portfolio">
          <div className="pl-section-label">портфель: где каждый продукт стоит</div>
          {(data.portfolio || []).map((p) => {
            const isOpen = !!open[p.slug];
            return (
              <div key={p.slug} className={`pl-card ${isOpen ? 'pl-card-open' : ''}`}
                   onClick={() => setOpen(o => ({ ...o, [p.slug]: !o[p.slug] }))}>
                <div className="pl-card-head">
                  <div className="pl-card-name">{p.product}</div>
                  <div className="pl-card-badges">
                    <span className={`pl-src pl-src-${p.source}`}>
                      {p.source === 'council' ? 'в фокусе совета' : 'по корпусу'}
                    </span>
                    {p.confidence != null && (
                      <span className="pl-conf-pill" style={{ color: confColor(p.confidence) }}>{p.confidence}/10</span>
                    )}
                    <span className="pl-chevron">{isOpen ? '−' : '+'}</span>
                  </div>
                </div>
                <p className="pl-card-oneliner">{p.one_liner}</p>
                {isOpen && (
                  <div className="pl-card-body">
                    {p.where_stands && <div className="pl-field"><span className="pl-flabel">позиция</span><span>{p.where_stands}</span></div>}
                    {p.competition && <div className="pl-field"><span className="pl-flabel">конкуренция</span><span>{p.competition}</span></div>}
                    {p.action && <div className="pl-field pl-action"><span className="pl-flabel">действие</span><span>{p.action}</span></div>}
                  </div>
                )}
              </div>
            );
          })}
        </div>

        {/* ── Провенанс (честность) ── */}
        <div className="pl-provenance">
          сделано из экспертного разбора от {m.council_date || '—'} ({m.council_scope === 'full' ? 'полный корпус' : 'выборка'})
          и корпуса в <span className="pl-num">{m.corpus_total || '—'}</span> стартапов из <span className="pl-num">{m.corpus_sources || '—'}</span> источников.
          каждое утверждение прослеживается до источника. это редакционный слой поверх совета, совет не меняется.
        </div>

      </div></section>

      <style>{`
        .pl-page { padding-bottom: 90px; }
        .pl-masthead { border-bottom: 2px solid var(--brand-bronze); padding-bottom: 12px; margin-bottom: 28px; }
        .pl-masthead-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
        .pl-history {
          font-family: var(--font-mono); font-size: 12px; color: var(--text-secondary);
          background: var(--surface-elevated); border: 1px solid var(--border-subtle);
          border-radius: 8px; padding: 6px 10px; cursor: pointer; max-width: 60%;
        }
        .pl-history:hover { border-color: var(--brand-bronze); }
        .pl-eyebrow {
          font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.16em;
          text-transform: uppercase; color: var(--brand-bronze); font-weight: 600;
        }
        .pl-issue { font-family: var(--font-mono); font-size: 12.5px; color: var(--text-tertiary); margin-top: 6px; }
        .pl-num { font-variant-numeric: tabular-nums; }

        .pl-lede-wrap { margin-bottom: 36px; }
        .pl-lede {
          font-family: var(--font-serif); font-size: 30px; line-height: 1.32; font-style: italic;
          color: var(--text-primary); margin: 0 0 10px 0; font-weight: 400; letter-spacing: -0.01em;
        }
        .pl-conf { font-family: var(--font-mono); font-size: 12px; }

        .pl-section-label {
          font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase;
          color: var(--text-tertiary); margin-bottom: 14px;
        }
        .pl-takeaways { margin-bottom: 40px; }
        .pl-take-list { margin: 0; padding: 0; counter-reset: tk; list-style: none; }
        .pl-take {
          position: relative; padding: 12px 0 12px 40px; border-top: 1px solid var(--border-subtle);
          font-family: var(--font-serif-body, var(--font-serif)); font-size: 16.5px; line-height: 1.5; color: var(--text-primary);
          counter-increment: tk;
        }
        .pl-take:last-child { border-bottom: 1px solid var(--border-subtle); }
        .pl-take::before {
          content: counter(tk); position: absolute; left: 0; top: 12px;
          font-family: var(--font-mono); font-size: 13px; font-weight: 600; color: var(--brand-bronze);
          width: 26px; height: 26px; border: 1px solid var(--brand-bronze-subtle); border-radius: 50%;
          display: flex; align-items: center; justify-content: center;
        }

        .pl-market { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-bottom: 44px; }
        .pl-mcol { background: var(--surface-elevated); border: 1px solid var(--border-subtle); border-radius: 12px; padding: 18px; }
        .pl-mcol-title { font-family: var(--font-serif); font-size: 17px; font-style: italic; font-weight: 400; margin: 0 0 12px; color: var(--brand-bronze); }
        .pl-mitem { display: flex; gap: 8px; align-items: flex-start; padding: 8px 0; font-size: 13.5px; line-height: 1.45; color: var(--text-secondary); }
        .pl-dot { width: 7px; height: 7px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; }
        .pl-mitem-text { flex: 1; }
        .pl-mitem-conf { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-tertiary); flex-shrink: 0; }

        .pl-portfolio { margin-bottom: 36px; }
        .pl-card {
          background: var(--surface-elevated); border: 1px solid var(--border-subtle); border-radius: 12px;
          padding: 16px 18px; margin-bottom: 10px; cursor: pointer; transition: border-color .15s, box-shadow .15s;
        }
        .pl-card:hover { border-color: var(--brand-bronze-subtle); }
        .pl-card-open { border-color: var(--brand-bronze); box-shadow: var(--shadow-sm); }
        .pl-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
        .pl-card-name { font-family: var(--font-serif); font-size: 19px; font-weight: 500; color: var(--text-primary); }
        .pl-card-badges { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
        .pl-src { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; padding: 3px 8px; border-radius: 20px; }
        .pl-src-council { background: var(--hue-emerald-subtle); color: var(--hue-emerald); }
        .pl-src-corpus { background: var(--surface-sunken); color: var(--text-tertiary); }
        .pl-conf-pill { font-family: var(--font-mono); font-size: 11px; font-variant-numeric: tabular-nums; }
        .pl-chevron { font-family: var(--font-mono); font-size: 16px; color: var(--text-tertiary); width: 16px; text-align: center; }
        .pl-card-oneliner { font-family: var(--font-serif-body, var(--font-serif)); font-size: 15px; line-height: 1.5; color: var(--text-secondary); margin: 8px 0 0; }
        .pl-card-body { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border-subtle); display: flex; flex-direction: column; gap: 10px; }
        .pl-field { display: flex; gap: 12px; font-size: 14px; line-height: 1.5; color: var(--text-secondary); }
        .pl-flabel { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-tertiary); width: 92px; flex-shrink: 0; padding-top: 2px; }
        .pl-action { color: var(--text-primary); }
        .pl-action .pl-flabel { color: var(--brand-bronze); }

        .pl-provenance {
          margin-top: 28px; padding: 16px 20px; background: var(--surface-recessed, var(--surface-sunken));
          border-left: 3px solid var(--brand-bronze); border-radius: 8px;
          font-family: var(--font-sans); font-size: 12.5px; line-height: 1.6; color: var(--text-tertiary);
        }
        @media (max-width: 760px) {
          .pl-lede { font-size: 23px; }
          .pl-market { grid-template-columns: 1fr; }
        }
      `}</style>
    </main>
  );
}

window.PulsePage = PulsePage;
