/**
 * Flynn Live Ops Dashboard
 *
 * Shows core counters, model performance, event stream, active requests,
 * and channel status. Fast metrics refresh every 3s, slow health every 10s.
 */

let _fastTimer = null;
let _slowTimer = null;

function formatUptime(seconds) {
  const d = Math.floor(seconds / 86400);
  const h = Math.floor((seconds % 86400) / 3600);
  const m = Math.floor((seconds % 3600) / 60);
  const s = seconds % 60;
  const parts = [];
  if (d > 0) {parts.push(`${d}d`);}
  if (h > 0) {parts.push(`${h}h`);}
  if (m > 0) {parts.push(`${m}m`);}
  parts.push(`${s}s`);
  return parts.join(' ');
}

function timeAgo(timestamp) {
  const secs = Math.floor((Date.now() - timestamp) / 1000);
  if (secs < 60) {return `${secs}s ago`;}
  if (secs < 3600) {return `${Math.floor(secs / 60)}m ago`;}
  return `${Math.floor(secs / 3600)}h ago`;
}

function formatTime(timestamp) {
  const d = new Date(timestamp);
  return d.toLocaleTimeString('en-GB', { hour12: false });
}

function escapeHtml(str) {
  const div = document.createElement('div');
  div.textContent = str;
  return div.innerHTML;
}

// ── Initial full render ─────────────────────────────────────────

function renderSkeleton(el) {
  el.innerHTML = `
    <h1 class="page-title">Live Ops Dashboard</h1>

    <h2 class="section-title">Core Counters</h2>
    <div class="stats-grid" id="ops-counters">
      <div class="stat-card"><div class="stat-label">Loading...</div><div class="stat-value">—</div></div>
    </div>

    <h2 class="section-title">Model Performance</h2>
    <div id="ops-model-table">
      <div class="text-muted text-sm">Loading...</div>
    </div>

    <h2 class="section-title">Event Stream</h2>
    <div class="event-stream" id="ops-events">
      <div class="event-row event-level-info">Loading events...</div>
    </div>

    <h2 class="section-title">Active Requests</h2>
    <div id="ops-requests">
      <div class="text-muted text-sm">Loading...</div>
    </div>

    <h2 class="section-title">Services</h2>
    <div id="ops-services" class="services-grid">
      <div class="text-muted text-sm">Loading...</div>
    </div>
  `;
}

// ── Section updaters (targeted DOM updates) ─────────────────────

function updateCounters(metrics, health) {
  const el = document.getElementById('ops-counters');
  if (!el) {return;}

  const sessions = health?.sessions ?? 0;
  const errCount = metrics?.errors ?? 0;

  const cards = [
    { label: 'Messages Processed', value: String(metrics?.messagesProcessed ?? 0), cls: '' },
    { label: 'Active Sessions', value: String(sessions), cls: '' },
    { label: 'Queue Depth', value: String(metrics?.queueDepth ?? 0), cls: '' },
    { label: 'Uptime', value: formatUptime(metrics?.uptime ?? 0), cls: '' },
    { label: 'Active Requests', value: String(metrics?.activeRequests ?? 0), cls: '' },
    { label: 'Errors', value: String(errCount), cls: errCount > 0 ? 'error' : '' },
  ];

  el.innerHTML = cards.map(c =>
    `<div class="stat-card">
      <div class="stat-label">${c.label}</div>
      <div class="stat-value ${c.cls}">${c.value}</div>
    </div>`,
  ).join('');
}

function updateModelTable(metrics) {
  const el = document.getElementById('ops-model-table');
  if (!el) {return;}

  const mc = metrics?.modelCalls;
  const calls = mc?.recentCalls ?? [];

  if (calls.length === 0) {
    el.innerHTML = '<div class="text-muted text-sm">No model calls recorded yet</div>';
    return;
  }

  const totalCalls = mc.total ?? 0;
  const avgLatency = mc.avgLatency ?? 0;
  const errorRate = mc.errorRate ?? 0;

  const summaryHtml = `
    <div class="metrics-summary">
      <div class="metric"><span>Total Calls:</span> <span class="metric-value">${totalCalls}</span></div>
      <div class="metric"><span>Avg Latency:</span> <span class="metric-value">${avgLatency}ms</span></div>
      <div class="metric"><span>Error Rate:</span> <span class="metric-value">${(errorRate * 100).toFixed(2)}%</span></div>
    </div>
  `;

  // Show newest first
  const rows = [...calls].reverse().map(c => {
    const status = c.error ? '<span class="text-error">✗</span>' : '<span class="text-success">✓</span>';
    return `<tr>
      <td>${timeAgo(c.timestamp)}</td>
      <td>${escapeHtml(c.provider)}</td>
      <td>${c.latency}ms</td>
      <td>${c.tokensPerSec.toFixed(1)}</td>
      <td>${c.inputTokens}/${c.outputTokens}</td>
      <td>${status}</td>
    </tr>`;
  }).join('');

  el.innerHTML = `
    ${summaryHtml}
    <table>
      <thead>
        <tr>
          <th>Time</th>
          <th>Provider</th>
          <th>Latency</th>
          <th>Tokens/sec</th>
          <th>In/Out</th>
          <th>Status</th>
        </tr>
      </thead>
      <tbody>${rows}</tbody>
    </table>
  `;
}

function updateEvents(eventsData) {
  const el = document.getElementById('ops-events');
  if (!el) {return;}

  const events = eventsData?.events ?? [];

  if (events.length === 0) {
    el.innerHTML = '<div class="event-row event-level-info">No events recorded yet</div>';
    return;
  }

  // Events come newest-first from the API; show newest at bottom for log feel
  const reversed = [...events].reverse();

  el.innerHTML = reversed.map(e => {
    const time = formatTime(e.timestamp);
    const level = (e.level || 'info').toUpperCase();
    const cls = `event-level-${e.level || 'info'}`;
    return `<div class="event-row ${cls}">[${time}] [${level}] ${escapeHtml(e.source)}: ${escapeHtml(e.message)}</div>`;
  }).join('');

  // Auto-scroll to bottom
  el.scrollTop = el.scrollHeight;
}

function updateActiveRequests(requestsData) {
  const el = document.getElementById('ops-requests');
  if (!el) {return;}

  const requests = requestsData?.requests ?? [];

  if (requests.length === 0) {
    el.innerHTML = '<div class="text-muted text-sm">No active requests</div>';
    return;
  }

  const rows = requests.map(r => {
    const duration = r.durationMs < 1000
      ? `${r.durationMs}ms`
      : `${(r.durationMs / 1000).toFixed(1)}s`;
    const started = formatTime(r.startedAt);
    return `<tr>
      <td>${escapeHtml(r.sessionId)}</td>
      <td>${escapeHtml(r.channel)}</td>
      <td>${duration}</td>
      <td>${started}</td>
    </tr>`;
  }).join('');

  el.innerHTML = `
    <table>
      <thead>
        <tr>
          <th>Session</th>
          <th>Channel</th>
          <th>Duration</th>
          <th>Started</th>
        </tr>
      </thead>
      <tbody>${rows}</tbody>
    </table>
  `;
}

function updateChannels(channelsData) {
  const el = document.getElementById('ops-channels');
  if (!el) {return;}

  const channels = channelsData?.channels ?? [];

  if (channels.length === 0) {
    el.innerHTML = '<div class="text-muted text-sm">No channels registered</div>';
    return;
  }

  el.innerHTML = channels.map(ch =>
    `<div class="channel-card">
      <span class="channel-dot ${ch.status}"></span>
      <span class="channel-name">${escapeHtml(ch.name)}</span>
    </div>`,
  ).join('');
}

function updateServices(servicesData) {
  const el = document.getElementById('ops-services');
  if (!el) {return;}

  const services = servicesData?.services ?? [];

  if (services.length === 0) {
    el.innerHTML = '<div class="text-muted text-sm">No services configured</div>';
    return;
  }

  el.innerHTML = services.map(svc => {
    const typeIcon = svc.type === 'channel' ? '📡' : svc.type === 'automation' ? '⚙️' : '🔧';
    const statusClass = svc.status === 'connected'
      ? 'connected'
      : svc.status === 'configured'
        ? 'configured'
        : svc.status === 'error'
          ? 'error'
          : svc.status === 'not_configured'
            ? 'not-configured'
            : 'disconnected';
    const itemCount = svc.itemCount ? ` (${svc.itemCount})` : '';
    return `<div class="service-card service-${statusClass}">
      <span class="service-type-icon">${typeIcon}</span>
      <span class="service-name">${escapeHtml(svc.name)}${itemCount}</span>
      <span class="service-status">${escapeHtml(svc.status)}</span>
      <span class="service-description text-muted text-xs">${escapeHtml(svc.description)}</span>
    </div>`;
  }).join('');
}

// ── Data fetching ───────────────────────────────────────────────

async function fetchFast(client) {
  try {
    const [metrics, eventsData, requestsData] = await Promise.all([
      client.call('system.metrics'),
      client.call('system.events', { limit: 50 }),
      client.call('system.activeRequests'),
    ]);
    return { metrics, eventsData, requestsData };
  } catch {
    return null;
  }
}

async function fetchSlow(client) {
  try {
    const [health, services] = await Promise.all([
      client.call('system.health'),
      client.call('system.services'),
    ]);
    return { health, services };
  } catch {
    return null;
  }
}

// ── Main load function ──────────────────────────────────────────

let _lastHealth = null;
let _lastMetrics = null;

async function loadDashboard(el, client) {
  renderSkeleton(el);

  // Fetch everything initially
  const [fast, slow] = await Promise.all([
    fetchFast(client),
    fetchSlow(client),
  ]);

  _lastHealth = slow?.health ?? null;
  _lastMetrics = fast?.metrics ?? null;

  if (fast) {
    updateCounters(fast.metrics, _lastHealth);
    updateModelTable(fast.metrics);
    updateEvents(fast.eventsData);
    updateActiveRequests(fast.requestsData);
  }
  if (slow) {
    updateServices(slow.services);
  }

  // Fast refresh: 3 seconds for metrics, events, requests
  _fastTimer = setInterval(async () => {
    const data = await fetchFast(client);
    if (data) {
      _lastMetrics = data.metrics;
      updateCounters(data.metrics, _lastHealth);
      updateModelTable(data.metrics);
      updateEvents(data.eventsData);
      updateActiveRequests(data.requestsData);
    }
  }, 3000);

  // Slow refresh: 10 seconds for health, services
  _slowTimer = setInterval(async () => {
    const data = await fetchSlow(client);
    if (data) {
      _lastHealth = data.health;
      updateCounters(_lastMetrics, data.health);
      updateServices(data.services);
    }
  }, 10000);
}

export const DashboardPage = {
  async render(el, client) {
    await loadDashboard(el, client);
  },

  teardown() {
    if (_fastTimer) {
      clearInterval(_fastTimer);
      _fastTimer = null;
    }
    if (_slowTimer) {
      clearInterval(_slowTimer);
      _slowTimer = null;
    }
    _lastHealth = null;
    _lastMetrics = null;
  },
};
