// ─── Knowledge Base Page ─────────────────────────────────────────────────────

const JOB_STATUS_C = { completed: 'green', processing: 'blue', failed: 'red', pending: 'gray', queued: 'amber' };
const SRC_STATUS_C = { active: 'green', pending: 'amber', error: 'red', inactive: 'gray', processing: 'blue' };

function KBPage() {
  const [kbTab, setKbTab] = React.useState('Overview');
  const [sources, setSources] = React.useState([]);
  const [jobs, setJobs] = React.useState([]);
  const [status, setStatus] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [searchQ, setSearchQ] = React.useState('');
  const [searchResult, setSearchResult] = React.useState(null);
  const [newUrl, setNewUrl] = React.useState('');
  const [newUrlTitle, setNewUrlTitle] = React.useState('');
  const { toasts, addToast } = C.useToast();
  const [cfg, setCfg] = React.useState({
    leadrat_enabled: false,
    leadrat_tenant: '', leadrat_api_key: '', leadrat_secret_key: '', leadrat_base_url: 'https://connect.leadrat.com',
    leadrat_sync_interval_minutes: 5,
    kb_backend: 'local_faiss', kb_data_dir: 'data/kb',
    kb_embedding_provider: 'local', kb_embedding_model: 'BAAI/bge-small-en-v1.5',
    kb_embedding_fallback_provider: 'gemini', kb_embedding_fallback_model: 'gemini-embedding-001',
    kb_index_kind: 'flat_ip', kb_rerank_enabled: false,
    kb_top_k: 4, kb_inventory_top_k: 3, kb_similarity_threshold: 0.18,
    kb_context_char_budget: 2800, kb_live_timeout_ms: 150, kb_live_context_char_budget: 900, kb_cache_ttl_seconds: 45,
    kb_chunk_size: 400, kb_chunk_overlap: 60, kb_worker_poll_seconds: 20,
  });
  const set = k => v => setCfg(p => ({ ...p, [k]: v }));

  const reload = () => Promise.all([
    fetch('/api/kb/sources').then(r => r.json()).catch(() => ({ items: [] })),
    fetch('/api/kb/jobs').then(r => r.json()).catch(() => ({ items: [] })),
    fetch('/api/kb/status').then(r => r.json()).catch(() => null),
  ]).then(([s, j, st]) => {
    setSources(Array.isArray(s) ? s : (Array.isArray(s?.items) ? s.items : []));
    setJobs(Array.isArray(j) ? j : (Array.isArray(j?.items) ? j.items : []));
    setStatus(st);
    setLoading(false);
  });

  React.useEffect(() => {
    reload();
    fetch('/api/config').then(r => r.json()).then(data => {
      setCfg(p => ({
        ...p,
        leadrat_enabled: data.leadrat_enabled ?? p.leadrat_enabled,
        leadrat_tenant: data.leadrat_tenant || p.leadrat_tenant,
        leadrat_api_key: data.leadrat_api_key || p.leadrat_api_key,
        leadrat_secret_key: data.leadrat_secret_key || p.leadrat_secret_key,
        leadrat_base_url: data.leadrat_base_url || p.leadrat_base_url,
        leadrat_sync_interval_minutes: data.leadrat_sync_interval_minutes || p.leadrat_sync_interval_minutes,
        kb_backend: data.kb_backend || p.kb_backend,
        kb_data_dir: data.kb_data_dir || p.kb_data_dir,
        kb_embedding_provider: data.kb_embedding_provider || p.kb_embedding_provider,
        kb_embedding_model: data.kb_embedding_model || p.kb_embedding_model,
        kb_embedding_fallback_provider: data.kb_embedding_fallback_provider || p.kb_embedding_fallback_provider,
        kb_embedding_fallback_model: data.kb_embedding_fallback_model || p.kb_embedding_fallback_model,
        kb_index_kind: data.kb_index_kind || p.kb_index_kind,
        kb_rerank_enabled: data.kb_rerank_enabled ?? p.kb_rerank_enabled,
        kb_top_k: data.kb_top_k || p.kb_top_k,
        kb_inventory_top_k: data.kb_inventory_top_k || p.kb_inventory_top_k,
        kb_similarity_threshold: data.kb_similarity_threshold || p.kb_similarity_threshold,
        kb_context_char_budget: data.kb_context_char_budget || p.kb_context_char_budget,
        kb_live_timeout_ms: data.kb_live_timeout_ms || p.kb_live_timeout_ms,
        kb_live_context_char_budget: data.kb_live_context_char_budget || p.kb_live_context_char_budget,
        kb_cache_ttl_seconds: data.kb_cache_ttl_seconds || p.kb_cache_ttl_seconds,
        kb_chunk_size: data.kb_chunk_size || p.kb_chunk_size,
        kb_chunk_overlap: data.kb_chunk_overlap || p.kb_chunk_overlap,
        kb_worker_poll_seconds: data.kb_worker_poll_seconds || p.kb_worker_poll_seconds,
      }));
    }).catch(() => {});
  }, []);

  const handleSearch = async () => {
    if (!searchQ.trim()) return;
    try {
      const res = await fetch('/api/kb/search', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ query: searchQ, top_k: 5 }),
      });
      const data = await res.json();
      // The API returns {status, result, grounding} — result can be an object or array
      let items = [];
      if (Array.isArray(data)) items = data;
      else if (Array.isArray(data.results)) items = data.results;
      else if (Array.isArray(data.result)) items = data.result;
      else if (data.result && typeof data.result === 'object') {
        items = [].concat(data.result.chunk_hits || data.result.chunks || [], data.result.inventory_hits || data.result.inventory || [], data.result.items || []);
      }
      setSearchResult({ query: searchQ, results: items, grounding: data.grounding || '' });
    } catch {
      setSearchResult({ query: searchQ, results: [], grounding: '' });
    }
  };

  const handleAddUrl = async () => {
    if (!newUrl) return;
    try {
      const res = await fetch('/api/kb/sources', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ source_type: 'web_url', source_url: newUrl, title: newUrlTitle || newUrl }),
      });
      const data = await res.json();
      if (data.source) setSources(p => [...p, data.source]);
      else reload();
      setNewUrl(''); setNewUrlTitle('');
      addToast('URL source added successfully', 'success');
    } catch (e) {
      addToast('Failed to add URL source: ' + (e.message || 'Unknown error'), 'error');
    }
  };

  const handleDeleteSource = async id => {
    try {
      await fetch(`/api/kb/sources/${id}`, { method: 'DELETE' });
      setSources(p => p.filter(s => s.id !== id));
      addToast('Source deleted', 'success');
    } catch (e) {
      addToast('Failed to delete source', 'error');
    }
  };

  const handleSyncSource = async id => {
    addToast('Sync started — processing in background…', 'info');
    try {
      const res = await fetch(`/api/kb/sources/${id}/sync`, { method: 'POST' });
      const data = await res.json();
      if (res.ok) {
        addToast('Sync job queued successfully', 'success');
      } else {
        addToast(data.message || 'Sync failed', 'error');
      }
      reload();
    } catch (e) {
      addToast('Failed to sync source: ' + (e.message || 'Unknown error'), 'error');
    }
  };

  const totalChunks = status?.counts?.chunks ?? sources.reduce((a, s) => a + (s.chunks || 0), 0);
  const crmRecords = status?.counts?.entities ?? jobs.filter(j => j.status === 'completed').reduce((a, j) => Math.max(a, (j.last_result?.entity_count || 0)), 0);
  const activeJobs = jobs.filter(j => j.status === 'processing').length;
  const lrStatus = status?.leadrat || {};

  // Build a lookup map for source titles by source_id
  const sourceMap = {};
  sources.forEach(s => { sourceMap[s.id] = s.title; });

  return (
    <div>
      <C.ToastContainer toasts={toasts} />
      <C.PageHeader title="Knowledge Base" sub="Hybrid retrieval across PDF, URL, and LeadRat CRM inventory" />
      <C.Tabs tabs={['Overview','Config','Sources','Jobs','Search Preview']} active={kbTab} onChange={setKbTab} />
      <div style={{ marginTop: 20 }}>

        {kbTab === 'Overview' && (loading ? <C.Spinner /> : (
          <div style={{ display: 'grid', gap: 20 }}>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4,1fr)', gap: 16 }}>
              <C.Stat label="Sources" value={sources.length} sub="PDF + URL + CRM" />
              <C.Stat label="Structured Records" value={crmRecords || '—'} sub="CRM inventory rows" />
              <C.Stat label="Total Chunks" value={totalChunks} sub="Embedded text blocks" />
              <C.Stat label="Active Jobs" value={activeJobs} sub="Currently processing" accent={activeJobs > 0 ? '#fbbf24' : '#34d399'} />
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
              <C.Card title="KB Runtime">
                <div style={{ padding: '12px 20px', display: 'grid', gap: 10 }}>
                  {[
                    { label: 'Runtime', value: status?.runtime || 'Local FAISS + SQLite' },
                    { label: 'Embedding Model', value: status?.embedding_model || cfg.kb_embedding_model },
                    { label: 'Vectors', value: status?.vector_count ?? totalChunks },
                    { label: 'Data Dir', value: status?.data_dir || cfg.kb_data_dir },
                    { label: 'Last Rebuild', value: status?.last_rebuild_at ? new Date(status.last_rebuild_at).toLocaleString('en-IN') : '-' },
                    { label: 'Worker Poll', value: `${cfg.kb_worker_poll_seconds}s` },
                    { label: 'Cache TTL', value: `${cfg.kb_cache_ttl_seconds}s` },
                  ].map(r => (
                    <div key={r.label} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
                      <span style={{ color: '#7b849a' }}>{r.label}</span>
                      <span style={{ color: '#e8eaef', fontWeight: 600 }}>{r.value}</span>
                    </div>
                  ))}
                </div>
              </C.Card>
              <C.Card title="LeadRat CRM Sync">
                <div style={{ padding: '12px 20px', display: 'grid', gap: 8 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4 }}>
                    <C.Badge color={!lrStatus.enabled ? 'amber' : (lrStatus.connected ? 'green' : 'gray')}>
                      {!lrStatus.enabled ? 'Disabled' : (lrStatus.connected ? 'Connected' : 'Not Connected')}
                    </C.Badge>
                    {lrStatus.last_sync && <span style={{ fontSize: 12, color: '#5a6375' }}>Last sync {lrStatus.last_sync}</span>}
                  </div>
                  {[
                    { label: 'Tenant', value: cfg.leadrat_tenant || '—' },
                    { label: 'Sync Interval', value: `${cfg.leadrat_sync_interval_minutes} min` },
                    { label: 'Records Synced', value: lrStatus.records ?? '—' },
                  ].map(r => (
                    <div key={r.label} style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
                      <span style={{ color: '#7b849a' }}>{r.label}</span>
                      <span style={{ color: '#e8eaef', fontWeight: 600 }}>{r.value}</span>
                    </div>
                  ))}
                  {!lrStatus.enabled && (
                    <div style={{ fontSize: 12, color: '#fbbf24', marginTop: 4 }}>
                      LeadRat sync is turned off. Enable it in Config before running sync.
                    </div>
                  )}
                  <C.Btn variant="ghost" size="sm" style={{ marginTop: 8 }} onClick={async () => {
                    addToast('LeadRat sync started…', 'info');
                    try {
                      const res = await fetch('/api/kb/integrations/leadrat/sync', { method: 'POST' });
                      const data = await res.json();
                      if (res.ok) addToast('LeadRat sync completed', 'success');
                      else addToast(data.message || 'LeadRat sync failed', 'error');
                      reload();
                    } catch (e) { addToast('LeadRat sync error: ' + e.message, 'error'); }
                  }}>Sync Now</C.Btn>
                </div>
              </C.Card>
            </div>
          </div>
        ))}

        {kbTab === 'Config' && (
          <C.Card style={{ padding: 24 }}>
            <C.SectionTitle>LeadRat CRM Connection</C.SectionTitle>
            <C.Toggle
              label="Enable LeadRat CRM sync"
              checked={!!cfg.leadrat_enabled}
              onChange={v => set('leadrat_enabled')(v)}
              hint="This must be on, otherwise the backend will refuse LeadRat sync requests."
            />
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, marginBottom: 16 }}>
              <C.Input label="Tenant Name" value={cfg.leadrat_tenant} onChange={set('leadrat_tenant')} />
              <C.Input label="Sync Interval (min)" type="number" value={cfg.leadrat_sync_interval_minutes} onChange={v => set('leadrat_sync_interval_minutes')(parseInt(v))} />
              <C.Input label="API Key" type="password" value={cfg.leadrat_api_key} onChange={set('leadrat_api_key')} />
              <C.Input label="Secret Key" type="password" value={cfg.leadrat_secret_key} onChange={set('leadrat_secret_key')} />
              <div style={{ gridColumn: '1 / -1' }}>
                <C.Input label="Base URL" value={cfg.leadrat_base_url} onChange={set('leadrat_base_url')} />
              </div>
            </div>
            <div style={{ display: 'flex', gap: 8, marginBottom: 24 }}>
              <C.Btn variant="primary" size="sm" onClick={async () => {
                try {
                  addToast('Saving configuration…', 'info');
                  await fetch('/api/config', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(cfg) });
                  addToast('Configuration saved. Testing connection…', 'info');
                  const res = await fetch('/api/kb/integrations/leadrat/connect', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ tenant: cfg.leadrat_tenant }) });
                  const data = await res.json();
                  if (res.ok) addToast('LeadRat connection test passed ✓', 'success');
                  else addToast(data.message || 'Connection test failed', 'error');
                  reload();
                } catch (e) { addToast('Error: ' + e.message, 'error'); }
              }}>Save & Test Connection</C.Btn>
              <C.Btn variant="ghost" size="sm" onClick={async () => {
                addToast('LeadRat sync started…', 'info');
                try {
                  const res = await fetch('/api/kb/integrations/leadrat/sync', { method: 'POST' });
                  const data = await res.json().catch(() => ({}));
                  if (res.ok) addToast('LeadRat sync completed', 'success');
                  else addToast(data.message || 'LeadRat sync failed', 'error');
                  reload();
                } catch (e) { addToast('Sync error: ' + e.message, 'error'); }
              }}>Sync Now</C.Btn>
            </div>
            <C.SectionTitle>Retrieval Settings</C.SectionTitle>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
              <C.Input label="KB Backend" value={cfg.kb_backend} onChange={set('kb_backend')} />
              <C.Input label="Data Directory" value={cfg.kb_data_dir} onChange={set('kb_data_dir')} />
              <C.Input label="Embedding Provider" value={cfg.kb_embedding_provider} onChange={set('kb_embedding_provider')} />
              <C.Input label="Embedding Model" value={cfg.kb_embedding_model} onChange={set('kb_embedding_model')} />
              <C.Input label="Fallback Provider" value={cfg.kb_embedding_fallback_provider} onChange={set('kb_embedding_fallback_provider')} />
              <C.Input label="Fallback Model" value={cfg.kb_embedding_fallback_model} onChange={set('kb_embedding_fallback_model')} />
              <C.Input label="Index Kind" value={cfg.kb_index_kind} onChange={set('kb_index_kind')} />
              <C.Input label="Live Timeout (ms)" type="number" value={cfg.kb_live_timeout_ms} onChange={v => set('kb_live_timeout_ms')(parseInt(v))} />
              <C.Input label="KB Top K (similarity)" type="number" value={cfg.kb_top_k} onChange={v => set('kb_top_k')(parseInt(v))} />
              <C.Input label="KB Top K (inventory)" type="number" value={cfg.kb_inventory_top_k} onChange={v => set('kb_inventory_top_k')(parseInt(v))} />
              <C.Input label="Similarity Threshold" type="number" value={cfg.kb_similarity_threshold} onChange={v => set('kb_similarity_threshold')(parseFloat(v))} hint="0.0 – 1.0" />
              <C.Input label="Context Budget (chars)" type="number" value={cfg.kb_context_char_budget} onChange={v => set('kb_context_char_budget')(parseInt(v))} />
              <C.Input label="Live Context Budget" type="number" value={cfg.kb_live_context_char_budget} onChange={v => set('kb_live_context_char_budget')(parseInt(v))} />
              <C.Input label="Cache TTL (s)" type="number" value={cfg.kb_cache_ttl_seconds} onChange={v => set('kb_cache_ttl_seconds')(parseInt(v))} />
              <C.Input label="Worker Poll (s)" type="number" value={cfg.kb_worker_poll_seconds} onChange={v => set('kb_worker_poll_seconds')(parseInt(v))} />
              <C.Input label="Chunk Size" type="number" value={cfg.kb_chunk_size} onChange={v => set('kb_chunk_size')(parseInt(v))} />
              <C.Input label="Chunk Overlap" type="number" value={cfg.kb_chunk_overlap} onChange={v => set('kb_chunk_overlap')(parseInt(v))} />
            </div>
          </C.Card>
        )}

        {kbTab === 'Sources' && (
          <div style={{ display: 'grid', gap: 16 }}>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
              <C.Card title="Add Web URL" style={{ padding: '0 0 16px' }}>
                <div style={{ padding: '16px 20px', display: 'grid', gap: 12 }}>
                  <C.Input label="URL" value={newUrl} onChange={setNewUrl} placeholder="https://…" />
                  <C.Input label="Title" value={newUrlTitle} onChange={setNewUrlTitle} placeholder="Custom title" />
                  <C.Btn variant="primary" size="sm" onClick={handleAddUrl} disabled={!newUrl}>Add URL Source</C.Btn>
                </div>
              </C.Card>
              <C.Card title="Upload PDF" style={{ padding: '0 0 16px' }}>
                <div style={{ padding: '16px 20px', display: 'grid', gap: 12 }}>
                  <div style={{ border: '2px dashed rgba(255,255,255,0.1)', borderRadius: 10, padding: '24px', textAlign: 'center' }}>
                    <div style={{ fontSize: 24, marginBottom: 8 }}>📄</div>
                    <div style={{ fontSize: 13, color: '#7b849a' }}>Drag & drop PDF or click to browse</div>
                    <div style={{ fontSize: 11, color: '#5a6375', marginTop: 4 }}>Max 20 MB · PDF only</div>
                  </div>
                  <label style={{ cursor: 'pointer' }}>
                    <C.Btn variant="ghost" size="sm" style={{ width: '100%' }}>Choose File</C.Btn>
                    <input type="file" accept=".pdf" style={{ display: 'none' }} onChange={async e => {
                      const file = e.target.files?.[0];
                      if (!file) return;
                      const fd = new FormData();
                      fd.append('file', file);
                      const res = await fetch('/api/kb/upload', { method: 'POST', body: fd }).catch(() => null);
                      if (res?.ok) reload();
                    }} />
                  </label>
                </div>
              </C.Card>
            </div>
            <C.Card title={`Current Sources (${sources.length})`}>
              <C.Table cols={['Title','Type','Status','Updated','Actions']}
                empty="No sources yet."
                rows={sources.map(s => [
                  <div style={{ fontWeight: 600, color: '#e8eaef' }}>{s.title}</div>,
                  <C.Badge color={s.source_type === 'web_url' ? 'blue' : s.source_type === 'leadrat_crm' ? 'green' : 'purple'}>{(s.source_type || 'unknown').replace('_', ' ').toUpperCase()}</C.Badge>,
                  <C.Badge color={SRC_STATUS_C[s.status] || 'gray'}>{s.status}</C.Badge>,
                  <span style={{ fontSize: 12, color: '#7b849a' }}>{s.updated_at ? new Date(s.updated_at).toLocaleDateString('en-IN') : '—'}</span>,
                  <div style={{ display: 'flex', gap: 6 }}>
                    <C.Btn variant="ghost" size="sm" onClick={() => handleSyncSource(s.id)}>Sync</C.Btn>
                    <C.Btn variant="danger" size="sm" onClick={() => handleDeleteSource(s.id)}>Delete</C.Btn>
                  </div>,
                ])} />
            </C.Card>
          </div>
        )}

        {kbTab === 'Jobs' && (
          <C.Card title={`Ingestion Jobs (${jobs.length})`}>
            <C.Table cols={['Source','Type','Status','Progress','Started','Duration']}
              empty="No jobs yet."
              rows={jobs.map(j => {
                const progress = j.last_result?.percent ?? j.progress ?? 0;
                const duration = (j.started_at && j.finished_at) ? (() => {
                  const ms = new Date(j.finished_at) - new Date(j.started_at);
                  const mins = Math.floor(ms / 60000);
                  const secs = Math.floor((ms % 60000) / 1000);
                  return mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
                })() : (j.started_at ? 'Running…' : '—');
                return [
                  <span style={{ fontWeight: 600, color: '#e8eaef' }}>{sourceMap[j.source_id] || j.source_type || '—'}</span>,
                  <span style={{ fontSize: 12, color: '#7b849a', textTransform: 'uppercase', letterSpacing: '0.04em' }}>{j.job_type || j.source_type || '—'}</span>,
                  <C.Badge color={JOB_STATUS_C[j.status] || 'gray'}>{j.status}</C.Badge>,
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 130 }}>
                    <div style={{ flex: 1, height: 6, background: 'rgba(255,255,255,0.08)', borderRadius: 999, overflow: 'hidden' }}>
                      <div style={{ width: `${progress}%`, height: '100%', background: progress >= 100 ? '#34d399' : '#5a7ef5', borderRadius: 999, transition: 'width 0.3s' }} />
                    </div>
                    <span style={{ fontSize: 12, color: '#7b849a', flexShrink: 0 }}>{progress}%</span>
                  </div>,
                  <span style={{ fontSize: 12, color: '#7b849a' }}>{j.started_at ? new Date(j.started_at).toLocaleTimeString('en-IN', { hour: '2-digit', minute: '2-digit' }) : '—'}</span>,
                  <span style={{ fontSize: 12, color: '#7b849a' }}>{duration}</span>,
                ];
              })} />
          </C.Card>
        )}

        {kbTab === 'Search Preview' && (
          <div style={{ display: 'grid', gap: 16 }}>
            <C.Card title="Hybrid Search Preview" style={{ padding: '0 0 20px' }}>
              <div style={{ padding: '16px 20px', display: 'flex', gap: 10 }}>
                <input value={searchQ} onChange={e => setSearchQ(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleSearch()}
                  placeholder="e.g. 3 BHK near Whitefield under 1.2 crore…"
                  style={{ flex: 1, background: '#1a1e28', border: '1px solid rgba(255,255,255,0.08)', borderRadius: 8, color: '#e8eaef', fontSize: 13, padding: '9px 12px', outline: 'none', fontFamily: 'inherit' }} />
                <C.Btn variant="primary" onClick={handleSearch}>Search</C.Btn>
              </div>
            </C.Card>
            {searchResult && (
              <div style={{ display: 'grid', gap: 12 }}>
                <div style={{ fontSize: 12, color: '#7b849a' }}>Results for: <span style={{ color: '#e8eaef', fontWeight: 600 }}>"{searchResult.query}"</span></div>
                {(searchResult.results || []).length === 0 && <div style={{ fontSize: 13, color: '#5a6375', fontStyle: 'italic' }}>No results found.</div>}
                {(searchResult.results || []).map((r, i) => (
                  <div key={i} style={{ background: '#13161e', border: '1px solid rgba(255,255,255,0.07)', borderRadius: 12, padding: '14px 18px' }}>
                    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
                      <span style={{ fontSize: 12, fontWeight: 700, color: '#5a7ef5' }}>{r.source || r.title || 'Source'}</span>
                      {r.score != null && <span style={{ fontSize: 11, color: '#34d399', fontWeight: 700 }}>Score: {typeof r.score === 'number' ? r.score.toFixed(2) : r.score}</span>}
                    </div>
                    <div style={{ fontSize: 13, color: '#c8cdd8', lineHeight: 1.6, whiteSpace: 'pre-wrap' }}>{r.text || r.content || r.preview || r.fact_block || r.chunk || ''}</div>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { KBPage });
