// panes/tools.js — MCP tool browser & invoker with schema-driven forms.
import { registerPane } from '../app.js';
import { mcp, escapeHtml } from '../lib/api.js';
import { fmtJSON, ok, err, copyToClipboard, inputFromSchema, collectSchemaForm, historyStore } from '../lib/ui.js';

const callHist = historyStore('cx_tool_calls', 30);
const FAV_KEY = 'cx_tool_favs';
const favs = new Set(JSON.parse(localStorage.getItem(FAV_KEY) || '[]'));
function persistFavs() { localStorage.setItem(FAV_KEY, JSON.stringify([...favs])); }

const TPL = `
  <div class="pane-head">
    <div><div class="title">Tools</div><div class="sub">Discover and invoke MCP tools.</div></div>
    <div class="grow"></div>
    <button class="btn btn-secondary" id="tl-refresh">Reload</button>
  </div>

  <div class="grid" style="grid-template-columns: 320px 1fr; gap: 16px;">
    <div class="card no-pad scroll" style="max-height:72vh">
      <div class="p-2 flex gap-2">
        <input class="input" id="tl-search" placeholder="filter tools…"/>
      </div>
      <div class="p-2">
        <div class="seg" id="tl-seg">
          <button class="active" data-g="all">All</button>
          <button data-g="fav">Favorites</button>
          <button data-g="recent">Recent</button>
        </div>
      </div>
      <div id="tl-list">loading…</div>
    </div>

    <div class="card">
      <div class="card-title">
        <h2 id="tl-name">Select a tool</h2>
        <button class="btn btn-ghost" id="tl-fav" hidden>★</button>
      </div>
      <p class="muted small" id="tl-desc">Choose a tool on the left.</p>

      <div id="tl-body" hidden>
        <div class="seg mb-2" id="tl-mode">
          <button class="active" data-m="form">Form</button>
          <button data-m="json">JSON</button>
        </div>

        <form id="tl-form" class="grid gap-3"></form>
        <textarea id="tl-json" class="input" rows="8" placeholder='{"key":"value"}' hidden></textarea>

        <div class="btn-row mt-3">
          <button class="btn btn-primary" id="tl-call">Call</button>
          <button class="btn btn-secondary" id="tl-copy-args">Copy args</button>
          <button class="btn btn-ghost" id="tl-reset">Reset</button>
        </div>

        <div class="divider"></div>

        <div class="card-title"><h2 style="font-size:14px">Result</h2><span id="tl-meta" class="muted xsmall"></span></div>
        <pre id="tl-result" class="code" style="max-height:32vh">—</pre>

        <details class="card-d mt-3"><summary>Recent calls</summary>
          <div id="tl-hist" class="body"></div>
        </details>
      </div>
    </div>
  </div>
`;

let allTools = [];
let current = null;
let mode = 'form';
let group = 'all';

function passes(t, q) {
  const blob = (t.name + ' ' + (t.description || '')).toLowerCase();
  if (q && !blob.includes(q)) return false;
  if (group === 'fav' && !favs.has(t.name)) return false;
  if (group === 'recent') {
    const recents = new Set(callHist.list().map(r => r.tool));
    if (!recents.has(t.name)) return false;
  }
  return true;
}

function renderList(host) {
  const q = host.querySelector('#tl-search').value.trim().toLowerCase();
  const items = allTools.filter(t => passes(t, q));
  host.querySelector('#tl-list').innerHTML = items.length
    ? items.map(t => `<button class="nav-item" data-tool="${escapeHtml(t.name)}">
        <span class="grow truncate"><span class="mono">${escapeHtml(t.name)}</span></span>
        ${favs.has(t.name) ? '<span class="muted">★</span>' : ''}
      </button>`).join('')
    : '<div class="muted xsmall p-2">no tools match</div>';
  host.querySelectorAll('[data-tool]').forEach(b => b.addEventListener('click', () => select(host, b.dataset.tool)));
}

function renderForm(host) {
  if (!current) return;
  const f = host.querySelector('#tl-form');
  const schema = current.inputSchema || current.input_schema || {};
  const props = schema.properties || {};
  const names = Object.keys(props);
  if (!names.length) {
    f.innerHTML = '<div class="muted xsmall">no input schema — call with empty args or use JSON</div>';
    return;
  }
  f.innerHTML = names.map(n => inputFromSchema(n, props[n])).join('');
}

function renderHist(host) {
  const list = callHist.list().filter(r => r.tool === current?.name);
  host.querySelector('#tl-hist').innerHTML = list.length
    ? list.map((r, i) => `<button class="nav-item" data-hi="${i}">
        <span class="muted xsmall">${new Date(r.t).toLocaleTimeString()}</span>
        <span class="grow truncate mono xsmall">${escapeHtml(JSON.stringify(r.args))}</span>
      </button>`).join('')
    : '<div class="muted xsmall">no recent calls</div>';
  host.querySelectorAll('#tl-hist [data-hi]').forEach(b => b.addEventListener('click', () => {
    const r = list[+b.dataset.hi];
    if (r) { host.querySelector('#tl-json').value = fmtJSON(r.args); switchMode(host, 'json'); }
  }));
}

function select(host, name) {
  current = allTools.find(t => t.name === name);
  if (!current) return;
  host.querySelector('#tl-name').textContent = current.name;
  host.querySelector('#tl-desc').textContent = current.description || '—';
  host.querySelector('#tl-body').hidden = false;
  const favBtn = host.querySelector('#tl-fav');
  favBtn.hidden = false;
  favBtn.textContent = favs.has(name) ? '★ unfavorite' : '☆ favorite';
  host.querySelector('#tl-json').value = '{}';
  renderForm(host); renderHist(host);
}

function switchMode(host, m) {
  mode = m;
  host.querySelectorAll('#tl-mode button').forEach(b => b.classList.toggle('active', b.dataset.m === m));
  host.querySelector('#tl-form').hidden = m !== 'form';
  host.querySelector('#tl-json').hidden = m !== 'json';
}

function gatherArgs(host) {
  if (mode === 'form') return collectSchemaForm(host.querySelector('#tl-form'));
  const t = host.querySelector('#tl-json').value.trim();
  if (!t) return {};
  return JSON.parse(t);
}

async function load(host) {
  try {
    const j = await mcp.tools();
    allTools = (j.tools || []).slice().sort((a, b) => a.name.localeCompare(b.name));
    renderList(host);
  } catch (e) {
    host.querySelector('#tl-list').innerHTML = `<div class="muted xsmall p-2">${escapeHtml(e.message)}</div>`;
  }
}

registerPane('tools', {
  label: 'Tools',
  init(host) {
    host.innerHTML = TPL;
    host.querySelector('#tl-refresh').addEventListener('click', () => load(host));
    host.querySelector('#tl-search').addEventListener('input', () => renderList(host));
    host.querySelectorAll('#tl-seg button').forEach(b => b.addEventListener('click', () => {
      host.querySelectorAll('#tl-seg button').forEach(x => x.classList.toggle('active', x === b));
      group = b.dataset.g; renderList(host);
    }));
    host.querySelectorAll('#tl-mode button').forEach(b => b.addEventListener('click', () => switchMode(host, b.dataset.m)));

    host.querySelector('#tl-fav').addEventListener('click', () => {
      if (!current) return;
      if (favs.has(current.name)) favs.delete(current.name); else favs.add(current.name);
      persistFavs();
      host.querySelector('#tl-fav').textContent = favs.has(current.name) ? '★ unfavorite' : '☆ favorite';
      renderList(host);
    });

    host.querySelector('#tl-copy-args').addEventListener('click', () => {
      try { copyToClipboard(fmtJSON(gatherArgs(host)), 'args copied'); } catch (e) { err(e.message); }
    });
    host.querySelector('#tl-reset').addEventListener('click', () => {
      if (current) select(host, current.name);
    });

    host.querySelector('#tl-call').addEventListener('click', async () => {
      if (!current) return;
      let args; try { args = gatherArgs(host); } catch (e) { return err('args: ' + e.message); }
      const t0 = performance.now();
      const pre = host.querySelector('#tl-result');
      pre.textContent = 'calling…';
      try {
        const j = await mcp.call(current.name, args);
        const dt = (performance.now() - t0).toFixed(0);
        host.querySelector('#tl-meta').textContent = `${dt} ms`;
        pre.textContent = fmtJSON(j);
        callHist.push({ t: Date.now(), tool: current.name, args });
        renderHist(host);
        ok('called ' + current.name);
      } catch (e) {
        pre.textContent = 'error: ' + e.message;
        err(e.message);
      }
    });

    load(host);
  },
});
