(() => {
  'use strict';

const BASE_API = '/mikrotik/admin/api/';

const URLS = {
  counts: BASE_API + 'noc_counts.php',
  routers: BASE_API + 'noc_routers_card.php',
  sectors: BASE_API + 'noc_sectors_card.php',
  receivers: BASE_API + 'noc_receivers_card.php',
  traffic: BASE_API + 'noc_traffic_card.php',
  billing: BASE_API + 'billing_alerts.php'
};
  const UI_REFRESH_MS = 5000;
  const DATA_REFRESH_MS = 5000;
  const TRAFFIC_UI_MS = 3000;
  const MAX_HISTORY = 28;

  const state = {
    counts: null,
    routers: null,
    sectors: null,
    receivers: null,
    traffic: null,
    billing: null,
    history: { total: [], rx: [], tx: [] },
    sourceHistory: new Map(),
    lastFetched: {}, inFlight: {}
  };

  const $ = (id) => document.getElementById(id);
  const num = (v, d = 0) => { const n = parseFloat(v); return Number.isFinite(n) ? n : d; };
  const esc = (v) => String(v ?? '').replace(/[&<>'"]/g, (ch) => ({ '&':'&amp;','<':'&lt;','>':'&gt;',"'":'&#39;','"':'&quot;' }[ch]));
  const fmt1 = (v) => num(v, 0).toFixed(1);
  const setText = (id, value) => { const el = $(id); if (el) el.textContent = value; };

  async function fetchJson(url) {
    const res = await fetch(url + (url.includes('?') ? '&' : '?') + '_=' + Date.now(), { cache: 'no-store', credentials: 'same-origin' });
    if (!res.ok) throw new Error('HTTP ' + res.status);
    return await res.json();
  }

  function shouldFetch(key, now = Date.now()) {
    return !state.lastFetched[key] || (now - state.lastFetched[key]) >= DATA_REFRESH_MS;
  }

  async function softFetch(key, url) {
    if (state.inFlight[key] || !shouldFetch(key)) return;
    state.inFlight[key] = true;
    state.lastFetched[key] = Date.now();
    try {
      const payload = await fetchJson(url);
      if (payload && typeof payload === 'object') { state[key] = payload; renderAll(); }
    } catch (_) {
    } finally {
      state.inFlight[key] = false;
    }
  }

  function meterClass(value) {
    const v = num(value, 0);
    if (v >= 85) return 'danger';
    if (v >= 65) return 'warn';
    return 'ok';
  }
  function statusClass(stateText) {
    const s = String(stateText || '').toUpperCase();
    if (s === 'ONLINE' || s === 'UP') return 'online';
    if (s === 'PARTIAL' || s === 'ONLINE_PARTIAL') return 'partial';
    if (s === 'WARN' || s === 'WARNING') return 'warn';
    return 'offline';
  }
  function statusLabel(stateText) {
    const s = String(stateText || '').toUpperCase();
    if (s === 'ONLINE' || s === 'UP') return 'ONLINE';
    if (s === 'PARTIAL' || s === 'ONLINE_PARTIAL') return 'PARTIAL';
    if (s === 'WARN' || s === 'WARNING') return 'WARN';
    return 'OFFLINE';
  }
  function renderMeter(value) {
    const v = Math.max(0, Math.min(100, Math.round(num(value, 0))));
    const cls = meterClass(v);
    return `<div class="nocx-meter ${cls}"><div class="nocx-meter__bar"><i style="width:${v}%"></i></div><strong>${v}%</strong></div>`;
  }

  function drawMainChart() {
    const canvas = $('trafficCanvas');
    if (!canvas) return;
    const dpr = Math.max(1, window.devicePixelRatio || 1);
    const box = canvas.parentElement?.getBoundingClientRect();
    const width = Math.max(480, Math.floor((box?.width || canvas.clientWidth || 900) * dpr));
    const height = Math.max(220, Math.floor((box?.height || canvas.clientHeight || 250) * dpr));
    if (canvas.width !== width || canvas.height !== height) { canvas.width = width; canvas.height = height; }
    const ctx = canvas.getContext('2d'); if (!ctx) return;
    ctx.clearRect(0, 0, width, height);
    const pad = { top: 18*dpr, right:16*dpr, bottom:24*dpr, left:42*dpr };
    const innerW = width-pad.left-pad.right; const innerH = height-pad.top-pad.bottom;
    const maxVal = Math.max(8, ...state.history.total, ...state.history.rx, ...state.history.tx) * 1.2;
    ctx.lineWidth = 1*dpr; ctx.font = `${11*dpr}px sans-serif`; ctx.fillStyle = 'rgba(196,216,255,.55)';
    for (let i=0;i<=4;i++) { const y=pad.top + (innerH/4)*i; ctx.beginPath(); ctx.moveTo(pad.left,y); ctx.lineTo(width-pad.right,y); ctx.strokeStyle='rgba(255,255,255,.07)'; ctx.stroke(); ctx.fillText(((maxVal*(4-i))/4).toFixed(0), 6*dpr, y+4*dpr); }
    const len = Math.max(state.history.total.length, 2);
    for (let i=0;i<len;i++) { const x=pad.left + (innerW/(len-1))*i; ctx.beginPath(); ctx.moveTo(x,pad.top); ctx.lineTo(x,height-pad.bottom); ctx.strokeStyle='rgba(255,255,255,.035)'; ctx.stroke(); }
    const drawSeries = (values, stroke, fillTop) => {
      if (!values.length) return;
      ctx.beginPath(); values.forEach((v,i)=>{ const x=pad.left + (innerW/Math.max(1,values.length-1))*i; const y=pad.top+innerH-(num(v,0)/maxVal)*innerH; if(!i) ctx.moveTo(x,y); else ctx.lineTo(x,y); });
      ctx.strokeStyle=stroke; ctx.lineWidth=3*dpr; ctx.shadowColor=stroke; ctx.shadowBlur=14*dpr; ctx.stroke(); ctx.shadowBlur=0;
      ctx.beginPath(); values.forEach((v,i)=>{ const x=pad.left + (innerW/Math.max(1,values.length-1))*i; const y=pad.top+innerH-(num(v,0)/maxVal)*innerH; if(!i) ctx.moveTo(x,y); else ctx.lineTo(x,y); });
      ctx.lineTo(pad.left+innerW,pad.top+innerH); ctx.lineTo(pad.left,pad.top+innerH); ctx.closePath();
      const g=ctx.createLinearGradient(0,pad.top,0,pad.top+innerH); g.addColorStop(0,fillTop); g.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=g; ctx.fill();
    };
    drawSeries(state.history.rx, '#4ab8ff', 'rgba(74,184,255,.18)');
    drawSeries(state.history.tx, '#ffb055', 'rgba(255,176,85,.14)');
  }

  function drawMiniSpark(canvas, values) {
    if (!canvas) return;
    const dpr = Math.max(1, window.devicePixelRatio || 1);
    const box = canvas.getBoundingClientRect();
    const width = Math.max(120, Math.floor((box.width || 160) * dpr));
    const height = Math.max(34, Math.floor((box.height || 40) * dpr));
    if (canvas.width !== width || canvas.height !== height) { canvas.width = width; canvas.height = height; }
    const ctx = canvas.getContext('2d'); if (!ctx) return; ctx.clearRect(0, 0, width, height); if (!values?.length) return;
    const maxVal = Math.max(2, ...values) * 1.15; const pad = 4 * dpr;
    ctx.beginPath(); values.forEach((v, i) => { const x = pad + ((width - pad * 2) / Math.max(1, values.length - 1)) * i; const y = height - pad - (num(v, 0) / maxVal) * (height - pad * 2); if (!i) ctx.moveTo(x, y); else ctx.lineTo(x, y); });
    ctx.strokeStyle = '#4ab8ff'; ctx.lineWidth = 2 * dpr; ctx.stroke();
  }

  function renderRouters() {
    const list = $('routerList');
    const payload = state.routers || { items: [], online: 0, total: 0 };
    const routers = Array.isArray(payload.items) ? payload.items : [];
    setText('routersOnlineCount', payload.online ?? 0);
    setText('routersTotalCount', payload.total ?? routers.length);
    setText('summaryRoutersOnline', payload.online ?? 0);
    if (!list) return;
    if (!routers.length) { list.innerHTML = '<div class="nocx-empty">بانتظار قراءة الراوترات...</div>'; return; }
    list.innerHTML = routers.map((r) => `
      <article class="nocx-router-item">
        <div class="nocx-router-head">
          <div class="nocx-router-name">
            <strong>${esc(r.name || r.identity || 'Router')}</strong>
            <small>${esc(r.model || '—')} · ${esc(r.host || '—')}</small>
          </div>
          <span class="nocx-status-badge ${statusClass(r.state)}">${statusLabel(r.state)}</span>
        </div>
        <div class="nocx-router-meta">
          <div class="nocx-router-meta-item"><span>CPU</span><strong>${renderMeter(r.cpu_pct)}</strong></div>
          <div class="nocx-router-meta-item"><span>RAM</span><strong>${renderMeter(r.ram_pct)}</strong></div>
          <div class="nocx-router-meta-item"><span>جلسات/حمل</span><strong>${esc(r.ppp_active ?? '—')}</strong></div>
          <div class="nocx-router-meta-item"><span>Uptime</span><strong>${esc(r.uptime || '—')}</strong></div>
        </div>
      </article>`).join('');
  }

  function onlineish(item) {
    if (!item || typeof item !== 'object') return false;
    const s = String(item.state || '').toUpperCase();
    if (s === 'ONLINE' || s === 'UP') return true;
    return item.cpu !== null || item.memory !== null || item.quality !== null || item.capacity !== null || item.model;
  }

  function statusClassForItem(item) {
    return onlineish(item) ? 'online' : statusClass(item.state);
  }
  function statusLabelForItem(item) {
    return onlineish(item) ? 'ONLINE' : statusLabel(item.state);
  }

  function airmaxRowSector(item) {
    return `
      <tr>
        <td><div class="nocx-host-cell"><strong>${esc(item.name || '—')}</strong><small>${esc(item.host || '—')}</small></div></td>
        <td>${esc(item.model || '—')}</td>
        <td>${item.cpu !== null && item.cpu !== undefined ? renderMeter(item.cpu) : '—'}</td>
        <td>${item.memory !== null && item.memory !== undefined ? renderMeter(item.memory) : '—'}</td>
        <td><span class="nocx-status-badge ${statusClassForItem(item)}">${statusLabelForItem(item)}</span></td>
      </tr>`;
  }

  function airmaxRowReceiver(item) {
    return `
      <tr>
        <td><div class="nocx-host-cell"><strong>${esc(item.name || '—')}</strong><small>${esc(item.host || '—')}</small></div></td>
        <td>${esc(item.model || '—')}</td>
        <td>${item.quality !== null && item.quality !== undefined ? renderMeter(item.quality) : '—'}</td>
        <td>${item.capacity !== null && item.capacity !== undefined ? renderMeter(item.capacity) : '—'}</td>
        <td>${item.cpu !== null && item.cpu !== undefined ? renderMeter(item.cpu) : '—'}</td>
        <td>${item.memory !== null && item.memory !== undefined ? renderMeter(item.memory) : '—'}</td>
        <td><span class="nocx-status-badge ${statusClassForItem(item)}">${statusLabelForItem(item)}</span></td>
      </tr>`;
  }

  function renderAirmax() {
    const sectorsPayload = state.sectors || { items: [], summary: { total: 0, down: 0 } };
    const receiversPayload = state.receivers || { items: [], summary: { total: 0, total_stations: 0 } };
    const sectors = Array.isArray(sectorsPayload.items) ? sectorsPayload.items : [];
    const subtowers = Array.isArray(receiversPayload.items) ? receiversPayload.items : [];
    const sectorBody = $('sectorTableBody');
    const subtowerBody = $('subtowerTableBody');
    const receiverStationsBody = $('receiverStationsBody');
    setText('sectorsDownCount', sectorsPayload.summary?.down ?? 0);
    setText('sectorsTotalCount', sectorsPayload.summary?.total ?? sectors.length);
    setText('summarySectorsDown', sectorsPayload.summary?.down ?? 0);
    const totalStations = receiversPayload.summary?.total_stations ?? subtowers.reduce((a,it)=>a+num(it.stations ?? it.clients,0),0);
    setText('subtowerStationsCount', totalStations);
    setText('subtowerTotalCount', receiversPayload.summary?.total ?? subtowers.length);
    setText('summaryReceivers', receiversPayload.summary?.total ?? subtowers.length);
    if (sectorBody) sectorBody.innerHTML = sectors.length ? sectors.map(airmaxRowSector).join('') : '<tr><td colspan="5" class="nocx-empty-cell">لا توجد بيانات سكتورات حالياً.</td></tr>';
    if (subtowerBody) subtowerBody.innerHTML = subtowers.length ? subtowers.map(airmaxRowReceiver).join('') : '<tr><td colspan="7" class="nocx-empty-cell">لا توجد بيانات حالياً.</td></tr>';
    if (receiverStationsBody) {
      receiverStationsBody.innerHTML = subtowers.length ? subtowers.map((it) => `<div class="nocx-receiver-station"><strong>${esc(it.name || '—')}</strong><span>${esc(it.stations ?? it.clients ?? 0)}</span></div>`).join('') : '<div class="nocx-empty">لا توجد بيانات حالياً.</div>';
    }
  }


  function renderAlerts() {
    const wrap = $('alertFeed');
    if (!wrap) return;
    const alerts = [];
    const counts = state.counts || {};
    const unsafe = num(counts.unsafe_speed, 0);
    if (unsafe > 0) {
      alerts.push(`<article class="nocx-alert-item warn"><div class="nocx-alert-item__top"><strong class="nocx-alert-item__title">تنبيه تقييد السرعة</strong><small class="nocx-alert-item__meta">السرعات</small></div><div class="nocx-alert-item__text">يوجد ${unsafe} حساب يعمل بلا تقييد سرعة فعلي.</div></article>`);
    }
    const sectorsDown = num(state.sectors?.summary?.down, 0);
    if (sectorsDown > 0) {
      alerts.push(`<article class="nocx-alert-item danger"><div class="nocx-alert-item__top"><strong class="nocx-alert-item__title">السكتورات</strong><small class="nocx-alert-item__meta">airMAX</small></div><div class="nocx-alert-item__text">يوجد ${sectorsDown} سكتور بحالة DOWN.</div></article>`);
    }
    const receiversDown = (Array.isArray(state.receivers?.items) ? state.receivers.items.filter((it) => String(it.state || '').toUpperCase() === 'DOWN' || String(it.state || '').toUpperCase() === 'OFFLINE').length : 0);
    if (receiversDown > 0) {
      alerts.push(`<article class="nocx-alert-item warn"><div class="nocx-alert-item__top"><strong class="nocx-alert-item__title">المستقبلات</strong><small class="nocx-alert-item__meta">PowerBeam</small></div><div class="nocx-alert-item__text">يوجد ${receiversDown} مستقبل بحالة DOWN/OFFLINE.</div></article>`);
    }
    const billingItems = Array.isArray(state.billing?.items) ? state.billing.items : [];
    billingItems.forEach((item) => {
      const level = String(item.kind || 'warn').toLowerCase();
      const btn = item.requires_approval ? `<div style="margin-top:8px"><button type="button" class="btn btn-sm btn-light js-billing-approve" data-queue-id="${esc(item.id)}">موافقة وتنفيذ</button></div>` : '';
      alerts.push(`<article class="nocx-alert-item ${level}"><div class="nocx-alert-item__top"><strong class="nocx-alert-item__title">${esc(item.title || 'تنبيه')}</strong><small class="nocx-alert-item__meta">الفوترة</small></div><div class="nocx-alert-item__text">${esc(item.message || '')}</div>${btn}</article>`);
    });
    setText('nocAlertCount', alerts.length);
    wrap.innerHTML = alerts.length ? alerts.join('') : '<div class="nocx-empty">لا يوجد إنذارات حالياً.</div>';
  }

  function renderSummary() {
    const counts = state.counts || {};
    let pppActive = counts.ppp_active ?? 0;
    if (!pppActive && state.routers?.items?.length) {
      pppActive = state.routers.items.reduce((sum, r) => sum + num(r.ppp_active, 0), 0);
    }
    setText('nocPppActiveTop', pppActive);
    setText('summaryOpenAllMode', num(counts.open_all_mode, 0) === 1 ? 'مفتوحة' : 'طبيعية');
  }

  function pushHistory(name, value) { const arr = state.history[name]; if (!arr) return; arr.push(num(value, 0)); while (arr.length > MAX_HISTORY) arr.shift(); }
  function pushSourceHistory(key, value) { if (!state.sourceHistory.has(key)) state.sourceHistory.set(key, []); const arr = state.sourceHistory.get(key); arr.push(num(value, 0)); while (arr.length > MAX_HISTORY) arr.shift(); }

  function renderTraffic() {
    const data = state.traffic || { sum: { rx_mbps: 0, tx_mbps: 0, total_mbps: 0 }, kpi: { wan_total_mbps: 0 }, iface: { selected: '', max_mbps: 300 }, sources: [] };
    setText('summaryTrafficTotal', fmt1(data.sum?.total_mbps ?? 0));
    setText('heroRx', fmt1(data.sum?.rx_mbps ?? 0) + ' Mbps');
    setText('heroTx', fmt1(data.sum?.tx_mbps ?? 0) + ' Mbps');
    setText('heroTotal', fmt1(data.sum?.total_mbps ?? 0) + ' Mbps');
    setText('trafficSourcesLabel', 'المصادر: ' + (data.iface?.selected || '—'));
    const maxMbps = Math.max(1, num(data.iface?.max_mbps, 300));
    const totalPct = Math.max(0, Math.min(100, (num(data.sum?.total_mbps, 0) / maxMbps) * 100));
    const bar = $('wanTotalBar'); if (bar) bar.style.width = `${totalPct}%`;
    pushHistory('rx', data.sum?.rx_mbps ?? 0); pushHistory('tx', data.sum?.tx_mbps ?? 0); pushHistory('total', data.sum?.total_mbps ?? 0);
    drawMainChart();
    const list = $('trafficRailList');
    const sources = Array.isArray(data.sources) ? data.sources : [];
    setText('trafficSourcesCount', sources.length);
    if (list) {
      if (!sources.length) list.innerHTML = '<div class="nocx-empty">لا توجد مصادر ترافيك معرفة.</div>';
      else {
        list.innerHTML = sources.map((src, idx) => {
          const key = `${src.router_id || 0}:${src.iface || idx}`;
          pushSourceHistory(key, src.total_mbps ?? 0);
          return `<article class="nocx-traffic-source"><div class="nocx-traffic-source__top"><div class="nocx-traffic-source__name"><strong>${esc(src.label || src.iface || 'Source')}</strong><small>${esc(src.router_name || '')}${src.iface ? ' · ' + esc(src.iface) : ''}</small></div><span class="nocx-status-badge ${src.ok ? 'online' : 'offline'}">${src.ok ? 'LIVE' : 'DOWN'}</span></div><div class="nocx-traffic-source__rates"><div><span>Up</span><strong>${fmt1(src.tx_mbps)} Mbps</strong></div><div><span>Down</span><strong>${fmt1(src.rx_mbps)} Mbps</strong></div><div><span>Total</span><strong>${fmt1(src.total_mbps)} Mbps</strong></div></div><div class="nocx-traffic-source__spark"><canvas data-source-key="${esc(key)}"></canvas></div></article>`;
        }).join('');
        list.querySelectorAll('canvas[data-source-key]').forEach((canvas) => drawMiniSpark(canvas, state.sourceHistory.get(canvas.getAttribute('data-source-key')) || []));
      }
    }
  }

  function renderAll() { renderSummary(); renderRouters(); renderAirmax(); renderTraffic(); renderAlerts(); }

  async function pollCore() {
    await Promise.allSettled([
      softFetch('counts', URLS.counts),
      softFetch('routers', URLS.routers),
      softFetch('sectors', URLS.sectors),
      softFetch('receivers', URLS.receivers),
      softFetch('traffic', URLS.traffic),
      softFetch('billing', URLS.billing)
    ]);
  }

  setInterval(() => { void pollCore(); }, UI_REFRESH_MS);
  window.addEventListener('resize', () => { drawMainChart(); document.querySelectorAll('canvas[data-source-key]').forEach((canvas) => drawMiniSpark(canvas, state.sourceHistory.get(canvas.getAttribute('data-source-key')) || [])); });
  pollCore();
})();
