(function () {
  const buffers = {};
  let liveEs = null;

  function esc(s) {
    const d = document.createElement('div');
    d.textContent = s || '';
    return d.innerHTML;
  }

  function nowIso() {
    return new Date().toISOString();
  }

  function lineClass(type) {
    if (!type) return 'line-action';
    if (type === 'command') return 'line-command';
    if (type === 'output') return 'line-output';
    if (String(type).indexOf('handoff') >= 0) return 'line-handoff';
    if (type === 'error') return 'line-error';
    if (String(type).indexOf('monitor') >= 0) return 'line-handoff';
    if (String(type).indexOf('browse') >= 0) return 'line-action';
    return 'line-action';
  }

  function formatLine(entry) {
    const t = (entry.at || '').substring(11, 19) || (entry.at || '').substring(11, 16) || '--:--';
    const msg = entry.message || entry.title || '';
    const detail = entry.detail ? ' — ' + String(entry.detail).slice(0, 200) : '';
    return (
      '<div class="term-line ' +
      lineClass(entry.type) +
      '"><span class="term-ts">' +
      esc(t) +
      '</span><span class="term-msg">' +
      esc(msg + detail) +
      '</span></div>'
    );
  }

  function render(key) {
    const els = document.querySelectorAll('[data-term-key="' + key + '"]');
    if (!els.length) return;
    const lines = buffers[key] || [];
    const html =
      !lines.length
        ? '<div class="term-line term-idle"><span class="term-msg">Typ <code>help</code> voor commando\'s · Enter om uit te voeren</span></div>'
        : lines.slice(-80).map(formatLine).join('');
    els.forEach(function (el) {
      el.innerHTML = html;
      el.scrollTop = el.scrollHeight;
      const win = el.closest('.agent-term-window');
      if (win && lines.length) win.classList.add('is-live');
    });
  }

  function pushLine(key, entry, skipDup) {
    if (!key || !entry) return;
    key = String(key).toLowerCase();
    if (!buffers[key]) buffers[key] = [];
    if (skipDup && entry._id) {
      const seen = buffers[key].some(function (l) {
        return l._id === entry._id;
      });
      if (seen) return;
    }
    if (!entry.at) entry.at = nowIso();
    buffers[key].push(entry);
    if (buffers[key].length > 120) buffers[key].shift();
    render(key);
  }

  function setBusy(key, busy) {
    document.querySelectorAll('[data-term-input="' + key + '"]').forEach(function (input) {
      input.disabled = !!busy;
      input.classList.toggle('is-busy', !!busy);
    });
    document.querySelectorAll('[data-term-key="' + key + '"]').forEach(function (body) {
      const win = body.closest('.agent-term-window');
      if (win) win.classList.toggle('is-running', !!busy);
    });
  }

  async function runCommand(key, cmd) {
    key = String(key || '').toLowerCase();
    cmd = (cmd || '').trim();
    if (!cmd) return;
    if (cmd.toLowerCase() === 'clear') {
      buffers[key] = [];
      render(key);
      return;
    }
    pushLine(key, { type: 'command', message: '$ ' + cmd, at: nowIso() });
    setBusy(key, true);
    try {
      const r = await fetch('/api/agents/souls/' + encodeURIComponent(key) + '/terminal/command', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ command: cmd }),
      });
      const data = await r.json().catch(function () {
        return {};
      });
      if (!r.ok) {
        const err =
          (typeof data.detail === 'string' && data.detail) ||
          (Array.isArray(data.detail) && data.detail[0]?.msg) ||
          'Commando mislukt';
        pushLine(key, { type: 'error', message: err, at: nowIso() });
        return;
      }
      (data.lines || []).forEach(function (line) {
        pushLine(key, {
          type: line.type || 'output',
          message: line.message || '',
          detail: line.detail || '',
          at: nowIso(),
        });
      });
    } catch (e) {
      pushLine(key, { type: 'error', message: e.message || 'Netwerkfout', at: nowIso() });
    } finally {
      setBusy(key, false);
    }
  }

  function bindInputs() {
    document.querySelectorAll('[data-term-input]').forEach(function (input) {
      if (input._termBound) return;
      input._termBound = true;
      const key = input.getAttribute('data-term-input');
      input.addEventListener('keydown', function (e) {
        if (e.key === 'Enter') {
          e.preventDefault();
          e.stopPropagation();
          const val = input.value;
          input.value = '';
          runCommand(key, val);
        }
      });
      input.addEventListener('click', function (e) {
        e.stopPropagation();
      });
    });
  }

  async function loadHistory(key) {
    try {
      const r = await fetch('/api/agents/souls/' + encodeURIComponent(key) + '/events?limit=30');
      if (!r.ok) return;
      const data = await r.json();
      buffers[key] = (data.items || []).map(function (ev) {
        const meta = ev.metadata || {};
        let type = 'action';
        const et = ev.event_type || '';
        if (et.indexOf('handoff') >= 0) type = 'handoff_out';
        if (meta.target_agent) type = 'handoff_out';
        if (meta.source_agent) type = 'handoff_in';
        if (et.indexOf('monitor') >= 0) type = 'monitor';
        if (et.indexOf('browse') >= 0) type = 'browse';
        if (et === 'terminal_in') type = 'command';
        if (et === 'terminal_out' || et === 'terminal_note') type = 'output';
        return {
          _id: ev.id,
          type: type,
          message: ev.title || ev.event_type,
          detail: ev.body,
          at: ev.created_at,
        };
      });
      render(key);
    } catch (e) {}
  }

  function handleLivePayload(d) {
    if (!d || d.type === 'connected' || d.type === 'error') return;
    const key = (d.agent || '').toLowerCase();
    if (!key) return;
    pushLine(
      key,
      {
        _id: d.id,
        type: d.type,
        message: d.message,
        detail: d.detail,
        at: d.at,
      },
      true
    );
    document.querySelectorAll('[data-term-key="' + key + '"]').forEach(function (el) {
      const win = el.closest('.agent-term-window');
      if (win) win.classList.add('is-live');
    });
  }

  function startLiveStream() {
    if (liveEs || typeof EventSource === 'undefined') return;
    liveEs = new EventSource('/api/agents/live/stream');
    liveEs.onmessage = function (ev) {
      try {
        handleLivePayload(JSON.parse(ev.data));
      } catch (e) {}
    };
    liveEs.onerror = function () {
      /* EventSource auto-reconnects */
    };
  }

  function stopLiveStream() {
    if (liveEs) {
      try {
        liveEs.close();
      } catch (e) {}
      liveEs = null;
    }
  }

  async function mountAll() {
    const nodes = document.querySelectorAll('[data-term-key]');
    const keys = [];
    nodes.forEach(function (n) {
      const k = n.getAttribute('data-term-key');
      if (k && keys.indexOf(k) < 0) keys.push(k);
    });
    await Promise.all(keys.map(loadHistory));
    bindInputs();
    startLiveStream();
  }

  function stopAll() {
    stopLiveStream();
  }

  window.AgentsTerminals = {
    mountAll,
    stopAll,
    pushLine,
    render,
    runCommand,
    bindInputs,
    startLiveStream,
    stopLiveStream,
  };
})();
