/*
 * client.js — Eaglercraft Load-Testing Dashboard Frontend
 * Handles tabs, Socket.IO, bot list, proxy management, logs, inspector.
 */

'use strict';

const socket = io();

const $ = (sel) => document.querySelector(sel);
const $$ = (sel) => document.querySelectorAll(sel);

const tabButtons = $$('.tab-btn');
const tabPanels = $$('.tab-panel');

const targetUrlInput = $('#target-url');
const botCountInput = $('#bot-count');
const botCountDisplay = $('#bot-count-display');
const spawnDelayInput = $('#spawn-delay');
const spawnDelayDisplay = $('#spawn-delay-display');
const usernamePrefixInput = $('#username-prefix');
const botPasswordInput = $('#bot-password');
const chatMessagesInput = $('#chat-messages');
const stayConnectedInput = $('#stay-connected');
const proxyStrategyInput = $('#proxy-strategy');
const btnStartTest = $('#btn-start-test');
const btnStopTest = $('#btn-stop-test');
const btnReset = $('#btn-reset');
const botsTableBody = $('#bots-table-body');
const activeBotCountBadge = $('#active-bot-count-badge');

const proxyInput = $('#proxy-input');
const btnValidateProxies = $('#btn-validate-proxies');
const btnClearDead = $('#btn-clear-dead');
const btnRetestAll = $('#btn-retest-all');
const btnRetestTarget = $('#btn-retest-target');
const proxyImportResult = $('#proxy-import-result');
const proxyTableBody = $('#proxy-table-body');
const proxyCountBadge = $('#proxy-count-badge');
const proxyStatsBadge = $('#proxy-stats-badge');
const proxySearch = $('#proxy-search');
const proxyStatusFilter = $('#proxy-status-filter');
const proxySort = $('#proxy-sort');

const logConsole = $('#log-console');
const btnClearLogs = $('#btn-clear-logs');
const autoScrollLogs = $('#auto-scroll-logs');
const logSearch = $('#log-search');
const filterInfo = $('#filter-info');
const filterWarn = $('#filter-warn');
const filterError = $('#filter-error');
const filterSuccess = $('#filter-success');

const statActiveBots = $('#stat-active-bots');
const statTotalSpawned = $('#stat-total-spawned');
const statHandshakesOk = $('#stat-handshakes-ok');
const statFailed = $('#stat-failed');
const statKeepalives = $('#stat-keepalives');
const statProxiesAlive = $('#stat-proxies-alive');
const statProxiesDead = $('#stat-proxies-dead');
const statAvgScore = $('#stat-avg-score');

const stat2ActiveBots = $('#stat2-active-bots');
const stat2HandshakesOk = $('#stat2-handshakes-ok');
const stat2Failed = $('#stat2-failed');
const stat2Keepalives = $('#stat2-keepalives');
const stat2ProxiesAlive = $('#stat2-proxies-alive');
const stat2ProxiesDead = $('#stat2-proxies-dead');
const stat2AvgScore = $('#stat2-avg-score');
const stat2P95Latency = $('#stat2-p95-latency');
const stat2Target = $('#stat2-target');
const stat2Status = $('#stat2-status');
const stat2Memory = $('#stat2-memory');
const stat2Uptime = $('#stat2-uptime');

const statusIndicator = $('#status-indicator');
const statusText = $('#status-text');
const uptimeText = $('#uptime-text');

let currentBots = [];
let currentProxies = [];
let proxyJobActive = false;
let lastLogEntry = null;

tabButtons.forEach(btn => {
  btn.addEventListener('click', () => {
    const tabId = btn.dataset.tab;
    tabButtons.forEach(b => b.classList.remove('active'));
    tabPanels.forEach(p => p.classList.remove('active'));
    btn.classList.add('active');
    $(`#tab-${tabId}`).classList.add('active');
  });
});

botCountInput.addEventListener('input', () => {
  botCountDisplay.textContent = botCountInput.value;
});

spawnDelayInput.addEventListener('input', () => {
  spawnDelayDisplay.textContent = spawnDelayInput.value;
});

function escapeHtml(str) {
  if (str === null || str === undefined) return '';
  const div = document.createElement('div');
  div.textContent = String(str);
  return div.innerHTML;
}

function formatDuration(ms) {
  if (!ms || ms < 1000) return '<1s';
  const seconds = Math.floor(ms / 1000) % 60;
  const minutes = Math.floor(ms / 60000) % 60;
  const hours = Math.floor(ms / 3600000);
  if (hours > 0) return `${hours}h ${minutes}m`;
  if (minutes > 0) return `${minutes}m ${seconds}s`;
  return `${seconds}s`;
}

function formatUptime(seconds) {
  if (seconds < 60) return `${seconds}s`;
  const m = Math.floor(seconds / 60) % 60;
  const h = Math.floor(seconds / 3600);
  if (h > 0) return `${h}h ${m}m`;
  return `${m}m`;
}

function formatBytes(b) {
  if (b < 1024) return `${b}B`;
  if (b < 1024 * 1024) return `${Math.round(b / 1024)}KB`;
  return `${Math.round(b / 1024 / 1024)}MB`;
}

function scoreClass(score) {
  if (score >= 80) return 'score-high';
  if (score >= 50) return 'score-mid';
  if (score > 0) return 'score-low';
  return 'score-zero';
}

btnStartTest.addEventListener('click', async () => {
  const target = targetUrlInput.value.trim();
  if (!target) {
    alert('Please enter a target WebSocket URL.');
    return;
  }
  if (!target.startsWith('ws://') && !target.startsWith('wss://')) {
    alert('Target must start with ws:// or wss://');
    return;
  }
  btnStartTest.disabled = true;
  const body = {
    target,
    bots: parseInt(botCountInput.value, 10),
    usernamePrefix: usernamePrefixInput.value.trim() || 'TestBot',
    spawnDelay: parseInt(spawnDelayInput.value, 10),
    botPassword: botPasswordInput.value.trim() || 'password123',
    chatMessages: chatMessagesInput.value,
    stayConnected: stayConnectedInput.checked,
    proxyStrategy: proxyStrategyInput.value,
  };
  try {
    const res = await fetch('/api/test/start', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
    const data = await res.json();
    if (!res.ok) {
      if (res.status === 429) {
        alert('Rate limit hit. Wait a moment before starting another test.');
      } else if (res.status === 409) {
        const doReset = confirm(data.error + '\n\nForce-reset the stuck state?');
        if (doReset) {
          await fetch('/api/test/reset', { method: 'POST' });
          alert('State reset. Try starting the test again.');
        }
      } else {
        alert(data.error || 'Failed to start test.');
      }
    }
  } catch (err) {
    alert('Network error: ' + err.message);
  } finally {
    btnStartTest.disabled = false;
  }
});

btnStopTest.addEventListener('click', async () => {
  btnStopTest.disabled = true;
  try {
    await fetch('/api/test/stop', { method: 'POST' });
  } catch (err) {
    alert('Network error: ' + err.message);
  } finally {
    btnStopTest.disabled = false;
  }
});

btnReset.addEventListener('click', async () => {
  try {
    await fetch('/api/test/stop', { method: 'POST' });
    await fetch('/api/test/reset', { method: 'POST' });
  } catch (err) {
    alert('Network error: ' + err.message);
  }
});

function renderBotList(bots) {
  currentBots = bots;
  activeBotCountBadge.textContent = bots.length;
  if (bots.length === 0) {
    botsTableBody.innerHTML = '<tr><td colspan="7" class="empty-row">No bots running</td></tr>';
    return;
  }
  const now = Date.now();
  botsTableBody.innerHTML = bots.map(bot => {
    const uptime = bot.connectedAt ? formatDuration(now - bot.connectedAt) : '—';
    const stateClass = `badge-${(bot.state || 'unknown').toLowerCase()}`;
    return `
      <tr>
        <td>${escapeHtml(bot.id)}</td>
        <td>${escapeHtml(bot.username)}</td>
        <td>${escapeHtml(bot.proxy || 'direct')}</td>
        <td><span class="badge ${stateClass}">${escapeHtml(bot.state)}</span></td>
        <td>${bot.packetsSent}</td>
        <td>${uptime}</td>
        <td>
          <button class="btn btn-danger btn-small" onclick="removeBot('${bot.id}')">Remove</button>
          <button class="btn btn-secondary btn-small" onclick="inspectBot('${bot.id}')">Inspect</button>
        </td>
      </tr>
    `;
  }).join('');
}

async function removeBot(botId) {
  try {
    await fetch(`/api/bots/${botId}/remove`, { method: 'POST' });
  } catch (err) {
    console.error('Failed to remove bot:', err);
  }
}
window.removeBot = removeBot;

async function inspectBot(botId) {
  try {
    const res = await fetch(`/api/bots/${botId}`);
    if (!res.ok) {
      alert('Bot not found or no longer running.');
      return;
    }
    const data = await res.json();
    const bot = data.bot;
    const inspector = $('#bot-inspector');
    const overlay = $('#bot-inspector-overlay');
    const body = $('#bot-inspector-body');
    $('#bot-inspector-title').textContent = `Bot ${bot.id} — ${bot.username}`;
    body.innerHTML = `
      <div class="form-group">
        <label>State</label>
        <div>${escapeHtml(bot.state)}</div>
      </div>
      <div class="form-group">
        <label>Proxy</label>
        <div>${escapeHtml(bot.proxy || 'direct')}</div>
      </div>
      <div class="form-group">
        <label>Proxy Key</label>
        <div>${escapeHtml(bot.proxyKey || '—')}</div>
      </div>
      <div class="form-group">
        <label>Packets Sent / Received</label>
        <div>${bot.packetsSent} / ${bot.packetsReceived}</div>
      </div>
      <div class="form-group">
        <label>Connected At</label>
        <div>${bot.connectedAt ? new Date(bot.connectedAt).toLocaleString() : '—'}</div>
      </div>
      <div class="form-group">
        <label>Last Packet</label>
        <div>${bot.lastPacketAt ? new Date(bot.lastPacketAt).toLocaleString() : '—'}</div>
      </div>
      <div class="form-group">
        <label>Last Keep-Alive</label>
        <div>${bot.lastKeepAliveAt ? new Date(bot.lastKeepAliveAt).toLocaleString() : '—'}</div>
      </div>
      <div class="form-group">
        <label>Last Error</label>
        <div style="color: var(--accent-red); word-break: break-all;">${escapeHtml(bot.lastError || '—')}</div>
      </div>
      <div class="form-group">
        <label>Send Chat From This Bot</label>
        <div style="display:flex;gap:8px;">
          <input type="text" id="inspector-chat" placeholder="Type a message..." style="flex:1;" />
          <button class="btn btn-primary btn-small" id="inspector-chat-send">Send</button>
        </div>
      </div>
      <div class="button-row">
        <button class="btn btn-danger btn-small" onclick="removeBot('${bot.id}'); closeInspector();">Remove Bot</button>
      </div>
    `;
    inspector.classList.add('open');
    overlay.classList.add('open');
    $('#inspector-chat-send').addEventListener('click', async () => {
      const msg = $('#inspector-chat').value.trim();
      if (!msg) return;
      try {
        const r = await fetch(`/api/bots/${bot.id}/chat`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ message: msg }),
        });
        if (r.ok) $('#inspector-chat').value = '';
        else {
          const d = await r.json();
          alert(d.error || 'Failed');
        }
      } catch (e) { alert('Network error: ' + e.message); }
    });
  } catch (err) {
    console.error(err);
  }
}
window.inspectBot = inspectBot;

function closeInspector() {
  $('#bot-inspector').classList.remove('open');
  $('#bot-inspector-overlay').classList.remove('open');
}
$('#btn-close-inspector').addEventListener('click', closeInspector);
$('#bot-inspector-overlay').addEventListener('click', closeInspector);

btnValidateProxies.addEventListener('click', async () => {
  const text = proxyInput.value.trim();
  if (!text) { alert('Please paste proxy list into the textarea.'); return; }
  btnValidateProxies.disabled = true;
  proxyJobActive = true;
  proxyImportResult.classList.remove('hidden', 'success', 'error');
  proxyImportResult.innerHTML = '<strong>Queued for validation…</strong>';
  try {
    const res = await fetch('/api/proxy/upload', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ proxies: text }),
    });
    const data = await res.json();
    if (res.status === 429) {
      proxyImportResult.classList.add('error');
      proxyImportResult.textContent = 'Rate limit hit. Try again later.';
      btnValidateProxies.disabled = false;
      proxyJobActive = false;
      return;
    }
    if (res.ok && data.success) {
      proxyInput.value = '';
      proxyImportResult.classList.add('success');
      proxyImportResult.innerHTML = `
        <strong>Queued ${data.queued} proxies</strong> for validation.<br>
        ${data.duplicates} duplicates skipped, ${data.invalid} invalid.<br>
        <span id="proxy-progress-text">Starting validation…</span>
      `;
    } else {
      proxyImportResult.classList.add('error');
      proxyImportResult.textContent = data.error || 'Failed to queue proxies.';
      btnValidateProxies.disabled = false;
      proxyJobActive = false;
    }
  } catch (err) {
    proxyImportResult.classList.add('error');
    proxyImportResult.textContent = 'Network error: ' + err.message;
    btnValidateProxies.disabled = false;
    proxyJobActive = false;
  }
});

socket.on('proxy-progress', (job) => {
  const progressText = document.getElementById('proxy-progress-text');
  if (progressText) {
    const pct = job.total > 0 ? Math.round((job.processed / job.total) * 100) : 0;
    progressText.textContent = `Validating: ${job.processed}/${job.total} (${pct}%) — ${job.imported ?? job.alive ?? 0} alive, ${job.dead ?? 0} dead`;
  }
  loadProxyList();
});

socket.on('proxy-done', (job) => {
  btnValidateProxies.disabled = false;
  proxyJobActive = false;
  proxyImportResult.classList.remove('hidden');
  proxyImportResult.classList.add('success');
  const alive = job.imported ?? job.alive ?? 0;
  proxyImportResult.innerHTML = `
    <strong>Validation complete</strong><br>
    Alive: ${alive} &middot; Dead: ${job.dead ?? 0}<br>
    ${job.errors && job.errors.length > 0 ? '<br><strong>Errors (first 20):</strong><br>' + job.errors.slice(0, 20).map(e => escapeHtml(e)).join('<br>') : ''}
  `;
  loadProxyList();
});

socket.on('proxy:update', () => loadProxyList());
socket.on('proxy:remove', () => loadProxyList());

btnClearDead.addEventListener('click', async () => {
  try {
    const res = await fetch('/api/proxy/clear-dead', { method: 'POST' });
    const data = await res.json();
    loadProxyList();
    alert(`Removed ${data.removed} dead proxies.`);
  } catch (err) {
    alert('Error: ' + err.message);
  }
});

btnRetestAll.addEventListener('click', async () => {
  btnRetestAll.disabled = true;
  try {
    const res = await fetch('/api/proxy/test-all', { method: 'POST' });
    if (!res.ok) {
      const data = await res.json();
      alert(data.error || 'Failed to start re-test.');
    }
  } catch (err) {
    alert('Error: ' + err.message);
  } finally {
    setTimeout(() => { btnRetestAll.disabled = false; }, 5000);
  }
});

btnRetestTarget.addEventListener('click', async () => {
  btnRetestTarget.disabled = true;
  try {
    const res = await fetch('/api/proxy/retest', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' });
    if (!res.ok) {
      const data = await res.json();
      alert(data.error || 'Failed to start target retest.');
    }
  } catch (err) {
    alert('Error: ' + err.message);
  } finally {
    setTimeout(() => { btnRetestTarget.disabled = false; }, 5000);
  }
});

async function loadProxyList() {
  try {
    const params = new URLSearchParams();
    if (proxyStatusFilter.value) params.set('status', proxyStatusFilter.value);
    if (proxySort.value) params.set('sortBy', proxySort.value);
    const res = await fetch('/api/proxy/list?' + params.toString());
    const data = await res.json();
    currentProxies = data.proxies || [];
    renderProxyList(currentProxies, data.stats);
  } catch (err) {
    console.error('Failed to load proxies:', err);
  }
}

function renderProxyList(proxies, stats) {
  const search = proxySearch.value.trim().toLowerCase();
  const filtered = search
    ? proxies.filter(p => p.host.toLowerCase().includes(search) || p.port.toString().includes(search))
    : proxies;
  proxyCountBadge.textContent = proxies.length;
  if (stats) {
    proxyStatsBadge.textContent = `avg: ${stats.avgScore || 0} | alive: ${stats.alive} | dead: ${stats.dead}`;
    stat2AvgScore.textContent = stats.avgScore || 0;
    stat2P95Latency.textContent = stats.p95Latency ? `${stats.p95Latency}ms` : '—';
  }
  if (filtered.length === 0) {
    proxyTableBody.innerHTML = '<tr><td colspan="8" class="empty-row">No proxies loaded</td></tr>';
    return;
  }
  proxyTableBody.innerHTML = filtered.map((p, i) => {
    const statusClass = `badge-${p.status}`;
    const scoreCls = scoreClass(p.score);
    const tested = p.lastTestedAt ? new Date(p.lastTestedAt).toLocaleTimeString() : '—';
    const latency = p.p50LatencyMs ? `${p.p50LatencyMs}ms` : (p.responseTime ? `${p.responseTime}ms` : '—');
    return `
      <tr>
        <td>${i + 1}</td>
        <td>${escapeHtml(p.host)}:${p.port}</td>
        <td>${escapeHtml(p.type.toUpperCase())}</td>
        <td><span class="badge ${statusClass}">${p.status}</span></td>
        <td><span class="score-cell ${scoreCls}">${p.score}</span></td>
        <td>${latency}</td>
        <td>${tested}</td>
        <td>
          <button class="btn btn-secondary btn-small" onclick="retestProxy('${p.key}')">Retest</button>
          <button class="btn btn-danger btn-small" onclick="deleteProxy('${p.key}')">Delete</button>
        </td>
      </tr>
    `;
  }).join('');
}

async function retestProxy(key) {
  try {
    const res = await fetch(`/api/proxy/retest/${encodeURIComponent(key)}`, { method: 'POST' });
    const data = await res.json();
    if (res.ok) {
      loadProxyList();
    } else {
      alert(data.error || 'Failed to retest.');
    }
  } catch (err) {
    alert('Error: ' + err.message);
  }
}
window.retestProxy = retestProxy;

async function deleteProxy(key) {
  try {
    const res = await fetch(`/api/proxy/${encodeURIComponent(key)}`, { method: 'DELETE' });
    loadProxyList();
  } catch (err) {
    console.error(err);
  }
}
window.deleteProxy = deleteProxy;

proxySearch.addEventListener('input', () => renderProxyList(currentProxies));
proxyStatusFilter.addEventListener('change', loadProxyList);
proxySort.addEventListener('change', loadProxyList);

socket.on('log', (entry) => appendLog(entry));

socket.on('clearLogs', () => {
  logConsole.innerHTML = '<div class="log-empty">Logs cleared.</div>';
});

btnClearLogs.addEventListener('click', async () => {
  try {
    await fetch('/api/logs', { method: 'DELETE' });
    logConsole.innerHTML = '<div class="log-empty">Logs cleared.</div>';
  } catch (err) {
    console.error(err);
  }
});

function levelEnabled(level) {
  if (level === 'info') return filterInfo.checked;
  if (level === 'warn') return filterWarn.checked;
  if (level === 'error') return filterError.checked;
  if (level === 'success') return filterSuccess.checked;
  return true;
}

function logMatches(entry) {
  if (!levelEnabled(entry.level)) return false;
  const q = logSearch.value.trim().toLowerCase();
  if (q && !entry.message.toLowerCase().includes(q)) return false;
  return true;
}

function appendLog(entry) {
  lastLogEntry = entry;
  if (!logMatches(entry)) return;
  const empty = logConsole.querySelector('.log-empty');
  if (empty) empty.remove();
  const div = document.createElement('div');
  div.className = `log-entry log-${entry.level}`;
  div.innerHTML = `<span class="log-time">[${entry.time}]</span> ${escapeHtml(entry.message)}`;
  logConsole.appendChild(div);
  while (logConsole.children.length > 500) {
    logConsole.removeChild(logConsole.firstChild);
  }
  if (autoScrollLogs.checked) {
    logConsole.scrollTop = logConsole.scrollHeight;
  }
}

[filterInfo, filterWarn, filterError, filterSuccess].forEach(el => el.addEventListener('change', () => {
  if (!lastLogEntry) return;
  const all = Array.from(logConsole.querySelectorAll('.log-entry'));
  all.forEach(node => {
    const level = Array.from(node.classList).find(c => c.startsWith('log-'))?.replace('log-', '');
    if (!levelEnabled(level)) node.style.display = 'none';
    else node.style.display = '';
  });
}));

logSearch.addEventListener('input', () => {
  if (!lastLogEntry) return;
  const all = Array.from(logConsole.querySelectorAll('.log-entry'));
  all.forEach(node => {
    const level = Array.from(node.classList).find(c => c.startsWith('log-'))?.replace('log-', '');
    const text = node.textContent.toLowerCase();
    const q = logSearch.value.trim().toLowerCase();
    if ((!levelEnabled(level)) || (q && !text.includes(q))) {
      node.style.display = 'none';
    } else {
      node.style.display = '';
    }
  });
});

socket.on('stats', (data) => {
  statActiveBots.textContent = data.activeBots;
  statTotalSpawned.textContent = data.totalBotsSpawned;
  statHandshakesOk.textContent = data.totalHandshakesOk || 0;
  statFailed.textContent = data.totalConnectionsFailed;
  statKeepalives.textContent = data.totalKeepAlivesSent;
  statProxiesAlive.textContent = data.activeProxies;
  statProxiesDead.textContent = data.deadProxies;
  stat2ActiveBots.textContent = data.activeBots;
  stat2HandshakesOk.textContent = data.totalHandshakesOk || 0;
  stat2Failed.textContent = data.totalConnectionsFailed;
  stat2Keepalives.textContent = data.totalKeepAlivesSent;
  stat2ProxiesAlive.textContent = data.activeProxies;
  stat2ProxiesDead.textContent = data.deadProxies;
  stat2Target.textContent = data.currentTarget || 'None';
  stat2Status.textContent = data.testRunning ? 'Running' : 'Idle';
  if (data.testRunning) {
    statusIndicator.className = 'status-dot running';
    statusText.textContent = `Running (${data.activeBots} bots)`;
  } else {
    statusIndicator.className = 'status-dot idle';
    statusText.textContent = 'Idle';
  }
  renderBotList(data.bots || []);
  renderControlsBotList(data.bots || []);
});

socket.on('bot:update', () => {
  socket.emit('stats_request');
});

async function fetchDiagnostics() {
  try {
    const res = await fetch('/api/diagnostics');
    if (res.ok) {
      const d = await res.json();
      stat2Memory.textContent = d.memory ? formatBytes(d.memory.rss) : '—';
      stat2Uptime.textContent = formatUptime(d.uptime || 0);
      uptimeText.textContent = `up ${formatUptime(d.uptime || 0)}`;
    }
  } catch (_) {}
}

setInterval(fetchDiagnostics, 5000);

const btnBotControls = $('#btn-bot-controls');
const btnCloseControls = $('#btn-close-controls');
const botControlsPanel = $('#bot-controls-panel');
const botControlsOverlay = $('#bot-controls-overlay');
const liveChatInput = $('#live-chat-input');
const btnSendChat = $('#btn-send-chat');
const controlsBotList = $('#controls-bot-list');
const quickCommandsRow = $('#quick-commands-row');

btnBotControls.addEventListener('click', () => {
  botControlsPanel.classList.add('open');
  botControlsOverlay.classList.add('open');
  liveChatInput.focus();
});
btnCloseControls.addEventListener('click', () => {
  botControlsPanel.classList.remove('open');
  botControlsOverlay.classList.remove('open');
});
botControlsOverlay.addEventListener('click', () => {
  botControlsPanel.classList.remove('open');
  botControlsOverlay.classList.remove('open');
});

async function sendChatToAll(message) {
  if (!message.trim()) return;
  try {
    const res = await fetch('/api/bots/chat', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ message: message.trim() }),
    });
    const data = await res.json();
    if (res.status === 429) {
      alert('Rate limit hit. Slow down.');
    } else if (!res.ok) {
      alert(data.error || 'Failed to send');
    } else {
      liveChatInput.value = '';
    }
  } catch (err) {
    alert('Network error: ' + err.message);
  }
}

btnSendChat.addEventListener('click', () => sendChatToAll(liveChatInput.value));
liveChatInput.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') sendChatToAll(liveChatInput.value);
});

function renderControlsBotList(bots) {
  if (bots.length === 0) {
    controlsBotList.innerHTML = '<div class="empty-row">No bots connected</div>';
    return;
  }
  controlsBotList.innerHTML = bots.map(b => {
    const stateClass = `badge-${(b.state || 'unknown').toLowerCase()}`;
    return `<div style="display:flex;justify-content:space-between;padding:4px 0;border-bottom:1px solid var(--border-color);font-size:0.75rem;">
      <span>${escapeHtml(b.username)}</span>
      <span class="badge ${stateClass}">${escapeHtml(b.state)}</span>
    </div>`;
  }).join('');
}

fetch('/api/quick-commands')
  .then(r => r.json())
  .then(data => {
    const cmds = data.commands || [];
    if (cmds.length > 0) {
      quickCommandsRow.innerHTML = cmds.map(cmd =>
        `<button class="btn btn-secondary btn-small btn-quick-cmd" data-cmd="${escapeHtml(cmd)}">${escapeHtml(cmd)}</button>`
      ).join('');
      quickCommandsRow.querySelectorAll('.btn-quick-cmd').forEach(btn => {
        btn.addEventListener('click', () => sendChatToAll(btn.dataset.cmd));
      });
    }
  })
  .catch(() => {});

fetch('/api/test/strategies')
  .then(r => r.json())
  .then(data => {
    if (data.default && proxyStrategyInput) {
      proxyStrategyInput.value = data.default;
    }
  })
  .catch(() => {});

fetch('/api/logs')
  .then(r => r.json())
  .then(data => {
    if (data.logs) {
      data.logs.forEach(entry => appendLog(entry));
    }
  })
  .catch(() => {});

loadProxyList();
fetchDiagnostics();
