/* KeywordSetsPanel — 페르소나 카테고리에서 GFA 맞춤타겟 키워드 세트 자동 발굴
   1세트 최대 100개, 총 최대 2000개. 복사 / 다운로드 / 포맷 전환.
*/

const { useState: useKWState, useMemo: useKWMemo, useEffect: useKWEffect } = React;

function KeywordSetsPanel({ query }) {
  const [perSet, setPerSet] = useKWState(100);
  const [maxTotal, setMaxTotal] = useKWState(2000);
  const [format, setFormat] = useKWState('grouped');
  const [showAll, setShowAll] = useKWState(false);
  const [copied, setCopied] = useKWState(false);

  const sets = useKWMemo(() => {
    if (!window.KeywordEngine) return [];
    return window.KeywordEngine.generateKeywordSets(query, { perSet, maxTotal });
  }, [JSON.stringify(query), perSet, maxTotal]);

  // v3.11 — 연관검색어(실검색 grounding, tier-B 관측). 기존 휴리스틱 세트에 '가산'(무중단).
  //  시드 = 최상위 세트의 terminal 카테고리(예: "러닝화"). DataLab.serpRelated(워커 /api/proxy).
  //  거짓정밀 금지: 빈/에러는 정직 표기, 추정 생성 안 함. picked 만 출력에 합류.
  const seed = useKWMemo(() => {
    const s0 = sets[0];
    if (!s0 || !s0.label) return '';
    return String(s0.label).split('›').pop().trim();
  }, [sets]);
  const [ground, setGround] = useKWState({ loading: false, related: [], error: '', source: '', cached: false });
  const [picked, setPicked] = useKWState([]);

  useKWEffect(() => {
    if (!seed || !(window.DataLab && window.DataLab.serpRelated)) { setGround({ loading: false, related: [], error: '', source: '', cached: false }); return; }
    let alive = true;
    setGround(g => ({ ...g, loading: true, error: '' }));
    window.DataLab.serpRelated({ query: seed })
      .then(r => { if (!alive) return;
        setGround({ loading: false, related: Array.isArray(r && r.related) ? r.related : [], error: (r && r.error) || '', source: (r && r.source) || '', cached: !!(r && r.__cached), mock: r && r.__source === 'mock' }); })
      .catch(e => { if (alive) setGround({ loading: false, related: [], error: String((e && e.message) || e), source: '', cached: false }); });
    return () => { alive = false; };
  }, [seed]);

  function togglePick(term) {
    setPicked(p => p.includes(term) ? p.filter(t => t !== term) : [...p, term]);
  }

  // v3.27 — NVIDIA NIM(Nemotron) AI 롱테일 배리에이션(tier-C 표본추정, 옵트인·수동 트리거).
  //  serpRelated(tier-B, 자동조회)와 달리 25% 확률 콜드스타트 타임아웃 실측(2026-07-01) →
  //  사용자가 버튼을 눌러야만 호출(무중단·기존 흐름 불변). 실패도 정직하게 표시.
  const seedFull = useKWMemo(() => {
    const s0 = sets[0];
    return s0 && s0.label ? String(s0.label).replace(/›/g, ' > ').trim() : '';
  }, [sets]);
  const [ai, setAi] = useKWState({ loading: false, keywords: [], note: '', tried: false });
  const [pickedAi, setPickedAi] = useKWState([]);

  // v3.29 — 이미 조회된 실측(tier-B) 연관검색어(ground.related, 동일 seed 스코프)를 RAG 근거로 함께 전달.
  //  같은 카테고리 안에서만 스코핑되므로 브랜드/카테고리 교차오염 없음(2026-07-02 격리 원칙과 합치).
  function requestAiVariation() {
    if (!seedFull || !(window.KeywordEngine && window.KeywordEngine.fetchAiVariation)) return;
    setAi(a => ({ ...a, loading: true, tried: true }));
    window.KeywordEngine.fetchAiVariation(seedFull, ground.related).then(r => {
      setAi({ loading: false, keywords: r.keywords || [], note: r.ok ? '' : (r.note || '생성 실패'), tried: true, grounded: !!r.grounded, groundCount: r.groundCount || 0 });
    });
  }
  function togglePickAi(term) {
    setPickedAi(p => p.includes(term) ? p.filter(t => t !== term) : [...p, term]);
  }

  const summary = useKWMemo(() => window.KeywordEngine?.summary(sets), [sets]);
  const formattedOutput = useKWMemo(() => {
    if (!window.KeywordEngine) return '';
    let base = format === 'flat' ? window.KeywordEngine.format(sets, 'flat')
             : format === 'csv'  ? window.KeywordEngine.format(sets, 'csv')
             : window.KeywordEngine.format(sets, 'newline');
    // 선택한 연관검색어(tier-B)를 출력 말미에 합류 — 출처 라벨로 휴리스틱과 구분(거짓정밀 금지)
    if (picked.length) {
      if (format === 'csv') base += '\n' + picked.map(k => `"${k}",연관검색어(tier-B)`).join('\n');
      else base += `\n\n■ 연관검색어 · 실검색(tier-B)\n` + picked.join(format === 'flat' ? ', ' : '\n');
    }
    // 선택한 AI 롱테일(tier-C 표본추정)도 출력 말미에 합류 — 별도 출처 라벨 유지
    if (pickedAi.length) {
      if (format === 'csv') base += '\n' + pickedAi.map(k => `"${k}",AI 롱테일(tier-C)`).join('\n');
      else base += `\n\n■ AI 롱테일 · 표본추정(tier-C)\n` + pickedAi.join(format === 'flat' ? ', ' : '\n');
    }
    return base;
  }, [sets, format, picked, pickedAi]);

  function copyAll() {
    window.safeCopy(formattedOutput);
    setCopied(true);
    setTimeout(() => setCopied(false), 1800);
  }
  function downloadTxt() {
    const blob = new Blob([formattedOutput], { type: 'text/plain;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `keywords_${sets.length}sets_${summary.totalKeywords}건.txt`;
    a.click();
    URL.revokeObjectURL(url);
  }

  if (!sets.length) {
    return (
      <div className="kw-empty">
        <div style={{ fontSize: 28, color: 'var(--text-mute)' }}>◇</div>
        <div style={{ fontSize: 13, marginTop: 6 }}>키워드 세트를 발굴할 카테고리가 없습니다</div>
        <div style={{ fontSize: 11, color: 'var(--text-mute)', marginTop: 4 }}>
          페르소나의 관심사·구매의도가 키워드 시드에 매칭되어야 합니다.
        </div>
      </div>
    );
  }

  return (
    <div className="kw-panel">
      <div className="kw-head">
        <div>
          <strong style={{ fontSize: 16 }}>맞춤타겟 키워드 세트</strong>
          <div className="mono mute" style={{ fontSize: 11, marginTop: 2 }}>
            {summary.setCount}개 세트 · 총 <strong style={{ color: 'var(--signal)' }}>{summary.totalKeywords.toLocaleString()}</strong>개 키워드 · 평균 {summary.avgPerSet}개/세트
          </div>
        </div>
        <div className="kw-actions">
          <button onClick={copyAll} className="kw-btn" data-tone={copied ? 'plant' : 'signal'}>
            {copied ? '✓ 복사됨' : '📋 전체 복사'}
          </button>
          <button onClick={downloadTxt} className="kw-btn">⬇ TXT 다운로드</button>
        </div>
      </div>

      <div className="kw-controls">
        <label>
          <span>세트당 키워드</span>
          <input type="number" min="10" max="100" step="10" value={perSet}
                 onChange={e => setPerSet(Math.min(100, Math.max(10, +e.target.value || 100)))} />
          <small>최대 100</small>
        </label>
        <label>
          <span>총 키워드 한도</span>
          <input type="number" min="100" max="2000" step="100" value={maxTotal}
                 onChange={e => setMaxTotal(Math.min(2000, Math.max(100, +e.target.value || 2000)))} />
          <small>최대 2,000</small>
        </label>
        <label>
          <span>출력 형식</span>
          <div className="kw-format">
            <button aria-pressed={format === 'grouped'} onClick={() => setFormat('grouped')}>그룹별</button>
            <button aria-pressed={format === 'flat'} onClick={() => setFormat('flat')}>플랫</button>
            <button aria-pressed={format === 'csv'} onClick={() => setFormat('csv')}>CSV</button>
          </div>
        </label>
      </div>

      <div className="kw-sets">
        {sets.slice(0, showAll ? sets.length : 5).map((s, i) => (
          <div key={i} className="kw-set">
            <div className="kw-set-head">
              <strong>■ {s.label}</strong>
              <span className="mono mute">{s.count}건</span>
            </div>
            <div className="kw-set-list">
              {s.keywords.map((k, ki) => (
                <span key={ki} className="kw-chip">{k}</span>
              ))}
            </div>
          </div>
        ))}
        {!showAll && sets.length > 5 && (
          <button className="kw-more" onClick={() => setShowAll(true)}>
            +{sets.length - 5}개 세트 더 보기 →
          </button>
        )}
      </div>

      {seed && (
        <div className="kw-ground">
          <div className="kw-ground-head">
            <strong>◈ 연관검색어 · 실검색 grounding</strong>
            <span className="kw-tierb" title="관측 신호(실측 아님). 실검색 연관질의 — 매출·전환 아님.">tier-B 관측</span>
            <span className="mono mute" style={{ fontSize: 10 }}>시드 「{seed}」{ground.cached ? ' · 캐시' : ''}</span>
          </div>
          {ground.loading ? (
            <div className="kw-ground-msg">연관검색어 조회 중…</div>
          ) : ground.mock ? (
            <div className="kw-ground-msg">연관검색 미연결(프록시 mock) — 실데이터 없음</div>
          ) : ground.error ? (
            <div className="kw-ground-msg">연관검색 조회 실패: {ground.error}</div>
          ) : !ground.related.length ? (
            <div className="kw-ground-msg">연관질의 없음(저검색량 가능) — 휴리스틱 세트만 사용</div>
          ) : (
            <>
              <div className="kw-ground-note">클릭해 키워드에 추가 · 선택 {picked.length}개는 복사/다운로드에 합류</div>
              <div className="kw-ground-list">
                {ground.related.map((k, i) => (
                  <button key={i} className="kw-ground-chip" aria-pressed={picked.includes(k)} onClick={() => togglePick(k)}>
                    {picked.includes(k) ? '✓ ' : '+ '}{k}
                  </button>
                ))}
              </div>
            </>
          )}
        </div>
      )}

      {seedFull && (
        <div className="kw-ground kw-ai">
          <div className="kw-ground-head">
            <strong>✦ AI 롱테일 키워드</strong>
            <span className="kw-tierc" title="AI 생성 표본추정(실측 아님). 규칙기반 세트가 못 만드는 속성·증상 롱테일 보강.">tier-C 표본추정</span>
          </div>
          {!ai.tried ? (
            <>
              <div className="kw-ground-note">규칙기반 세트에 없는 속성·증상 키워드(예: 알레르기·저칼로리·소형견)를 AI로 추가 생성합니다{ground.related.length ? ` · 실측 연관검색어 ${ground.related.length}건을 참고 근거로 함께 전달합니다` : ''}. 10~15초 정도 걸리고, 드물게 실패할 수 있습니다.</div>
              <button className="kw-btn" onClick={requestAiVariation}>✦ AI 롱테일 생성</button>
            </>
          ) : ai.loading ? (
            <div className="kw-ground-msg">AI 키워드 생성 중… (최대 20초)</div>
          ) : ai.note ? (
            <>
              <div className="kw-ground-msg">생성 실패: {ai.note} — 기존 규칙기반 세트만 사용해도 무방합니다.</div>
              <button className="kw-btn" onClick={requestAiVariation}>다시 시도</button>
            </>
          ) : !ai.keywords.length ? (
            <div className="kw-ground-msg">생성된 키워드 없음</div>
          ) : (
            <>
              <div className="kw-ground-note">클릭해 키워드에 추가 · 선택 {pickedAi.length}개는 복사/다운로드에 합류{ai.grounded ? ` · 실측 연관검색어 ${ai.groundCount}건 기반 RAG 생성` : ' · 근거 데이터 없이 순수 생성(참고용)'}</div>
              <div className="kw-ground-list">
                {ai.keywords.map((k, i) => (
                  <button key={i} className="kw-ground-chip kw-ai-chip" aria-pressed={pickedAi.includes(k)} onClick={() => togglePickAi(k)}>
                    {pickedAi.includes(k) ? '✓ ' : '+ '}{k}
                  </button>
                ))}
              </div>
            </>
          )}
        </div>
      )}

      <details className="kw-output-details">
        <summary>붙여넣기용 텍스트 (선택해서 Ctrl+C){picked.length ? ` · 연관검색어 ${picked.length}개 포함` : ''}{pickedAi.length ? ` · AI 롱테일 ${pickedAi.length}개 포함` : ''}</summary>
        <textarea readOnly value={formattedOutput} className="kw-textarea" />
      </details>

      <style>{`
        .kw-panel { display: flex; flex-direction: column; gap: 14px; }
        .kw-empty {
          padding: 30px; text-align: center;
          color: var(--text-dim);
          background: oklch(0.10 0.02 240 / 0.5);
          border: 1px dashed var(--border-strong);
        }
        .kw-head {
          display: flex; justify-content: space-between; align-items: flex-start;
          gap: 12px;
          padding: 12px 14px;
          background: linear-gradient(120deg, oklch(0.80 0.14 72 / 0.06), transparent 60%);
          border: 1px solid rgba(255,240,220,0.10);
          border-left: 2px solid var(--signal);
        }
        .kw-actions { display: flex; gap: 6px; flex-shrink: 0; }
        .kw-btn {
          padding: 6px 12px;
          background: oklch(0.10 0.02 240 / 0.6);
          border: 1px solid var(--border-strong);
          color: var(--text);
          font-size: 11px; font-weight: 600;
          font-family: var(--font-sans);
          cursor: pointer;
          white-space: nowrap;
        }
        .kw-btn[data-tone="signal"] { background: var(--signal); color: var(--ink-000); border-color: var(--signal); }
        .kw-btn[data-tone="plant"]  { background: var(--plant);  color: var(--ink-000); border-color: var(--plant); }
        .kw-btn:hover { transform: translateY(-1px); }
        .kw-controls {
          display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
          gap: 10px;
          padding: 10px 14px;
          background: oklch(0.08 0.01 240 / 0.5);
          border: 1px solid var(--border);
        }
        .kw-controls label {
          display: flex; flex-direction: column; gap: 4px;
        }
        .kw-controls label > span { font-size: 11px; color: var(--text-dim); font-weight: 600; }
        .kw-controls input {
          background: rgba(255,240,220,0.04);
          border: 1px solid var(--border-strong);
          color: var(--text);
          padding: 6px 10px; font-size: 13px;
          font-family: var(--font-mono);
          outline: none;
        }
        .kw-controls input:focus { border-color: var(--signal); }
        .kw-controls small { font-size: 9px; color: var(--text-mute); }
        .kw-format { display: flex; }
        .kw-format button {
          flex: 1; padding: 6px 10px;
          background: oklch(0.10 0.02 240);
          border: 1px solid var(--border-strong);
          color: var(--text-dim);
          font-size: 11px; cursor: pointer;
        }
        .kw-format button + button { border-left: none; }
        .kw-format button[aria-pressed="true"] {
          background: var(--signal); color: var(--ink-000); border-color: var(--signal); font-weight: 600;
        }
        .kw-sets { display: flex; flex-direction: column; gap: 10px; }
        .kw-set {
          padding: 10px 12px;
          background: oklch(0.10 0.02 240 / 0.5);
          border: 1px solid var(--border);
        }
        .kw-set-head {
          display: flex; justify-content: space-between; align-items: baseline;
          gap: 8px; margin-bottom: 8px;
        }
        .kw-set-head strong { font-size: 12px; color: var(--text); font-weight: 600; }
        .kw-set-list { display: flex; flex-wrap: wrap; gap: 4px; max-height: 140px; overflow-y: auto; }
        .kw-chip {
          padding: 2px 7px;
          background: rgba(255,240,220,0.05);
          border: 1px solid var(--border-strong);
          font-family: var(--font-mono);
          font-size: 10px;
          color: var(--text);
        }
        .kw-more {
          padding: 8px 12px;
          background: none;
          border: 1px dashed var(--border-strong);
          color: var(--cyan);
          font-size: 12px; cursor: pointer; font-family: var(--font-sans);
        }
        .kw-more:hover { background: oklch(0.78 0.12 220 / 0.05); }
        /* v3.11 연관검색어 grounding — tier-B = 점선 ghost(추정/관측 질감, 거짓정밀 금지 시각화) */
        .kw-ground {
          padding: 11px 13px;
          background: oklch(0.10 0.02 300 / 0.4);
          border: 1px dashed oklch(0.55 0.12 300 / 0.55);
          border-left: 2px solid oklch(0.62 0.16 300 / 0.7);
        }
        .kw-ground-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
        .kw-ground-head strong { font-size: 12px; color: var(--text); font-weight: 600; }
        .kw-tierb {
          font-size: 9px; font-weight: 700; letter-spacing: 0.04em;
          padding: 1px 6px; border-radius: 2px;
          color: oklch(0.82 0.12 300); background: oklch(0.30 0.08 300 / 0.4);
          border: 1px solid oklch(0.55 0.12 300 / 0.5);
        }
        .kw-ground-note { font-size: 10px; color: var(--text-mute); margin-bottom: 7px; }
        /* v3.27 AI 롱테일 — tier-C는 tier-B보다 더 옅은 ghost 질감(같은 바이올렛 계열, 신뢰도 낮음을 표현) */
        .kw-ai { opacity: 0.92; border-style: dotted; }
        .kw-tierc {
          font-size: 9px; font-weight: 700; letter-spacing: 0.04em;
          padding: 1px 6px; border-radius: 2px;
          color: oklch(0.78 0.09 300 / 0.9); background: oklch(0.24 0.05 300 / 0.35);
          border: 1px dotted oklch(0.55 0.12 300 / 0.45);
        }
        .kw-ai-chip { border-style: dotted; }
        .kw-ground-msg { font-size: 11px; color: var(--text-dim); padding: 4px 0; }
        .kw-ground-list { display: flex; flex-wrap: wrap; gap: 5px; max-height: 150px; overflow-y: auto; }
        .kw-ground-chip {
          padding: 3px 8px;
          background: oklch(0.14 0.03 300 / 0.5);
          border: 1px dashed oklch(0.55 0.12 300 / 0.5);
          color: var(--text);
          font-family: var(--font-mono); font-size: 10px;
          cursor: pointer; transition: all 0.12s;
        }
        .kw-ground-chip:hover { border-style: solid; background: oklch(0.20 0.05 300 / 0.6); }
        .kw-ground-chip[aria-pressed="true"] {
          background: oklch(0.62 0.16 300 / 0.85); color: var(--ink-000);
          border: 1px solid oklch(0.62 0.16 300); font-weight: 600;
        }
        .kw-output-details summary {
          padding: 8px 12px;
          background: oklch(0.10 0.02 240 / 0.5);
          border: 1px solid var(--border);
          cursor: pointer;
          font-size: 12px; font-weight: 600;
          color: var(--text-dim);
        }
        .kw-output-details[open] summary { color: var(--text); }
        .kw-textarea {
          width: 100%; min-height: 200px;
          background: oklch(0.08 0.01 240 / 0.7);
          border: 1px solid var(--border);
          border-top: none;
          color: var(--bone-200);
          padding: 10px 12px;
          font-family: var(--font-mono);
          font-size: 11px;
          line-height: 1.6;
          resize: vertical;
        }
      `}</style>
    </div>
  );
}

Object.assign(window, { KeywordSetsPanel });
