/* global React */
const { useState, useEffect, useRef, useCallback } = React;

// All KB API calls go through /api/kb (proxied by Robylab, X-Secret added server-side)
function kb(path, opts = {}) {
  return fetch('/api/kb' + path, { headers: authHeader(), ...opts });
}

function KnowledgeBaseScreen() {
  const [status, setStatus] = useState(null);
  const [sub, setSub] = useState('dashboard');
  const [syncRunning, setSyncRunning] = useState({ crm: false, files: false, summarize: false });
  const toast = useToast();

  const loadStatus = useCallback(async () => {
    try {
      const r = await kb('/status');
      if (!r.ok) return;
      setStatus(await r.json());
    } catch {}
  }, []);

  const checkRunning = useCallback(async () => {
    try {
      const r = await kb('/sync/status');
      if (!r.ok) return;
      const d = await r.json();
      setSyncRunning({ crm: !!d.crm_running, files: !!d.files_running, summarize: !!d.summarize_running });
    } catch {}
  }, []);

  useEffect(() => { loadStatus(); checkRunning(); const id = setInterval(() => { loadStatus(); checkRunning(); }, 30000); return () => clearInterval(id); }, []);

  const triggerCrm = async () => {
    try {
      const r = await kb('/sync/crm', { method: 'POST' });
      if (!r.ok) throw new Error(r.status);
      toast('CRM sync started', 'success');
      setSyncRunning(s => ({ ...s, crm: true }));
    } catch (e) { toast('Failed to start CRM sync', 'danger'); }
  };

  const triggerFiles = async () => {
    try {
      const r = await kb('/sync/files', { method: 'POST' });
      if (!r.ok) throw new Error(r.status);
      toast('Files sync started', 'success');
      setSyncRunning(s => ({ ...s, files: true }));
    } catch (e) { toast('Failed to start files sync', 'danger'); }
  };

  const triggerSummarize = async () => {
    try {
      const r = await kb('/summarize/all', { method: 'POST' });
      if (!r.ok) throw new Error(r.status);
      toast('AI summarisation started', 'success');
      setSyncRunning(s => ({ ...s, summarize: true }));
    } catch (e) { toast('Failed to start summarisation', 'danger'); }
  };

  const crm = status?.crm || {};
  const docs = status?.documents || {};
  const docsTotal = Object.values(docs).reduce((a, b) => a + Number(b), 0);
  const docsDone = Number(docs.done || 0);
  const chunks = Number(status?.total_chunks || 0);

  const subs = [
    { value: 'dashboard', label: 'Dashboard',  icon: <Icon d={I.home} size={13}/> },
    { value: 'search',    label: 'Search',     icon: <Icon d={I.search} size={13}/> },
    { value: 'records',   label: 'Records',    icon: <Icon d={I.database} size={13}/> },
    { value: 'log',       label: 'Sync log',   icon: <Icon d={I.list} size={13}/> },
    { value: 'settings',  label: 'Settings',   icon: <Icon d={I.settings} size={13}/> },
  ];

  const anyRunning = syncRunning.crm || syncRunning.files || syncRunning.summarize;

  return (
    <div className="route-in" style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <div style={{ padding: '24px 32px 0', maxWidth: 1280, width: '100%', margin: '0 auto' }}>
        <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 24, marginBottom: 18, flexWrap: 'wrap' }}>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
              <div className="micro">Tool</div>
              {anyRunning && <Badge tone="success" dot>Running</Badge>}
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
              <div style={{ width: 36, height: 36, borderRadius: 8, background: 'var(--s-info-weak)', color: 'var(--s-info)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <Icon d={I.book} size={18}/>
              </div>
              <h1 style={{ fontFamily: 'var(--s-font-display)', fontWeight: 400, fontSize: 28, letterSpacing: '-0.01em' }}>Knowledge Base</h1>
            </div>
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <Button variant={syncRunning.crm ? 'secondary' : 'primary'} icon={<Icon d={syncRunning.crm ? I.stop : I.refresh} size={13}/>}
              onClick={syncRunning.crm ? () => kb('/sync/crm/stop',{method:'POST'}).then(()=>setSyncRunning(s=>({...s,crm:false}))) : triggerCrm}>
              {syncRunning.crm ? 'Stop CRM' : 'Sync CRM'}
            </Button>
            <Button variant="secondary" icon={<Icon d={I.cloud} size={13}/>} onClick={triggerFiles} loading={syncRunning.files}>
              {syncRunning.files ? 'Syncing files…' : 'Sync files'}
            </Button>
            <Button variant="secondary" icon={<Icon d={I.sparkles} size={13}/>} onClick={triggerSummarize} loading={syncRunning.summarize}>
              {syncRunning.summarize ? 'Summarising…' : 'AI summaries'}
            </Button>
          </div>
        </div>
        <Tabs value={sub} onChange={setSub} options={subs}/>
      </div>

      <div style={{ flex: 1, overflowY: 'auto' }}>
        <div style={{ padding: '20px 32px 64px', maxWidth: 1280, width: '100%', margin: '0 auto' }}>
          {sub === 'dashboard' && <KbDashboard status={status} crm={crm} docs={docs} docsTotal={docsTotal} docsDone={docsDone} chunks={chunks} syncRunning={syncRunning} onRefresh={loadStatus}/>}
          {sub === 'search'    && <KbSearch/>}
          {sub === 'records'   && <KbRecords/>}
          {sub === 'log'       && <KbLog/>}
          {sub === 'settings'  && <KbSettings onSaved={() => toast('Saved', 'success')}/>}
        </div>
      </div>
    </div>
  );
}

// ── Dashboard ──────────────────────────────────────────────────────────────────
function KbDashboard({ status, crm, docs, docsTotal, docsDone, chunks, syncRunning, onRefresh }) {
  function fmt(n) { return n != null ? Number(n).toLocaleString() : '—'; }
  function age(iso) {
    if (!iso) return 'Never';
    const d = Math.round((Date.now() - new Date(iso)) / 60000);
    if (d < 1) return 'Just now'; if (d < 60) return d + 'm ago';
    if (d < 1440) return Math.floor(d/60) + 'h ago'; return new Date(iso).toLocaleDateString();
  }

  const kpis = [
    { label: 'Deals',    value: fmt(crm.deal?.count),         hint: age(crm.deal?.last_synced_at),          type: 'deal' },
    { label: 'Orgs',     value: fmt(crm.organization?.count), hint: age(crm.organization?.last_synced_at),  type: 'organization' },
    { label: 'Contacts', value: fmt(crm.contact?.count),      hint: age(crm.contact?.last_synced_at),       type: 'contact' },
    { label: 'Documents',value: `${docsDone}/${docsTotal}`,   hint: `${docsDone} processed`,                type: 'document' },
    { label: 'Chunks',   value: chunks.toLocaleString(),      hint: 'vector embeddings',                    type: null },
  ];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 24 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
        <Button size="sm" variant="ghost" icon={<Icon d={I.refresh} size={12}/>} onClick={onRefresh}>Refresh stats</Button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 12 }}>
        {kpis.map(k => (
          <div key={k.label} className="card" style={{ padding: 16, cursor: k.type ? 'pointer' : 'default' }}>
            <div className="micro" style={{ marginBottom: 6 }}>{k.label}</div>
            <div style={{ fontSize: 26, fontWeight: 600, fontFamily: 'var(--s-font-display)', letterSpacing: '-0.01em', color: 'var(--s-fg-1)', lineHeight: 1.1 }}>{k.value || '—'}</div>
            <div style={{ fontSize: 12, color: 'var(--s-fg-3)', marginTop: 4 }}>{k.hint}</div>
          </div>
        ))}
      </div>

      <div className="card" style={{ padding: 20 }}>
        <SectionHead title="Sync status"/>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 12 }}>
          {[
            { label: 'CRM sync', running: syncRunning.crm },
            { label: 'Files sync', running: syncRunning.files },
            { label: 'AI summaries', running: syncRunning.summarize },
          ].map(s => (
            <div key={s.label} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', background: 'var(--s-bg-1)', borderRadius: 6, border: '1px solid var(--s-border)' }}>
              <span className={`status-dot ${s.running ? 'running' : 'idle'}`}/>
              <span style={{ fontSize: 13, fontWeight: 500 }}>{s.label}</span>
              <span style={{ fontSize: 12, color: 'var(--s-fg-3)', marginLeft: 'auto' }}>{s.running ? 'Running' : 'Idle'}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── Search ─────────────────────────────────────────────────────────────────────
function KbSearch() {
  const [q, setQ] = useState('');
  const [filter, setFilter] = useState('all');
  const [results, setResults] = useState([]);
  const [loading, setLoading] = useState(false);
  const [searched, setSearched] = useState(false);

  const doSearch = async () => {
    if (!q.trim()) return;
    setLoading(true); setSearched(true);
    try {
      const params = new URLSearchParams({ q, limit: 15 });
      if (filter !== 'all') params.set('source_type', filter);
      const r = await kb('/search?' + params);
      const d = await r.json();
      setResults(d.results || []);
    } catch { setResults([]); }
    setLoading(false);
  };

  const filters = ['all', 'crm', 'document'];

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ display: 'flex', gap: 10 }}>
        <div style={{ flex: 1, position: 'relative' }}>
          <span style={{ position: 'absolute', left: 10, top: '50%', transform: 'translateY(-50%)', color: 'var(--s-fg-3)', display: 'flex' }}><Icon d={I.search} size={16}/></span>
          <input className="input-base" style={{ paddingLeft: 34 }} value={q} onChange={e => setQ(e.target.value)}
            placeholder="Ask anything about your deals, companies or documents…"
            onKeyDown={e => e.key === 'Enter' && doSearch()}/>
        </div>
        <Button variant="primary" loading={loading} onClick={doSearch}>Search</Button>
      </div>

      <div style={{ display: 'flex', gap: 8 }}>
        {filters.map(f => (
          <button key={f} onClick={() => setFilter(f)} style={{
            padding: '5px 14px', borderRadius: 999, border: '1px solid var(--s-border-strong)', cursor: 'pointer', fontFamily: 'inherit', fontSize: 13, fontWeight: 500,
            background: filter === f ? 'var(--s-brand)' : 'transparent', color: filter === f ? '#fff' : 'var(--s-fg-2)',
            transition: 'all var(--s-dur-fast) var(--s-ease)',
          }}>{f === 'all' ? 'All' : f === 'crm' ? 'CRM only' : 'Documents only'}</button>
        ))}
      </div>

      {loading && <div style={{ textAlign: 'center', color: 'var(--s-fg-3)', padding: 32 }}><span className="spin-inline"/> Searching…</div>}

      {!loading && searched && results.length === 0 && (
        <div className="card" style={{ padding: 40, textAlign: 'center', color: 'var(--s-fg-3)' }}>No results found for "{q}"</div>
      )}

      {!loading && results.map((r, i) => {
        const isDoc = r.source_type === 'document';
        const type = isDoc ? 'document' : (r.record_type || 'crm');
        const toneMap = { deal: 'brand', organization: 'success', contact: 'warning', document: 'accent', crm: 'info' };
        const score = Math.round(r.score * 100);
        return (
          <div key={i} className="card" style={{ padding: 16 }}>
            <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, marginBottom: 8 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                <Badge tone={toneMap[type] || 'neutral'}>{type}</Badge>
                <strong style={{ fontSize: 13 }}>{r.title || r.file_name || 'Untitled'}</strong>
              </div>
              <div style={{ textAlign: 'right', flexShrink: 0 }}>
                <span style={{ fontSize: 12, fontWeight: 700, color: 'var(--s-link)' }}>{score}%</span>
                <div style={{ height: 4, width: 60, background: 'var(--s-bg-3)', borderRadius: 2, marginTop: 3 }}>
                  <div style={{ height: 4, borderRadius: 2, background: 'var(--s-brand)', width: score + '%' }}/>
                </div>
              </div>
            </div>
            {!isDoc && r.crm_metadata && (
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, fontSize: 12, color: 'var(--s-fg-3)', marginBottom: 6 }}>
                {r.crm_metadata.stage && <span>📍 {r.crm_metadata.stage}</span>}
                {r.crm_metadata.value && <span>💶 {r.crm_metadata.value}</span>}
                {r.crm_metadata.org_name && <span>🏢 {r.crm_metadata.org_name}</span>}
              </div>
            )}
            <p style={{ fontSize: 13, color: 'var(--s-fg-2)', lineHeight: 1.5 }}>{r.content_preview}</p>
          </div>
        );
      })}
    </div>
  );
}

// ── Records browser ────────────────────────────────────────────────────────────
function KbRecords() {
  const [type, setType] = useState('deal');
  const [records, setRecords] = useState([]);
  const [total, setTotal] = useState(0);
  const [offset, setOffset] = useState(0);
  const [search, setSearch] = useState('');
  const [loading, setLoading] = useState(false);
  const LIMIT = 50;
  const debounceRef = useRef(null);

  const load = async (off = 0) => {
    setLoading(true);
    try {
      const p = new URLSearchParams({ type, limit: LIMIT, offset: off });
      if (search) p.set('search', search);
      const r = await kb('/records?' + p);
      const d = await r.json();
      setRecords(d.records || []);
      setTotal(d.total || 0);
      setOffset(off);
    } catch { setRecords([]); }
    setLoading(false);
  };

  useEffect(() => { load(0); }, [type]);

  const onSearch = (v) => {
    setSearch(v);
    clearTimeout(debounceRef.current);
    debounceRef.current = setTimeout(() => load(0), 300);
  };

  const types = ['deal', 'organization', 'contact', 'document'];
  const pages = Math.ceil(total / LIMIT);
  const page = Math.floor(offset / LIMIT) + 1;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
        <div style={{ display: 'flex', gap: 6 }}>
          {types.map(t => (
            <button key={t} onClick={() => setType(t)} style={{
              padding: '5px 12px', borderRadius: 'var(--s-r-md)', border: '1px solid var(--s-border-strong)', cursor: 'pointer', fontFamily: 'inherit', fontSize: 12.5, fontWeight: 500,
              background: type === t ? 'var(--s-brand-weak)' : 'transparent', color: type === t ? 'var(--s-link)' : 'var(--s-fg-2)',
            }}>{t.charAt(0).toUpperCase() + t.slice(1)}s</button>
          ))}
        </div>
        <div style={{ flex: 1, minWidth: 200 }}>
          <Input icon={<Icon d={I.search} size={13}/>} placeholder="Filter records…" value={search} onChange={e => onSearch(e.target.value)}/>
        </div>
      </div>

      <div className="card" style={{ overflow: 'hidden' }}>
        <div style={{ overflowX: 'auto', maxHeight: 520 }}>
          <table className="data">
            <thead>
              <tr><th>Name</th><th>Details</th><th>Synced</th></tr>
            </thead>
            <tbody>
              {loading && <tr><td colSpan={3} style={{ textAlign: 'center', padding: 32 }}><span className="spin-inline"/></td></tr>}
              {!loading && records.map((r, i) => {
                const m = r.metadata || {};
                const details = [m.stage, m.value && `${m.value} ${m.currency||''}`, m.org_name, m.email, m.file_type?.toUpperCase()].filter(Boolean).join(' · ');
                return (
                  <tr key={i}>
                    <td style={{ fontWeight: 500 }}>{r.title || r.file_name || '—'}</td>
                    <td style={{ fontSize: 12, color: 'var(--s-fg-3)' }}>{details || '—'}</td>
                    <td className="mono" style={{ fontSize: 12, color: 'var(--s-fg-3)' }}>{r.synced_at ? new Date(r.synced_at).toLocaleDateString() : '—'}</td>
                  </tr>
                );
              })}
              {!loading && records.length === 0 && <tr><td colSpan={3} style={{ textAlign: 'center', color: 'var(--s-fg-3)', padding: 32 }}>No records</td></tr>}
            </tbody>
          </table>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 14px', borderTop: '1px solid var(--s-border)', background: 'var(--s-bg-2)' }}>
          <span style={{ fontSize: 12, color: 'var(--s-fg-3)' }}>{total.toLocaleString()} total · page {page} of {Math.max(1, pages)}</span>
          <div style={{ display: 'flex', gap: 6 }}>
            <Button size="sm" variant="ghost" disabled={offset === 0} icon={<Icon d={I.chevLeft} size={12}/>} onClick={() => load(Math.max(0, offset - LIMIT))}>Prev</Button>
            <Button size="sm" variant="ghost" disabled={offset + LIMIT >= total} iconRight={<Icon d={I.chevRight} size={12}/>} onClick={() => load(offset + LIMIT)}>Next</Button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Sync log ───────────────────────────────────────────────────────────────────
function KbLog() {
  const [entries, setEntries] = useState([]);
  const [loading, setLoading] = useState(false);
  const logRef = useRef(null);

  const load = async () => {
    setLoading(true);
    try {
      const r = await kb('/sync/crm/log?limit=200');
      const d = await r.json();
      setEntries(d.entries || []);
    } catch { setEntries([]); }
    setLoading(false);
    setTimeout(() => { if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight; }, 50);
  };

  useEffect(() => { load(); }, []);

  const colours = { INFO: 'var(--s-info)', WARNING: 'var(--s-warning)', ERROR: 'var(--s-danger)', DEBUG: 'var(--s-fg-3)' };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
        <Button size="sm" variant="ghost" icon={<Icon d={I.refresh} size={12}/>} loading={loading} onClick={load}>Refresh</Button>
      </div>
      <div className="card" style={{ overflow: 'hidden' }}>
        <div ref={logRef} style={{ background: 'var(--s-bg-0)', padding: '12px 0', fontFamily: 'var(--s-font-mono)', fontSize: 12.5, maxHeight: 540, overflowY: 'auto' }}>
          {entries.length === 0 && <div style={{ color: 'var(--s-fg-3)', padding: 24, textAlign: 'center' }}>No log entries</div>}
          {entries.map((e, i) => (
            <div key={i} className="log-line" style={{ gridTemplateColumns: '76px 70px 1fr' }}>
              <span className="ts">{new Date(e.ts).toLocaleTimeString()}</span>
              <span className="lvl" style={{ color: colours[e.level] || 'var(--s-fg-2)' }}>{e.level}</span>
              <span className="msg">{e.msg}</span>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

// ── Settings ───────────────────────────────────────────────────────────────────
function KbSettings({ onSaved }) {
  const [schedule, setSchedule] = useState('daily');
  const [model, setModel] = useState('');
  const [prompt, setPrompt] = useState('');
  const [keys, setKeys] = useState([]);
  const [newKeyName, setNewKeyName] = useState('');
  const [newKeyValue, setNewKeyValue] = useState('');
  const [saving, setSaving] = useState(false);
  const toast = useToast();

  useEffect(() => {
    kb('/sync/schedule').then(r => r.json()).then(d => setSchedule(d.schedule || 'daily')).catch(() => {});
    kb('/summarize/config').then(r => r.json()).then(d => { setModel(d.model||''); setPrompt(d.prompt||''); }).catch(() => {});
    loadKeys();
  }, []);

  const loadKeys = () => kb('/auth/keys').then(r => r.json()).then(setKeys).catch(() => {});

  const saveSchedule = async () => {
    setSaving(true);
    try {
      await kb('/sync/schedule', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ schedule }) });
      toast('Schedule saved', 'success');
    } catch { toast('Failed to save schedule', 'danger'); }
    setSaving(false);
  };

  const saveSummaryConfig = async () => {
    if (!model) { toast('Model cannot be empty', 'danger'); return; }
    setSaving(true);
    try {
      await kb('/summarize/config', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model, prompt }) });
      toast('AI config saved', 'success');
    } catch { toast('Failed to save', 'danger'); }
    setSaving(false);
  };

  const createKey = async () => {
    if (!newKeyName.trim()) return;
    try {
      const r = await kb('/auth/keys', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: newKeyName }) });
      const d = await r.json();
      setNewKeyValue(d.secret || '');
      setNewKeyName('');
      loadKeys();
    } catch { toast('Failed to create key', 'danger'); }
  };

  const revokeKey = async (id, name) => {
    if (!confirm(`Revoke key for "${name}"?`)) return;
    try {
      await kb('/auth/keys/' + id, { method: 'DELETE' });
      loadKeys();
    } catch { toast('Failed to revoke key', 'danger'); }
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 24, maxWidth: 720 }}>
      {/* Schedule */}
      <div className="card" style={{ padding: 20 }}>
        <SectionHead title="Sync schedule" hint="Applies to CRM → Files → AI summaries chain"/>
        <Select label="Frequency" value={schedule} onChange={e => setSchedule(e.target.value)} options={[
          { value: 'disabled',  label: 'Disabled' },
          { value: 'hourly',    label: 'Every hour' },
          { value: 'every_6h', label: 'Every 6 hours' },
          { value: 'every_12h',label: 'Every 12 hours' },
          { value: 'daily',    label: 'Daily at 2am' },
          { value: 'weekly',   label: 'Weekly (Sunday 2am)' },
        ]} style={{ maxWidth: 280 }}/>
        <div style={{ marginTop: 12 }}>
          <Button variant="primary" loading={saving} onClick={saveSchedule} icon={<Icon d={I.check} size={13}/>}>Save schedule</Button>
        </div>
      </div>

      {/* AI summarisation */}
      <div className="card" style={{ padding: 20 }}>
        <SectionHead title="AI summarisation" hint="Model used for deal summaries via OpenRouter"/>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <Input label="Model (OpenRouter ID)" value={model} onChange={e => setModel(e.target.value)} placeholder="google/gemini-2.0-flash-lite-001"/>
          <label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
            <span style={{ color: 'var(--s-fg-2)', fontSize: 12, fontWeight: 500 }}>Summary prompt</span>
            <textarea className="input-base" rows={8} style={{ resize: 'vertical', lineHeight: 1.5, fontFamily: 'var(--s-font-mono)', fontSize: 12 }}
              value={prompt} onChange={e => setPrompt(e.target.value)} placeholder="Use {crm_content}, {pitch_content}, {website_content} as placeholders."/>
          </label>
          <div><Button variant="primary" loading={saving} onClick={saveSummaryConfig} icon={<Icon d={I.check} size={13}/>}>Save AI config</Button></div>
        </div>
      </div>

      {/* API keys (for MCP / Claude Desktop access) */}
      <div className="card" style={{ padding: 20 }}>
        <SectionHead title="MCP API keys" hint="For Claude Desktop and other MCP clients. Independent from Robylab login."/>
        <div style={{ background: 'var(--s-bg-1)', border: '1px solid var(--s-border)', borderRadius: 6, overflow: 'hidden', marginBottom: 12 }}>
          <table className="data" style={{ marginBottom: 0 }}>
            <thead><tr><th>Name</th><th>Key prefix</th><th>Created</th><th></th></tr></thead>
            <tbody>
              {keys.length === 0 && <tr><td colSpan={4} style={{ textAlign: 'center', color: 'var(--s-fg-3)', padding: 16 }}>No keys</td></tr>}
              {keys.map(k => (
                <tr key={k.id}>
                  <td style={{ fontWeight: 500 }}>{k.name}</td>
                  <td className="mono" style={{ fontSize: 12 }}>{k.prefix}</td>
                  <td style={{ fontSize: 12, color: 'var(--s-fg-3)' }}>{k.created_at ? new Date(k.created_at).toLocaleDateString() : '—'}</td>
                  <td style={{ textAlign: 'right' }}>
                    {k.deletable
                      ? <Button size="sm" variant="secondary" destructive onClick={() => revokeKey(k.id, k.name)}>Revoke</Button>
                      : <span style={{ fontSize: 12, color: 'var(--s-fg-3)' }}>master</span>
                    }
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <div style={{ display: 'flex', gap: 8 }}>
          <Input placeholder="Name (e.g. Claude Desktop, Roberto)" value={newKeyName} onChange={e => setNewKeyName(e.target.value)} onKeyDown={e => e.key === 'Enter' && createKey()}/>
          <Button variant="primary" onClick={createKey} style={{ flexShrink: 0 }}>Generate key</Button>
        </div>
        {newKeyValue && (
          <div style={{ marginTop: 12, padding: 14, background: 'var(--s-bg-0)', borderRadius: 6, border: '1px solid var(--s-warning)' }}>
            <div style={{ fontSize: 12, color: 'var(--s-warning)', marginBottom: 6 }}>⚠ Copy this key now — it won't be shown again.</div>
            <code style={{ fontFamily: 'var(--s-font-mono)', fontSize: 13, color: 'var(--s-success)', wordBreak: 'break-all' }}>{newKeyValue}</code>
            <div style={{ marginTop: 8 }}>
              <Button size="sm" variant="ghost" icon={<Icon d={I.copy} size={12}/>} onClick={() => navigator.clipboard.writeText(newKeyValue)}>Copy</Button>
              <Button size="sm" variant="ghost" onClick={() => setNewKeyValue('')} style={{ marginLeft: 6 }}>Dismiss</Button>
            </div>
          </div>
        )}
      </div>
    </div>
  );
}

window.KnowledgeBaseScreen = KnowledgeBaseScreen;
