// panes/agent.js — absorbs the standalone CxAI dashboard.
// MCP status + live events feed (2s poll) + semantic search.
import { registerPane } from '../app.js';
import { mcp, MCP_BASE, escapeHtml } from '../lib/api.js';
import { ok, err, fmtJSON, skeleton } from '../lib/ui.js';

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-2">
    <div class="card">
      <div class="card-title"><h2>Status</h2><span class="muted mono" id="agent-status-ts">—</span></div>
      <pre id="agent-status">${skeleton(4)}</pre>
    </div>

    <div class="card">
      <div class="card-title"><h2>Semantic search</h2><span class="muted" id="agent-search-meta"></span></div>
      <form id="agent-search-form" class="flex gap-2 mb-3">
        <input class="input" id="agent-q" placeholder="ask the index…" autocomplete="off" />
        <button class="btn btn-primary" type="submit">Search</button>
      </form>
      <div id="agent-hits" class="muted">Run a query to see results.</div>
    </div>
  </div>

  <div class="card mt-3">
    <div class="card-title">
      <h2>Live events</h2>
      <label class="check"><input type="checkbox" id="agent-tail" checked /> auto-refresh (2s)</label>
    </div>
    <div class="scroll" style="max-height: 50vh">
      <table class="t" id="agent-events">
        <thead><tr><th style="width:160px">time</th><th style="width:200px">kind</th><th>detail</th></tr></thead>
        <tbody><tr><td colspan="3" class="muted">loading…</td></tr></tbody>
      </table>
    </div>
  </div>
`;

let timer = 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)' : '';
  }
}

async function refreshStatus(host) {
  try {
    const s = await mcp.status();
    host.querySelector('#agent-status').textContent = fmtJSON(s);
    host.querySelector('#agent-status-ts').textContent = new Date().toLocaleTimeString();
    setPill('ok', 'connected');
  } 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); }
}

async function refreshEvents(host) {
  try {
    const arr = await mcp.events(150);
    const rows = (arr || []).slice().reverse().slice(0, 100).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 yet</td></tr>';
  } catch (e) {
    host.querySelector('#agent-events tbody').innerHTML =
      `<tr><td colspan="3" class="muted">events unavailable: ${escapeHtml(e.message)}</td></tr>`;
  }
}

async function search(host) {
  const q = host.querySelector('#agent-q').value.trim();
  if (!q) return;
  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: 10 });
    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">${(h.distance ?? h.score ?? '').toString().slice(0, 6)}</span>
      </div>
    `).join('') : '<div class="muted" style="padding:12px">no hits</div>';
  } 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);
    });
    refreshStatus(host);
    refreshEvents(host);

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