// panes/agent.js — MCP control plane + live events + semantic search with filters.
import { registerPane } from '../app.js';
import { mcp, MCP_BASE, escapeHtml } from '../lib/api.js';
import { ok, err, fmtJSON, skeleton, copyToClipboard, historyStore } from '../lib/ui.js';

const searchHist = historyStore('cx_agent_search', 20);
const kindFilter = new Set();

const TPL = `
  <div class="pane-head">
    <div>
      <div class="title">Agent</div>
      <div class="sub">CxAI MCP control plane · <span class="mono">${escapeHtml(MCP_BASE)}</span></div>
    </div>
    <div class="grow"></div>
    <span class="pill" id="agent-pill"><span class="dot"></span><span id="agent-pill-text">checking…</span></span>
  </div>

  <div class="grid cols-3 mb-3" id="agent-kpis"></div>

  <div class="grid cols-2 mb-3">
    <div class="card">
      <div class="card-title"><h2>Status</h2>
        <div class="flex gap-2 items-center">
          <span class="muted mono xsmall" id="agent-status-ts">—</span>
          <button class="btn btn-ghost" id="agent-copy-status">Copy</button>
        </div>
      </div>
      <pre id="agent-status" class="code" style="max-height:28vh">${skeleton(4)}</pre>
    </div>

    <div class="card">
      <div class="card-title"><h2>Semantic search</h2><span class="muted xsmall" id="agent-search-meta"></span></div>
      <form id="agent-search-form" class="flex gap-2 mb-2">
        <input class="input" id="agent-q" placeholder="ask the index…" autocomplete="off"/>
        <input class="input" id="agent-k" type="number" min="1" max="50" value="10" style="max-width:80px"/>
        <button class="btn btn-primary" type="submit">Search</button>
      </form>
      <div class="chips mb-2" id="agent-recent"></div>
      <div id="agent-hits" class="scroll muted" style="max-height:34vh">Run a query to see results.</div>
    </div>
  </div>

  <div class="card">
    <div class="card-title">
      <h2>Live events</h2>
      <div class="flex gap-2 items-center">
        <label class="check"><input type="checkbox" id="agent-tail" checked/> auto (2s)</label>
        <input class="input" id="agent-evfilter" placeholder="filter detail…" style="max-width:200px"/>
        <button class="btn btn-ghost" id="agent-clear-kinds">Clear filters</button>
      </div>
    </div>
    <div class="chips mb-2" id="agent-kinds"></div>
    <div class="scroll" style="max-height: 46vh">
      <table class="t" id="agent-events">
        <thead><tr><th style="width:140px">time</th><th style="width:180px">kind</th><th>detail</th></tr></thead>
        <tbody><tr><td colspan="3" class="muted">loading…</td></tr></tbody>
      </table>
    </div>
  </div>
`;

let timer = null;
let lastEvents = [];
let lastStatus = null;

function setPill(state, text) {
  const p = document.getElementById('agent-pill');
  const t = document.getElementById('agent-pill-text');
  const navPill = document.getElementById('nav-agent-pill');
  if (!p || !t) return;
  p.classList.remove('ok', 'err', 'warn', 'info');
  p.classList.add(state);
  t.textContent = text;
  if (navPill) {
    navPill.textContent = state === 'ok' ? '●' : state === 'err' ? '!' : '·';
    navPill.style.color = state === 'ok' ? 'var(--ok)' : state === 'err' ? 'var(--err)' : '';
  }
}

function kpi(label, value, sub) {
  return `<div class="kpi"><div class="label">${escapeHtml(label)}</div><div class="value">${escapeHtml(value)}</div><div class="sub">${escapeHtml(sub || '')}</div></div>`;
}

async function refreshStatus(host) {
  try {
    const s = await mcp.status();
    lastStatus = s;
    host.querySelector('#agent-status').textContent = fmtJSON(s);
    host.querySelector('#agent-status-ts').textContent = new Date().toLocaleTimeString();
    setPill('ok', 'connected');
    host.querySelector('#agent-kpis').innerHTML = [
      kpi('Tools',  String(s.tools_count ?? s.tools?.length ?? '—'), 'registered'),
      kpi('Events', String(s.events_count ?? s.events ?? lastEvents.length), 'since boot'),
      kpi('Index',  String(s.index_size ?? s.embeddings ?? '—'),     'vectors'),
    ].join('');
  } catch (e) {
    host.querySelector('#agent-status').textContent = `error: ${e.message}\n\nIs the MCP HTTP sidecar running on ${MCP_BASE}?`;
    setPill('err', 'unavailable');
  }
}

function fmtEventTs(ts) {
  if (!ts) return '';
  try { if (typeof ts === 'number') return new Date(ts * (ts < 1e12 ? 1000 : 1)).toLocaleTimeString(); return new Date(ts).toLocaleTimeString(); }
  catch { return String(ts); }
}

function renderKinds(host) {
  const counts = {};
  lastEvents.forEach(e => { const k = e.kind || e.type || 'event'; counts[k] = (counts[k] || 0) + 1; });
  const ks = Object.entries(counts).sort((a, b) => b[1] - a[1]);
  host.querySelector('#agent-kinds').innerHTML = ks.map(([k, n]) =>
    `<button class="chip ${kindFilter.has(k) ? 'active' : ''}" data-k="${escapeHtml(k)}">${escapeHtml(k)} <span class="muted">${n}</span></button>`
  ).join('');
  host.querySelectorAll('#agent-kinds .chip').forEach(b => b.addEventListener('click', () => {
    const k = b.dataset.k; if (kindFilter.has(k)) kindFilter.delete(k); else kindFilter.add(k);
    renderKinds(host); renderEvents(host);
  }));
}

function renderEvents(host) {
  const q = host.querySelector('#agent-evfilter')?.value.trim().toLowerCase() || '';
  const filtered = lastEvents
    .filter(ev => !kindFilter.size || kindFilter.has(ev.kind || ev.type || 'event'))
    .filter(ev => {
      if (!q) return true;
      const blob = (typeof ev.detail === 'string' ? ev.detail : JSON.stringify(ev.detail ?? ev.data ?? ev)).toLowerCase();
      return blob.includes(q);
    });
  const rows = filtered.slice().reverse().slice(0, 200).map(ev => `<tr>
    <td class="mono muted">${escapeHtml(fmtEventTs(ev.ts ?? ev.timestamp ?? ev.time))}</td>
    <td><span class="pill info">${escapeHtml(ev.kind || ev.type || 'event')}</span></td>
    <td class="mono" style="word-break:break-word">${escapeHtml(typeof ev.detail === 'string' ? ev.detail : JSON.stringify(ev.detail ?? ev.data ?? ev))}</td>
  </tr>`).join('');
  host.querySelector('#agent-events tbody').innerHTML = rows || '<tr><td colspan="3" class="muted">no events match</td></tr>';
}

async function refreshEvents(host) {
  try {
    lastEvents = (await mcp.events(200)) || [];
    renderKinds(host);
    renderEvents(host);
  } catch (e) {
    host.querySelector('#agent-events tbody').innerHTML =
      `<tr><td colspan="3" class="muted">events unavailable: ${escapeHtml(e.message)}</td></tr>`;
  }
}

function renderRecent(host) {
  const list = searchHist.list();
  host.querySelector('#agent-recent').innerHTML = list.length
    ? list.slice(0, 8).map(h => `<button class="chip" data-q="${escapeHtml(h.q)}">${escapeHtml(h.q)}</button>`).join('')
    : '';
  host.querySelectorAll('#agent-recent .chip').forEach(b => b.addEventListener('click', () => {
    host.querySelector('#agent-q').value = b.dataset.q;
    host.querySelector('#agent-search-form').requestSubmit();
  }));
}

async function search(host) {
  const q = host.querySelector('#agent-q').value.trim();
  if (!q) return;
  const k = +host.querySelector('#agent-k').value || 10;
  host.querySelector('#agent-search-meta').textContent = 'searching…';
  host.querySelector('#agent-hits').innerHTML = skeleton(3);
  try {
    const res = await mcp.call('search_semantic_tool', { query: q, k });
    const hits = res?.hits || res?.result?.hits || res?.results || res || [];
    host.querySelector('#agent-search-meta').textContent = `${hits.length} hits`;
    host.querySelector('#agent-hits').innerHTML = hits.length
      ? hits.map(h => `<div class="row">
          <div class="grow">
            <div class="ttl mono">${escapeHtml(h.path || h.id || '?')}</div>
            <div class="desc">${escapeHtml((h.snippet || h.text || '').slice(0, 280))}</div>
          </div>
          <span class="pill muted mono xsmall">${(h.distance ?? h.score ?? '').toString().slice(0, 6)}</span>
        </div>`).join('')
      : '<div class="muted" style="padding:12px">no hits</div>';
    searchHist.push({ q });
    renderRecent(host);
  } catch (e) {
    host.querySelector('#agent-search-meta').textContent = 'error';
    host.querySelector('#agent-hits').innerHTML = `<div class="muted" style="padding:12px">${escapeHtml(e.message)}</div>`;
    err(`search: ${e.message}`);
  }
}

registerPane('agent', {
  label: 'Agent',
  init(host) {
    host.innerHTML = TPL;
    host.querySelector('#agent-search-form').addEventListener('submit', (e) => { e.preventDefault(); search(host); });
    host.querySelector('#agent-evfilter').addEventListener('input', () => renderEvents(host));
    host.querySelector('#agent-clear-kinds').addEventListener('click', () => { kindFilter.clear(); renderKinds(host); renderEvents(host); });
    host.querySelector('#agent-copy-status').addEventListener('click', () => copyToClipboard(fmtJSON(lastStatus || {}), 'status copied'));

    renderRecent(host);
    refreshStatus(host); refreshEvents(host);
    timer = setInterval(() => {
      if (!host.classList.contains('active')) return;
      if (!host.querySelector('#agent-tail')?.checked) return;
      refreshEvents(host); refreshStatus(host);
    }, 2000);
  },
  refresh(host) { refreshStatus(host); refreshEvents(host); },
});
