// ═══════════════════════════════════════════════════════
//  CVC Dashboard — Main Application
// ═══════════════════════════════════════════════════════
import * as api from './api';
import { DashboardWS } from './ws';
import { initChat } from './chat';
import { initSettings, loadSettingsData } from './settings';
import { initAgents, loadAgentsData } from './agents';
import { initHive, loadHiveData } from './hive';
import type {
  CommitEntry, TimelineEntry, MCPTool, HiveMindAgent,
  ModelInfo, StatsResponse, ServiceStatus,
} from './types';

// ── Globals ─────────────────────────────────────────
let ws: DashboardWS;
let currentTab = 'chat';
let pollTimer: ReturnType<typeof setInterval> | null = null;

// ── Toast system ────────────────────────────────────
function toast(message: string, type: 'success' | 'error' | 'info' = 'info'): void {
  let container = document.querySelector('.toast-container') as HTMLElement;
  if (!container) {
    container = document.createElement('div');
    container.className = 'toast-container';
    document.body.appendChild(container);
  }
  const el = document.createElement('div');
  el.className = `toast ${type}`;
  el.textContent = message;
  container.appendChild(el);
  setTimeout(() => el.remove(), 4000);
}

// ── Make toast and actions globally available ──────
(window as any).toast = toast;
(window as any).serviceAction = async (service: string, action: string) => {
  try {
    const r = await api.serviceAction(service, action);
    toast(r.message || `${service} ${action}: OK`, 'success');
    setTimeout(() => refreshCurrentTab(), 1000);
  } catch (e) { toast((e as Error).message, 'error'); }
};
(window as any).showRegisterAgentDialog = () => {
  document.getElementById('register-dialog')?.classList.remove('hidden');
};
(window as any).hideRegisterAgentDialog = () => {
  document.getElementById('register-dialog')?.classList.add('hidden');
};
(window as any).doRegisterAgent = async () => {
  const agentId = (document.getElementById('reg-agent-id') as HTMLInputElement).value.trim();
  if (!agentId) { toast('Agent ID required', 'error'); return; }
  try {
    await api.registerHiveMindAgent({
      agent_id: agentId,
      name: (document.getElementById('reg-name') as HTMLInputElement).value.trim() || undefined,
      role: (document.getElementById('reg-role') as HTMLInputElement).value.trim() || 'worker',
      rank: (document.getElementById('reg-rank') as HTMLInputElement).value.trim() || 'private',
      squad: (document.getElementById('reg-squad') as HTMLInputElement).value.trim() || 'alpha',
    });
    toast('Agent registered', 'success');
    (window as any).hideRegisterAgentDialog();
    if (currentTab === 'sdk') loadSDK();
  } catch (e) { toast((e as Error).message, 'error'); }
};

// ── Operations (globally accessible) ───────────────
(window as any).doCommit = async () => {
  const msg = (document.getElementById('op-commit-msg') as HTMLInputElement).value.trim();
  if (!msg) { toast('Commit message required', 'error'); return; }
  try {
    const r = await api.opsCommit({
      message: msg,
      content: (document.getElementById('op-commit-content') as HTMLTextAreaElement).value || undefined,
      commit_type: (document.getElementById('op-commit-type') as HTMLSelectElement).value,
    });
    toast(`Committed: ${r.hash?.slice(0, 8) || 'OK'}`, 'success');
    (document.getElementById('op-commit-msg') as HTMLInputElement).value = '';
    (document.getElementById('op-commit-content') as HTMLTextAreaElement).value = '';
  } catch (e) { toast((e as Error).message, 'error'); }
};

(window as any).doBranch = async () => {
  const name = (document.getElementById('op-branch-name') as HTMLInputElement).value.trim();
  if (!name) { toast('Branch name required', 'error'); return; }
  try {
    await api.opsBranch({ name });
    toast(`Branch "${name}" created`, 'success');
    (document.getElementById('op-branch-name') as HTMLInputElement).value = '';
    loadBranchesList();
  } catch (e) { toast((e as Error).message, 'error'); }
};

(window as any).doMerge = async () => {
  const source = (document.getElementById('op-merge-source') as HTMLInputElement).value.trim();
  if (!source) { toast('Source branch required', 'error'); return; }
  try {
    const strategy = (document.getElementById('op-merge-strategy') as HTMLSelectElement).value;
    await api.opsMerge({ source_branch: source, strategy });
    toast(`Merged "${source}"`, 'success');
  } catch (e) { toast((e as Error).message, 'error'); }
};

(window as any).doRestore = async () => {
  const hash = (document.getElementById('op-restore-hash') as HTMLInputElement).value.trim();
  if (!hash) { toast('Commit hash required', 'error'); return; }
  try {
    await api.opsRestore({ commit_hash: hash });
    toast(`Restored to ${hash.slice(0, 8)}`, 'success');
  } catch (e) { toast((e as Error).message, 'error'); }
};

(window as any).doRecall = async () => {
  const query = (document.getElementById('op-recall-query') as HTMLInputElement).value.trim();
  if (!query) return;
  const el = document.getElementById('op-recall-results')!;
  el.textContent = 'Searching…';
  try {
    const r = await api.opsRecall(query);
    if (!r.results?.length) { el.textContent = 'No results.'; return; }
    el.innerHTML = r.results.map((item: any) =>
      `<div style="margin-bottom:8px"><strong>${esc(item.message || '')}</strong> <span class="text-muted">${item.distance != null ? `(${(100 - item.distance * 100).toFixed(0)}%)` : ''}</span><br><code>${(item.short_hash || item.commit_hash || '').slice(0, 8)}</code> <span class="tag tag-blue">${esc(item.relevance_source || '')}</span></div>`
    ).join('');
  } catch (e) { el.textContent = (e as Error).message; }
};

(window as any).doDiff = async () => {
  const h1 = (document.getElementById('op-diff-hash1') as HTMLInputElement).value.trim();
  const h2 = (document.getElementById('op-diff-hash2') as HTMLInputElement).value.trim();
  if (!h1 || !h2) { toast('Both hashes required', 'error'); return; }
  const el = document.getElementById('op-diff-result')!;
  el.textContent = 'Comparing…';
  try {
    const r = await api.opsDiff(h1, h2);
    el.innerHTML = `<pre>${esc(typeof r.diff === 'string' ? r.diff : JSON.stringify(r.diff, null, 2))}</pre>`;
  } catch (e) { el.textContent = (e as Error).message; }
};

// ── Helper ──────────────────────────────────────────
function esc(s: string): string {
  const d = document.createElement('div');
  d.textContent = s;
  return d.innerHTML;
}

function formatDate(ts: string | number): string {
  try {
    if (!ts || ts === 0 || ts === '0') return '—';
    // Unix timestamp in seconds → convert to milliseconds for JS Date
    const n = typeof ts === 'string' ? parseFloat(ts) : ts;
    if (isNaN(n) || n === 0) return '—';
    // If the value looks like seconds (< 1e12), multiply to get ms
    const ms = n < 1e12 ? n * 1000 : n;
    return new Date(ms).toLocaleString();
  } catch { return String(ts); }
}
(window as any).formatDate = formatDate;

function setDot(id: string, status: ServiceStatus): void {
  const el = document.getElementById(id);
  if (!el) return;
  el.className = 'status-dot';
  el.classList.add(status === 'running' ? 'running' : status === 'stopped' ? 'stopped' : 'unknown');
}

function setText(id: string, text: string | number): void {
  const el = document.getElementById(id);
  if (el) el.textContent = String(text);
}

// ── Tab Navigation ──────────────────────────────────
function setupNav(): void {
  document.querySelectorAll('.nav-link[data-tab]').forEach(link => {
    link.addEventListener('click', () => {
      const tab = (link as HTMLElement).dataset.tab!;
      switchTab(tab);
    });
  });
}

function switchTab(tab: string): void {
  currentTab = tab;

  // Update nav
  document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
  document.querySelector(`.nav-link[data-tab="${tab}"]`)?.classList.add('active');

  // Show content
  document.querySelectorAll('.tab-content').forEach(el => el.classList.add('hidden'));
  document.getElementById(`tab-${tab}`)?.classList.remove('hidden');

  // Update title
  const titles: Record<string, string> = {
    chat: 'Chat', overview: 'Overview', proxy: 'Proxy', agent: 'Agent',
    mcp: 'MCP Server', sdk: 'Hive Mind', operations: 'Operations',
    memory: 'Memory & Context', timeline: 'Timeline', models: 'Models',
    connections: 'Connections', settings: 'Settings',
  };
  setText('page-title', titles[tab] || tab);

  refreshCurrentTab();
}

// ── Data Loaders ────────────────────────────────────
async function loadServices(): Promise<void> {
  try {
    const data = await api.getServices();
    // data is a dict of {proxy: {...}, agent: {...}, ...} directly
    for (const [name, info] of Object.entries(data)) {
      if (!info || typeof info !== 'object') continue;
      const status = (info as any).status as ServiceStatus;
      setDot(`status-${name}`, status);
      setDot(`ov-status-${name}`, status);
    }
    // Proxy details
    const px = (data as any).proxy;
    if (px) {
      setText('ov-proxy-uptime', px.uptime || '—');
      setText('ov-proxy-pid', px.pid?.toString() || '—');
      setText('ov-proxy-port', px.port?.toString() || '19333');
      setDot('px-status', px.status as ServiceStatus);
      setText('px-status-text', px.status);
      setText('px-pid', px.pid?.toString() || '—');
      setText('px-uptime', px.uptime || '—');
      setText('px-port', px.port?.toString() || '19333');
    }
    // Agent details
    const ag = (data as any).agent;
    if (ag) {
      setText('ov-agent-status', ag.status);
    }
    // MCP tools count
    const mcp = (data as any).mcp;
    if (mcp && typeof (mcp as any).tool_count === 'number') {
      setText('ov-mcp-tools', (mcp as any).tool_count);
    }
  } catch { /* ignore */ }
}

async function loadAnalytics(): Promise<void> {
  try {
    const a = await api.getAnalytics();
    const totalCommits = a.commits?.total ?? 0;
    const totalTokens = a.tokens?.total ?? 0;
    const estCost = a.tokens?.estimated_cost_usd ?? 0;
    setText('stat-commits', totalCommits);
    setText('stat-tokens', totalTokens.toLocaleString());
    setText('stat-cost', `$${estCost.toFixed(2)}`);
    setText('hive-commits-count', totalCommits);
  } catch { /* ignore */ }
}

function formatBytes(b: number): string {
  if (!b || b === 0) return '0 B';
  const k = 1024;
  const sizes = ['B', 'KB', 'MB', 'GB'];
  const i = Math.floor(Math.log(b) / Math.log(k));
  return parseFloat((b / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}

async function loadStats(): Promise<void> {
  try {
    const s = await api.getStats();
    setText('stat-db-size', formatBytes(s.database_size_bytes));
    setText('stat-blobs', s.blob_count);
    setText('stat-branches', s.total_branches);
    setText('mem-db-size', formatBytes(s.database_size_bytes));
    setText('mem-blob-count', s.blob_count);
  } catch { /* ignore */ }
}

async function loadCommits(): Promise<void> {
  try {
    const result = await api.getCommits(20);
    const commits = (result as any)?.commits || [];
    const el = document.getElementById('activity-feed')!;
    if (!commits.length) { el.innerHTML = '<p class="text-muted">No commits yet.</p>'; return; }
    el.innerHTML = `<table class="data-table"><thead><tr><th>Hash</th><th>Message</th><th>Type</th><th>Time</th></tr></thead><tbody>` +
      commits.map((c: any) =>
        `<tr><td><code>${esc((c.hash || '').slice(0, 8))}</code></td><td>${esc(c.message || '')}</td><td><span class="tag tag-blue">${esc(c.type || 'checkpoint')}</span></td><td>${formatDate(c.created_at)}</td></tr>`
      ).join('') + '</tbody></table>';

    // Also update agent tab commits
    const agEl = document.getElementById('agent-commits');
    if (agEl) agEl.innerHTML = el.innerHTML;
  } catch (e) {
    const el = document.getElementById('activity-feed');
    if (el) el.innerHTML = `<p class="text-muted">${esc((e as Error).message)}</p>`;
  }
}

async function loadBranchesList(): Promise<void> {
  try {
    const result = await api.opsBranches();
    const bs = (result as any)?.branches || [];
    const el = document.getElementById('branches-list')!;
    if (!bs.length) { el.innerHTML = '<p class="text-muted">No branches yet.</p>'; return; }
    el.innerHTML = bs.map((b: any) => `<span class="tag tag-green" style="margin:2px">${esc(b.name || b)}</span>`).join(' ');
    // Also show in operations
    const opEl = document.getElementById('op-branches-list');
    if (opEl) opEl.innerHTML = el.innerHTML;
  } catch { /* ignore */ }
}

async function loadTimeline(): Promise<void> {
  try {
    const result = await api.opsTimeline(50);
    const entries = (result as any)?.timeline || [];
    const el = document.getElementById('timeline-view')!;
    if (!entries.length) { el.innerHTML = '<p class="text-muted">No timeline entries.</p>'; return; }
    el.innerHTML = entries.map((e: any) => `
      <div class="timeline-entry">
        <div class="tl-time">${formatDate(e.created_at)}</div>
        <div class="tl-body">
          <div class="tl-msg">${esc(e.message)}</div>
          <div class="tl-hash">${esc((e.hash || '').slice(0, 12))}</div>
          ${e.type ? `<span class="tl-type">${esc(e.type)}</span>` : ''}
        </div>
      </div>
    `).join('');
  } catch (e) {
    const el = document.getElementById('timeline-view');
    if (el) el.innerHTML = `<p class="text-muted">${esc((e as Error).message)}</p>`;
  }
}

async function loadOpsStatus(): Promise<void> {
  try {
    const s = await api.opsStatus();
    const el = document.getElementById('ops-status')!;
    el.innerHTML = `
      <div class="detail-grid">
        <div><span class="label">DB Size</span><span class="value">${formatBytes(s.database_size_bytes)}</span></div>
        <div><span class="label">Commits</span><span class="value">${s.total_commits}</span></div>
        <div><span class="label">Branches</span><span class="value">${s.total_branches}</span></div>
        <div><span class="label">HEAD</span><span class="value code">${esc((s.head || 'none').slice(0, 12))}</span></div>
        <div><span class="label">Blobs</span><span class="value">${s.blob_count}</span></div>
      </div>
    `;
  } catch { /* ignore */ }
}

async function loadMemory(): Promise<void> {
  try {
    const [ctx, blobs, stats] = await Promise.all([
      api.getMemoryContext().catch(() => ({ messages: [], token_count: 0 })),
      api.getMemoryBlobs().catch(() => ({ blobs: [], total: 0 })),
      api.getMemoryStats().catch(() => ({ database_size_bytes: 0, blob_count: 0, blob_total_bytes: 0, cvc_root: '' })),
    ]);

    setText('mem-db-size', formatBytes((stats as any).database_size_bytes));
    setText('mem-blob-count', (stats as any).blob_count || 0);

    const ctxEl = document.getElementById('memory-context')!;
    const ctxData = (ctx as any).messages || [];
    if (ctxData.length === 0) {
      ctxEl.innerHTML = '<p class="text-muted">No context entries.</p>';
    } else {
      ctxEl.innerHTML = `<p style="margin-bottom:8px">Token count: <strong>${(ctx as any).token_count || '—'}</strong> | Messages: <strong>${(ctx as any).total || ctxData.length}</strong></p>` +
        ctxData.slice(0, 20).map((e: any) =>
          `<div style="padding:6px 0;border-bottom:1px solid var(--border)"><span class="tag tag-blue">${esc(e.role)}</span> ${esc((e.content || '').slice(0, 200))}</div>`
        ).join('');
    }

    const blobEl = document.getElementById('memory-blobs')!;
    const blobData = (blobs as any).blobs || [];
    if (blobData.length === 0) {
      blobEl.innerHTML = '<p class="text-muted">No blobs stored.</p>';
    } else {
      blobEl.innerHTML = `<table class="data-table"><thead><tr><th>Hash</th><th>Size</th></tr></thead><tbody>` +
        blobData.slice(0, 50).map((b: any) =>
          `<tr><td><code>${esc((b.hash || '').slice(0, 12))}</code></td><td>${b.size || '—'}</td></tr>`
        ).join('') + '</tbody></table>';
    }
  } catch { /* ignore */ }
}

async function loadModels(): Promise<void> {
  try {
    const [catalog, current] = await Promise.all([
      api.getModelCatalog().catch(() => ({ providers: {} })),
      api.getCurrentModel().catch(() => ({ provider: '—', model: '—', api_key_set: false })),
    ]);

    // Current model
    const curEl = document.getElementById('current-model-info')!;
    curEl.innerHTML = `
      <div class="detail-grid">
        <div><span class="label">Provider</span><span class="value">${esc(current.provider)}</span></div>
        <div><span class="label">Model</span><span class="value code">${esc(current.model)}</span></div>
        <div><span class="label">API Key</span><span class="value">${current.api_key_set ? '<span class="tag tag-green">Set</span>' : '<span class="tag tag-red">Not set</span>'}</span></div>
      </div>
    `;
    setText('ag-provider', current.provider);
    setText('ag-model', current.model);
    setText('ov-agent-provider', current.provider);
    setText('ov-agent-model', current.model);

    // Catalog
    const catEl = document.getElementById('model-catalog')!;
    const providers = (catalog as any).providers || {};
    const providerNames = Object.keys(providers);
    if (!providerNames.length) {
      catEl.innerHTML = '<p class="text-muted">No model catalog available.</p>';
      return;
    }

    let html = '<div class="model-grid">';
    for (const prov of providerNames) {
      const models = providers[prov] || [];
      for (const m of models) {
        const isActive = (m.id || m.name) === current.model && prov === current.provider;
        html += `<div class="model-card ${isActive ? 'active-model' : ''}" onclick="switchModel('${esc(prov)}','${esc(m.id || m.name)}')">
          <div class="model-name">${esc(m.name || m.id || '?')}</div>
          <div class="model-provider">${esc(prov)}</div>
          ${m.context_window ? `<div class="model-ctx">${(m.context_window / 1000).toFixed(0)}k context</div>` : ''}
        </div>`;
      }
    }
    html += '</div>';
    catEl.innerHTML = html;
  } catch { /* ignore */ }
}

(window as any).switchModel = async (provider: string, model: string) => {
  try {
    await api.switchModel(provider, model);
    toast(`Switched to ${model}`, 'success');
    loadModels();
  } catch (e) { toast((e as Error).message, 'error'); }
};

async function loadMCP(): Promise<void> {
  try {
    const [tools, status] = await Promise.all([
      api.getMCPTools().catch(() => []),
      api.getMCPStatus().catch(() => ({ available: false, transport: 'stdio', tool_count: 0 })),
    ]);

    setText('mcp-transport', status.transport || 'stdio');
    setText('mcp-status-val', status.available ? 'available' : 'unavailable');
    setText('mcp-tool-count', status.tool_count || (tools as any[]).length || 0);

    const el = document.getElementById('mcp-tools-list')!;
    const toolList = Array.isArray(tools) ? tools : [];
    if (!toolList.length) {
      el.innerHTML = '<p class="text-muted">No tools loaded.</p>';
      return;
    }
    el.innerHTML = `<table class="data-table"><thead><tr><th>Tool</th><th>Description</th></tr></thead><tbody>` +
      toolList.map(t =>
        `<tr><td><code>${esc(t.name)}</code></td><td>${esc(t.description || '')}</td></tr>`
      ).join('') + '</tbody></table>';
  } catch { /* ignore */ }
}

async function loadSDK(): Promise<void> {
  try {
    const agents = await api.getHiveMindAgents().catch(() => []);
    const list = Array.isArray(agents) ? agents : ((agents as any).agents || []);
    setText('hive-agents-count', list.length);

    const el = document.getElementById('sdk-agents-table')!;
    if (!list.length) {
      el.innerHTML = '<p class="text-muted">No agents registered.</p>';
      return;
    }
    el.innerHTML = `<table class="data-table"><thead><tr><th>ID</th><th>Name</th><th>Role</th><th>Squad</th><th>Actions</th></tr></thead><tbody>` +
      list.map(a =>
        `<tr><td><code>${esc(a.agent_id)}</code></td><td>${esc(a.name || '—')}</td><td>${esc(a.role || '—')}</td><td>${esc(a.squad || '—')}</td><td><button class="btn btn-sm btn-red" onclick="removeAgent('${esc(a.agent_id)}')">Remove</button></td></tr>`
      ).join('') + '</tbody></table>';
  } catch { /* ignore */ }

  // Also load agents module + hive data
  loadAgentsData();
  loadHiveData();
}

(window as any).removeAgent = async (id: string) => {
  try {
    await api.removeHiveMindAgent(id);
    toast(`Agent "${id}" removed`, 'success');
    loadSDK();
  } catch (e) { toast((e as Error).message, 'error'); }
};

async function loadSessions(): Promise<void> {
  try {
    const sessions = await api.getSessions();
    const el = document.getElementById('proxy-sessions')!;
    const list = Array.isArray(sessions) ? sessions : [];
    if (!list.length) {
      el.innerHTML = '<p class="text-muted">No active sessions.</p>';
      return;
    }
    el.innerHTML = `<table class="data-table"><thead><tr><th>Session</th><th>Details</th></tr></thead><tbody>` +
      list.map((s: any, i: number) =>
        `<tr><td>#${i + 1}</td><td><pre style="margin:0">${esc(JSON.stringify(s, null, 2))}</pre></td></tr>`
      ).join('') + '</tbody></table>';
  } catch { /* ignore */ }
}

async function loadConnections(): Promise<void> {
  try {
    const data = await api.getConnections();
    const connEl = document.getElementById('connections-list')!;
    setText('conn-url', `http://127.0.0.1:19333/v1`);

    const tools = [
      { icon: '🔷', name: 'Cursor', desc: 'Add CVC as an OpenAI-compatible provider' },
      { icon: '🟢', name: 'Windsurf', desc: 'Configure as custom API endpoint' },
      { icon: '🟣', name: 'Continue.dev', desc: 'Set as OpenAI proxy in config.json' },
      { icon: '⬛', name: 'Cline', desc: 'Use CVC proxy URL in Cline settings' },
      { icon: '🔵', name: 'VS Code Copilot', desc: 'Route through CVC proxy' },
      { icon: '🌐', name: 'Open WebUI', desc: 'Add as OpenAI-compatible connection' },
      { icon: '📟', name: 'CLI (curl)', desc: 'Direct API access via curl/httpie' },
    ];

    connEl.innerHTML = tools.map(t => `
      <div class="connection-card">
        <div class="conn-icon">${t.icon}</div>
        <div>
          <div class="conn-name">${esc(t.name)}</div>
          <div class="conn-desc">${esc(t.desc)}</div>
        </div>
      </div>
    `).join('');
  } catch { /* ignore */ }
}

async function loadSettings(): Promise<void> {
  await loadSettingsData();
}

async function loadProxy(): Promise<void> {
  await loadServices();
  await loadSessions();
  try {
    const config = await api.getConfig();
    const el = document.getElementById('proxy-config')!;
    el.innerHTML = `<div class="code-block"><div class="code-title">Proxy Configuration</div><pre>${esc(JSON.stringify(config, null, 2))}</pre></div>`;
  } catch { /* ignore */ }
}

// ── Refresh Logic ───────────────────────────────────
function refreshCurrentTab(): void {
  switch (currentTab) {
    case 'overview':
      loadServices(); loadAnalytics(); loadStats(); loadCommits(); loadBranchesList();
      break;
    case 'proxy': loadProxy(); break;
    case 'agent': loadModels(); loadCommits(); break;
    case 'mcp': loadMCP(); break;
    case 'sdk': loadSDK(); loadAnalytics(); break;
    case 'operations': loadOpsStatus(); loadBranchesList(); break;
    case 'memory': loadMemory(); break;
    case 'timeline': loadTimeline(); break;
    case 'models': loadModels(); break;
    case 'connections': loadConnections(); break;
    case 'settings': loadSettings(); break;
  }
}

// ── Clock ───────────────────────────────────────────
function startClock(): void {
  const tick = () => {
    const now = new Date();
    setText('clock', now.toLocaleTimeString());
  };
  tick();
  setInterval(tick, 1000);
}

// ── Init ────────────────────────────────────────────
document.addEventListener('DOMContentLoaded', () => {
  setupNav();
  initChat();
  initSettings();
  initAgents();
  initHive();
  startClock();

  // WebSocket
  ws = new DashboardWS();
  ws.connect();
  ws.on(msg => {
    if (msg.type === 'status_update') {
      loadServices();
    } else if (msg.type === 'commit') {
      toast(`New commit: ${(msg.data as any)?.message || ''}`, 'info');
      if (currentTab === 'overview' || currentTab === 'timeline') refreshCurrentTab();
    }
  });

  // Initial data load
  loadServices();

  // Periodic refresh — every 15s
  pollTimer = setInterval(() => {
    loadServices();
    if (currentTab === 'overview') {
      loadAnalytics();
      loadStats();
    }
  }, 15000);
});
