// app-panels.js — Web UI part 2/3 (MCP, skills, users, platforms, WhatsApp, files, cron). Continuation of app-core.js; global scope.

function showAddMCP() { document.getElementById('mcp-add-form').style.display = ''; }

async function addMCP() {
  const name = document.getElementById('mcp-name').value.trim();
  const command = document.getElementById('mcp-command').value.trim();
  const argsStr = document.getElementById('mcp-args').value.trim();
  const url = document.getElementById('mcp-url').value.trim();
  if (!name) { toast('Name required', 'error'); return; }
  const args = argsStr ? argsStr.split(',').map(a => a.trim()) : [];
  const res = await fetch(API + '/api/mcp/add', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name, command: command || undefined, args: args.length ? args : undefined, url: url || undefined }),
  });
  const data = await res.json();
  if (data.ok) { toast('MCP server added. Restart needed.'); document.getElementById('mcp-add-form').style.display = 'none'; loadPlugins(); }
  else toast(data.error, 'error');
}

async function removeMCP(name) {
  if (!confirm(`Remove MCP server "${name}"?`)) return;
  await fetch(API + '/api/mcp/remove', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name }) });
  toast('Removed'); loadPlugins();
}

async function discoverMCP() {
  const el = document.getElementById('mcp-discover-results');
  el.innerHTML = `<div class="sub" style="padding:8px">${icon('search', 14)} Scanning system for MCP servers...</div>`;
  const res = await fetch(API + '/api/mcp/discover');
  const data = await res.json();
  if (!data.discovered?.length) { el.innerHTML = `<div class="sub" style="padding:8px">No MCP servers found on this system.</div>`; return; }
  el.innerHTML = `<div style="padding:8px;font-size:0.85em"><strong>Found ${data.discovered.length} MCP server(s):</strong></div>` +
    data.discovered.map(d => `<div class="list-item" style="padding:8px 12px">
      <div class="info"><div class="name">${escapeHtml(d.name)} <span class="badge">${d.source}</span></div>
      <div class="desc">${d.command} ${d.args.join(' ')}</div></div>
      <button class="btn btn-sm" onclick="installDiscoveredMCP('${escapeHtml(d.name)}','${escapeHtml(d.command)}','${escapeHtml(d.args.join(','))}')">${icon('plus', 14)} Add</button>
    </div>`).join('');
}

async function installDiscoveredMCP(name, command, argsStr) {
  const args = argsStr.split(',').filter(Boolean);
  const res = await fetch(API + '/api/mcp/add', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name, command, args }),
  });
  const data = await res.json();
  if (data.ok) { toast(`${name} added!`); loadPlugins(); }
  else toast(data.error, 'error');
}

// ── Skills Management Functions ─────────────────────────

function showAddSkill() { document.getElementById('skill-add-form').style.display = ''; }

async function createSkill() {
  const skill = {
    id: document.getElementById('skill-id').value.trim(),
    name: document.getElementById('skill-name').value.trim(),
    description: document.getElementById('skill-desc').value.trim(),
    triggers: document.getElementById('skill-triggers').value.trim(),
    category: document.getElementById('skill-category').value.trim(),
    priority: parseInt(document.getElementById('skill-priority').value) || 3,
    content: document.getElementById('skill-content').value,
  };
  if (!skill.id || !skill.name) { toast('ID and name required', 'error'); return; }
  const res = await fetch(API + '/api/skills/create', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(skill),
  });
  const data = await res.json();
  if (data.ok) { toast('Skill created!'); document.getElementById('skill-add-form').style.display = 'none'; loadPlugins(); }
  else toast(data.error, 'error');
}

async function editSkill(id) {
  const res = await fetch(API + `/api/skills/detail/${id}`);
  const data = await res.json();
  if (!data.ok) { toast('Skill not found', 'error'); return; }
  const s = data.skill;
  // Populate form
  document.getElementById('skill-id').value = s.id;
  document.getElementById('skill-name').value = s.name;
  document.getElementById('skill-desc').value = s.description || '';
  document.getElementById('skill-triggers').value = s.triggers.join(', ');
  document.getElementById('skill-category').value = s.category || '';
  document.getElementById('skill-priority').value = String(s.priority || 3);
  document.getElementById('skill-content').value = s.content || '';
  document.getElementById('skill-add-form').style.display = '';
}

async function deleteSkill(id) {
  if (!confirm(`Delete skill "${id}"?`)) return;
  const res = await fetch(API + '/api/skills/delete', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ id }),
  });
  const data = await res.json();
  if (data.ok) { toast('Skill deleted'); loadPlugins(); }
  else toast(data.error, 'error');
}

// ── Users ───────────────────────────────────────────────
const PLATFORM_ICONS = { telegram: 'send', whatsapp: 'message-circle', discord: 'signal', signal: 'shield', webui: 'globe', web: 'globe' };

function timeAgo(ts) {
  if (!ts) return '—';
  const diff = Date.now() - ts;
  if (diff < 60000) return t('users.just.now');
  if (diff < 3600000) return t('users.min.ago', { n: Math.floor(diff/60000) });
  if (diff < 86400000) return t('users.hrs.ago', { n: Math.floor(diff/3600000) });
  return new Date(ts).toLocaleDateString(getLang() === 'de' ? 'de-DE' : 'en-US', { day:'numeric', month:'short', year:'numeric' });
}

async function loadUsers() {
  const res = await fetch(API + '/api/users');
  const data = await res.json();
  const el = document.getElementById('users-list');

  if (data.users.length === 0) {
    el.innerHTML = `<div class="card"><h3>${t('users.none')}</h3><div class="sub">${t('users.none.desc')}</div></div>`;
    return;
  }

  el.innerHTML = data.users.map(u => {
    const platformIconName = PLATFORM_ICONS[u.lastPlatform] || 'globe';
    const platformName = u.lastPlatform ? u.lastPlatform.charAt(0).toUpperCase() + u.lastPlatform.slice(1) : t('users.platform.unknown');
    const lastMsg = u.lastMessage ? `<div class="user-last-msg">"${escapeHtml(u.lastMessage)}"</div>` : '';
    const sessionInfo = u.session ? `
      <div class="user-session-info">
        ${u.session.isProcessing ? `<span class="badge badge-yellow">${icon('clock', 10)} ${t('users.processing')}</span>` : ''}
        ${u.session.hasActiveQuery ? `<span class="badge badge-yellow">${icon('refresh-cw', 10)} ${t('users.query.active')}</span>` : ''}
        ${u.session.queuedMessages > 0 ? `<span class="badge badge-blue">${icon('mail', 10)} ${t('users.in.queue', { count: u.session.queuedMessages })}</span>` : ''}
        <span title="${t('users.cost')}">${icon('zap', 10)} $${u.session.totalCost.toFixed(4)}</span>
        <span title="${t('users.msgs')}">${icon('message-square', 10)} ${u.session.messageCount}</span>
        <span title="${t('users.tools')}">${icon('wrench', 10)} ${u.session.toolUseCount}</span>
        <span title="${t('users.history')}">${icon('list', 10)} ${u.session.historyLength}</span>
        <span title="${t('users.effort')}">${icon('brain', 10)} ${u.session.effort}</span>
      </div>` : `<div class="user-session-info"><span class="sub">${t('users.no.session')}</span></div>`;

    const killBtn = u.isOwner ? '' : `<button class="btn btn-danger btn-sm" onclick="killUser(${u.userId}, '${escapeHtml(u.name)}')" title="${t('delete')}">${icon('trash-2', 12)}</button>`;

    return `<div class="card user-card" style="margin-bottom:12px">
      <div style="display:flex;align-items:flex-start;gap:12px">
        <div class="icon" style="font-size:1.6em;min-width:36px;text-align:center">${u.isOwner ? icon('crown', 28) : icon('user', 28)}</div>
        <div style="flex:1;min-width:0">
          <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">
            <strong>${escapeHtml(u.name)}</strong>
            ${u.username ? `<span class="sub">@${escapeHtml(u.username)}</span>` : ''}
            <span class="badge badge-${u.session ? 'green' : 'gray'}" style="font-size:0.7em">${u.session ? t('online') : t('offline')}</span>
            ${killBtn}
          </div>
          <div class="sub" style="margin-top:4px;display:flex;align-items:center;gap:4px">
            ${icon(platformIconName, 12)} ${platformName} · ${t('users.messages.total', { n: u.totalMessages })} · ${t('users.last.active')}: ${timeAgo(u.lastActive)}
          </div>
          ${lastMsg}
          ${sessionInfo}
        </div>
      </div>
    </div>`;
  }).join('');
}

async function killUser(userId, name) {
  if (!confirm(t('users.kill.confirm', { name }))) return;
  try {
    const res = await fetch(API + `/api/users/${userId}`, { method: 'DELETE' });
    const data = await res.json();
    if (data.ok) {
      const summary = data.deleted.length > 0 ? t('users.deleted.summary', { items: data.deleted.join(', ') }) : t('users.nothing');
      alert(`${t('users.deleted')}\n\n${summary}`);
      loadUsers();
    } else {
      alert(`${t('error')}: ${data.error || 'Unknown'}`);
    }
  } catch (e) {
    alert(`${t('error')}: ${e.message}`);
  }
}

// ── Platforms ────────────────────────────────────────────
async function loadPlatforms() {
  const res = await fetch(API + '/api/platforms/setup');
  const data = await res.json();

  let html = `<div style="margin-bottom:20px"><h3 style="font-size:1em;margin-bottom:4px;display:flex;align-items:center;gap:8px">${icon('smartphone', 20)} ${t('platforms.title')}</h3><div class="sub">${t('platforms.desc')}</div></div>`;

  for (const p of data.platforms) {
    let statusBadge;
    if (p.configured && p.depsInstalled) {
      statusBadge = `<span class="badge badge-green" id="badge-${p.id}">${icon('circle-check', 12)} ${t('platforms.ready')}</span>`;
    } else if (p.configured && !p.depsInstalled) {
      statusBadge = `<span class="badge badge-yellow" id="badge-${p.id}">${icon('package', 12)} ${t('platforms.deps.missing')}</span>`;
    } else {
      statusBadge = `<span class="badge badge-red" id="badge-${p.id}">${t('platforms.not.configured')}</span>`;
    }

    html += `<div class="card setup-card" style="margin-bottom:16px">
      <div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
        <span style="font-size:1.8em">${p.icon}</span>
        <div style="flex:1">
          <h3 style="font-size:0.95em;text-transform:none;letter-spacing:0">${p.name}</h3>
          <div class="sub">${p.description}</div>
        </div>
        ${statusBadge}
      </div>`;

    html += `<details ${p.configured ? '' : 'open'} style="margin-bottom:12px"><summary style="cursor:pointer;color:var(--accent2);font-size:0.82em;font-weight:500;display:flex;align-items:center;gap:4px">${icon('clipboard', 14)} ${t('platforms.setup.guide')}</summary><ol style="margin:8px 0 0 16px;color:var(--fg2);font-size:0.82em;line-height:1.6">`;
    for (const step of p.setupSteps) html += `<li>${step}</li>`;
    if (p.setupUrl) html += `<li><a href="${p.setupUrl}" target="_blank" style="color:var(--accent2)">${p.setupUrl}</a></li>`;
    html += `</ol></details>`;

    html += `<div style="display:flex;flex-direction:column;gap:8px;margin-bottom:8px">`;
    for (const v of p.envVars) {
      if (v.type === 'toggle') {
        const checked = p.values[v.key] === 'true' ? 'checked' : '';
        html += `<label style="display:flex;align-items:center;gap:8px;font-size:0.85em;cursor:pointer">
          <input type="checkbox" id="pv-${p.id}-${v.key}" ${checked} style="width:18px;height:18px;accent-color:var(--accent)">
          <span>${v.label}</span>
        </label>`;
      } else {
        html += `<div style="display:flex;gap:8px;align-items:center">
          <label style="font-size:0.78em;color:var(--fg2);min-width:120px">${v.label}</label>
          <input type="${v.secret ? 'password' : 'text'}" id="pv-${p.id}-${v.key}" placeholder="${v.placeholder}" value="${p.values[v.key] || ''}" style="flex:1;background:var(--bg3);border:1px solid var(--glass-border);border-radius:6px;padding:8px 12px;color:var(--fg);font:inherit;font-size:0.85em;font-family:monospace;outline:none">
        </div>`;
      }
    }
    html += `</div>`;

    html += `<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
      <button class="btn btn-sm" onclick="savePlatform('${p.id}')">${icon('save', 12)} ${t('platforms.save')}</button>`;
    if (p.npmPackages && !p.depsInstalled) {
      html += `<button class="btn btn-sm btn-outline" onclick="installPlatformDeps('${p.id}')">${icon('package', 12)} ${t('platforms.install.deps')}</button>`;
    }
    if (p.configured) {
      html += `<button class="btn btn-sm btn-outline" onclick="testPlatformConnection('${p.id}')">${icon('test-tube', 12)} ${t('platforms.test')}</button>`;
      html += `<button class="btn btn-sm btn-outline" style="color:var(--red)" onclick="disablePlatform('${p.id}')">${t('platforms.disable')}</button>`;
    }
    html += `<span id="platform-live-${p.id}" style="font-size:0.78em;margin-left:4px"></span>`;
    html += `</div>`;

    if (p.id === 'whatsapp' && p.configured && p.depsInstalled) {
      html += `<div id="wa-qr-area" style="margin-top:12px;padding:12px;background:var(--bg3);border-radius:8px">
        <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
          <span id="wa-status-dot" style="font-size:1.2em">${icon('clock', 16)}</span>
          <span id="wa-status-text" style="font-size:0.85em;color:var(--fg2)">${t('wa.status.loading')}</span>
          <div style="flex:1"></div>
          <button class="btn btn-sm btn-outline" onclick="checkWhatsAppStatus()">${icon('refresh-cw', 12)} ${t('wa.check.status')}</button>
          <button class="btn btn-sm btn-outline" style="color:var(--red);font-size:0.78em" onclick="disconnectWhatsApp()">${icon('plug', 12)} ${t('wa.disconnect')}</button>
        </div>
        <div id="wa-qr-container" style="display:none;text-align:center;padding:16px;background:#fff;border-radius:8px;margin-top:8px">
          <canvas id="wa-qr-canvas" style="image-rendering:pixelated"></canvas>
          <div style="color:#333;font-size:0.82em;margin-top:8px">${t('wa.scan.qr')}</div>
        </div>
      </div>`;
    }

    if (p.id === 'whatsapp' && (p.configured || p.depsInstalled)) {
      html += `<div style="margin-top:16px;border-top:1px solid var(--glass-border);padding-top:12px">
        <details id="wa-groups-details">
          <summary style="cursor:pointer;font-weight:600;font-size:0.9em;display:flex;align-items:center;gap:8px">
            ${icon('message-circle', 16)} ${t('wa.groups')}
            <span style="font-size:0.75em;color:var(--fg2);font-weight:normal" id="wa-groups-badge"></span>
          </summary>
          <div id="wa-groups-content" style="margin-top:12px"><div style="color:var(--fg2);font-size:0.85em">${t('wa.groups.loading')}</div></div>
        </details>
      </div>`;
    }

    html += `<div id="platform-result-${p.id}" style="font-size:0.78em;margin-top:6px"></div></div>`;
  }

  document.getElementById('platforms-setup').innerHTML = html;
  if (document.getElementById('wa-groups-content')) loadWAGroups();

  // Load statuses
  loadPlatformStatuses();
  if (document.getElementById('wa-qr-area')) checkWhatsAppStatus();
}

async function savePlatform(platformId) {
  const platform = document.querySelectorAll(`[id^="pv-${platformId}-"]`);
  const values = {};
  platform.forEach(el => {
    const key = el.id.replace(`pv-${platformId}-`, '');
    values[key] = el.type === 'checkbox' ? (el.checked ? 'true' : '') : el.value.trim();
  });
  const res = await fetch(API + '/api/platforms/configure', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ platformId, values }),
  });
  const data = await res.json();
  const resultDiv = document.getElementById('platform-result-' + platformId);
  if (data.ok) {
    if (data.restartNeeded === false) {
      toast(t('platforms.saved'));
      resultDiv.innerHTML = `<span style="color:var(--green)">${icon('circle-check', 12)} ${t('platforms.saved')}</span>`;
    } else {
      toast(t('platforms.saved.restart'));
      resultDiv.innerHTML = `<span style="color:var(--green)">${icon('circle-check', 12)} ${t('platforms.saved.restart')}</span>`;
    }
  } else {
    toast(data.error, 'error');
    resultDiv.innerHTML = `<span style="color:var(--red)">${icon('circle-x', 12)} ${data.error}</span>`;
  }
}

async function installPlatformDeps(platformId) {
  toast(t('platforms.installing'));
  const resultDiv = document.getElementById('platform-result-' + platformId);
  resultDiv.innerHTML = `<span style="color:var(--fg2)">${t('loading')}</span>`;
  const res = await fetch(API + '/api/platforms/install-deps', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ platformId }),
  });
  const data = await res.json();
  if (data.ok) {
    toast(t('platforms.installed'));
    resultDiv.innerHTML = `<span style="color:var(--green)">${icon('circle-check', 12)} ${t('platforms.installed')}</span>`;
    loadPlatforms();
  } else {
    toast(t('error') + ': ' + data.error, 'error');
    resultDiv.innerHTML = `<span style="color:var(--red)">${icon('circle-x', 12)} ${data.error}</span>`;
  }
}

async function disablePlatform(platformId) {
  if (!confirm(t('platforms.disable.confirm', { id: platformId }))) return;
  const inputs = document.querySelectorAll(`[id^="pv-${platformId}-"]`);
  const values = {};
  inputs.forEach(el => { const key = el.id.replace(`pv-${platformId}-`, ''); values[key] = ''; });
  await fetch(API + '/api/platforms/configure', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ platformId, values }),
  });
  toast(t('platforms.disabled'));
  loadPlatforms();
}

async function testPlatformConnection(platformId) {
  const el = document.getElementById('platform-live-' + platformId);
  if (el) el.innerHTML = `${t('platforms.testing')}`;
  try {
    const res = await fetch(API + '/api/platforms/test-connection', {
      method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ platformId }),
    });
    const data = await res.json();
    if (el) {
      el.innerHTML = data.ok
        ? `<span style="color:var(--green)">${icon('circle-check', 12)} ${data.info || t('platforms.connected')}</span>`
        : `<span style="color:var(--red)">${icon('circle-x', 12)} ${data.error || t('error')}</span>`;
    }
  } catch (err) {
    if (el) el.innerHTML = `<span style="color:var(--red)">${icon('circle-x', 12)} ${err.message}</span>`;
  }
}

async function loadPlatformStatuses() {
  try {
    const res = await fetch(API + '/api/platforms/status');
    const statuses = await res.json();
    for (const [id, state] of Object.entries(statuses)) {
      const el = document.getElementById('platform-live-' + id);
      const badge = document.getElementById('badge-' + id);
      const s = state;

      if (el && s.status && s.status !== 'not_configured' && s.status !== 'unknown') {
        let extra = '';
        if (s.botUsername) extra = ` @${s.botUsername}`;
        else if (s.botTag) extra = ` ${s.botTag}`;
        else if (s.guildCount) extra = ` (${s.guildCount} Server)`;
        else if (s.apiVersion) extra = ` v${s.apiVersion}`;
        const statusColor = s.status === 'connected' ? 'var(--green)' : (s.status === 'error' || s.status === 'logged_out') ? 'var(--red)' : 'var(--fg2)';
        const statusIcon = s.status === 'connected' ? icon('circle-check', 12) : s.status === 'error' ? icon('circle-x', 12) : icon('clock', 12);
        const statusLabel = t(`platforms.status.${s.status.replace('_', '.')}`) || s.status;
        el.innerHTML = `<span style="color:${statusColor}">${statusIcon} ${statusLabel}${extra}</span>`;
      }

      if (badge) {
        if (s.status === 'connected') {
          badge.className = 'badge badge-green'; badge.innerHTML = `${icon('circle-check', 12)} ${t('platforms.connected')}`;
        } else if (s.status === 'qr') {
          badge.className = 'badge badge-yellow'; badge.innerHTML = `${icon('qr-code', 12)} QR`;
        } else if (s.status === 'connecting') {
          badge.className = 'badge badge-yellow'; badge.innerHTML = `${icon('clock', 12)} ${t('platforms.status.connecting')}`;
        } else if (s.status === 'error' || s.status === 'logged_out') {
          badge.className = 'badge badge-red'; badge.innerHTML = `${icon('circle-x', 12)} ${t('error')}`;
        } else if (s.status === 'disconnected') {
          badge.className = 'badge badge-yellow'; badge.innerHTML = `${icon('circle-dot', 12)} ${t('platforms.status.disconnected')}`;
        }
      }
    }
  } catch { }
}

// ── WhatsApp QR + Status ────────────────────────────────
let waStatusInterval = null;

async function checkWhatsAppStatus() {
  try {
    const res = await fetch(API + '/api/whatsapp/status');
    const state = await res.json();
    const dot = document.getElementById('wa-status-dot');
    const text = document.getElementById('wa-status-text');
    const qrContainer = document.getElementById('wa-qr-container');
    if (!dot || !text) return;

    const statusMap = {
      disconnected: [icon('circle-dot', 16), t('platforms.status.disconnected')],
      connecting: [icon('clock', 16), t('platforms.status.connecting')],
      qr: [icon('qr-code', 16), t('wa.qr.ready')],
      connected: [icon('circle-check', 16), `${t('platforms.connected')}${state.connectedAt ? ` (${new Date(state.connectedAt).toLocaleTimeString(getLang() === 'de' ? 'de-DE' : 'en-US')})` : ''}`],
      logged_out: [icon('circle-x', 16), t('platforms.status.logged.out')],
    };
    const [statusIc, label] = statusMap[state.status] || [icon('info', 16), state.status];
    dot.innerHTML = statusIc;
    text.textContent = label;

    const badge = document.getElementById('badge-whatsapp');
    if (badge) {
      if (state.status === 'connected') { badge.className = 'badge badge-green'; badge.innerHTML = `${icon('circle-check', 12)} ${t('platforms.connected')}`; }
      else if (state.status === 'qr') { badge.className = 'badge badge-yellow'; badge.innerHTML = `${icon('qr-code', 12)} QR`; }
      else if (state.status === 'connecting') { badge.className = 'badge badge-yellow'; badge.innerHTML = `${icon('clock', 12)} ...`; }
      else if (state.status === 'error') { badge.className = 'badge badge-red'; badge.innerHTML = `${icon('circle-x', 12)} ${t('error')}`; }
    }

    const liveEl = document.getElementById('platform-live-whatsapp');
    if (liveEl) {
      const infoStr = state.info ? ` (${state.info})` : '';
      if (state.status === 'connected') liveEl.innerHTML = `<span style="color:var(--green)">${icon('circle-check', 12)} ${t('platforms.connected')}${infoStr}</span>`;
      else if (state.status === 'qr') liveEl.innerHTML = `<span style="color:var(--fg2)">${icon('qr-code', 12)} ${t('wa.qr.available')}</span>`;
      else if (state.status === 'connecting') liveEl.innerHTML = `<span style="color:var(--fg2)">${icon('clock', 12)} ...</span>`;
      else if (state.status === 'error') liveEl.innerHTML = `<span style="color:var(--red)">${icon('circle-x', 12)} ${state.error || t('error')}</span>`;
    }

    if (state.status === 'qr' && state.qrString && qrContainer) {
      qrContainer.style.display = '';
      renderQrCode(state.qrString);
      if (!waStatusInterval) waStatusInterval = setInterval(checkWhatsAppStatus, 3000);
    } else if (state.status === 'connecting') {
      if (qrContainer) qrContainer.style.display = 'none';
      if (!waStatusInterval) waStatusInterval = setInterval(checkWhatsAppStatus, 3000);
    } else {
      if (qrContainer) qrContainer.style.display = 'none';
      if (state.status === 'connected' && waStatusInterval) { clearInterval(waStatusInterval); waStatusInterval = null; }
    }
  } catch (err) {
    const text = document.getElementById('wa-status-text');
    if (text) text.textContent = t('error') + ': ' + err.message;
  }
}

async function disconnectWhatsApp() {
  if (!confirm(t('wa.disconnect.confirm'))) return;
  try {
    const res = await fetch(API + '/api/whatsapp/disconnect', { method: 'POST' });
    const data = await res.json();
    toast(data.ok ? t('wa.disconnected') : data.error, data.ok ? 'success' : 'error');
  } catch (err) { toast(t('error') + ': ' + err.message, 'error'); }
}

function renderQrCode(text) {
  const canvas = document.getElementById('wa-qr-canvas');
  if (!canvas) return;
  if (typeof QRCode !== 'undefined') { new QRCode(canvas.parentElement, { text, width: 256, height: 256, correctLevel: QRCode.CorrectLevel.M }); return; }
  if (!window._qrScriptLoaded) {
    window._qrScriptLoaded = true;
    const script = document.createElement('script');
    script.src = 'https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js';
    script.onload = () => renderQrCodeFromLib(text, canvas);
    document.head.appendChild(script);
  } else if (typeof qrcode !== 'undefined') {
    renderQrCodeFromLib(text, canvas);
  }
}

function renderQrCodeFromLib(text, canvas) {
  try {
    const qr = qrcode(0, 'M'); qr.addData(text); qr.make();
    const ctx = canvas.getContext('2d');
    const moduleCount = qr.getModuleCount();
    const cellSize = Math.max(4, Math.floor(256 / moduleCount));
    const size = moduleCount * cellSize;
    canvas.width = size; canvas.height = size;
    ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, size, size);
    ctx.fillStyle = '#000000';
    for (let row = 0; row < moduleCount; row++) {
      for (let col = 0; col < moduleCount; col++) {
        if (qr.isDark(row, col)) ctx.fillRect(col * cellSize, row * cellSize, cellSize, cellSize);
      }
    }
  } catch (err) { console.error('QR render error:', err); }
}

// ── Personality ─────────────────────────────────────────
async function loadPersonality() {
  const res = await fetch(API + '/api/soul');
  const data = await res.json();
  document.getElementById('soul-editor').value = data.content || '';
}

async function saveSoul() {
  const content = document.getElementById('soul-editor').value;
  const res = await fetch(API + '/api/soul/save', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ content }),
  });
  const data = await res.json();
  toast(data.ok ? t('personality.saved') : data.error, data.ok ? 'success' : 'error');
}

// ── Settings ────────────────────────────────────────────
async function loadSettings() {
  const [envRes, sudoRes] = await Promise.all([
    fetch(API + '/api/env'),
    fetch(API + '/api/sudo/status'),
  ]);
  const envData = await envRes.json();
  const sudoData = await sudoRes.json();

  let html = '';

  const sudoIcon = sudoData.configured ? (sudoData.verified ? icon('circle-check', 20, 'style="color:var(--green)"') : icon('circle-alert', 20, 'style="color:var(--yellow)"')) : icon('circle-x', 20, 'style="color:var(--red)"');
  const sudoStatusText = sudoData.configured
    ? (sudoData.verified ? t('settings.sudo.active') : t('settings.sudo.configured'))
    : t('settings.sudo.not.set');

  html += `<div class="card" style="margin-bottom:16px">
    <div style="display:flex;align-items:center;gap:10px;margin-bottom:12px">
      <span style="display:flex">${icon('lock', 24)}</span>
      <div style="flex:1">
        <h3 style="font-size:0.95em;text-transform:none;letter-spacing:0">${t('settings.sudo')}</h3>
        <div class="sub">${t('settings.sudo.desc')}</div>
      </div>
      ${sudoIcon}
    </div>
    <div style="font-size:0.85em;margin-bottom:12px">
      <div><strong>${t('settings.sudo.status')}:</strong> ${sudoStatusText}</div>
      <div><strong>${t('settings.sudo.storage')}:</strong> ${sudoData.storageMethod}</div>
      <div><strong>${t('settings.sudo.system')}:</strong> ${sudoData.platform} (${sudoData.user})</div>
      ${sudoData.permissions.accessibility !== null ? `<div><strong>${t('settings.sudo.accessibility')}:</strong> ${sudoData.permissions.accessibility ? icon('circle-check', 14, 'style="color:var(--green)"') : `${icon('circle-x', 14, 'style="color:var(--red)"')} <button class="btn btn-sm btn-outline" onclick="openSysSettings('accessibility')" style="font-size:0.8em;padding:2px 6px">${t('settings.sudo.open')}</button>`}</div>` : ''}
      ${sudoData.permissions.fullDiskAccess !== null ? `<div><strong>${t('settings.sudo.fda')}:</strong> ${sudoData.permissions.fullDiskAccess ? icon('circle-check', 14, 'style="color:var(--green)"') : `${icon('circle-x', 14, 'style="color:var(--red)"')} <button class="btn btn-sm btn-outline" onclick="openSysSettings('full-disk-access')" style="font-size:0.8em;padding:2px 6px">${t('settings.sudo.open')}</button>`}</div>` : ''}
    </div>`;

  if (!sudoData.configured) {
    html += `<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px">
      <input type="password" id="sudo-password" placeholder="${t('settings.sudo.password')}" style="flex:1;background:var(--bg3);border:1px solid var(--glass-border);border-radius:6px;padding:8px 12px;color:var(--fg);font:inherit;font-size:0.85em;outline:none">
      <button class="btn btn-sm" onclick="setupSudo()">${icon('lock', 12)} ${t('settings.sudo.setup')}</button>
    </div>
    <div class="sub">${t('settings.sudo.stored.secure')}</div>`;
  } else {
    html += `<div style="display:flex;gap:8px;flex-wrap:wrap">
      <button class="btn btn-sm btn-outline" onclick="verifySudo()">${icon('test-tube', 12)} ${t('settings.sudo.verify')}</button>
      <button class="btn btn-sm btn-outline" onclick="testSudoCommand()">${icon('zap', 12)} ${t('settings.sudo.test')}</button>
      ${sudoData.platform === 'darwin' ? `<button class="btn btn-sm btn-outline" onclick="showAdminDialog()">${icon('monitor', 12)} ${t('settings.sudo.admin.dialog')}</button>` : ''}
      <button class="btn btn-sm btn-outline" style="color:var(--red)" onclick="revokeSudo()">${icon('circle-x', 12)} ${t('settings.sudo.revoke')}</button>
    </div>`;
  }
  html += `<div id="sudo-result" style="font-size:0.78em;margin-top:6px"></div></div>`;

  const envHtml = envData.vars.map(v => `
    <div class="list-item">
      <div class="info">
        <div class="name" style="font-family:monospace;font-size:0.85em">${v.key}</div>
        <div class="desc">${v.value || '(empty)'}</div>
      </div>
      <button class="btn btn-sm btn-outline" onclick="editEnvVar('${v.key}')">${t('edit')}</button>
    </div>
  `).join('');

  html += `<div class="card" style="margin-bottom:16px">
    <h3 style="font-size:0.95em;text-transform:none;letter-spacing:0;margin-bottom:8px;display:flex;align-items:center;gap:6px">${icon('settings', 16)} ${t('settings.env')}</h3>
    ${envHtml}
    <div style="margin-top:12px;display:flex;gap:8px">
      <button class="btn btn-sm" onclick="addEnvVar()">${icon('plus', 14)} ${t('settings.env.add')}</button>
    </div>
  </div>`;

  document.getElementById('settings-content').innerHTML = html;
}

async function setupSudo() {
  const pw = document.getElementById('sudo-password').value;
  if (!pw) { toast(t('settings.sudo.password'), 'error'); return; }
  const resultDiv = document.getElementById('sudo-result');
  resultDiv.innerHTML = `<span style="color:var(--fg2)">${t('loading')}</span>`;
  const res = await fetch(API + '/api/sudo/setup', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password: pw }) });
  const data = await res.json();
  if (data.ok && data.verified) { toast(t('settings.sudo.setup.ok')); loadSettings(); }
  else { resultDiv.innerHTML = `<span style="color:var(--red)">${icon('circle-x', 12)} ${data.error || t('error')}</span>`; toast(data.error || t('error'), 'error'); }
}

async function verifySudo() {
  const resultDiv = document.getElementById('sudo-result');
  resultDiv.innerHTML = `<span style="color:var(--fg2)">${t('settings.sudo.verifying')}</span>`;
  const res = await fetch(API + '/api/sudo/verify', { method: 'POST' });
  const data = await res.json();
  resultDiv.innerHTML = data.ok
    ? `<span style="color:var(--green)">${icon('circle-check', 12)} ${t('settings.sudo.verified')}</span>`
    : `<span style="color:var(--red)">${icon('circle-x', 12)} ${data.error}</span>`;
}

async function testSudoCommand() {
  const cmd = prompt(t('settings.sudo.test.prompt'), 'whoami');
  if (!cmd) return;
  const resultDiv = document.getElementById('sudo-result');
  resultDiv.innerHTML = `<span style="color:var(--fg2)">${t('settings.sudo.executing')}</span>`;
  const res = await fetch(API + '/api/sudo/exec', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ command: cmd }) });
  const data = await res.json();
  resultDiv.innerHTML = data.ok
    ? `<span style="color:var(--green)">${icon('circle-check', 12)} ${t('settings.sudo.output')}:</span><pre style="margin:4px 0;padding:6px;background:var(--bg3);border-radius:4px;font-size:0.9em;overflow-x:auto">${escapeHtml(data.output.slice(0, 500))}</pre>`
    : `<span style="color:var(--red)">${icon('circle-x', 12)} ${data.error}</span>`;
}

async function revokeSudo() {
  if (!confirm(t('settings.sudo.revoke.confirm'))) return;
  await fetch(API + '/api/sudo/revoke', { method: 'POST' });
  toast(t('settings.sudo.revoked'));
  loadSettings();
}

async function showAdminDialog() {
  const reason = prompt(t('settings.sudo.admin.reason'), t('settings.sudo.admin.default.reason'));
  if (!reason) return;
  toast(t('settings.sudo.admin.showing'));
  const res = await fetch(API + '/api/sudo/admin-dialog', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reason }) });
  const data = await res.json();
  toast(data.ok ? t('settings.sudo.admin.confirmed') : t('settings.sudo.admin.denied'), data.ok ? 'success' : 'error');
}

async function openSysSettings(pane) {
  await fetch(API + '/api/sudo/open-settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ pane }) });
  toast(t('settings.sysopen'));
}

function editEnvVar(key) {
  const value = prompt(t('settings.env.new.prompt', { key }), '');
  if (value === null) return;
  fetch(API + '/api/env/set', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key, value }) })
    .then(r => r.json()).then(d => {
      toast(d.ok ? t('settings.env.saved', { key }) : d.error, d.ok ? 'success' : 'error');
      loadSettings();
    });
}

function addEnvVar() {
  const key = prompt(t('settings.env.name.prompt'));
  if (!key) return;
  const value = prompt(t('settings.env.value.prompt', { key }));
  if (value === null) return;
  fetch(API + '/api/env/set', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key, value }) })
    .then(r => r.json()).then(d => {
      toast(d.ok ? t('settings.env.added', { key }) : d.error, d.ok ? 'success' : 'error');
      loadSettings();
    });
}

// ── Doctor & Backup ─────────────────────────────────────
async function repairIssue(action) {
  const res = await fetch(API + '/api/doctor/repair', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action }) });
  const data = await res.json();
  toast(data.ok ? data.message : data.message, data.ok ? 'success' : 'error');
  loadMaintenance();
}

async function repairAll() {
  if (!confirm(t('maint.doctor.fix.all.confirm'))) return;
  const res = await fetch(API + '/api/doctor/repair-all', { method: 'POST' });
  const data = await res.json();
  const ok = data.results.filter(r => r.ok).length;
  const fail = data.results.filter(r => !r.ok).length;
  toast(`${t('maint.doctor.fixed', { ok })}${fail > 0 ? `, ${t('maint.doctor.failed', { fail })}` : ''}`, fail > 0 ? 'error' : 'success');
  loadMaintenance();
}

async function createBackup() {
  const name = prompt(t('maint.backup.name.prompt'), '');
  toast(t('maint.backup.creating'));
  const res = await fetch(API + '/api/backups/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name || undefined }) });
  const data = await res.json();
  if (data.ok) { toast(t('maint.backup.created', { id: data.id, count: data.files.length })); loadMaintenance(); }
  else { toast(data.error || t('error'), 'error'); }
}
function createBackupMaint() { createBackup(); }

async function restoreBackup(id) {
  if (!confirm(t('maint.backup.restore.confirm', { id }))) return;
  const res = await fetch(API + '/api/backups/restore', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id }) });
  const data = await res.json();
  if (data.ok || data.restored?.length > 0) {
    toast(t('maint.backup.restored', { count: data.restored.length }));
    if (data.errors?.length > 0) toast(`${data.errors.length} ${t('error')}`, 'error');
    loadMaintenance();
  } else {
    toast(data.errors?.[0] || t('error'), 'error');
  }
}

async function showBackupFiles(id) {
  const area = document.getElementById('backup-files-area');
  if (area.style.display !== 'none' && area.dataset.id === id) { area.style.display = 'none'; return; }
  const res = await fetch(API + `/api/backups/${id}/files`);
  const data = await res.json();
  area.dataset.id = id; area.style.display = '';
  area.innerHTML = `<div style="font-weight:500;margin-bottom:6px">${icon('clipboard', 14)} ${t('maint.backup.files.in', { id })}:</div>` +
    data.files.map(f => `<div style="padding:2px 0;color:var(--fg2)">${icon('file-text', 12)} ${f}</div>`).join('') +
    `<div style="margin-top:8px"><button class="btn btn-sm btn-outline" onclick="document.getElementById('backup-files-area').style.display='none'">${t('close')}</button></div>`;
}

async function deleteBackup(id) {
  if (!confirm(t('maint.backup.delete.confirm', { id }))) return;
  await fetch(API + '/api/backups/delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id }) });
  toast(t('maint.backup.deleted'));
  loadMaintenance();
}

// ── PM2 ─────────────────────────────────────────────────
async function pm2Action(action) {
  const dangerous = ['stop'];
  if (dangerous.includes(action) && !confirm(t('maint.pm2.stop.confirm'))) return;
  if (action === 'restart' && !confirm(t('maint.pm2.restart.confirm'))) return;

  toast(`PM2 ${action}...`);
  try {
    const res = await fetch(API + '/api/pm2/action', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action }) });
    const data = await res.json();
    if (data.ok) {
      toast(t('maint.pm2.action.ok', { action }));
      if (action === 'stop') {
        document.getElementById('pm2-status').innerHTML = `<span class="badge badge-red">${icon('pause', 12)} ${t('maint.pm2.stop')}</span>`;
      } else {
        setTimeout(refreshPM2Status, 2000);
        if (['restart', 'reload', 'start'].includes(action)) setTimeout(connectWS, 3000);
      }
    } else {
      toast(t('maint.pm2.action.fail', { action }) + ': ' + (data.error || ''), 'error');
    }
  } catch (e) {
    toast(t('maint.pm2.lost'), 'error');
    document.getElementById('pm2-status').innerHTML = `<span class="badge badge-red">${icon('circle-x', 12)} ${t('maint.pm2.unreachable')}</span>`;
  }
}

async function refreshPM2Status() {
  try {
    const res = await fetch(API + '/api/pm2/status');
    const data = await res.json();
    const el = document.getElementById('pm2-status');
    if (!el) return;
    if (data.error) { el.innerHTML = `<span class="badge badge-yellow">${icon('alert-triangle', 12)} ${data.error}</span>`; return; }

    const p = data.process;
    const statusColors = { online: 'green', stopping: 'yellow', stopped: 'red', errored: 'red', launching: 'yellow' };
    const statusIcons = { online: 'circle-check', stopping: 'clock', stopped: 'circle-x', errored: 'circle-x', launching: 'zap' };
    const color = statusColors[p.status] || 'gray';
    const sIcon = statusIcons[p.status] || 'info';
    const uptime = p.uptime > 0 ? formatDuration(p.uptime) : '—';
    const mem = p.memory ? (p.memory / 1024 / 1024).toFixed(1) + ' MB' : '—';
    const cpu = p.cpu !== undefined ? p.cpu + '%' : '—';

    el.innerHTML = `
      <div style="display:flex;flex-wrap:wrap;gap:12px;align-items:center">
        <span class="badge badge-${color}">${icon(sIcon, 12)} ${p.status}</span>
        <span title="Uptime">${icon('clock', 12)} ${uptime}</span>
        <span title="Memory">${icon('hard-drive', 12)} ${mem}</span>
        <span title="CPU">${icon('monitor', 12)} ${cpu}</span>
        <span title="Restarts">${icon('refresh-cw', 12)} ${p.restarts}x</span>
        <span title="PID">PID: ${p.pid || '—'}</span>
        <span title="PM2 Name" style="font-family:monospace;color:var(--accent2)">${p.name}</span>
      </div>`;
  } catch (e) {
    const el = document.getElementById('pm2-status');
    if (el) el.innerHTML = `<span class="badge badge-red">${icon('circle-x', 12)} ${t('maint.pm2.unreachable')}</span>`;
  }
}

function formatDuration(ms) {
  const s = Math.floor(ms / 1000);
  if (s < 60) return s + 's';
  const m = Math.floor(s / 60);
  if (m < 60) return m + 'm ' + (s % 60) + 's';
  const h = Math.floor(m / 60);
  if (h < 24) return h + 'h ' + (m % 60) + 'm';
  const d = Math.floor(h / 24);
  return d + 'd ' + (h % 24) + 'h';
}

async function loadPM2Logs() {
  const el = document.getElementById('pm2-log-output');
  if (!el) return;
  el.textContent = t('loading');
  try {
    const res = await fetch(API + '/api/pm2/logs');
    const data = await res.json();
    if (data.error) el.textContent = t('error') + ': ' + data.error;
    else { el.textContent = data.logs || t('no.data'); el.scrollTop = el.scrollHeight; }
  } catch (e) { el.textContent = t('error'); }
}

async function restartBot() {
  if (!confirm(t('maint.bot.restart.confirm'))) return;
  toast(t('maint.bot.restarting'));
  await fetch(API + '/api/bot/restart', { method: 'POST' });
  setTimeout(() => { toast(t('maint.bot.reconnecting')); connectWS(); }, 3000);
}

async function reconnectBot() {
  toast(t('reconnecting'));
  if (ws) ws.close();
  setTimeout(connectWS, 500);
}

// ── Files ───────────────────────────────────────────────
let currentFilePath = '.';

async function navigateFiles(dir) {
  if (dir === '..') {
    const parts = currentFilePath.split('/').filter(Boolean);
    parts.pop();
    currentFilePath = parts.join('/') || '.';
  } else if (dir !== '.') {
    currentFilePath = currentFilePath === '.' ? dir : currentFilePath + '/' + dir;
  }

  const res = await fetch(API + '/api/files?path=' + encodeURIComponent(currentFilePath));
  const data = await res.json();
  document.getElementById('file-breadcrumb').innerHTML = `${icon('folder', 14)} /${currentFilePath === '.' ? '' : currentFilePath}`;

  if (data.entries) {
    document.getElementById('file-editor-area').style.display = 'none';
    const fileIcons = { ts:'code', js:'code', json:'file-text', md:'file-text', html:'globe', css:'palette', sh:'terminal', py:'code', txt:'file-text', env:'lock' };
    document.getElementById('file-list').innerHTML = data.entries.map(e => {
      const ic = e.type === 'dir' ? 'folder' : (fileIcons[e.name.split('.').pop()?.toLowerCase()] || 'file-text');
      const size = e.type === 'file' ? formatSize(e.size) : '';
      const fpath = (currentFilePath === '.' ? '' : currentFilePath + '/') + e.name;
      return `<div class="file-item" onclick="${e.type==='dir' ? `navigateFiles('${e.name}')` : `openFile('${fpath}')`}">
        <span class="file-icon">${icon(ic, 16)}</span><span class="file-name">${e.name}</span><span class="file-meta">${size}</span></div>`;
    }).join('');
  }
}

async function openFile(filePath) {
  const res = await fetch(API + '/api/files?path=' + encodeURIComponent(filePath));
  const data = await res.json();
  if (data.error) { toast(data.error, 'error'); return; }
  if (data.content !== undefined && data.content !== null) {
    document.getElementById('file-editor-area').style.display = '';
    document.getElementById('file-edit-name').textContent = filePath;
    document.getElementById('file-editor').value = data.content;
    const lines = data.content.split('\n').length;
    const sizeStr = data.size ? formatSize(data.size) : '';
    document.getElementById('file-edit-meta')?.remove();
    const meta = document.createElement('div');
    meta.id = 'file-edit-meta';
    meta.style.cssText = 'font-size:0.75em;color:var(--fg2);margin-top:4px';
    meta.textContent = `${t('files.lines', { count: lines })} · ${sizeStr}`;
    document.getElementById('file-editor').parentNode.insertBefore(meta, document.getElementById('file-editor'));
  } else if (data.binary) {
    toast(t('files.binary'), 'error');
  } else {
    toast(t('files.open.error'), 'error');
  }
}

async function saveFile() {
  const path = document.getElementById('file-edit-name').textContent;
  const content = document.getElementById('file-editor').value;
  const res = await fetch(API + '/api/files/save', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path, content }) });
  const data = await res.json();
  toast(data.ok ? t('files.saved') : data.error, data.ok ? 'success' : 'error');
}

async function createNewFile() {
  const name = prompt(t('files.name.prompt'));
  if (!name) return;
  const filePath = currentFilePath === '.' ? name : currentFilePath + '/' + name;
  const res = await fetch(API + '/api/files/save', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: filePath, content: '' }) });
  const data = await res.json();
  if (data.ok) { toast(t('files.created')); navigateFiles('.'); openFile(filePath); }
  else { toast(data.error || t('files.create.error'), 'error'); }
}

async function deleteFile(filePath) {
  if (!confirm(t('files.delete.confirm', { path: filePath }))) return;
  const res = await fetch(API + '/api/files/delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ path: filePath }) });
  const data = await res.json();
  if (data.ok) { toast(t('files.deleted')); document.getElementById('file-editor-area').style.display = 'none'; navigateFiles('.'); }
  else { toast(data.error || t('files.delete.error'), 'error'); }
}

function formatSize(bytes) {
  if (bytes < 1024) return bytes + ' B';
  if (bytes < 1048576) return (bytes/1024).toFixed(1) + ' KB';
  return (bytes/1048576).toFixed(1) + ' MB';
}

// ── Cron ────────────────────────────────────────────────
async function loadCron() {
  const res = await fetch(API + '/api/cron');
  const data = await res.json();
  const list = document.getElementById('cron-list');

  if (data.jobs.length === 0) {
    list.innerHTML = `<div class="card"><h3>${t('cron.none')}</h3><div class="sub">${t('cron.none.desc')}</div></div>`;
    return;
  }

  const typeIcons = { reminder: 'timer', shell: 'zap', http: 'globe', message: 'message-square', 'ai-query': 'bot' };

  list.innerHTML = data.jobs.map(j => {
    const statusIcon = j.enabled ? icon('circle-check', 14, 'style="color:var(--green)"') : icon('pause', 14, 'style="color:var(--fg3)"');
    const errIcon = j.lastError ? ` <span style="color:var(--red)">${icon('alert-triangle', 14)}</span>` : '';
    const ic = typeIcons[j.type] || 'clipboard';
    const payload = j.payload.text || j.payload.command || j.payload.url || j.payload.prompt || '';
    const schedLabel = j.scheduleReadable || j.schedule;
    const recBadge = j.oneShot
      ? `<span class="badge badge-yellow">${icon('zap', 10)} ${t('cron.single')}</span>`
      : `<span class="badge" style="background:var(--accent);color:#fff">${icon('refresh-cw', 10)} ${escapeHtml(schedLabel)}</span>`;

    return `<div class="card" style="margin-bottom:12px">
      <div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
        ${statusIcon}
        <span style="font-weight:500;flex:1;display:flex;align-items:center;gap:6px">${icon(ic, 16)} ${escapeHtml(j.name)}${errIcon}</span>
        ${recBadge}
      </div>
      <div id="cron-edit-${j.id}" style="display:none;margin-bottom:10px;padding:12px;background:var(--bg3);border-radius:8px">
        ${buildScheduleEditor(j.id, j.schedule, j.oneShot)}
      </div>
      <div style="font-size:0.82em;color:var(--fg2);margin-bottom:8px">
        <span>${t('cron.next.run')}: <strong>${j.nextRunFormatted || '—'}</strong></span> · 
        <span>${t('cron.runs')}: ${j.runCount}</span> · 
        <span>${t('cron.last.run')}: ${j.lastRunFormatted || t('cron.never')}</span>
      </div>
      ${payload ? `<div style="font-size:0.78em;font-family:monospace;color:var(--fg2);padding:6px 8px;background:var(--bg3);border-radius:4px;margin-bottom:8px;word-break:break-all">${escapeHtml(payload.slice(0, 200))}</div>` : ''}
      ${j.lastError ? `<div style="font-size:0.78em;color:var(--red);margin-bottom:8px">${icon('circle-x', 12)} ${escapeHtml(j.lastError)}</div>` : ''}
      <div style="display:flex;gap:6px">
        <button class="btn btn-sm btn-outline" onclick="toggleCronJob('${j.id}')">${j.enabled ? `${icon('pause', 12)} ${t('cron.pause')}` : `${icon('play', 12)} ${t('cron.start')}`}</button>
        <button class="btn btn-sm btn-outline" onclick="runCronJob('${j.id}')">${icon('play', 12)} ${t('cron.run.now')}</button>
        <button class="btn btn-sm btn-outline" onclick="editCronSchedule('${j.id}')">${icon('edit', 12)} ${t('cron.edit')}</button>
        <button class="btn btn-sm btn-outline" style="color:var(--red)" onclick="deleteCronJob('${j.id}')">${icon('trash-2', 12)}</button>
      </div>
    </div>`;
  }).join('');
}

function showCreateCron() {
  document.getElementById('cron-create-form').style.display = '';
  const container = document.getElementById('cron-create-schedule-builder');
  if (container && !container.innerHTML.trim()) {
    container.innerHTML = buildScheduleEditor(null, '0 8 * * *', false);
  }
}

async function createCronJob() {
  const name = document.getElementById('cron-name').value.trim();
  const type = document.getElementById('cron-type').value;
  const payloadText = document.getElementById('cron-payload').value.trim();
  if (!name) { toast(t('cron.name.required'), 'error'); return; }

  const result = fieldsToCron(null);
  if (!result) return;

  const payload = {};
  switch (type) {
    case 'reminder': case 'message': payload.text = payloadText; break;
    case 'shell': payload.command = payloadText; break;
    case 'http': payload.url = payloadText; break;
    case 'ai-query': payload.prompt = payloadText; break;
  }

  const res = await fetch(API + '/api/cron/create', {
    method: 'POST', headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ name, type, schedule: result.schedule, oneShot: result.oneShot, payload, target: { platform: 'telegram', chatId: 'YOUR_USER_ID' } }),
  });
  const data = await res.json();
  if (data.ok) {
    toast(t('cron.created'));
    document.getElementById('cron-create-form').style.display = 'none';
    document.getElementById('cron-name').value = '';
    document.getElementById('cron-payload').value = '';
    document.getElementById('cron-create-schedule-builder').innerHTML = '';
    loadCron();
  } else {
    toast(data.error, 'error');
  }
}

async function toggleCronJob(id) {
  await fetch(API + '/api/cron/toggle', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id }) });
  loadCron();
}

async function deleteCronJob(id) {
  if (!confirm(t('cron.delete.confirm'))) return;
  await fetch(API + '/api/cron/delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id }) });
  toast(t('cron.deleted'));
  loadCron();
}

// ── Schedule Builder ─────────────────────────────────────

