"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.startConfigUI = startConfigUI;
const http_1 = __importDefault(require("http"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const app_paths_1 = require("./utils/app-paths");
const CONFIG_UI_PORT = 9898;
function startConfigUI(agent) {
    const server = http_1.default.createServer((req, res) => {
        // Only allow local connections
        const remoteAddr = req.socket.remoteAddress || '';
        const isLocal = remoteAddr === '127.0.0.1' || remoteAddr === '::1' || remoteAddr === '::ffff:127.0.0.1';
        if (!isLocal) {
            res.writeHead(403, { 'Content-Type': 'text/plain' });
            res.end('Access denied: Config UI is only accessible from localhost');
            return;
        }
        const url = new URL(req.url || '/', `http://localhost:${CONFIG_UI_PORT}`);
        const origin = String(req.headers.origin || '');
        const isAllowedOrigin = !origin
            || /^http:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i.test(origin)
            || /^(chrome-extension|moz-extension|edge-extension):\/\//i.test(origin);
        if (!isAllowedOrigin) {
            res.writeHead(403, { 'Content-Type': 'text/plain' });
            res.end('Access denied: origin is not allowed');
            return;
        }
        // CORS for localhost UI and browser-extension origins only
        if (origin) {
            res.setHeader('Access-Control-Allow-Origin', origin);
            res.setHeader('Vary', 'Origin');
        }
        res.setHeader('Cache-Control', 'no-store');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
        if (req.method === 'OPTIONS') {
            res.writeHead(204);
            res.end();
            return;
        }
        // API routes
        if (url.pathname === '/api/status' && req.method === 'GET') {
            const extensionOrigin = /^(chrome-extension|moz-extension|edge-extension):\/\//i.test(origin);
            const status = { ...(agent.getStatus() || {}) };
            if (!extensionOrigin) {
                delete status.token;
            }
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(status));
            return;
        }
        if (url.pathname === '/api/config' && req.method === 'GET') {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(agent.getConfig()));
            return;
        }
        if (url.pathname === '/api/config' && req.method === 'PUT') {
            let body = '';
            req.on('data', chunk => body += chunk);
            req.on('end', () => {
                try {
                    const updates = JSON.parse(body);
                    agent.updateConfig(updates);
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ message: 'Configuration updated. Restart agent to apply changes.' }));
                }
                catch (e) {
                    res.writeHead(400, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: e.message }));
                }
            });
            return;
        }
        if (url.pathname === '/api/restart' && req.method === 'POST') {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ message: 'Agent restart initiated' }));
            setTimeout(() => agent.restart(), 500);
            return;
        }
        if (url.pathname === '/api/logs' && req.method === 'GET') {
            const lines = parseInt(url.searchParams.get('lines') || '100');
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ logs: agent.getLogs(lines) }));
            return;
        }
        if (url.pathname === '/api/system' && req.method === 'GET') {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({
                hostname: os_1.default.hostname(),
                platform: os_1.default.platform(),
                arch: os_1.default.arch(),
                cpus: os_1.default.cpus().length,
                totalMemory: os_1.default.totalmem(),
                freeMemory: os_1.default.freemem(),
                uptime: os_1.default.uptime(),
                nodeVersion: process.version,
                pid: process.pid,
            }));
            return;
        }
        if (url.pathname.startsWith('/extensions/') && req.method === 'GET') {
            const fileName = path_1.default.basename(url.pathname);
            const allowed = new Set(['updates.xml', 'appstats-browser-extension.crx', 'appstats-browser-extension.xpi']);
            if (!allowed.has(fileName)) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Not found');
                return;
            }
            const extRoot = (0, app_paths_1.getBrowserExtensionDataDir)();
            const fullPath = path_1.default.join(extRoot, fileName);
            if (!fs_1.default.existsSync(fullPath)) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Not found');
                return;
            }
            const mime = fileName.endsWith('.xml')
                ? 'application/xml'
                : fileName.endsWith('.crx')
                    ? 'application/x-chrome-extension'
                    : 'application/x-xpinstall';
            res.writeHead(200, {
                'Content-Type': mime,
                'Content-Length': String(fs_1.default.statSync(fullPath).size),
                'Cache-Control': 'no-cache',
            });
            fs_1.default.createReadStream(fullPath).pipe(res);
            return;
        }
        // Serve the HTML UI
        if (url.pathname === '/' || url.pathname === '/index.html') {
            res.writeHead(200, { 'Content-Type': 'text/html' });
            res.end(getConfigUIHTML());
            return;
        }
        res.writeHead(404, { 'Content-Type': 'text/plain' });
        res.end('Not found');
    });
    server.listen(CONFIG_UI_PORT, '127.0.0.1', () => {
        console.log(`Agent Config UI available at http://localhost:${CONFIG_UI_PORT}`);
    });
    server.on('error', (err) => {
        if (err.code === 'EADDRINUSE') {
            console.warn(`Config UI port ${CONFIG_UI_PORT} already in use, skipping`);
        }
        else {
            console.error('Config UI server error:', err.message);
        }
    });
    return server;
}
function getConfigUIHTML() {
    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AppStats Agent Configuration</title>
  <style>
    :root {
      --bg-primary: #0f172a;
      --bg-secondary: #1e293b;
      --bg-tertiary: #334155;
      --text-primary: #f1f5f9;
      --text-secondary: #94a3b8;
      --accent: #3b82f6;
      --success: #22c55e;
      --warning: #f59e0b;
      --danger: #ef4444;
    }
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body {
      font-family: 'Segoe UI', -apple-system, sans-serif;
      background: var(--bg-primary); color: var(--text-primary);
      padding: 24px; max-width: 900px; margin: 0 auto;
    }
    h1 { font-size: 1.5rem; margin-bottom: 8px; color: var(--accent); }
    h2 { font-size: 1.1rem; margin: 0 0 12px 0; }
    .subtitle { font-size: 0.85rem; color: var(--text-secondary); margin-bottom: 24px; }
    .card {
      background: var(--bg-secondary); border-radius: 12px;
      border: 1px solid var(--bg-tertiary); padding: 20px; margin-bottom: 16px;
    }
    .card-header {
      display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;
    }
    .status-grid {
      display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px;
    }
    .status-item { padding: 12px; background: var(--bg-primary); border-radius: 8px; }
    .status-item .label { font-size: 0.75rem; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; }
    .status-item .value { font-size: 1.2rem; font-weight: 600; margin-top: 4px; }
    .badge {
      padding: 2px 10px; border-radius: 12px; font-size: 0.75rem; font-weight: 600;
    }
    .badge-online { background: rgba(34,197,94,0.2); color: var(--success); }
    .badge-offline { background: rgba(239,68,68,0.2); color: var(--danger); }
    .badge-warning { background: rgba(245,158,11,0.2); color: var(--warning); }
    .form-group { margin-bottom: 14px; }
    .form-group label {
      display: block; margin-bottom: 4px; font-size: 0.8rem;
      color: var(--text-secondary); font-weight: 500;
    }
    .input {
      background: var(--bg-primary); border: 1px solid var(--bg-tertiary);
      border-radius: 8px; padding: 8px 12px; color: var(--text-primary);
      font-size: 0.85rem; width: 100%;
    }
    .input:focus { outline: none; border-color: var(--accent); }
    .btn {
      padding: 8px 16px; border-radius: 8px; border: none; cursor: pointer;
      font-size: 0.85rem; font-weight: 500; transition: all 0.2s;
      display: inline-flex; align-items: center; gap: 6px;
    }
    .btn-primary { background: var(--accent); color: white; }
    .btn-primary:hover { background: #2563eb; }
    .btn-danger { background: var(--danger); color: white; }
    .btn-success { background: var(--success); color: white; }
    .btn-sm { padding: 4px 10px; font-size: 0.75rem; }
    .btn:disabled { opacity: 0.5; cursor: not-allowed; }
    .log-viewer {
      background: var(--bg-primary); border-radius: 8px; padding: 12px;
      font-family: 'Consolas', 'Courier New', monospace; font-size: 0.75rem;
      max-height: 300px; overflow-y: auto; white-space: pre-wrap;
      color: var(--text-secondary); line-height: 1.6;
    }
    .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
    .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
    .toast {
      position: fixed; bottom: 20px; right: 20px;
      padding: 12px 20px; border-radius: 8px; color: white;
      font-size: 0.85rem; z-index: 200; animation: slideIn 0.3s;
    }
    .toast-success { background: var(--success); }
    .toast-error { background: var(--danger); }
    @keyframes slideIn { from { transform: translateX(100%); } to { transform: translateX(0); } }
    @media (max-width: 600px) { .grid-2, .grid-3 { grid-template-columns: 1fr; } .status-grid { grid-template-columns: 1fr 1fr; } }
  </style>
</head>
<body>
  <h1>⚡ AppStats Agent</h1>
  <p class="subtitle">Local Configuration &amp; Status Dashboard</p>

  <!-- Status -->
  <div class="card">
    <div class="card-header">
      <h2>Agent Status</h2>
      <span id="connection-badge" class="badge badge-offline">Checking...</span>
    </div>
    <div class="status-grid" id="status-grid">
      <div class="status-item"><div class="label">Agent ID</div><div class="value" id="s-agent-id">-</div></div>
      <div class="status-item"><div class="label">Hostname</div><div class="value" id="s-hostname">-</div></div>
      <div class="status-item"><div class="label">Server</div><div class="value" id="s-server" style="font-size:0.85rem;">-</div></div>
      <div class="status-item"><div class="label">Active Channel</div><div class="value" id="s-reporting-channel" style="font-size:0.95rem;">-</div></div>
      <div class="status-item"><div class="label">Data Plane</div><div class="value" id="s-data-plane" style="font-size:0.95rem;">-</div></div>
      <div class="status-item"><div class="label">Transport Policy</div><div class="value" id="s-transport-mode" style="font-size:0.95rem;">-</div></div>
      <div class="status-item"><div class="label">Channel Priority</div><div class="value" id="s-channel-priority" style="font-size:0.8rem;">-</div></div>
      <div class="status-item"><div class="label">Primary Domain</div><div class="value" id="s-primary-domain" style="font-size:0.85rem;">-</div></div>
      <div class="status-item"><div class="label">Secondary Domain</div><div class="value" id="s-secondary-domain" style="font-size:0.85rem;">-</div></div>
      <div class="status-item"><div class="label">WireGuard Domain</div><div class="value" id="s-wireguard-domain" style="font-size:0.85rem;">-</div></div>
      <div class="status-item"><div class="label">Uptime</div><div class="value" id="s-uptime">-</div></div>
      <div class="status-item"><div class="label">CPU Cores</div><div class="value" id="s-cpus">-</div></div>
      <div class="status-item"><div class="label">Memory</div><div class="value" id="s-memory">-</div></div>
    </div>
  </div>

  <!-- Configuration -->
  <div class="card">
    <div class="card-header">
      <h2>Server Connection</h2>
      <button class="btn btn-primary btn-sm" onclick="saveConfig()">💾 Save Changes</button>
    </div>
    <div class="grid-2">
      <div class="form-group">
        <label>Primary Server URL</label>
        <input class="input" id="cfg-server-url" placeholder="http://server:3000">
      </div>
      <div class="form-group">
        <label>Primary WebSocket URL</label>
        <input class="input" id="cfg-ws-url" placeholder="ws://server:3001">
      </div>
      <div class="form-group">
        <label>Secondary Server URL (optional)</label>
        <input class="input" id="cfg-secondary-server-url" placeholder="https://secondary-server:3000">
      </div>
      <div class="form-group">
        <label>Secondary WebSocket URL (optional)</label>
          <input class="input" id="cfg-secondary-ws-url" placeholder="wss://secondary-server/ws">
      </div>
      <div class="form-group">
        <label>Transport Policy</label>
        <select class="input" id="cfg-transport-mode">
          <option value="auto">Auto (priority order)</option>
          <option value="force_wss">Force Internet/WSS</option>
          <option value="force_wireguard">Force WireGuard First</option>
        </select>
      </div>
      <div class="form-group">
        <label>Channel Priority</label>
        <div class="grid-3">
          <select class="input" id="cfg-priority-1">
            <option value="wireguard">WireGuard</option>
            <option value="primary">Primary</option>
            <option value="secondary">Secondary</option>
          </select>
          <select class="input" id="cfg-priority-2">
            <option value="wireguard">WireGuard</option>
            <option value="primary">Primary</option>
            <option value="secondary">Secondary</option>
          </select>
          <select class="input" id="cfg-priority-3">
            <option value="wireguard">WireGuard</option>
            <option value="primary">Primary</option>
            <option value="secondary">Secondary</option>
          </select>
        </div>
      </div>
    </div>
    <div class="form-group">
      <label>Agent Token</label>
      <input class="input" id="cfg-token" type="password" placeholder="Deployment token">
    </div>
    <div class="grid-2">
      <div class="form-group">
        <label>Tags (comma-separated)</label>
        <input class="input" id="cfg-tags" placeholder="production, web-team">
      </div>
      <div class="form-group">
        <label>Groups (comma-separated)</label>
        <input class="input" id="cfg-groups" placeholder="engineering">
      </div>
    </div>
  </div>

  <!-- Collector Settings -->
  <div class="card">
    <h2 style="margin-bottom:16px;">Collector Settings</h2>
    <div class="grid-2">
      <div class="form-group">
        <label>System Metrics Interval (ms)</label>
        <input class="input" id="cfg-sys-interval" type="number" value="30000">
      </div>
      <div class="form-group">
        <label>Process Scan Interval (ms)</label>
        <input class="input" id="cfg-proc-interval" type="number" value="60000">
      </div>
      <div class="form-group">
        <label>Productivity Track Interval (ms)</label>
        <input class="input" id="cfg-prod-interval" type="number" value="5000">
      </div>
      <div class="form-group">
        <label>Heartbeat Interval (ms)</label>
        <input class="input" id="cfg-heartbeat" type="number" value="30000">
      </div>
    </div>
  </div>

  <!-- Actions -->
  <div class="card">
    <div class="card-header">
      <h2>Actions</h2>
    </div>
    <div style="display:flex;gap:12px;flex-wrap:wrap;">
      <button class="btn btn-danger" onclick="restartAgent()">🔄 Restart Agent</button>
      <button class="btn btn-primary" onclick="refreshAll()">📡 Refresh Status</button>
      <button class="btn btn-success" onclick="testConnection()">🧪 Test Connection</button>
    </div>
  </div>

  <!-- Logs -->
  <div class="card">
    <div class="card-header">
      <h2>Recent Logs</h2>
      <button class="btn btn-sm btn-primary" onclick="loadLogs()">Refresh</button>
    </div>
    <div class="log-viewer" id="log-viewer">Loading logs...</div>
  </div>

  <script>
    const API = '';

    async function apiFetch(path, opts) {
      const res = await fetch(API + path, {
        ...opts,
        headers: { 'Content-Type': 'application/json', ...(opts?.headers || {}) },
      });
      if (!res.ok) {
        const err = await res.json().catch(() => ({ error: res.statusText }));
        throw new Error(err.error || 'Request failed');
      }
      return res.json();
    }

    async function loadStatus() {
      try {
        const [status, system] = await Promise.all([
          apiFetch('/api/status'),
          apiFetch('/api/system'),
        ]);

        document.getElementById('s-agent-id').textContent = status.agentId || system.hostname;
        document.getElementById('s-hostname').textContent = system.hostname;
        document.getElementById('s-server').textContent = status.serverUrl || status.primaryServerUrl || '-';
        document.getElementById('s-reporting-channel').textContent = formatChannelLabel(status.activeReportingChannel || 'unknown');
        document.getElementById('s-data-plane').textContent = formatChannelLabel(status.primaryDataPlane || (status.wireguardActive ? 'wireguard' : 'internet'));
        document.getElementById('s-transport-mode').textContent = formatChannelLabel(status.transportMode || 'auto');
        document.getElementById('s-channel-priority').textContent = formatPriority(status.channelPriority);
        document.getElementById('s-primary-domain').textContent = status.primaryDomain || '-';
        document.getElementById('s-secondary-domain').textContent = status.secondaryDomain || '-';
        document.getElementById('s-wireguard-domain').textContent = status.wireguardDomain || '-';
        document.getElementById('s-uptime').textContent = formatUptime(system.uptime);
        document.getElementById('s-cpus').textContent = system.cpus;
        document.getElementById('s-memory').textContent = formatBytes(system.totalMemory);

        const badge = document.getElementById('connection-badge');
        if (status.connected) {
          badge.className = 'badge badge-online';
          badge.textContent = 'Connected';
        } else {
          badge.className = 'badge badge-offline';
          badge.textContent = 'Disconnected';
        }
      } catch (e) {
        document.getElementById('connection-badge').className = 'badge badge-warning';
        document.getElementById('connection-badge').textContent = 'Agent Not Running';
      }
    }

    async function loadConfig() {
      try {
        const [cfg, status] = await Promise.all([
          apiFetch('/api/config'),
          apiFetch('/api/status').catch(() => null),
        ]);
        const priority = normalizePriority(status?.channelPriority || cfg.channelPriority || cfg.channel_priority);
        document.getElementById('cfg-server-url').value =
          status?.primaryServerUrl || status?.serverUrl || cfg.primaryServerUrl || cfg.serverUrl || cfg.server?.primaryUrl || cfg.server?.url || '';
        document.getElementById('cfg-ws-url').value =
          status?.primaryWsUrl || status?.wsUrl || cfg.primaryWsUrl || cfg.wsUrl || cfg.server?.primaryWsUrl || cfg.server?.wsUrl || '';
        document.getElementById('cfg-secondary-server-url').value =
          status?.secondaryServerUrl || cfg.secondaryServerUrl || cfg.server?.secondaryUrl || '';
        document.getElementById('cfg-secondary-ws-url').value =
          status?.secondaryWsUrl || cfg.secondaryWsUrl || cfg.server?.secondaryWsUrl || '';
        document.getElementById('cfg-transport-mode').value =
          status?.transportMode || cfg.transportMode || cfg.transport_mode || 'auto';
        document.getElementById('cfg-priority-1').value = priority[0];
        document.getElementById('cfg-priority-2').value = priority[1];
        document.getElementById('cfg-priority-3').value = priority[2];
        document.getElementById('cfg-token').value = cfg.token || cfg.server?.token || '';
        document.getElementById('cfg-tags').value = (cfg.tags || []).join(', ');
        document.getElementById('cfg-groups').value = (cfg.groups || []).join(', ');
        if (cfg.collectors?.system?.interval) document.getElementById('cfg-sys-interval').value = cfg.collectors.system.interval;
        if (cfg.collectors?.process?.interval) document.getElementById('cfg-proc-interval').value = cfg.collectors.process.interval;
        if (cfg.collectors?.productivity?.interval) document.getElementById('cfg-prod-interval').value = cfg.collectors.productivity.interval;
        if (cfg.heartbeatInterval) document.getElementById('cfg-heartbeat').value = cfg.heartbeatInterval;
      } catch (e) {
        console.error('Failed to load config:', e);
      }
    }

    async function saveConfig() {
      try {
        const channelPriority = normalizePriority([
          document.getElementById('cfg-priority-1').value,
          document.getElementById('cfg-priority-2').value,
          document.getElementById('cfg-priority-3').value,
        ]);
        const updates = {
          serverUrl: document.getElementById('cfg-server-url').value,
          wsUrl: document.getElementById('cfg-ws-url').value,
          primaryServerUrl: document.getElementById('cfg-server-url').value,
          primaryWsUrl: document.getElementById('cfg-ws-url').value,
          secondaryServerUrl: document.getElementById('cfg-secondary-server-url').value,
          secondaryWsUrl: document.getElementById('cfg-secondary-ws-url').value,
          transportMode: document.getElementById('cfg-transport-mode').value || 'auto',
          channelPriority,
          token: document.getElementById('cfg-token').value,
          tags: document.getElementById('cfg-tags').value.split(',').map(s => s.trim()).filter(Boolean),
          groups: document.getElementById('cfg-groups').value.split(',').map(s => s.trim()).filter(Boolean),
          collectors: {
            system: { enabled: true, interval: parseInt(document.getElementById('cfg-sys-interval').value) },
            process: { enabled: true, interval: parseInt(document.getElementById('cfg-proc-interval').value) },
            productivity: { enabled: true, interval: parseInt(document.getElementById('cfg-prod-interval').value) },
            network: { enabled: true },
            activity: { enabled: true },
          },
          heartbeatInterval: parseInt(document.getElementById('cfg-heartbeat').value),
        };
        await apiFetch('/api/config', { method: 'PUT', body: JSON.stringify(updates) });
        showToast('Configuration saved! Restart the agent to apply changes.', 'success');
      } catch (e) {
        showToast('Failed to save: ' + e.message, 'error');
      }
    }

    async function restartAgent() {
      if (!confirm('Restart the AppStats agent? This will briefly disconnect from the server.')) return;
      try {
        await apiFetch('/api/restart', { method: 'POST' });
        showToast('Agent restart initiated. Page will reload in 5 seconds...', 'success');
        setTimeout(() => location.reload(), 5000);
      } catch (e) {
        showToast('Restart failed: ' + e.message, 'error');
      }
    }

    async function testConnection() {
      try {
        const status = await apiFetch('/api/status');
        if (status.connected) {
          showToast('✅ Successfully connected to server', 'success');
        } else {
          showToast('⚠️ Agent is running but not connected to server', 'error');
        }
      } catch (e) {
        showToast('❌ Cannot reach agent: ' + e.message, 'error');
      }
    }

    async function loadLogs() {
      try {
        const data = await apiFetch('/api/logs?lines=50');
        document.getElementById('log-viewer').textContent = (data.logs || []).join('\\n') || 'No logs available';
      } catch (e) {
        document.getElementById('log-viewer').textContent = 'Failed to load logs: ' + e.message;
      }
    }

    function refreshAll() {
      loadStatus();
      loadConfig();
      loadLogs();
      showToast('Refreshed', 'success');
    }

    function normalizePriority(values) {
      const defaults = ['wireguard', 'primary', 'secondary'];
      const raw = Array.isArray(values) ? values : String(values || '').split(',');
      const normalized = [];
      for (const value of raw) {
        const v = String(value || '').trim().toLowerCase();
        if (defaults.includes(v) && !normalized.includes(v)) normalized.push(v);
      }
      for (const fallback of defaults) {
        if (!normalized.includes(fallback)) normalized.push(fallback);
      }
      return normalized.slice(0, 3);
    }

    function formatChannelLabel(value) {
      const v = String(value || '').trim().toLowerCase();
      if (v === 'force_wss') return 'Force Internet/WSS';
      if (v === 'force_wireguard') return 'Force WireGuard';
      if (v === 'wireguard') return 'WireGuard';
      if (v === 'primary') return 'Primary';
      if (v === 'secondary') return 'Secondary';
      if (v === 'internet') return 'Internet';
      if (v === 'auto') return 'Auto';
      if (!v) return '-';
      return v.replace(/_/g, ' ');
    }

    function formatPriority(priority) {
      return normalizePriority(priority).map(formatChannelLabel).join(' -> ');
    }

    function formatUptime(seconds) {
      if (!seconds) return '-';
      const d = Math.floor(seconds / 86400);
      const h = Math.floor((seconds % 86400) / 3600);
      const m = Math.floor((seconds % 3600) / 60);
      if (d > 0) return d + 'd ' + h + 'h';
      if (h > 0) return h + 'h ' + m + 'm';
      return m + 'm';
    }

    function formatBytes(bytes) {
      if (!bytes) return '-';
      const gb = bytes / (1024 * 1024 * 1024);
      return gb.toFixed(1) + ' GB';
    }

    function showToast(msg, type) {
      const el = document.createElement('div');
      el.className = 'toast toast-' + type;
      el.textContent = msg;
      document.body.appendChild(el);
      setTimeout(() => el.remove(), 4000);
    }

    // Initial load
    loadStatus();
    loadConfig();
    loadLogs();

    // Auto-refresh status every 10s
    setInterval(loadStatus, 10000);
  </script>
</body>
</html>`;
}
//# sourceMappingURL=config-ui.js.map