/* nemotron-panel.jsx — Nemotron-Personas-Korea 관심사 결합(co-occurrence) 패널
 *
 *  Nemotron 설계 메커니즘 이식 결과를 노출:
 *    · PGM 결합분포 → 관심사 카테고리 동시발생 lift (주변분포 아닌 결합 근거)
 *    · 투명한 독립가정 선언 → 카테고리별 성×연령 독립/상관 플래그
 *    · 거짓 정밀 금지 → 표본 부족(n<MIN) 시 휴면 상태 + 전체 데이터 로드 안내
 *
 *  데이터: window.NemotronKR (합성·tier-C). 데모 14행이면 대부분 휴면.
 */
(function () {
  function Badge({ tone, children }) {
    var c = { amber: ['#3a2a12', '#f0b46a'], cyan: ['#11303a', '#5fc7e0'],
              plant: ['#13301f', '#5fcf94'], mute: ['#23262d', '#9aa0aa'],
              red: ['#3a1b1b', '#e08a8a'] }[tone || 'mute'];
    return (
      <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '2px 7px',
        borderRadius: 4, fontSize: 10.5, fontFamily: 'var(--font-mono)', fontWeight: 600,
        background: c[0], color: c[1], whiteSpace: 'nowrap' }}>{children}</span>
    );
  }

  function NemotronCooccurPanel() {
    var N = window.NemotronKR;
    if (!N) return (
      <div style={{ padding: 24, color: 'var(--ink-400)' }}>참고 표본 데이터 미로드.</div>
    );
    var prov = N.provenance;
    var pairs = N.cooccurrence();
    var cats = N.summary();
    var active = pairs.length > 0;

    return (
      <div style={{ padding: '18px 20px', maxWidth: 1080, margin: '0 auto' }}>
        {/* Provenance header */}
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 14, flexWrap: 'wrap',
          padding: '14px 16px', background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 8 }}>
          <div style={{ flex: '1 1 380px' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
              <strong style={{ fontFamily: 'var(--font-display)', fontSize: 16 }}>관심사 결합분포 · AI 참고 표본</strong>
              <Badge tone="amber">tier C · 참고</Badge>
              <Badge tone="mute">{prov.license}</Badge>
              <Badge tone={prov.isFull ? 'plant' : 'cyan'}>{prov.isFull ? '전체 데이터' : '데모 ' + prov.rows + '행'}</Badge>
            </div>
            <p style={{ margin: '8px 0 0', fontSize: 12, lineHeight: 1.55, color: 'var(--ink-300)' }}>
              {prov.kind}. {prov.note}
            </p>
            <p style={{ margin: '4px 0 0', fontSize: 11, color: 'var(--ink-400)', fontFamily: 'var(--font-mono)' }}>
              {prov.attribution} · {prov.coverage} · 전체 {prov.fullRows.toLocaleString()}행
            </p>
          </div>
        </div>

        {!active && (
          <div style={{ marginTop: 14, padding: '16px 18px', borderRadius: 8,
            background: 'var(--surface)', border: '1px dashed var(--border)' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
              <Badge tone="cyan">휴면</Badge>
              <strong style={{ fontSize: 13 }}>표본 부족 — 결합분포 비활성</strong>
            </div>
            <p style={{ margin: 0, fontSize: 12, lineHeight: 1.6, color: 'var(--ink-300)' }}>
              현재 데모 {prov.rows}행으로는 카테고리 쌍 동시발생 표본이 임계(쌍 n≥{N.MIN_PAIR}, 카테고리 n≥{N.MIN_N})에 못 미칩니다.
              거짓 정밀 방지를 위해 결합분포·co-occurrence는 <b>주입하지 않고 휴면</b>합니다.
              전체 데이터(<code style={{ fontFamily: 'var(--font-mono)' }}>nemotron-personas.sample.js</code>)를 드롭하면 자동 활성화됩니다.
            </p>
          </div>
        )}

        {/* Category joint profiles + independence flags */}
        <h4 style={{ margin: '20px 0 8px', fontSize: 12, letterSpacing: '0.04em', color: 'var(--ink-400)',
          textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>카테고리 결합 프로파일 · 독립가정 플래그</h4>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(220px,1fr))', gap: 10 }}>
          {cats.map(function (c) {
            var jp = N.categoryJointProfile(c.cat);
            var st = jp && jp.independence.sexAge;
            var tone = st === 'correlated' ? 'amber' : st === 'approx-independent' ? 'plant' : 'mute';
            var lab = st === 'correlated' ? '성×연령 상관' : st === 'approx-independent' ? '근사 독립' : '결합 미상';
            return (
              <div key={c.cat} style={{ padding: '11px 13px', background: 'var(--surface)',
                border: '1px solid var(--border)', borderRadius: 7 }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 6 }}>
                  <strong style={{ fontSize: 13 }}>{c.cat}</strong>
                  <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--ink-400)' }}>n={c.n}</span>
                </div>
                <div style={{ marginTop: 6, display: 'flex', gap: 5, flexWrap: 'wrap' }}>
                  <Badge tone={tone}>{lab}</Badge>
                  {c.femaleSkew != null && <Badge tone="mute">여 {Math.round(c.femaleSkew * 100)}%</Badge>}
                </div>
                {jp && <p style={{ margin: '7px 0 0', fontSize: 10.5, lineHeight: 1.5, color: 'var(--ink-400)' }}>{jp.independence.note}</p>}
              </div>
            );
          })}
        </div>

        {/* Co-occurrence pairs (active only) */}
        {active && (
          <>
            <h4 style={{ margin: '22px 0 8px', fontSize: 12, letterSpacing: '0.04em', color: 'var(--ink-400)',
              textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>관심사 동시발생 lift · P(B|A)/P(B)</h4>
            <div style={{ border: '1px solid var(--border)', borderRadius: 8, overflow: 'hidden' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12.5 }}>
                <thead>
                  <tr style={{ background: 'var(--surface)', color: 'var(--ink-400)', textAlign: 'left' }}>
                    <th style={{ padding: '8px 12px', fontWeight: 600 }}>관심사 A</th>
                    <th style={{ padding: '8px 12px', fontWeight: 600 }}>관심사 B</th>
                    <th style={{ padding: '8px 12px', fontWeight: 600, fontFamily: 'var(--font-mono)' }}>lift</th>
                    <th style={{ padding: '8px 12px', fontWeight: 600, fontFamily: 'var(--font-mono)' }}>P(B|A)</th>
                    <th style={{ padding: '8px 12px', fontWeight: 600, fontFamily: 'var(--font-mono)' }}>n(A∩B)</th>
                  </tr>
                </thead>
                <tbody>
                  {pairs.slice(0, 40).map(function (p, i) {
                    return (
                      <tr key={i} style={{ borderTop: '1px solid var(--border)' }}>
                        <td style={{ padding: '7px 12px' }}>{p.a}</td>
                        <td style={{ padding: '7px 12px' }}>{p.b}</td>
                        <td style={{ padding: '7px 12px', fontFamily: 'var(--font-mono)',
                          color: p.lift >= 1.3 ? 'var(--plant, #5fcf94)' : p.lift < 0.8 ? 'var(--ink-400)' : 'var(--ink-200)' }}>
                          {p.lift != null ? p.lift.toFixed(2) + '×' : '—'}</td>
                        <td style={{ padding: '7px 12px', fontFamily: 'var(--font-mono)', color: 'var(--ink-300)' }}>{(p.pBgivenA * 100).toFixed(1)}%</td>
                        <td style={{ padding: '7px 12px', fontFamily: 'var(--font-mono)', color: 'var(--ink-400)' }}>{p.nAB}</td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
            <p style={{ margin: '8px 2px 0', fontSize: 11, color: 'var(--ink-400)', lineHeight: 1.5 }}>
              lift &gt; 1 = 함께 묶이는 경향(시드 1개 선택 시 동반 추천 근거). 합성 표본 기반 tier-C 참고치로, 실측 brand 데이터를 override하지 않습니다.
            </p>
          </>
        )}

        {/* v3.26 가산 — 1M 실데이터 enrichment (세분 관심사 · 라이프스타일 키워드 · 인구통계 교차) */}
        {N.hasEnrichment && N.hasEnrichment() && (function () {
          var fine = N.fineSummary().filter(function (f) { return f.eligible; });
          var coarse = cats.filter(function (c) { return c.eligible; }).map(function (c) { return c.cat; });
          var H4 = function (t) { return (
            <h4 style={{ margin: '22px 0 8px', fontSize: 12, letterSpacing: '0.04em', color: 'var(--ink-400)',
              textTransform: 'uppercase', fontFamily: 'var(--font-mono)' }}>{t}</h4>
          ); };
          var Chip = function (txt, n) { return (
            <span style={{ display: 'inline-flex', gap: 5, padding: '3px 8px', borderRadius: 5, fontSize: 11.5,
              background: 'var(--surface)', border: '1px solid var(--border)', color: 'var(--ink-200)' }}>
              {txt}{n != null && <em style={{ fontStyle: 'normal', fontFamily: 'var(--font-mono)', color: 'var(--ink-400)' }}>{n}</em>}
            </span>
          ); };
          return (
            <div style={{ marginTop: 28, paddingTop: 18, borderTop: '1px solid var(--border)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                <strong style={{ fontFamily: 'var(--font-display)', fontSize: 15 }}>1M 실데이터 보강</strong>
                <Badge tone="plant">enriched · {N.provenance.fullRows.toLocaleString()}행</Badge>
                <Badge tone="amber">tier C · 참고</Badge>
              </div>
              <p style={{ margin: '6px 0 0', fontSize: 11.5, color: 'var(--ink-400)', lineHeight: 1.5 }}>
                100만 합성 페르소나의 관심사 원문·인구통계 25개 컬럼에서 추출. 합성 표본 빈도이며 실측 선호가 아닙니다(override 안 함).
              </p>

              {/* 세분 관심사 */}
              {H4('세분 관심사 · ' + fine.length + '종 (coarse 7 → fine 세분)')}
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(150px,1fr))', gap: 8 }}>
                {fine.slice(0, 25).map(function (f) {
                  return (
                    <div key={f.cat} style={{ padding: '9px 11px', background: 'var(--surface)',
                      border: '1px solid var(--border)', borderRadius: 7 }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', gap: 6 }}>
                        <strong style={{ fontSize: 12.5 }}>{f.cat}</strong>
                        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10.5, color: 'var(--ink-400)' }}>n={(f.n / 1000).toFixed(0)}k</span>
                      </div>
                      {f.femaleSkew != null && (
                        <div style={{ marginTop: 5 }}><Badge tone="mute">여 {Math.round(f.femaleSkew * 100)}%</Badge></div>
                      )}
                    </div>
                  );
                })}
              </div>

              {/* 라이프스타일 키워드 (관심사 원문 빈도) */}
              {H4('라이프스타일 키워드 · 관심사 원문 빈도 top')}
              <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                {coarse.map(function (cat) {
                  var kws = N.lifestyleKeywords(cat, 10) || [];
                  if (!kws.length) return null;
                  return (
                    <div key={cat}>
                      <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 6, color: 'var(--ink-300)' }}>{cat}</div>
                      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                        {kws.map(function (o, i) { return <span key={i}>{Chip(o.kw, (o.count / 1000).toFixed(0) + 'k')}</span>; })}
                      </div>
                    </div>
                  );
                })}
              </div>

              {/* 인구통계 교차 */}
              {H4('인구통계 교차 · 카테고리별 혼인·학력·직업 (tier-C)')}
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(260px,1fr))', gap: 10 }}>
                {coarse.map(function (cat) {
                  var dp = N.demographicProfile(cat);
                  if (!dp) return null;
                  var topShare = function (obj) {
                    if (!obj) return null;
                    var k = Object.keys(obj)[0];
                    return k ? k + ' ' + Math.round(obj[k] * 100) + '%' : null;
                  };
                  return (
                    <div key={cat} style={{ padding: '11px 13px', background: 'var(--surface)',
                      border: '1px solid var(--border)', borderRadius: 7 }}>
                      <strong style={{ fontSize: 13 }}>{cat}</strong>
                      <div style={{ marginTop: 7, display: 'flex', flexDirection: 'column', gap: 4, fontSize: 11.5, color: 'var(--ink-300)' }}>
                        {dp.maritalStatus && <div>혼인 · <b>{topShare(dp.maritalStatus)}</b></div>}
                        {dp.educationLevel && <div>학력 · <b>{topShare(dp.educationLevel)}</b></div>}
                        {dp.occupationTop && dp.occupationTop.length > 0 &&
                          <div style={{ color: 'var(--ink-400)' }}>직업 top · {dp.occupationTop.slice(0, 3).map(function (x) { return x.name; }).join(', ')}</div>}
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })()}

        {/* v3.31 가산 — 신규 합성속성 5종 + 세대구분(2026 기준). 원본 1M행과 별도 레이어(tier-C, 참고). */}
        {N.hasSynthLayer && N.hasSynthLayer() && (function () {
          var meta = N.synthMeta();
          var coarseCats = cats.filter(function (c) { return c.eligible; }).map(function (c) { return c.cat; });
          return (
            <div style={{ marginTop: 28, paddingTop: 18, borderTop: '1px solid var(--border)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                <strong style={{ fontFamily: 'var(--font-display)', fontSize: 15 }}>신규 합성속성 · 세대구분(2026)</strong>
                <Badge tone="amber">tier C · 참고</Badge>
                {meta.stale
                  ? <Badge tone="red">생성 후 {meta.ageDays}일 경과 — 재생성 권장</Badge>
                  : <Badge tone="plant">생성 {meta.ageDays}일 전 (신선)</Badge>}
              </div>
              <p style={{ margin: '6px 0 0', fontSize: 11.5, color: 'var(--ink-400)', lineHeight: 1.5 }}>
                원본 1M 실데이터에 없는 신규 차원 — 세대구분(산업화/베이비붐/X/밀레니얼/Z/알파, LLM 미사용 결정론 계산)과
                LLM 해석 5속성(구매동기·회피톤·선호채널·소비트렌드키워드·선호콘텐츠포맷)을 원본과 절대 혼합하지 않는 별도 레이어로 병기합니다.
                트렌드성 값(소비트렌드키워드 등)은 시간이 지나면 낡을 수 있어 {meta.staleAfterDays}일 경과 시 위 배너로 재생성을 권고합니다
                (재생성: <code style={{ fontFamily: 'var(--font-mono)' }}>node tools/nemotron-synth-refresh.mjs</code>).
                {meta.trendGrounding ? ' 실시간 트렌드(tier-B) 그라운딩: ' + meta.trendGrounding + '.' : ''}
              </p>

              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(260px,1fr))', gap: 10, marginTop: 14 }}>
                {coarseCats.map(function (cat) {
                  var s = N.synthLayer(cat);
                  if (!s) return null;
                  var g = s.generation;
                  var genText = g.mixed
                    ? (g.dominant + ' 주도 혼재(' + Math.round(g.dominantShare * 100) + '%)')
                    : g.dominant;
                  return (
                    <div key={cat} style={{ padding: '11px 13px', background: 'var(--surface)',
                      border: '1px solid var(--border)', borderRadius: 7 }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 6 }}>
                        <strong style={{ fontSize: 13 }}>{cat}</strong>
                        {!s.trendGrounded && <Badge tone="mute">트렌드 미그라운딩</Badge>}
                      </div>
                      <div style={{ marginTop: 6, display: 'flex', gap: 5, flexWrap: 'wrap' }}>
                        <Badge tone={g.mixed ? 'cyan' : 'plant'}>{genText}</Badge>
                        {g.compositeLabels && g.compositeLabels.map(function (c, i) { return <Badge key={i} tone="mute">{c}</Badge>; })}
                      </div>
                      <div style={{ marginTop: 8, fontSize: 11.5, color: 'var(--ink-300)', display: 'flex', flexDirection: 'column', gap: 4 }}>
                        <div>구매동기 · {s.motivations.slice(0, 3).join(', ')}</div>
                        <div>회피톤 · <span style={{ color: 'var(--ink-400)' }}>{s.avoid_tone}</span></div>
                        <div>선호채널 · <b>{s.preferred_channel}</b></div>
                        <div>소비트렌드 · {s.consumption_trend_keywords.join(', ')}</div>
                        <div>선호포맷 · <b>{s.preferred_content_format}</b></div>
                        {s.reasoning && (
                          <details style={{ marginTop: 2 }}>
                            <summary style={{ cursor: 'pointer', color: 'var(--ink-400)', fontSize: 10.5 }}>근거(v3.50) 보기</summary>
                            <div style={{ marginTop: 4, fontSize: 10.5, color: 'var(--ink-400)', lineHeight: 1.5 }}>{s.reasoning}</div>
                          </details>
                        )}
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })()}

        {/* v3.48 가산 — leaf(560-taxonomy) 단위 신규 합성속성. coarse(v3.31)가 "fine 25종은 범위 밖"으로
            미뤄둔 후속과제를 fine 대신 leaf 단위(GFA 타겟팅 실제 사용 단위)로 확장. tier-C, 참고. */}
        {N.hasSynthLeafLayer && N.hasSynthLeafLayer() && (function () {
          var meta = N.synthLeafMeta();
          var leaves = N.synthLeafList().map(function (p) { return N.synthLeaf(p); }).filter(Boolean)
            .sort(function (a, b) { return (b.n || 0) - (a.n || 0); });
          var byCat = {};
          leaves.forEach(function (l) { (byCat[l.sourceCat] = byCat[l.sourceCat] || []).push(l); });
          var catOrder = Object.keys(byCat).sort(function (a, b) { return byCat[b].length - byCat[a].length; });
          var CAP_PER_CAT = 6;
          return (
            <div style={{ marginTop: 28, paddingTop: 18, borderTop: '1px solid var(--border)' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                <strong style={{ fontFamily: 'var(--font-display)', fontSize: 15 }}>신규 합성속성 · leaf 단위 확장(560-taxonomy)</strong>
                <Badge tone="amber">tier C · 참고</Badge>
                <Badge tone="cyan">{leaves.length}개 leaf</Badge>
                {meta.stale
                  ? <Badge tone="red">생성 후 {meta.ageDays}일 경과 — 재생성 권장</Badge>
                  : <Badge tone="plant">생성 {meta.ageDays}일 전 (신선)</Badge>}
              </div>
              <p style={{ margin: '6px 0 0', fontSize: 11.5, color: 'var(--ink-400)', lineHeight: 1.5 }}>
                위 "신규 합성속성"(coarse 7종)이 미뤘던 fine 25종 후속과제를, GFA 타겟팅이 실제로 쓰는
                leaf(세부 관심사) 단위로 대체 확장했습니다 — leaf 고유 실측 라이프스타일 원문(topPhrases)을
                grounding으로 사용해 상위 카테고리보다 더 구체적인 해석을 뽑습니다.
                ★femaleSkew/연령/세대는 leaf 고유 실측이 아니라 상위 카테고리에서 상속(coarse-inherited) —
                구매동기·톤·채널·트렌드·포맷만 leaf 고유 grounding입니다(거짓정밀 금지, byLeaf statSource 그대로 승계).
                {meta.minNThreshold ? ' 표본 n<' + meta.minNThreshold + ' leaf는 제외.' : ''}
                재생성: <code style={{ fontFamily: 'var(--font-mono)' }}>node tools/nemotron-synth-refresh-leaf.mjs</code>
              </p>

              {catOrder.map(function (cat) {
                var arr = byCat[cat].slice(0, CAP_PER_CAT);
                return (
                  <div key={cat} style={{ marginTop: 16 }}>
                    <div style={{ fontSize: 12, fontWeight: 600, marginBottom: 8, color: 'var(--ink-300)',
                      display: 'flex', alignItems: 'center', gap: 6 }}>
                      {cat}
                      <span style={{ fontFamily: 'var(--font-mono)', fontSize: 10.5, color: 'var(--ink-400)', fontWeight: 400 }}>
                        {byCat[cat].length}개 중 상위 {arr.length}개
                      </span>
                    </div>
                    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(260px,1fr))', gap: 10 }}>
                      {arr.map(function (s) {
                        var leafName = s.path.split(' > ').slice(1).join(' › ');
                        return (
                          <div key={s.path} style={{ padding: '11px 13px', background: 'var(--surface)',
                            border: '1px solid var(--border)', borderRadius: 7 }}>
                            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 6 }}>
                              <strong style={{ fontSize: 12.5, lineHeight: 1.3 }}>{leafName}</strong>
                              {!s.trendGrounded && <Badge tone="mute">트렌드 미그라운딩</Badge>}
                            </div>
                            <div style={{ marginTop: 6, fontFamily: 'var(--font-mono)', fontSize: 10.5, color: 'var(--ink-400)' }}>
                              n={(s.n / 1000).toFixed(s.n >= 10000 ? 0 : 1)}k
                            </div>
                            <div style={{ marginTop: 7, fontSize: 11, color: 'var(--ink-300)', display: 'flex', flexDirection: 'column', gap: 3 }}>
                              <div>구매동기 · {s.motivations.slice(0, 3).join(', ')}</div>
                              <div>회피톤 · <span style={{ color: 'var(--ink-400)' }}>{s.avoid_tone}</span></div>
                              <div>선호채널 · <b>{s.preferred_channel}</b></div>
                              {s.consumption_trend_keywords.length > 0 &&
                                <div>소비트렌드 · {s.consumption_trend_keywords.join(', ')}</div>}
                              <div>선호포맷 · <b>{s.preferred_content_format}</b></div>
                              {s.reasoning && (
                                <details style={{ marginTop: 2 }}>
                                  <summary style={{ cursor: 'pointer', color: 'var(--ink-400)', fontSize: 10 }}>근거(v3.50) 보기</summary>
                                  <div style={{ marginTop: 4, fontSize: 10, color: 'var(--ink-400)', lineHeight: 1.45 }}>{s.reasoning}</div>
                                </details>
                              )}
                            </div>
                          </div>
                        );
                      })}
                    </div>
                  </div>
                );
              })}
            </div>
          );
        })()}
      </div>
    );
  }

  Object.assign(window, { NemotronCooccurPanel: NemotronCooccurPanel });
})();
