/* Main app composition for GFA Persona Matrix Lab. */

const { useState: useAppState, useEffect: useAppEffect, useMemo: useAppMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "dark",
  "density": "comfortable",
  "vizMode": "heatmap",
  "fontPair": "plex",
  "booleanUI": "expression",
  "motion3d": true,
  "motionIntensity": 0.55
}/*EDITMODE-END*/;

function App() {
  // --- View / tweaks ---
  const [tweaks, setTweaks] = useAppState(TWEAK_DEFAULTS);
  const [mode, setMode] = useAppState(() => {
    try { return localStorage.getItem('gfa-pm-mode') || 'wizard'; } catch { return 'wizard'; }
  });
  const [view, setView] = useAppState('matrix');
  const [chrome, setChrome] = useAppState(() => {
    try { return JSON.parse(localStorage.getItem('gfa-pm-chrome') || 'null') || { rightRail: false, intel: 'collapsed' }; }
    catch { return { rightRail: false, intel: 'collapsed' }; }
  });
  function updChrome(patch) {
    const next = { ...chrome, ...patch };
    setChrome(next);
    try { localStorage.setItem('gfa-pm-chrome', JSON.stringify(next)); } catch {}
  }

  function switchMode(m) {
    setMode(m);
    try { localStorage.setItem('gfa-pm-mode', m); } catch {}
  }

  // --- Domain state ---
  // Seeded with a sample query so the matrix view has data on first visit.
  const [query, setQuery] = useAppState([
    { op: 'OR', leaves: [
      '관심사 > 뷰티 > 스킨케어',
      '관심사 > 뷰티 > 메이크업/색조',
      '구매의도 > 뷰티 > 스킨케어 제품 > 페이셜 케어 제품',
    ]},
    { op: 'AND', leaves: [
      '관심사 > 라이프 이벤트 > 결혼',
    ]},
  ]);
  const [target, setTarget] = useAppState({
    gender: 'all',
    ages: [2, 3, 4], // 25-29, 30-34, 35-39
    includeUnknownGender: false,
  });
  const [exposure, setExposure] = useAppState({
    placements: ['feed', 'smartcast', 'banner'],
    times: ['t1', 't2', 't3'],
    budget: 500_000,
    bid: 'oCPM',
  });
  const [personas, setPersonas] = useAppState([]);

  // Apply tweaks to body
  useAppEffect(() => {
    document.body.dataset.theme = tweaks.theme;
    document.body.dataset.density = tweaks.density;
    document.body.dataset.fontPair = tweaks.fontPair;
    document.body.dataset.motion = tweaks.motion3d ? 'on' : 'off';
  }, [tweaks]);

  // Live derived data for reactive intelligence
  const liveResult = useAppMemo(() => window.SimEngine.evalQuery(query), [query]);
  const liveCorr = useAppMemo(() => {
    const all = query.flatMap(g => g.leaves).slice(0, 10);
    return window.SimEngine.buildCorrelation(all);
  }, [query]);
  const liveArchetypes = useAppMemo(() => window.SimEngine.rankArchetypes(query), [query]);

  function addLeaf(path) {
    setQuery(prev => {
      const copy = prev.map(g => ({ ...g, leaves: [...g.leaves] }));
      // add to last group; if already present anywhere, remove all
      const flat = copy.flatMap(g => g.leaves);
      if (flat.includes(path)) {
        return copy.map(g => ({ ...g, leaves: g.leaves.filter(l => l !== path) }));
      }
      copy[copy.length - 1].leaves.push(path);
      return copy;
    });
  }
  const selectedSet = useAppMemo(
    () => new Set(query.flatMap(g => g.leaves)),
    [query]
  );

  function savePersona(name) {
    const result = window.SimEngine.evalQuery(query);
    const stamp = new Date().toISOString().slice(5, 16).replace('T', ' ');
    const p = {
      id: 'p_' + Date.now(),
      name, query: JSON.parse(JSON.stringify(query)),
      target: { ...target }, exposure: { ...exposure },
      savedAt: stamp,
      result,
    };
    setPersonas(prev => [p, ...prev].slice(0, 10));
  }
  function loadPersona(id) {
    const p = personas.find(x => x.id === id);
    if (!p) return;
    setQuery(JSON.parse(JSON.stringify(p.query)));
    setTarget({ ...p.target });
    setExposure({ ...p.exposure });
  }
  function deletePersona(id) {
    setPersonas(prev => prev.filter(p => p.id !== id));
  }
  function applyRecommendation(r) {
    setQuery([{ op: r.op, leaves: r.leaves }]);
    setView('matrix');
  }

  const totalLeaves = query.reduce((s, g) => s + g.leaves.length, 0);

  return (
    <>
      {tweaks.motion3d && <MotionBackdrop intensity={tweaks.motionIntensity || 1} motion={tweaks.motion3d} />}
      {mode === 'wizard' ? (
        <div className="wizard-shell">
          <header className="wizard-header">
            <div className="brand">
              <div style={{ width: 28, height: 28, display: 'grid', placeItems: 'center' }}>
                {tweaks.motion3d ? <WireCube size={26} /> : <div className="brand-mark"><span>GF</span></div>}
              </div>
              <div className="brand-name">
                <strong>GFA 페르소나 매트릭스</strong>
                <small>네이버 GFA 광고 페르소나 자동 생성기</small>
              </div>
            </div>
            <div className="wizard-header-actions">
              <span className="mono mute" style={{ fontSize: 11 }}>v0.4 · {window.TOTAL_LEAVES}종 카테고리</span>
              <button className="btn" data-variant="ghost" data-size="sm" onClick={() => switchMode('advanced')}>
                고급 모드 →
              </button>
            </div>
          </header>
          <ErrorBoundary name="기본 워크플로우">
            <Workflow onGotoAdvanced={() => switchMode('advanced')} taxonomy={window.TAXONOMY} />
          </ErrorBoundary>
          <TweaksLayer tweaks={tweaks} setTweaks={setTweaks} />
        </div>
      ) : (
        <div className={'app-shell' + (chrome.rightRail ? '' : ' no-right')} data-screen-label="00 GFA Lab">
      {/* HEADER */}
      <header className="app-header">
        <div className="brand">
          <div style={{ width: 28, height: 28, display: 'grid', placeItems: 'center' }}>
            {tweaks.motion3d ? <WireCube size={26} /> : <div className="brand-mark"><span>GF</span></div>}
          </div>
          <div className="brand-name">
            <strong>GFA Persona Matrix Lab</strong>
            <small>고급 모드 · 풀 대시보드</small>
          </div>
        </div>
        <button className="back-to-wizard" onClick={() => switchMode('wizard')}
                title="기본 4단계 워크플로우로 돌아갑니다">
          <span style={{ fontSize: 14 }}>←</span>
          <span>쉬운 모드로 돌아가기</span>
        </button>
        <nav className="nav-tabs">
          {[
            { id: 'builder', label: '조합 빌더',     hint: '카테고리·인구통계·노출' },
            { id: 'matrix',  label: '시뮬레이션',    hint: 'KPI 매트릭스 결과' },
            { id: 'analysis', label: '심화 분석',    hint: '히트맵 · AI 추천 · API' },
            { id: 'compare', label: '저장·비교',     hint: '페르소나 라이브러리' },
          ].map((t, i) => (
            <button key={t.id} className="nav-tab" aria-current={view === t.id || (t.id === 'analysis' && ['heatmap','ai','agent'].includes(view))}
              onClick={() => setView(t.id === 'analysis' ? (['heatmap','ai','agent'].includes(view) ? view : 'heatmap') : t.id)}>
              <span className="idx">{String(i+1).padStart(2, '0')}</span>
              <span className="nav-tab-stack">
                <span className="nav-tab-label">{t.label}</span>
                <span className="nav-tab-hint">{t.hint}</span>
              </span>
            </button>
          ))}
        </nav>
        <div className="header-meta">
          <button className="hdr-toggle" onClick={() => updChrome({ rightRail: !chrome.rightRail })}
                  title={chrome.rightRail ? '우측 라이브러리 숨기기' : '우측 라이브러리 보이기'}>
            <span style={{ fontSize: 14 }}>{chrome.rightRail ? '▤' : '▥'}</span>
            <span>라이브러리</span>
          </button>
          <button className="hdr-toggle" onClick={() => updChrome({ intel: chrome.intel === 'collapsed' ? 'expanded' : 'collapsed' })}
                  title="실시간 인텔리전스 토글">
            <span style={{ fontSize: 14 }}>{chrome.intel === 'expanded' ? '◐' : '◯'}</span>
            <span>인텔</span>
          </button>
          <span style={{ color: 'var(--ink-400)' }}>|</span>
          <span className="pulse" /> LIVE · {window.TOTAL_LEAVES}개
        </div>
      </header>

      {/* LEFT — interest tree */}
      <aside className="app-left">
        <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--border)', background: 'var(--surface)' }}>
          <div className="label">관심사 · 구매의도</div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6, marginTop: 4 }}>
            <strong style={{ fontFamily: 'var(--font-display)', fontSize: 18, fontWeight: 700 }}>
              카테고리 선택
            </strong>
            <span className="mono mute" style={{ fontSize: 11 }}>종 560개</span>
          </div>
        </div>
        <InterestTree onAdd={addLeaf} selectedSet={selectedSet} />
      </aside>

      {/* MAIN — switching by view */}
      <main className="app-main">
        {chrome.intel === 'expanded' && (
          <ReactiveIntelligence
            query={query}
            result={liveResult}
            correlation={liveCorr}
            archetypes={liveArchetypes}
          />
        )}
        {/* View context bar */}
        <ViewContext view={view} setView={setView} />
        {view === 'builder' && (
          <ScrollWrap>
            <ErrorBoundary name="타겟 빌더">
              <BuilderView
                query={query} setQuery={setQuery}
                target={target} setTarget={setTarget}
                exposure={exposure} setExposure={setExposure}
              />
            </ErrorBoundary>
          </ScrollWrap>
        )}
        {view === 'matrix' && (
          <ScrollWrap>
            <ErrorBoundary name="시뮬레이션 결과">
              <GeographicMatrix4D query={query} target={target} exposure={exposure} />
              <details style={{ margin: '14px 18px', padding: 0 }}>
                <summary style={{ cursor: 'pointer', padding: '10px 14px', background: 'var(--surface)', border: '1px solid var(--border)', fontSize: 13, fontWeight: 600 }}>
                  ▾ 종합 KPI · 매트릭스 · 상관행렬 (펼치기)
                </summary>
                <div style={{ marginTop: 8 }}>
                  <MatrixDashboard query={query} target={target} exposure={exposure}
                                   vizMode={tweaks.vizMode} motion3d={tweaks.motion3d} />
                </div>
              </details>
            </ErrorBoundary>
          </ScrollWrap>
        )}
        {view === 'heatmap' && (
          <ScrollWrap><ErrorBoundary name="대형 히트맵"><HeatmapView query={query} vizMode={tweaks.vizMode} /></ErrorBoundary></ScrollWrap>
        )}
        {view === 'ai' && (
          <ScrollWrap><ErrorBoundary name="AI 추천"><AIView query={query} onApply={applyRecommendation} /></ErrorBoundary></ScrollWrap>
        )}
        {view === 'compare' && (
          <ScrollWrap><ErrorBoundary name="페르소나 비교"><CompareView personas={personas} current={{query, target, exposure}} /></ErrorBoundary></ScrollWrap>
        )}
      </main>

      {/* Quick action floating bar */}
      <QuickActions
        query={query} target={target} exposure={exposure}
        view={view} setView={setView}
        onSavePersona={savePersona}
        result={liveResult}
      />

      {/* FOOTER */}
      <footer className="app-footer">
        <span className="seg">선택된 카테고리 <strong>{totalLeaves}</strong>개 · 그룹 <strong>{query.length}</strong>개</span>
        <span className="sep">·</span>
        <span className="seg">성별 <strong>{target.gender === 'all' ? '전체' : target.gender === 'F' ? '여성' : '남성'}</strong> · 연령 <strong>{target.ages.length}</strong>개</span>
        <span className="sep">·</span>
        <span className="seg">노출지면 <strong>{exposure.placements.length}</strong>개 · 시간대 <strong>{exposure.times.length}</strong>개</span>
        <span className="sep">·</span>
        <span className="seg">입찰 <strong>{exposure.bid}</strong> · 일 예산 <strong>{(exposure.budget/10000).toFixed(0)}만원</strong></span>
        <span style={{ marginLeft: 'auto' }} className="seg mute">
          MAT 5.20.26 · 시뮬레이션 오차 ± 12% · 결정론적 시드
        </span>
      </footer>

      <TweaksLayer tweaks={tweaks} setTweaks={setTweaks} />
    </div>
      )}
    </>
  );
}

function ScrollWrap({ children }) {
  return (
    <div style={{ flex: 1, overflowY: 'auto' }}>
      {children}
    </div>
  );
}

/* === View context bar — breadcrumb + sub-tabs for analysis === */
const VIEW_META = {
  builder:  { title: '조합 빌더',      desc: '카테고리·인구통계·노출지면을 한 화면에서 구성합니다.',     icon: '◧' },
  matrix:   { title: '시뮬레이션 결과', desc: 'KPI · 매트릭스 · 페르소나 매칭을 종합해 보여드립니다.',     icon: '▦' },
  heatmap:  { title: '대형 히트맵',     desc: '도달·상관 매트릭스를 풀스크린으로 비교합니다.',           icon: '▩' },
  ai:       { title: 'AI 추천',        desc: '확장·집중·교차 3가지 방향의 자동 추천을 제공합니다.',       icon: '✦' },
  compare:  { title: '저장·비교',      desc: '저장된 페르소나를 나란히 비교하고 관리합니다.',            icon: '⇆' },
  agent:    { title: '에이전트 API',    desc: '외부 LLM 에이전트가 호출할 수 있는 JSON API를 노출합니다.', icon: '⌬' },
};
function ViewContext({ view, setView }) {
  const m = VIEW_META[view];
  if (!m) return null;
  const showAnalysisSub = ['heatmap', 'ai', 'agent'].includes(view);
  return (
    <div className="view-context">
      <div className="view-context-line">
        <span className="view-context-icon">{m.icon}</span>
        <div className="view-context-text">
          <strong>{m.title}</strong>
          <small>{m.desc}</small>
        </div>
        {showAnalysisSub && (
          <div className="view-sub-tabs">
            {[
              { id: 'heatmap', label: '대형 히트맵' },
              { id: 'ai',      label: 'AI 추천' },
              { id: 'agent',   label: '에이전트 API' },
            ].map(s => (
              <button key={s.id}
                      aria-pressed={view === s.id}
                      onClick={() => setView(s.id)}>{s.label}</button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* === Quick Actions floating panel === */
function QuickActions({ query, target, exposure, view, setView, onSavePersona, result }) {
  const [draftName, setDraftName] = useAppState('');
  const [showSave, setShowSave] = useAppState(false);
  const totalLeaves = query.reduce((s, g) => s + g.leaves.length, 0);
  const hasQuery = totalLeaves > 0;

  function saveNow() {
    if (!draftName.trim()) return;
    onSavePersona(draftName.trim());
    setDraftName('');
    setShowSave(false);
  }
  function copyResult() {
    const payload = {
      query, target, exposure, result,
      generatedAt: new Date().toISOString(),
    };
    window.safeCopy(JSON.stringify(payload, null, 2));
  }
  function runFullSweep() {
    setView('matrix');
  }

  return (
    <div className={'qa-bar' + (showSave ? ' is-expanded' : '')}>
      {showSave ? (
        <div className="qa-save">
          <input autoFocus type="text" placeholder="페르소나 이름을 입력하고 Enter"
                 value={draftName}
                 onChange={e => setDraftName(e.target.value)}
                 onKeyDown={e => { if (e.key === 'Enter') saveNow(); if (e.key === 'Escape') setShowSave(false); }} />
          <button className="btn" data-variant="primary" onClick={saveNow} disabled={!draftName.trim()}>저장</button>
          <button className="btn" data-variant="ghost" onClick={() => setShowSave(false)}>✕</button>
        </div>
      ) : (
        <>
          <div className="qa-summary">
            <span className="mono mute" style={{ fontSize: 10 }}>현재 쿼리</span>
            <strong>{totalLeaves}개 카테고리 · {query.length} 그룹</strong>
            {result && (
              <span className="qa-mini">
                도달 <strong>{window.SimEngine.fmtN(result.finalReach)}</strong> ·
                유효성 <strong>{result.validity}</strong>
              </span>
            )}
          </div>
          <button className="qa-btn" onClick={() => setShowSave(true)} disabled={!hasQuery} title="현재 쿼리를 페르소나로 저장">
            <span className="qa-btn-icon">+</span> 페르소나 저장
          </button>
          <button className="qa-btn" onClick={copyResult} disabled={!result} title="JSON 결과 복사">
            <span className="qa-btn-icon">⎘</span> 결과 복사
          </button>
          <button className="qa-btn" onClick={runFullSweep} disabled={view === 'matrix'} title="시뮬레이션 결과 화면으로">
            <span className="qa-btn-icon">▶</span> 매트릭스 보기
          </button>
        </>
      )}
    </div>
  );
}

// === Builder view: shows query builder + target + exposure ===

function BuilderView({ query, setQuery, target, setTarget, exposure, setExposure }) {
  function applySuggestion(sug) {
    // Replace query with the suggestion (preserve user demographic + exposure)
    setQuery([{ op: sug.op, leaves: sug.leaves }]);
  }
  return (
    <div style={{ padding: 18, overflow: 'auto', flex: 1, display: 'flex', flexDirection: 'column', gap: 14 }} data-screen-label="01 Builder">
      {/* Seed recommender on top — most prominent */}
      <section className="panel">
        <div className="panel-head">
          <h3>
            <span style={{ color: 'var(--signal)' }}>★</span>
            시드 1개 → AI 최적 조합 자동 추천
            <span className="tag">seed-based recommender</span>
          </h3>
        </div>
        <div className="panel-body">
          <SeedRecommender query={query} onApply={applySuggestion} />
        </div>
      </section>

      <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr', gap: 14 }}>
        <section className="panel" style={{ minHeight: 0 }}>
          <div className="panel-head">
            <h3>조합식 직접 편집<span className="tag">수동 빌더</span></h3>
          </div>
          <div className="panel-body">
            <QueryBuilder value={query} onChange={setQuery} />
          </div>
        </section>

        <section style={{ display: 'flex', flexDirection: 'column', gap: 14, minHeight: 0 }}>
          <div className="panel">
            <div className="panel-head">
              <h3>인구통계 타겟<span className="tag">성별·연령</span></h3>
            </div>
            <div className="panel-body">
              <GenderAgeBlock value={target} onChange={setTarget} />
            </div>
          </div>
          <div className="panel">
            <div className="panel-head">
              <h3>노출 설정<span className="tag">지면·시간·예산</span></h3>
            </div>
            <div className="panel-body">
              <ExposurePanel value={exposure} onChange={setExposure} />
            </div>
          </div>
        </section>
      </div>
    </div>
  );
}

// === Heatmap focused view ===
function HeatmapView({ query, vizMode }) {
  const allLeaves = useAppMemo(() => query.flatMap(g => g.leaves), [query]);
  const corr = useAppMemo(() => window.SimEngine.buildCorrelation(allLeaves.slice(0, 16)), [allLeaves]);
  const matrix = useAppMemo(() => window.SimEngine.buildMatrix(query), [query]);
  const [tab, setTab] = useAppState('reach'); // reach | corr
  const [zoom, setZoom] = useAppState(1);

  return (
    <div className="hm-view" data-screen-label="03 Heatmap">
      <div className="hm-toolbar">
        <div className="hm-tabs">
          <button aria-pressed={tab === 'reach'} onClick={() => setTab('reach')}>
            도달 매트릭스 <small>{matrix.rows.length}×{matrix.cols.length}</small>
          </button>
          <button aria-pressed={tab === 'corr'} onClick={() => setTab('corr')}>
            상관·중복도 <small>{corr.paths.length}×{corr.paths.length}</small>
          </button>
        </div>
        <div className="hm-zoom">
          <span className="label">셀 크기</span>
          <button onClick={() => setZoom(z => Math.max(0.6, +(z - 0.2).toFixed(1)))}>−</button>
          <span className="mono" style={{ width: 38, textAlign: 'center' }}>{Math.round(zoom * 100)}%</span>
          <button onClick={() => setZoom(z => Math.min(2.0, +(z + 0.2).toFixed(1)))}>+</button>
        </div>
      </div>

      <div className="hm-canvas">
        {tab === 'reach' ? (
          allLeaves.length
            ? <ReachMatrixFull matrix={matrix} mode={vizMode} zoom={zoom} />
            : <Empty msg="좌측 트리에서 카테고리를 먼저 선택하세요" />
        ) : (
          corr.paths.length >= 2
            ? <CorrelationMatrixFull data={corr} zoom={zoom} />
            : <Empty msg="상관관계 분석을 위해 2개 이상의 카테고리가 필요합니다" />
        )}
      </div>

      <style>{`
        .hm-view {
          display: flex; flex-direction: column;
          height: 100%;
          padding: 14px 18px;
          gap: 12px;
          min-height: 0;
        }
        .hm-toolbar {
          display: flex; align-items: center; justify-content: space-between;
          padding: 8px 12px;
          background: var(--surface);
          border: 1px solid var(--border);
          gap: 14px;
          flex: 0 0 auto;
        }
        .hm-tabs { display: flex; gap: 0; }
        .hm-tabs button {
          padding: 8px 16px;
          background: transparent;
          border: 1px solid var(--border-strong);
          color: var(--text-dim);
          font-size: var(--fs-sm);
          font-weight: 500;
          cursor: pointer;
          font-family: var(--font-sans);
        }
        .hm-tabs button + button { border-left: none; }
        .hm-tabs button small { font-family: var(--font-mono); font-size: 10px; opacity: 0.7; margin-left: 6px; }
        .hm-tabs button[aria-pressed="true"] {
          background: var(--signal);
          color: var(--ink-000);
          border-color: var(--signal);
          font-weight: 600;
        }
        .hm-zoom {
          display: flex; align-items: center; gap: 6px;
        }
        .hm-zoom button {
          width: 26px; height: 26px;
          background: var(--ink-200);
          border: 1px solid var(--border-strong);
          color: var(--text);
          font-size: 14px; cursor: pointer;
        }
        .hm-zoom button:hover { background: var(--ink-300); }
        .hm-canvas {
          flex: 1; min-height: 0;
          overflow: auto;
          background: oklch(0.10 0.02 240 / 0.45);
          border: 1px solid var(--border);
          padding: 12px;
          position: relative;
        }
      `}</style>
    </div>
  );
}
function ReachMatrixFull({ matrix, mode, zoom = 1 }) {
  return (
    <div style={{ minWidth: 'fit-content' }}>
      <MatrixCellsFull matrix={matrix} mode={mode} zoom={zoom} />
    </div>
  );
}
function MatrixCellsFull({ matrix, mode, zoom = 1 }) {
  const max = Math.max(1, ...matrix.rows.flatMap(r => r.cells));
  const cellMin = Math.round(58 * zoom);
  const rowH = Math.round(34 * zoom);
  const labelCol = Math.round(220 * zoom);
  return (
    <div className="matrix-grid hm-grid"
      style={{
        gridTemplateColumns: `${labelCol}px repeat(${matrix.cols.length}, minmax(${cellMin}px, 1fr))`,
        gridAutoRows: rowH + 'px',
      }}>
      <div className="hm-corner"></div>
      {matrix.cols.map(c => (
        <div key={c} className="matrix-rowlabel hm-collabel" style={{
          writingMode: 'horizontal-tb', transform: 'none', justifyContent: 'center',
          position: 'sticky', top: 0, zIndex: 4,
        }}>{c}</div>
      ))}
      {matrix.rows.map((row, ri) => (
        <React.Fragment key={ri}>
          <div className="matrix-rowlabel hm-rowlabel" title={row.path} style={{ position: 'sticky', left: 0, zIndex: 3 }}>
            {row.label}
          </div>
          {row.cells.map((v, ci) => {
            const intensity = Math.min(1, v / max);
            const fill = `oklch(${0.16 + intensity * 0.58} ${0.03 + intensity * 0.16} 72)`;
            return (
              <div key={ci} className="matrix-cell" style={{ background: fill }} title={`${row.label} · ${matrix.cols[ci]} → ${v.toLocaleString()}명`}>
                {intensity > 0.28 && <span className="v" style={{ fontSize: Math.round(11 * zoom) }}>
                  {v >= 10000 ? (v/10000).toFixed(1) + '만' : v >= 1000 ? (v/1000).toFixed(1) + 'K' : v}
                </span>}
              </div>
            );
          })}
        </React.Fragment>
      ))}
      <style>{`
        .hm-corner { background: var(--ink-100); border: 1px solid var(--ink-050); position: sticky; left: 0; top: 0; z-index: 5; }
        .hm-collabel { background: oklch(0.13 0.015 240); border-bottom: 2px solid var(--border-strong) !important; }
        .hm-rowlabel { background: oklch(0.13 0.015 240); border-right: 2px solid var(--border-strong) !important; }
      `}</style>
    </div>
  );
}
function CorrelationMatrixFull({ data, zoom = 1 }) {
  const N = data.paths.length;
  const labels = data.paths.map(p => window.SimEngine.shortLabel(p));
  const cellSize = Math.round(34 * zoom);
  const labelCol = Math.round(200 * zoom);
  return (
    <div style={{ minWidth: 'fit-content' }}>
      <div className="matrix-grid"
        style={{
          gridTemplateColumns: `${labelCol}px repeat(${N}, ${cellSize}px)`,
          gridAutoRows: cellSize + 'px',
          width: 'max-content',
        }}>
        <div className="hm-corner"></div>
        {labels.map((l, i) => (
          <div key={i} className="matrix-collabel hm-collabel" title={data.paths[i]} style={{ position: 'sticky', top: 0, zIndex: 4 }}>{l}</div>
        ))}
        {labels.map((l, ri) => (
          <React.Fragment key={ri}>
            <div className="matrix-rowlabel hm-rowlabel" title={data.paths[ri]} style={{ position: 'sticky', left: 0, zIndex: 3 }}>{l}</div>
            {data.matrix[ri].map((v, ci) => {
              const self = ri === ci;
              if (self) return <div key={ci} className="matrix-cell" style={{ background: 'var(--ink-200)' }}>—</div>;
              let bg;
              if (v > 0.8)      bg = `oklch(0.65 0.18 70 / ${Math.min(1, (v-0.5)*1.6)})`;
              else if (v > 0.5) bg = `oklch(0.5 0.10 70 / ${v*0.7})`;
              else if (v > 0.3) bg = `oklch(0.4 0.06 220 / ${(0.5-v)*1.4})`;
              else              bg = `oklch(0.6 0.12 220 / ${(0.4-v)*2})`;
              return <div key={ci} className="matrix-cell" style={{ background: bg }} title={`${labels[ri]} ↔ ${labels[ci]} = ${v.toFixed(2)}`}>
                <span style={{ fontSize: Math.round(10 * zoom), opacity: 0.85 }}>{v.toFixed(2)}</span>
              </div>;
            })}
          </React.Fragment>
        ))}
      </div>
      <div style={{ display: 'flex', gap: 14, marginTop: 14, fontFamily: 'var(--font-sans)', fontSize: 11, color: 'var(--text-dim)' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          <span style={{ width: 12, height: 12, background: 'oklch(0.65 0.18 70)' }} /> 강한 중복 (베타)
        </span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          <span style={{ width: 12, height: 12, background: 'oklch(0.50 0.10 70)' }} /> 약한 중복
        </span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}>
          <span style={{ width: 12, height: 12, background: 'oklch(0.60 0.12 220)' }} /> 보완 관계
        </span>
      </div>
    </div>
  );
}

// === AI view ===
function AIView({ query, onApply }) {
  const recos = useAppMemo(() => window.SimEngine.aiRecommend(query, window.TAXONOMY), [query]);
  const archetypes = useAppMemo(() => window.SimEngine.rankArchetypes(query), [query]);

  return (
    <div style={{ padding: 18, display: 'flex', flexDirection: 'column', gap: 14 }} data-screen-label="04 AI">
      <div className="panel">
        <div className="panel-head"><h3>AI 자동 추천<span className="tag">3 vectors</span></h3></div>
        <div className="panel-body" style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12 }}>
          {recos.map((r, i) => (
            <div key={i} style={{ padding: 14, border: '1px solid var(--cyan)', background: 'var(--cyan-soft)' }}>
              <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                <strong style={{ fontFamily: 'var(--font-display)', fontSize: 16 }}>{r.title}</strong>
                <span className="chip" data-tone="cyan">{r.op}</span>
              </div>
              <div style={{ fontSize: 11, color: 'var(--text-dim)', marginTop: 6 }}>{r.rationale}</div>
              <div style={{ marginTop: 10, fontFamily: 'var(--font-mono)', fontSize: 10 }}>
                {r.leaves.map((l, i) => (
                  <div key={i} style={{ color: 'var(--text-dim)', padding: '2px 0' }}>
                    · {window.SimEngine.shortLabel(l)}
                  </div>
                ))}
              </div>
              <button className="btn" data-variant="primary" onClick={() => onApply(r)} style={{ marginTop: 12, width: '100%', justifyContent: 'center' }}>
                적용 →
              </button>
            </div>
          ))}
        </div>
      </div>
      <div className="panel">
        <div className="panel-head"><h3>아키타입 적합도 매트릭스<span className="tag">{archetypes.length} archetypes</span></h3></div>
        <div className="panel-body">
          {archetypes.map(a => (
            <div key={a.id} style={{ display: 'flex', alignItems: 'center', gap: 14, padding: '8px 0', borderBottom: '1px solid var(--border)' }}>
              <div style={{ width: 140 }}>
                <div style={{ fontSize: 13 }}>{a.name}</div>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--text-mute)' }}>{a.desc}</div>
              </div>
              <div className="bar" style={{ flex: 1, height: 14 }}>
                <div style={{ width: a.match + '%', background: a.match > 60 ? 'var(--plant)' : a.match > 40 ? 'var(--signal)' : 'var(--alert-dim)' }} />
              </div>
              <div className="mono" style={{ width: 60, textAlign: 'right', fontSize: 14 }}>{a.match}<span style={{ fontSize: 9, color: 'var(--text-mute)' }}> /100</span></div>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// === Compare view ===
function CompareView({ personas, current }) {
  const currentResult = window.SimEngine.evalQuery(current.query);
  const rows = [
    currentResult ? { id: '__cur', name: '★ 현재 쿼리', result: currentResult, query: current.query } : null,
    ...personas
  ].filter(Boolean);

  if (rows.length === 0) {
    return <div style={{ padding: 40, textAlign: 'center', color: 'var(--text-mute)' }}>비교할 페르소나 없음</div>;
  }

  const cols = [
    { k: 'finalReach', label: 'REACH',    fmt: window.SimEngine.fmtN, tone: 'cyan' },
    { k: 'ctr',        label: 'CTR(%)',   fmt: v => v.toFixed(2), tone: 'signal' },
    { k: 'cpm',        label: 'eCPM(₩)',  fmt: v => v.toLocaleString() },
    { k: 'conv',       label: 'CVR(%)',   fmt: v => v.toFixed(2), tone: 'plant' },
    { k: 'validity',   label: '유효성',   fmt: v => v },
    { k: 'compete',    label: '경쟁',     fmt: v => v },
    { k: 'budget',     label: '예상 예산',fmt: window.SimEngine.fmtKRW },
  ];

  return (
    <div style={{ padding: 18 }} data-screen-label="05 Compare">
      <div className="panel">
        <div className="panel-head"><h3>페르소나 비교 매트릭스<span className="tag">{rows.length} rows</span></h3></div>
        <div className="panel-body" style={{ overflowX: 'auto' }}>
          <table className="compare-tbl">
            <thead>
              <tr>
                <th style={{ textAlign: 'left' }}>페르소나</th>
                <th>카테고리</th>
                {cols.map(c => <th key={c.k}>{c.label}</th>)}
              </tr>
            </thead>
            <tbody>
              {rows.map(r => (
                <tr key={r.id}>
                  <td><strong>{r.name}</strong></td>
                  <td className="mono mute">{r.query.flatMap(g => g.leaves).length}</td>
                  {cols.map(c => {
                    const v = r.result[c.k] || 0;
                    return <td key={c.k} className="mono" style={{ color: c.tone === 'cyan' ? 'var(--cyan)' : c.tone === 'signal' ? 'var(--signal)' : c.tone === 'plant' ? 'var(--plant)' : 'var(--text)' }}>
                      {c.fmt(v)}
                    </td>;
                  })}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      <style>{`
        .compare-tbl {
          width: 100%;
          border-collapse: collapse;
          font-family: var(--font-mono);
          font-size: 11px;
        }
        .compare-tbl th {
          font-family: var(--font-sans);
          font-size: 10px;
          color: var(--text-mute);
          letter-spacing: 0.06em;
          text-transform: uppercase;
          text-align: right;
          padding: 6px 10px;
          border-bottom: 1px solid var(--border-strong);
          font-weight: 500;
        }
        .compare-tbl td {
          padding: 8px 10px;
          text-align: right;
          border-bottom: 1px dashed var(--border);
        }
        .compare-tbl td:first-child {
          text-align: left;
          font-family: var(--font-sans);
        }
      `}</style>
    </div>
  );
}

function Empty({ msg }) {
  return <div style={{ padding: 30, fontSize: 11, color: 'var(--text-mute)', textAlign: 'center' }}>{msg}</div>;
}

// === Tweaks ===

function TweaksLayer({ tweaks, setTweaks }) {
  const { TweaksPanel, TweakSection, TweakRadio, TweakSelect, TweakToggle, TweakSlider } = window;
  if (!TweaksPanel) return null;
  function set(k, v) {
    if (typeof k === 'object') {
      setTweaks(prev => ({ ...prev, ...k }));
      window.parent.postMessage({ type: '__edit_mode_set_keys', edits: k }, '*');
    } else {
      setTweaks(prev => ({ ...prev, [k]: v }));
      window.parent.postMessage({ type: '__edit_mode_set_keys', edits: { [k]: v } }, '*');
    }
  }
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection label="외관">
        <TweakRadio label="컬러 테마" value={tweaks.theme} onChange={v => set('theme', v)}
          options={[{ value: 'dark', label: '다크' }, { value: 'light', label: '라이트' }, { value: 'accent', label: '앰버' }]} />
        <TweakRadio label="레이아웃 밀도" value={tweaks.density} onChange={v => set('density', v)}
          options={[{ value: 'compact', label: '콤팩트' }, { value: 'comfortable', label: '여유' }]} />
        <TweakSelect label="타이포 페어링" value={tweaks.fontPair} onChange={v => set('fontPair', v)}
          options={[
            { value: 'plex',     label: 'IBM Plex Sans/Mono KR' },
            { value: 'pretendard', label: 'Pretendard / Mono' },
            { value: 'nanum',    label: 'Nanum Square / D2Coding' },
            { value: 'hahmlet',  label: 'Hahmlet / Plex Mono' },
          ]} />
      </TweakSection>
      <TweakSection label="3D 모션 그래픽">
        <TweakToggle label="3D 모션 활성"      value={tweaks.motion3d} onChange={v => set('motion3d', v)} />
        <TweakSlider label="모션 강도" min={0.2} max={1.6} step={0.05}
          value={tweaks.motionIntensity ?? 0.9} onChange={v => set('motionIntensity', v)} />
      </TweakSection>
      <TweakSection label="매트릭스 시각화">
        <TweakSelect label="셀 표현 방식" value={tweaks.vizMode} onChange={v => set('vizMode', v)}
          options={[
            { value: 'heatmap', label: '히트맵 (기본)' },
            { value: 'iso3d',   label: '3D 등각 매트릭스' },
            { value: 'dot',     label: '도트 사이즈' },
            { value: 'bars',    label: '셀 내부 바' },
            { value: 'numeric', label: '숫자만' },
            { value: 'glyph',   label: 'ASCII 글리프' },
          ]} />
      </TweakSection>
      <TweakSection label="Boolean UI">
        <TweakRadio label="조합 입력 방식" value={tweaks.booleanUI} onChange={v => set('booleanUI', v)}
          options={[
            { value: 'expression', label: '쿼리식' },
            { value: 'block',      label: '블록 빌더' },
          ]} />
      </TweakSection>
    </TweaksPanel>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
