// assets/js/app.js — Ship Network Admin Dashboard

const App = {
  aiHistory: [],
  alertCount: 0,
  slChart: null,

  init() {
    this.startClock();
    this.loadAll();
    setInterval(() => this.loadBandwidth(), 8000);
    this.checkSavedMsg();
  },

  startClock() {
    const el = document.getElementById('clock');
    if (!el) return;
    const tick = () => {
      const now = new Date();
      el.textContent = now.toLocaleTimeString('id-ID', {hour12: false}) + ' WIB';
    };
    tick();
    setInterval(tick, 1000);
  },

  checkSavedMsg() {
    const params = new URLSearchParams(window.location.search);
    const el = document.getElementById('save-msg');
    if (!el) return;
    if (params.get('saved')) {
      el.style.display = 'block';
      el.className = 'save-msg success';
      el.textContent = 'Pengaturan berhasil disimpan.';
      setTimeout(() => el.style.display = 'none', 3000);
    } else if (params.get('error')) {
      el.style.display = 'block';
      el.className = 'save-msg error';
      el.textContent = 'Gagal menyimpan: periksa permission folder /data/';
    }
  },

  async fetchJSON(url, opts = {}) {
    try {
      const r = await fetch(url, opts);
      return await r.json();
    } catch (e) {
      console.error('fetchJSON error:', url, e);
      return {error: e.message};
    }
  },

  async loadAll() {
    await Promise.all([
      this.loadFortinet(),
      this.loadAruba(),
      this.loadStarlink(),
      this.loadAlerts(),
    ]);
  },

  // ============================================================
  // FORTINET
  // ============================================================
  async loadFortinet() {
    const [status, ifaces, security, policy, vpn] = await Promise.all([
      this.fetchJSON('api/fortinet.php?action=status'),
      this.fetchJSON('api/fortinet.php?action=interfaces'),
      this.fetchJSON('api/fortinet.php?action=security'),
      this.fetchJSON('api/fortinet.php?action=policy'),
      this.fetchJSON('api/fortinet.php?action=vpn'),
    ]);

    const d = status.data || {};
    const demo = status.demo;

    // Overview metrics
    setEl('ov-ft-status', d.model ? 'Aktif' : '--');
    setEl('ov-ft-sub', (d.model || 'FortiGate') + (demo ? ' [demo]' : ''));

    // Fortinet tab - status
    setEl('ft-model', d.model || '--');
    setEl('ft-os', d.os_version || '--');
    setEl('ft-uptime', d.uptime || '--');
    setEl('ft-boot', d.boot_time ? 'Boot: ' + d.boot_time : '--');
    setEl('ft-sess', (d.sessions_current || 0).toLocaleString('id-ID'));
    setEl('ft-threat', (d.threats_blocked_today || 0).toLocaleString('id-ID'));

    // Bandwidth from status
    this.loadBandwidth(d);

    // Interfaces
    const ifaceEl = document.getElementById('ft-interfaces');
    if (ifaceEl && ifaces.data) {
      ifaceEl.innerHTML = ifaces.data.map(i => `
        <div class="row">
          <div class="row-label">${i.name}${i.alias ? ' <small>('+i.alias+')</small>' : ''}</div>
          <div style="display:flex;align-items:center;gap:6px">
            ${i.ip ? `<span class="mono-sm">${i.ip}</span>` : ''}
            <span class="badge ${i.status==='up'?'badge-green':i.status==='down'?'badge-red':'badge-gray'}">${i.status||'--'}</span>
          </div>
        </div>`).join('');
    }

    // Security
    const secEl = document.getElementById('ft-security');
    if (secEl && security.data) {
      secEl.innerHTML = security.data.map(s => `
        <div class="row">
          <div class="row-label">${s.feature}</div>
          <div style="display:flex;align-items:center;gap:6px">
            <span class="text-muted" style="font-size:10px">${s.detail||''}</span>
            <span class="badge ${s.status==='enable'?'badge-green':s.status==='partial'?'badge-amber':'badge-red'}">${s.status||'--'}</span>
          </div>
        </div>`).join('');
    }

    // Policy table
    const tbody = document.getElementById('policy-tbody');
    if (tbody && policy.data) {
      tbody.innerHTML = policy.data.map(p => `
        <tr>
          <td>${p.id}</td>
          <td><strong>${p.name}</strong></td>
          <td class="mono-sm">${p.srcintf||'any'}</td>
          <td class="mono-sm">${p.dstintf||'any'}</td>
          <td><span class="badge ${p.action==='accept'?'badge-green':'badge-red'}">${(p.action||'').toUpperCase()}</span></td>
          <td><span class="dot ${p.status==='enable'?'dg':'dr'}" style="display:inline-block"></span></td>
          <td>
            <button class="btn btn-xs" onclick="App.editPolicy(${p.id})"><i class="ti ti-edit"></i></button>
            <button class="btn btn-xs btn-danger-xs" onclick="App.deletePolicy(${p.id},'${p.name}')"><i class="ti ti-trash"></i></button>
          </td>
        </tr>`).join('');
    }

    // VPN
    const vpnEl = document.getElementById('vpn-list');
    if (vpnEl && vpn.data) {
      vpnEl.innerHTML = vpn.data.map(v => `
        <div class="row">
          <div class="row-label">
            <strong>${v.peer||v.name}</strong>
            <span class="text-muted" style="font-size:10px;margin-left:6px">${v.type||''} ${v.version||''}</span>
          </div>
          <div style="display:flex;align-items:center;gap:6px">
            ${v.duration ? `<span class="text-muted" style="font-size:10px">${v.duration}</span>` : ''}
            <span class="badge ${v.status==='up'?'badge-green':'badge-red'}">${v.status||'--'}</span>
            ${v.status==='down' ? `<button class="btn btn-xs btn-danger-xs" onclick="App.troubleshootVPN('${v.peer||v.name}')"><i class="ti ti-tool"></i></button>` : ''}
          </div>
        </div>`).join('');
    }

    this.addLog('Fortinet: data dimuat' + (demo ? ' [mode demo]' : ''), demo ? 'warn' : 'ok');
  },

  async loadBandwidth(d) {
    if (!d) {
      const r = await this.fetchJSON('api/fortinet.php?action=status');
      d = r.data || {};
    }
    // Simulasi jika demo
    const dlMbps  = d.dl_mbps  || (60 + Math.random() * 40);
    const ulMbps  = d.ul_mbps  || (15 + Math.random() * 20);
    const cpu     = d.cpu_usage || Math.round(15 + Math.random() * 25);
    const mem     = d.mem_usage || Math.round(35 + Math.random() * 15);
    const dlPct   = Math.min(100, (dlMbps / 150) * 100);
    const ulPct   = Math.min(100, (ulMbps / 50) * 100);

    setEl('val-dl', dlMbps.toFixed(1) + ' Mbps');
    setEl('val-ul', ulMbps.toFixed(1) + ' Mbps');
    setEl('val-cpu', cpu + '%');
    setEl('val-mem', mem + '%');
    setBar('bar-dl', dlPct);
    setBar('bar-ul', ulPct);
    setBar('bar-cpu', cpu);
    setBar('bar-mem', mem);
  },

  async runFtCLI() {
    const inp  = document.getElementById('ft-cli-inp');
    const out  = document.getElementById('ft-cli-out');
    const cmd  = inp.value.trim();
    if (!cmd) return;

    out.innerHTML += `\nFortiGate # <span class="cli-cmd">${escHtml(cmd)}</span>\n<span class="cli-loading">Menjalankan...</span>`;
    inp.value = '';

    const r = await this.fetchJSON('api/fortinet.php?action=cli', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({command: cmd}),
    });

    const outputEl = out.querySelector('.cli-loading');
    if (outputEl) outputEl.remove();

    const text = r.error ? `% Error: ${r.error}` : (r.data?.output || 'No output');
    out.innerHTML += `<span class="cli-output">${escHtml(text)}</span>\n\nFortiGate # <span class="cli-cursor">_</span>`;
    out.scrollTop = out.scrollHeight;
  },

  // ============================================================
  // ARUBA
  // ============================================================
  async loadAruba() {
    const [aps, clients, ssids] = await Promise.all([
      this.fetchJSON('api/aruba.php?action=aps'),
      this.fetchJSON('api/aruba.php?action=clients'),
      this.fetchJSON('api/aruba.php?action=ssids'),
    ]);

    const d = aps.data || {};
    const demo = aps.demo;

    setEl('ov-ap-count', `${d.online||0}/${d.total||0}`);
    setEl('ov-ap-sub', `Aruba IO • ${clients.data?.total||0} klien${demo?' [demo]':''}`);

    setEl('ar-total-ap', d.total || '--');
    setEl('ar-ap-sub', `${d.online||0} online, ${d.offline||0} offline`);
    setEl('ar-clients', clients.data?.total || '--');
    setEl('ar-ssid', ssids.data?.length || '--');

    const ssidNames = (ssids.data || []).map(s => s.name).join(', ');
    setEl('ar-ssid-names', ssidNames || '--');

    // Avg utilization
    const devices = d.devices || [];
    if (devices.length) {
      const avg = Math.round(devices.reduce((s, ap) => s + (ap.util_24 || 0), 0) / devices.length);
      const el = document.getElementById('ar-util');
      if (el) { el.textContent = avg + '%'; el.className = 'mcard-val ' + (avg > 80 ? 'red' : avg > 60 ? 'amber' : 'blue'); }
    }

    // AP table
    const tbody = document.getElementById('ap-tbody');
    if (tbody && devices.length) {
      tbody.innerHTML = devices.map(ap => {
        const util = ap.util_24 || 0;
        const utilColor = util > 80 ? 'color:var(--red-600);font-weight:500' : util > 60 ? 'color:var(--amber-600)' : '';
        return `<tr>
          <td><strong>${ap.name}</strong></td>
          <td class="text-muted">${ap.model||'--'}</td>
          <td class="mono-sm">${ap.ip||'--'}</td>
          <td style="text-align:center">${ap.clients||0}</td>
          <td><span class="badge badge-blue">${ap.band||'--'}</span></td>
          <td style="${utilColor}">${util}%</td>
          <td><span class="badge ${ap.status==='online'?'badge-green':ap.status==='warning'?'badge-amber':'badge-red'}">${ap.status||'--'}</span></td>
          <td>
            <button class="btn btn-xs" onclick="App.rebootAP('${ap.name}','${ap.ip}')"><i class="ti ti-refresh"></i></button>
            ${util>80?`<button class="btn btn-xs btn-warning-xs" onclick="App.optimizeAP('${ap.name}')"><i class="ti ti-settings"></i></button>`:''}
          </td>
        </tr>`;
      }).join('');
    }

    // SSID list
    const ssidEl = document.getElementById('ssid-list');
    if (ssidEl && ssids.data) {
      ssidEl.innerHTML = (ssids.data || []).map(s => `
        <div class="row">
          <div class="row-label">
            <strong>${s.name}</strong>
            <span class="text-muted" style="font-size:10px;margin-left:6px">${s.security||''} • VLAN ${s.vlan||'--'}</span>
          </div>
          <div style="display:flex;align-items:center;gap:6px">
            <span class="badge badge-blue">${s.band||'Dual'}</span>
            <span class="text-muted">${s.clients||0} klien</span>
            <span class="badge ${s.status==='active'?'badge-green':'badge-gray'}">${s.status||'--'}</span>
          </div>
        </div>`).join('');
    }

    this.addLog('Aruba: data AP dimuat' + (demo ? ' [mode demo]' : ''), demo ? 'warn' : 'ok');
  },

  // ============================================================
  // STARLINK
  // ============================================================
  async loadStarlink() {
    const [status, history] = await Promise.all([
      this.fetchJSON('api/starlink.php?action=status'),
      this.fetchJSON('api/starlink.php?action=history'),
    ]);

    const d = status.data || {};
    const demo = status.demo;

    const dlMbps = d.downlink_throughput_bps ? (d.downlink_throughput_bps / 1e6).toFixed(1) : '--';
    const ulMbps = d.uplink_throughput_bps ? (d.uplink_throughput_bps / 1e6).toFixed(1) : '--';
    const lat = d.pop_ping_latency_ms || '--';

    setEl('ov-sl-status', d.terminal_status === 'online' ? 'Baik' : (d.terminal_status || '--'));
    setEl('ov-sl-sub', `Latency ${lat}ms • ${dlMbps} Mbps${demo?' [demo]':''}`);

    setEl('sl-status', d.terminal_status === 'online' ? '🛰 Online' : (d.terminal_status || '--'));
    setEl('sl-hw', d.hardware_version || '--');
    setEl('sl-lat', lat + ' ms');
    setEl('sl-lat-avg', 'avg 30h: ' + (d.pop_ping_latency_ms_avg || lat) + 'ms');
    setEl('sl-dl', dlMbps + ' Mbps');
    setEl('sl-ul', ulMbps + ' Mbps');

    // Signal info
    const sigEl = document.getElementById('sl-signal');
    if (sigEl) {
      sigEl.innerHTML = `
        <div class="row"><div class="row-label">SNR</div><div class="row-val">${d.snr_db ?? '--'} dB</div></div>
        <div class="row"><div class="row-label">Obstruction</div><div class="row-val" style="color:${(d.obstruction_pct||0)>1?'var(--red-600)':'var(--green-800)'}">` +
        (d.obstruction_pct !== undefined ? d.obstruction_pct.toFixed(1) + '%' : '--') + `</div></div>
        <div class="row"><div class="row-label">Signal quality</div><div class="row-val"><span class="badge ${(d.signal_quality||0)>0.8?'badge-green':'badge-amber'}">${d.signal_quality ? Math.round(d.signal_quality*100)+'%' : '--'}</span></div></div>
        <div class="row"><div class="row-label">Packet loss</div><div class="row-val">${d.ping_drop_rate !== undefined ? (d.ping_drop_rate*100).toFixed(2)+'%' : '--'}</div></div>
        <div class="row"><div class="row-label">Uptime hari ini</div><div class="row-val">${d.uptime_seconds ? formatUptime(d.uptime_seconds) : '--'}</div></div>`;
    }

    // Terminal info
    const infoEl = document.getElementById('sl-info');
    if (infoEl) {
      infoEl.innerHTML = `
        <div class="row"><div class="row-label">Hardware</div><div class="row-val">${d.hardware_version||'--'}</div></div>
        <div class="row"><div class="row-label">Software</div><div class="row-val mono-sm">${d.software_version||'--'}</div></div>
        <div class="row"><div class="row-label">Tilt angle</div><div class="row-val">${d.tilt_angle_deg ?? '--'}°</div></div>
        <div class="row"><div class="row-label">Suhu dish</div><div class="row-val">${d.dish_temp_c ?? '--'}°C</div></div>
        <div class="row"><div class="row-label">Suhu board</div><div class="row-val">${d.board_temp_c ?? '--'}°C</div></div>
        <div class="row"><div class="row-label">Koordinat</div><div class="row-val mono-sm">${d.latitude ?? '--'}° / ${d.longitude ?? '--'}°</div></div>`;
    }

    // Chart throughput
    this.renderSlChart(history.data || []);
    this.addLog('Starlink: data dimuat' + (demo ? ' [mode demo]' : ''), demo ? 'warn' : 'ok');
  },

  renderSlChart(history) {
    const canvas = document.getElementById('sl-chart');
    if (!canvas || typeof Chart === 'undefined') return;

    if (this.slChart) { this.slChart.destroy(); this.slChart = null; }

    const labels = history.map((_, i) => i % 2 === 0 ? (i * 2) + ':00' : '').reverse();
    const dlData = history.map(h => h.downlink ? +(h.downlink / 1e6).toFixed(1) : 0).reverse();
    const ulData = history.map(h => h.uplink ? +(h.uplink / 1e6).toFixed(1) : 0).reverse();

    this.slChart = new Chart(canvas, {
      type: 'bar',
      data: {
        labels,
        datasets: [
          {label: 'Download (Mbps)', data: dlData, backgroundColor: '#85B7EB'},
          {label: 'Upload (Mbps)',   data: ulData, backgroundColor: '#5DCAA5'},
        ],
      },
      options: {
        responsive: true,
        plugins: {legend: {labels: {font: {size: 11}}}},
        scales: {
          x: {ticks: {font: {size: 10}}},
          y: {ticks: {font: {size: 10}}, title: {display: true, text: 'Mbps', font: {size: 10}}},
        },
      },
    });
  },

  // ============================================================
  // ALERTS
  // ============================================================
  async loadAlerts() {
    // Kumpulkan alert dari semua sumber
    const alerts = [];

    // Cek AP utilization tinggi dari data Aruba
    const aruba = await this.fetchJSON('api/aruba.php?action=aps');
    (aruba.data?.devices || []).forEach(ap => {
      if ((ap.util_24 || 0) > 80) {
        alerts.push({
          level: 'warning',
          icon: 'ti-wifi-off',
          title: `${ap.name}: Channel utilization ${ap.util_24}%`,
          desc: 'Threshold 80% terlampaui — performa klien mungkin menurun',
          detail: `Aruba • ${ap.ip}`,
          action: () => App.optimizeAP(ap.name),
          actionLabel: 'Optimalkan',
        });
      }
      if (ap.status === 'offline') {
        alerts.push({
          level: 'critical',
          icon: 'ti-wifi-off',
          title: `${ap.name}: AP Offline`,
          desc: 'AP tidak terjangkau — periksa koneksi fisik dan PoE',
          detail: `Aruba • ${ap.ip}`,
        });
      }
    });

    // Cek VPN down dari Fortinet
    const vpn = await this.fetchJSON('api/fortinet.php?action=vpn');
    (vpn.data || []).forEach(v => {
      if (v.status === 'down') {
        alerts.push({
          level: 'warning',
          icon: 'ti-lock-off',
          title: `VPN ${v.peer||v.name}: Down`,
          desc: 'Tunnel tidak aktif — peer tidak merespons',
          detail: `Fortinet • ${v.type||'IPsec'}`,
          action: () => App.troubleshootVPN(v.peer||v.name),
          actionLabel: 'Troubleshoot',
        });
      }
    });

    // Cek Starlink latency/signal
    const sl = await this.fetchJSON('api/starlink.php?action=status');
    if (sl.data?.pop_ping_latency_ms > 150) {
      alerts.push({
        level: 'warning',
        icon: 'ti-satellite',
        title: `Starlink: Latency tinggi ${sl.data.pop_ping_latency_ms}ms`,
        desc: 'Latency melebihi threshold — kemungkinan obstruksi atau cuaca buruk',
        detail: 'Starlink Maritime',
      });
    }
    if (sl.data?.terminal_status === 'offline') {
      alerts.push({
        level: 'critical',
        icon: 'ti-satellite-off',
        title: 'Starlink: Terminal offline',
        desc: 'Koneksi satelit terputus — periksa fisik dish dan power',
        detail: 'Starlink Maritime',
      });
    }

    this.alertCount = alerts.length;
    const countEl = document.getElementById('alert-count-badge');
    if (countEl) {
      countEl.textContent = this.alertCount;
      countEl.style.display = this.alertCount > 0 ? 'inline' : 'none';
    }
    const dotEl = document.getElementById('alert-dot');
    if (dotEl) dotEl.style.display = this.alertCount > 0 ? 'block' : 'none';

    setEl('ov-alert-count', this.alertCount);
    setEl('ov-alert-sub', this.alertCount > 0 ? 'Perlu perhatian' : 'Semua normal');

    const container = document.getElementById('alerts-container');
    const summaryEl = document.getElementById('alert-summary-text');

    if (!container) return;
    if (summaryEl) summaryEl.textContent = `${this.alertCount} alert aktif`;

    if (alerts.length === 0) {
      container.innerHTML = `<div class="no-alerts"><i class="ti ti-circle-check"></i><div>Semua sistem normal</div><small>Tidak ada alert aktif</small></div>`;
      return;
    }

    container.innerHTML = alerts.map((a, i) => `
      <div class="alert-item alert-${a.level}">
        <i class="ti ${a.icon} alert-icon"></i>
        <div class="alert-body">
          <div class="alert-title">${escHtml(a.title)}</div>
          <div class="alert-desc">${escHtml(a.desc)}</div>
          <div class="alert-meta">${a.level === 'critical' ? 'Kritis' : 'Peringatan'} • ${a.detail}</div>
          <div class="alert-actions">
            ${a.action ? `<button class="btn btn-xs btn-danger-xs" onclick="App.alertActions[${i}] && App.alertActions[${i}]()">
              <i class="ti ti-tool"></i> ${a.actionLabel}
            </button>` : ''}
            <button class="btn btn-xs" onclick="this.closest('.alert-item').remove(); App.alertCount--;App.updateAlertCount()">Abaikan</button>
          </div>
        </div>
      </div>`).join('');

    this.alertActions = alerts.map(a => a.action);
  },

  updateAlertCount() {
    const countEl = document.getElementById('alert-count-badge');
    if (countEl) { countEl.textContent = this.alertCount; countEl.style.display = this.alertCount > 0 ? 'inline' : 'none'; }
  },

  clearAllAlerts() {
    const container = document.getElementById('alerts-container');
    if (container) container.innerHTML = `<div class="no-alerts"><i class="ti ti-circle-check"></i><div>Semua bersih</div><small>Semua alert telah ditandai dibaca</small></div>`;
    this.alertCount = 0;
    this.updateAlertCount();
    document.getElementById('alert-dot').style.display = 'none';
  },

  // ============================================================
  // AI ASISTEN
  // ============================================================
  async sendAIQuestion() {
    const qEl  = document.getElementById('ai-question');
    const btn  = document.getElementById('ai-send-btn');
    const q    = qEl.value.trim();
    if (!q) return;

    btn.disabled = true;
    document.getElementById('ai-loading').style.display = 'flex';
    document.getElementById('ai-response-card').style.display = 'none';

    const r = await this.fetchJSON('api/ai.php', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({question: q, history: this.aiHistory}),
    });

    document.getElementById('ai-loading').style.display = 'none';
    btn.disabled = false;

    if (r.error) {
      document.getElementById('ai-response-text').innerHTML = `<span class="text-danger">${escHtml(r.error)}</span>`;
    } else {
      this.aiHistory.push({role: 'user', content: q});
      this.aiHistory.push({role: 'assistant', content: r.answer});

      const formatted = (r.answer || '')
        .replace(/```([\s\S]*?)```/g, '<pre class="code-block">$1</pre>')
        .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
        .replace(/\n\n/g, '</p><p>')
        .replace(/\n/g, '<br>');
      document.getElementById('ai-response-text').innerHTML = `<p>${formatted}</p>`;

      // Tambah ke history
      const histWrap = document.getElementById('ai-history-wrap');
      const histList = document.getElementById('ai-history-list');
      if (histWrap) histWrap.style.display = 'block';
      if (histList) {
        const item = document.createElement('div');
        item.className = 'hist-item';
        item.innerHTML = `<i class="ti ti-message"></i> ${escHtml(q.slice(0, 70))}${q.length > 70 ? '...' : ''}`;
        item.onclick = () => { document.getElementById('ai-question').value = q; };
        histList.prepend(item);
      }
    }

    document.getElementById('ai-response-card').style.display = 'block';
    qEl.value = '';
    this.addLog('AI konsultasi: ' + q.slice(0, 50), 'info');
  },

  quickAI(q) {
    document.getElementById('ai-question').value = q;
    this.sendAIQuestion();
  },

  // ============================================================
  // SETTINGS / TEST KONEKSI
  // ============================================================
  async testDevice(device) {
    const msgId = {fortinet: 'ft-test-msg', aruba: 'ar-test-msg', starlink: 'sl-test-msg'}[device];
    const el = document.getElementById(msgId);
    if (!el) return;
    el.textContent = 'Mengetes...';
    el.className = 'test-msg loading';

    const r = await this.fetchJSON(`api/${device}.php?action=test`);
    el.textContent = r.message || (r.success ? 'Berhasil' : 'Gagal');
    el.className = 'test-msg ' + (r.success ? 'success' : 'error');
  },

  // ============================================================
  // DEVICE ACTIONS
  // ============================================================
  async rebootAP(name, ip) {
    if (!confirm(`Reboot ${name} (${ip})? AP akan offline sementara.`)) return;
    this.addLog(`Reboot AP ${name} diminta`, 'warn');
    alert(`Perintah reboot dikirim ke ${name}. AP akan kembali dalam ~2 menit.`);
  },

  optimizeAP(name) {
    this.quickAI(`AP Aruba Instant On "${name}" memiliki channel utilization tinggi (>80%). Berikan langkah optimasi: apakah perlu ganti channel, aktifkan band steering, atau tambah AP? Jelaskan step-by-stepnya.`);
    switchTab('ai');
  },

  troubleshootVPN(peer) {
    this.quickAI(`VPN tunnel ke "${peer}" dalam status DOWN di FortiGate 60F. Berikan langkah troubleshooting lengkap: cek log, cek phase1/phase2, dan perintah CLI diagnostik yang diperlukan.`);
    switchTab('ai');
  },

  editPolicy(id) {
    alert(`Edit policy #${id} — integrasikan dengan Fortinet REST API di api/fortinet.php`);
  },

  async deletePolicy(id, name) {
    if (!confirm(`Hapus policy "${name}" (#${id})?`)) return;
    this.addLog(`Delete policy Fortinet #${id}: ${name}`, 'warn');
    alert(`Policy #${id} (${name}) akan dihapus via Fortinet API.`);
  },

  showPolicyModal() {
    document.getElementById('policy-modal').style.display = 'flex';
  },

  async submitPolicy() {
    const data = {
      name:    document.getElementById('pm-name').value,
      srcintf: document.getElementById('pm-src-intf').value,
      dstintf: document.getElementById('pm-dst-intf').value,
      action:  document.getElementById('pm-action').value,
      nat:     document.getElementById('pm-nat').value,
      logtraffic: document.getElementById('pm-log').value,
      status:  'enable',
    };
    const r = await this.fetchJSON('api/fortinet.php?action=add_policy', {
      method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data),
    });
    document.getElementById('policy-modal').style.display = 'none';
    this.addLog(`Tambah policy: ${data.name}`, 'ok');
    this.loadFortinet();
  },

  exportConfig() {
    window.open('api/export_config.php', '_blank');
  },

  addLog(msg, type = 'info') {
    const el = document.getElementById('ov-log');
    if (!el) return;
    const time = new Date().toLocaleTimeString('id-ID', {hour12: false});
    const div = document.createElement('div');
    div.className = `log-${type}`;
    div.textContent = `[${time}] ${msg}`;
    el.prepend(div);
    while (el.children.length > 30) el.removeChild(el.lastChild);
  },
};

// ============================================================
// HELPERS
// ============================================================
function setEl(id, val) {
  const el = document.getElementById(id);
  if (el) el.textContent = val;
}
function setBar(id, pct) {
  const el = document.getElementById(id);
  if (el) el.style.width = Math.min(100, Math.max(0, pct)) + '%';
}
function escHtml(s) {
  return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
function formatUptime(sec) {
  const d = Math.floor(sec / 86400);
  const h = Math.floor((sec % 86400) / 3600);
  return `${d}d ${h}h`;
}

function switchTab(tab) {
  document.querySelectorAll('.navtab').forEach(t => t.classList.remove('active'));
  document.querySelectorAll('.tab-pane').forEach(p => p.classList.remove('active'));
  const btn = document.querySelector(`.navtab[data-tab="${tab}"]`);
  if (btn) btn.classList.add('active');
  const pane = document.getElementById(`tab-${tab}`);
  if (pane) pane.classList.add('active');
}

function switchSubTab(parent, sub) {
  const container = document.getElementById(`tab-${parent}`);
  if (!container) return;
  container.querySelectorAll('.sub-tab').forEach(t => t.classList.remove('active'));
  container.querySelectorAll('.sub-pane').forEach(p => p.classList.remove('active'));
  event.target.classList.add('active');
  const pane = document.getElementById(`${parent[0]}t-${sub}`);
  if (pane) pane.classList.add('active');
}

function runFtCLI()    { App.runFtCLI(); }
function setCLI(cmd)   { const el = document.getElementById('ft-cli-inp'); if(el) el.value = cmd; }
function refreshAll()  { App.loadAll(); }
function clearAllAlerts() { App.clearAllAlerts(); }
function testDevice(d) { App.testDevice(d); }
function showPolicyModal() { App.showPolicyModal(); }
function sendAIQuestion()  { App.sendAIQuestion(); }
function quickAI(q)   { App.quickAI(q); }
function exportConfig() { App.exportConfig(); }

// Handle URL param tab
const urlTab = new URLSearchParams(window.location.search).get('tab');
if (urlTab) switchTab(urlTab);

document.addEventListener('DOMContentLoaded', () => App.init());
