<?php
// admin/footer.php (Unified lightweight footer - footer bar removed)
?>

<?php if (defined('UA_LIGHTWEIGHT_FRAME') && UA_LIGHTWEIGHT_FRAME): ?>
  </div>
</main>
</div>
</body>
</html>
<?php return; endif; ?>

<?php /* Final shell guards now load from header.php, not the footer, so pages do not repaint after content appears. */ ?>
<?php /* Legacy page skins remain disabled: ua_network_phase1.css, ua_page_unified_dark.css, ua_billing_phase2.css, ua_invoice_tables_master.css */ ?>
<?php /* page-by-page rebuild mode: old global compact stylesheet intentionally not loaded */ ?>

  </div>
</main>
</div>

<?php $ua_v_modern_js  = @filemtime(__DIR__ . '/assets/js/ua_modern.js') ?: time(); ?>
<?php $ua_v_sidebar_js = @filemtime(__DIR__ . '/assets/js/ua_sidebar3.js') ?: time(); ?>
<script src="assets/js/ua_modern.js?v=<?= (int)$ua_v_modern_js ?>"></script>
<script src="assets/js/ua_sidebar3.js?v=<?= (int)$ua_v_sidebar_js ?>"></script>
<?php $ua_v_global_feedback_js = @filemtime(__DIR__ . '/assets/js/ua_global_feedback.js') ?: time(); ?>
<script src="assets/js/ua_global_feedback.js?v=<?= (int)$ua_v_global_feedback_js ?>"></script>
<?php $ua_v_empty_states_js = @filemtime(__DIR__ . '/assets/js/ua_empty_states.js') ?: time(); ?>
<script src="assets/js/ua_empty_states.js?v=<?= (int)$ua_v_empty_states_js ?>"></script>
<?php $ua_v_workspace_registry_js = @filemtime(__DIR__ . '/assets/js/ua_workspace_registry.js') ?: time(); ?>
<script src="assets/js/ua_workspace_registry.js?v=<?= (int)$ua_v_workspace_registry_js ?>"></script>
<?php $ua_v_wm_js = @filemtime(__DIR__ . '/assets/js/ua_window_manager.js') ?: time(); ?>
<script src="assets/js/ua_window_manager.js?v=<?= (int)$ua_v_wm_js ?>"></script>
<?php if (defined('UA_ANDROID_APP') && UA_ANDROID_APP): ?>
  <?php $ua_v_android_app_js = @filemtime(__DIR__ . '/assets/js/ua_android_app.js') ?: time(); ?>
  <script src="assets/js/ua_android_app.js?v=<?= (int)$ua_v_android_app_js ?>"></script>
<?php endif; ?>
<?php $ua_v_shell_contract_js = @filemtime(__DIR__ . '/assets/js/ua_app_shell_contract.js') ?: time(); ?>
<script src="assets/js/ua_app_shell_contract.js?v=<?= (int)$ua_v_shell_contract_js ?>"></script>
<?php /* v13: ua_page_frame_normalizer.js intentionally not loaded; page extraction is CSS/class based. */ ?>
<?php $ua_v_network_phase1_js = @filemtime(__DIR__ . '/assets/js/ua_network_phase1.js') ?: time(); ?>
<script src="assets/js/ua_network_phase1.js?v=<?= (int)$ua_v_network_phase1_js ?>"></script>
<?php if (function_exists('ua_i18n_json_payload')): ?>
<script>window.UA_I18N = <?= ua_i18n_json_payload() ?: '{}' ?>;</script>
<?php $ua_v_i18n_js = @filemtime(__DIR__ . '/assets/js/ua_i18n.js') ?: time(); ?>
<script src="assets/js/ua_i18n.js?v=<?= (int)$ua_v_i18n_js ?>"></script>
<?php endif; ?>

<script>
(function(){
  var body = document.body;
  if (!body) return;
  var inFrame = false;
  try { inFrame = window.self !== window.top; } catch(e) { inFrame = true; }
  var params = new URLSearchParams(window.location.search || '');
  var frameMode = inFrame || params.has('iframe') || params.has('ua_tab') || body.classList.contains('ua-frame-context') || body.classList.contains('ua-tab-iframe-body');
  if (!frameMode) return;

  document.documentElement.classList.add('ua-in-frame');
  body.classList.add('ua-tab-iframe-body');

  function framedHref(href){
    if (!href || href.charAt(0) === '#') return '';
    if (/^(javascript:|mailto:|tel:)/i.test(href)) return '';
    try {
      var u = new URL(href, window.location.href);
      if (u.origin !== window.location.origin) return '';
      if (/\.(pdf|zip|rar|7z|xlsx?|csv|docx?|png|jpe?g|webp|gif|svg)(\?|#|$)/i.test(u.pathname)) return '';
      var file = (u.pathname.split('/').pop() || '').toLowerCase();
      if (/^(api|ajax|cron)\//i.test(u.pathname.replace(/^\/+/, ''))) return '';
      if (file === 'logout.php' || file === 'index.php') return '';
      u.searchParams.set('iframe', '1');
      u.searchParams.set('ua_tab', '1');
      return u.pathname.split('/').pop() + u.search + u.hash;
    } catch(e) {
      return '';
    }
  }

  function patchLink(a){
    if (!a || a.dataset.uaFramePatched === '1') return;
    if (a.target && a.target !== '_self') return;
    if (a.hasAttribute('download') || a.hasAttribute('data-no-frame')) return;
    var next = framedHref(a.getAttribute('href') || '');
    if (!next) return;
    a.setAttribute('href', next);
    a.dataset.uaFramePatched = '1';
  }

  document.querySelectorAll('a[href]').forEach(patchLink);
  document.addEventListener('click', function(ev){
    var a = ev.target && ev.target.closest ? ev.target.closest('a[href]') : null;
    patchLink(a);
  }, true);
})();
</script>

<script>
(function(){
  const isDashboard = document.body.classList.contains('ua-page-dashboard');
  const chrome = document.body.classList.contains('ua-shell-chrome') && !isDashboard;
  function uaShellPollActive(){
    if (document.hidden) return false;
    try {
      if (window.self !== window.top) {
        const frame = window.frameElement;
        const pane = frame && frame.closest ? frame.closest('.ua-wm-pane') : null;
        if (pane) {
          const st = window.top.getComputedStyle ? window.top.getComputedStyle(pane) : null;
          if (pane.hidden || pane.getAttribute('aria-hidden') === 'true' || pane.classList.contains('is-minimized')) return false;
          if (st && (st.display === 'none' || st.visibility === 'hidden')) return false;
        }
      }
    } catch(e) {}
    return true;
  }

  const shell = document.querySelector('[data-ua-livebar]');
  if (shell) {
    const ids = {
      total: shell.querySelector('[data-ua-stat-value="total"]'),
      online: shell.querySelector('[data-ua-stat-value="online"]'),
      offline: shell.querySelector('[data-ua-stat-value="offline"]'),
      disabled: shell.querySelector('[data-ua-stat-value="disabled"]'),
      unsafe: shell.querySelector('[data-ua-stat-value="unsafe"]'),
      alertCount: shell.querySelector('[data-ua-alert-count]'),
      alertFeed: shell.querySelector('[data-ua-alert-feed]'),
      alertDetails: shell.querySelector('[data-ua-alert-details]'),
      traffic: shell.querySelector('[data-ua-stat-value="traffic"]'),
      trafficChip: shell.querySelector('.ua-livebar__traffic'),
      unsafeChip: shell.querySelector('[data-ua-unsafe-chip]'),
      system: shell.querySelector('[data-ua-system-state]')
    };
    const shellState = { counts:{}, billing:null, networkAlerts:[], securityAlerts:[], sectors:null, receivers:null };
    function toInt(v, fallback){ const n = parseInt(v, 10); return Number.isFinite(n) ? n : (fallback || 0); }
    function toFloat(v, fallback){ const n = parseFloat(v); return Number.isFinite(n) ? n : (fallback || 0); }
    function set(el, value){ if (el) el.textContent = value; }
    function esc(s){
      return String(s == null ? '' : s).replace(/[&<>"']/g, function(c){ return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'})[c]; });
    }
    function fmtTraffic(v){
      const n = Math.max(0, toFloat(v, 0));
      if (n >= 1000) return (n / 1000).toFixed(n >= 10000 ? 0 : 1) + ' Gbps';
      return n.toFixed(n >= 100 ? 0 : 1) + ' Mbps';
    }
    async function parseJsonResponse(res){
      const text = await res.text();
      return JSON.parse(String(text || '').replace(/^\uFEFF/, ''));
    }
    function alertDismissKey(key){ return 'ua_shell_alert_dismiss_' + String(key || '').replace(/[^a-zA-Z0-9_\-:.]/g,'_'); }
    function isDismissed(key){
      try { return sessionStorage.getItem(alertDismissKey(key)) === '1'; } catch(e){ return false; }
    }
    function dismissAlert(key){
      try { sessionStorage.setItem(alertDismissKey(key), '1'); } catch(e){}
      renderShellAlerts();
    }
    function buildAlertItem(o){
      const key = String(o.key || 'alert');
      if (isDismissed(key)) return '';
      const tone = String(o.tone || 'info');
      const title = String(o.title || 'تنبيه');
      const text = String(o.text || '');
      const count = o.count == null ? '' : String(o.count);
      const href = String(o.href || '');
      const tag = href ? 'a' : 'article';
      const attrs = href
        ? `href="${esc(href)}" class="nocx-alert-line ${esc(tone)}" data-ua-wm-open`
        : `class="nocx-alert-line ${esc(tone)}"`;
      const countHtml = count !== '' ? `<span class="nocx-alert-line__count">${esc(count)}</span>` : '';
      return `<${tag} ${attrs} data-alert-key="${esc(key)}">`
        + `<span class="nocx-alert-line__main">${countHtml}<strong class="nocx-alert-line__title">${esc(title)}</strong><span class="nocx-alert-line__text">${esc(text)}</span></span>`
        + `<button type="button" class="nocx-alert-line__close" data-alert-dismiss="${esc(key)}" aria-label="إغلاق">×</button>`
        + `</${tag}>`;
    }
    function setAlertBadge(n){
      if (!ids.alertCount) return;
      const v = Math.max(0, toInt(n,0));
      ids.alertCount.textContent = v > 0 ? String(v) : '';
      ids.alertCount.classList.toggle('is-zero', v <= 0);
    }
    function renderShellAlerts(){
      if (!ids.alertFeed) return;
      const counts = shellState.counts || {};
      const billing = shellState.billing || {};
      const cleanup = billing.cleanup || {};
      const pending = billing.pending || {};
      const generation = billing.generation || {};
      const alerts = [];
      const unsafe = toInt(counts.unsafe_speed, 0);
      const unsafeKnown = unsafe >= 0 && !String(counts.unsafe_source || '').includes('unavailable');
      if (unsafeKnown && unsafe > 0) alerts.push(buildAlertItem({key:'unsafe_speed_'+unsafe, tone:'warn', count:unsafe, title:'تنبيه تقييد السرعة', text:'حسابات تعمل بلا تقييد سرعة فعلي.'}));
      const sectorsDown = toInt(shellState.sectors && shellState.sectors.summary ? shellState.sectors.summary.alert_down : 0, 0);
      if (sectorsDown > 0) alerts.push(buildAlertItem({key:'sectors_down_'+sectorsDown, tone:'danger', count:sectorsDown, title:'السكتورات', text:'سكتورات بحالة DOWN.'}));
      const receiversDown = toInt(shellState.receivers && shellState.receivers.summary ? shellState.receivers.summary.alert_down : 0, 0);
      if (receiversDown > 0) alerts.push(buildAlertItem({key:'receivers_down_'+receiversDown, tone:'warn', count:receiversDown, title:'المستقبلات', text:'مستقبلات بحالة DOWN/OFFLINE.'}));
      if (toInt(pending.reminder,0) > 0) alerts.unshift(buildAlertItem({key:'pending_reminder_'+pending.reminder, href:'billing_message_requests.php', tone:'info', count:pending.reminder, title:'رسائل التسديد', text:'رسائل بانتظار مراجعة وموافقة السوبر أدمن.'}));
      if (toInt(pending.limit,0) > 0) alerts.unshift(buildAlertItem({key:'pending_limit_'+pending.limit, href:'billing_limit_requests.php', tone:'warn', count:pending.limit, title:'طلبات التخفيض', text:'طلبات جاهزة للمراجعة والموافقة.'}));
      if (toInt(pending.cut,0) > 0) alerts.unshift(buildAlertItem({key:'pending_cut_'+pending.cut, href:'billing_cut_requests.php', tone:'danger', count:pending.cut, title:'طلبات القطع', text:'طلبات جاهزة للمراجعة والموافقة.'}));
      if (toInt(billing.generated_count,0) > 0) alerts.push(buildAlertItem({key:'generated_'+billing.generated_count+'_'+((billing.cycle&&billing.cycle.label)||''), tone:'info', count:billing.generated_count, title:'الفواتير', text:'تم توليد فواتير الدورة الحالية.'}));
      if (toInt(generation.pricing_missing,0) > 0) alerts.unshift(buildAlertItem({key:'billing_pricing_missing_'+generation.pricing_missing, href:'subscribers.php', tone:'danger', count:generation.pricing_missing, title:'تسعير غير مكتمل', text:'مشتركون بلا سرعة مطابقة أو بلا سعر صالح؛ لن تُنشأ لهم فاتورة حتى تصحيح البيانات.'}));
      const netAlerts = Array.isArray(shellState.networkAlerts) ? shellState.networkAlerts : [];
      netAlerts.forEach(function(a){
        const sev = String(a.severity || 'warn');
        const tone = sev === 'danger' ? 'danger' : (sev === 'success' ? 'info' : sev);
        const msg = String(a.message || '');
        const href = String(a.href || '');
        alerts.unshift(buildAlertItem({
          key:'mtwatch_'+String(a.id || a.alert_key || msg),
          href:href,
          tone:tone,
          count:a.hit_count && a.hit_count > 1 ? a.hit_count : '!',
          title:String(a.title || 'تنبيه شبكة'),
          text:msg
        }));
      });
      const secAlerts = Array.isArray(shellState.securityAlerts) ? shellState.securityAlerts : [];
      secAlerts.forEach(function(a){
        const sev = String(a.severity || 'warn');
        const tone = sev === 'danger' ? 'danger' : (sev === 'success' ? 'info' : sev);
        const msg = String(a.message || '');
        const href = String(a.href || 'security_alerts.php');
        alerts.unshift(buildAlertItem({
          key:'security_'+String(a.id || a.alert_key || msg),
          href:href,
          tone:tone,
          count:a.hit_count && a.hit_count > 1 ? a.hit_count : '!',
          title:String(a.title || 'تنبيه أمان'),
          text:msg
        }));
      });
      const html = alerts.filter(Boolean).join('');
      const visibleCount = alerts.filter(Boolean).length;
      setAlertBadge(visibleCount);
      ids.alertFeed.innerHTML = html || '<div class="nocx-empty">لا يوجد إنذارات حالياً.</div>';
      ids.alertFeed.querySelectorAll('[data-alert-dismiss]').forEach(function(btn){
        btn.addEventListener('click', function(ev){ ev.preventDefault(); ev.stopPropagation(); dismissAlert(btn.getAttribute('data-alert-dismiss') || ''); });
      });
      ids.alertFeed.querySelectorAll('a[href]').forEach(function(link){
        link.addEventListener('click', function(){
          if (ids.alertDetails) ids.alertDetails.open = false;
        });
      });
    }
    function notifyBillingApprovals(billing){
      const pending = billing && billing.pending ? billing.pending : {};
      const reminder = toInt(pending.reminder,0);
      const limit = toInt(pending.limit,0);
      const cut = toInt(pending.cut,0);
      const total = reminder + limit + cut;
      let previous = 0;
      try { previous = toInt(sessionStorage.getItem('ua_billing_approval_total_v1'),0); } catch(e){}
      if (total > previous && typeof window.uaToast === 'function') {
        window.uaToast('توجد ' + total + ' عملية فوترة بانتظار موافقة السوبر أدمن.', cut > 0 ? 'error' : (limit > 0 ? 'warning' : 'info'));
      }
      try { sessionStorage.setItem('ua_billing_approval_total_v1', String(total)); } catch(e){}
    }
    function applySystemHealth(data){
      if (!ids.system) return;
      const label = ids.system.querySelector('[data-ua-system-label]');
      const routerOnline = Object.prototype.hasOwnProperty.call(data, 'router_online') ? data.router_online : null;
      const reliable = data.live_data_reliable === true || data.live_data_reliable === 1;
      const dataAvailable = data.data_available === true || data.data_available === 1;
      const dataAge = Math.max(0, toInt(data.data_age ?? data.ppp_cache_age ?? data.age, 0));
      let text = 'بيانات مخزنة';
      let tone = 'is-yellow';
      let title = 'تعرض الواجهة آخر لقطة محفوظة حتى تصل قراءة حية جديدة.';
      if (data.ok === false) {
        text = 'تعذر التحديث';
        tone = 'is-red';
        title = 'تعذر تحديث إحصاءات الشبكة.';
      } else if (dataAvailable && !reliable) {
        text = 'آخر قراءة';
        tone = 'is-yellow';
        title = 'تعذر تحديث RouterOS الآن. تُعرض آخر قراءة موثقة من الراوتر منذ ' + dataAge + ' ثانية دون تغيير حالة المشتركين بسبب انقطاع مسار الإدارة.';
      } else if (routerOnline === false) {
        text = 'غير متصل';
        tone = 'is-red';
        title = 'لا يوجد اتصال حي بالراوتر؛ أعداد الاتصال محسوبة من حالة الانقطاع الحالية.';
      } else if (routerOnline === true && reliable) {
        text = 'متصل';
        tone = 'is-green';
        title = 'الراوتر متصل والأرقام مبنية على قراءة حية موثوقة.';
      }
      ids.system.classList.remove('is-green','is-red','is-yellow','is-purple','is-pending');
      ids.system.classList.add(tone);
      ids.system.setAttribute('title', title);
      ids.system.dataset.routerOnline = routerOnline === null ? 'unknown' : (routerOnline ? '1' : '0');
      ids.system.dataset.liveReliable = reliable ? '1' : '0';
      set(label, text);
    }
    function applyTraffic(data){
      if (!data || typeof data !== 'object') return;
      if (shellState.counts && shellState.counts.router_online === false) {
        set(ids.traffic, '—');
        if (ids.trafficChip) {
          ids.trafficChip.classList.add('is-muted');
          ids.trafficChip.setAttribute('title', 'الترافيك الحي غير متاح لأن الراوتر غير متصل.');
        }
        return;
      }
      const sum = data.sum || {};
      const kpi = data.kpi || {};
      const total = toFloat(sum.total_mbps ?? kpi.wan_total_mbps, 0);
      set(ids.traffic, fmtTraffic(total));
      if (ids.trafficChip) {
        ids.trafficChip.classList.remove('is-muted');
        ids.trafficChip.setAttribute('title', 'إجمالي الترافيك الحي من مصادر WAN.');
      }
      try { sessionStorage.setItem('ua_shell_traffic_v1', JSON.stringify({ts:Date.now(), data:{total_mbps:total}})); } catch(e){}
    }
    function apply(data){
      if (!data || typeof data !== 'object') return;
      const total = toInt(data.total, 0);
      const online = toInt(data.online ?? data.connected, 0);
      const offline = toInt(data.offline, Math.max(0, total - online));
      const disabled = toInt(data.financial_cut ?? data.disabled, 0);
      const unsafe = toInt(data.unsafe_speed, 0);
      const unsafeSource = String(data.unsafe_source || '');
      const unsafeReliable = unsafeSource !== '' && !unsafeSource.includes('unavailable') && unsafeSource !== 'none';
      set(ids.total, total);
      set(ids.online, online);
      set(ids.offline, offline);
      set(ids.disabled, disabled);
      set(ids.unsafe, unsafeReliable ? unsafe : '—');
      if (ids.unsafeChip) {
        ids.unsafeChip.classList.toggle('is-muted', !unsafeReliable);
        ids.unsafeChip.setAttribute('title', unsafeReliable ? (unsafeSource.includes('database') ? 'العدد من حالة الحسابات المحفوظة حتى تتوفر قراءة MikroTik حية.' : 'حسابات تعمل بلا تقييد سرعة فعلي.') : 'تعذر تحديد عدد الحسابات غير المقيدة حالياً.');
      }
      shellState.counts = {
        total, online, offline, disabled, unsafe_speed:unsafe,
        router_online: Object.prototype.hasOwnProperty.call(data, 'router_online') ? data.router_online : null,
        live_data_reliable: data.live_data_reliable === true || data.live_data_reliable === 1,
        online_source: String(data.online_source || ''),
        disabled_source: String(data.disabled_source || ''),
        unsafe_source: String(data.unsafe_source || '')
      };
      applySystemHealth(Object.assign({}, data, shellState.counts));
      if (shellState.counts.router_online === false) applyTraffic({});
      renderShellAlerts();
      try { sessionStorage.setItem('ua_shell_counts_v3', JSON.stringify({ts:Date.now(), data:Object.assign({}, data, shellState.counts)})); } catch(e){}
    }
    try {
      const cached = JSON.parse(sessionStorage.getItem('ua_shell_counts_v3') || 'null');
      if (cached && cached.data) apply(cached.data);
    } catch(e){}
    try {
      const cachedTraffic = JSON.parse(sessionStorage.getItem('ua_shell_traffic_v1') || 'null');
      if (cachedTraffic && cachedTraffic.data) applyTraffic({sum:{total_mbps:cachedTraffic.data.total_mbps}});
    } catch(e){}
    let inFlight = false;
    let trafficInFlight = false;
    let billingInFlight = false;
    let networkAlertsInFlight = false;
    let securityAlertsInFlight = false;
    let infrastructureInFlight = false;
    const refreshAge = { counts: 15000, traffic: 15000, billing: 90000, network: 180000, security: 180000, infrastructure: 90000 };
    async function refresh(){
      if (inFlight || !uaShellPollActive()) return;
      inFlight = true;
      try {
        const res = await fetch('api/noc_counts.php?_=' + Date.now(), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json'}});
        if (res.ok) apply(await parseJsonResponse(res));
      } catch(e) {
      } finally {
        inFlight = false;
      }
    }
    async function refreshTraffic(){
      if (!ids.traffic || trafficInFlight || !uaShellPollActive()) return;
      if (shellState.counts && shellState.counts.router_online === false) {
        applyTraffic({});
        return;
      }
      trafficInFlight = true;
      try {
        const res = await fetch('api/noc_traffic_card.php?cache_only=1&_=' + Date.now(), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json'}});
        if (res.ok) applyTraffic(await parseJsonResponse(res));
      } catch(e) {
      } finally {
        trafficInFlight = false;
      }
    }
    async function refreshBilling(){
      if (!ids.alertFeed || billingInFlight || !uaShellPollActive()) return;
      billingInFlight = true;
      try {
        const res = await fetch('api/billing_alerts.php?_=' + Date.now(), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json'}});
        if (res.ok) {
          const data = await parseJsonResponse(res);
          shellState.billing = data && typeof data === 'object' ? data : {};
          renderShellAlerts();
          notifyBillingApprovals(shellState.billing);
        }
      } catch(e) {
      } finally {
        billingInFlight = false;
      }
    }
    async function refreshNetworkAlerts(){
      if (!ids.alertFeed || networkAlertsInFlight || !uaShellPollActive()) return;
      networkAlertsInFlight = true;
      try {
        const res = await fetch('api/subscriber_network_alerts.php?_=' + Date.now(), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json'}});
        if (res.ok) {
          const data = await parseJsonResponse(res);
          shellState.networkAlerts = data && Array.isArray(data.alerts) ? data.alerts : [];
          renderShellAlerts();
        }
      } catch(e) {
      } finally {
        networkAlertsInFlight = false;
      }
    }
    async function refreshSecurityAlerts(){
      if (!ids.alertFeed || securityAlertsInFlight || !uaShellPollActive()) return;
      securityAlertsInFlight = true;
      try {
        const res = await fetch('api/security_alerts.php?_=' + Date.now(), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json'}});
        if (res.ok) {
          const data = await parseJsonResponse(res);
          shellState.securityAlerts = data && Array.isArray(data.alerts) ? data.alerts : [];
          renderShellAlerts();
        }
      } catch(e) {
      } finally {
        securityAlertsInFlight = false;
      }
    }
    async function refreshInfrastructureAlerts(){
      if (!ids.alertFeed || infrastructureInFlight || !uaShellPollActive()) return;
      infrastructureInFlight = true;
      try {
        const results = await Promise.allSettled([
          fetch('api/noc_sectors_card.php?_=' + Date.now(), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json'}}),
          fetch('api/noc_receivers_card.php?_=' + Date.now(), {credentials:'same-origin', cache:'no-store', headers:{'Accept':'application/json'}})
        ]);
        if (results[0].status === 'fulfilled' && results[0].value.ok) shellState.sectors = await parseJsonResponse(results[0].value);
        if (results[1].status === 'fulfilled' && results[1].value.ok) shellState.receivers = await parseJsonResponse(results[1].value);
        renderShellAlerts();
      } catch(e) {
      } finally {
        infrastructureInFlight = false;
      }
    }
    if (ids.alertDetails) {
      document.addEventListener('click', function(ev){
        if (!ids.alertDetails.open) return;
        if (ids.alertDetails.contains(ev.target)) return;
        ids.alertDetails.open = false;
      });
    }
    setTimeout(function(){ refresh(); }, 250);
    setTimeout(function(){ refreshTraffic(); }, 900);
    setTimeout(function(){ refreshBilling(); refreshNetworkAlerts(); refreshSecurityAlerts(); refreshInfrastructureAlerts(); }, 1800);
    setInterval(refresh, refreshAge.counts);
    setInterval(refreshTraffic, refreshAge.traffic);
    setInterval(refreshBilling, refreshAge.billing);
    setInterval(refreshNetworkAlerts, refreshAge.network);
    setInterval(refreshSecurityAlerts, refreshAge.security);
    setInterval(refreshInfrastructureAlerts, refreshAge.infrastructure);
    document.addEventListener('visibilitychange', function(){ if (uaShellPollActive()) { refresh(); refreshTraffic(); refreshBilling(); refreshNetworkAlerts(); refreshSecurityAlerts(); refreshInfrastructureAlerts(); } });
  }

  const nav = document.getElementById('uaShellScrollNav') || document.getElementById('nocxGoldScrollbar');
  const thumb = document.getElementById('uaShellScrollThumb') || document.getElementById('nocxGoldScrollbarThumb');
  if (nav && thumb && chrome) {
    let dragging = false;
    const scroller = document.scrollingElement || document.documentElement;
    const page = document.querySelector('.ua-page') || document.body;
    const arrowSize = 34;

    function ensureScrollButtons(){
      if (nav.querySelector('[data-ua-scroll-dir]')) return;
      const up = document.createElement('button');
      const down = document.createElement('button');
      up.type = down.type = 'button';
      up.className = 'ua-shell-scroll-btn ua-shell-scroll-btn--up';
      down.className = 'ua-shell-scroll-btn ua-shell-scroll-btn--down';
      up.setAttribute('data-ua-scroll-dir', '-1');
      down.setAttribute('data-ua-scroll-dir', '1');
      up.setAttribute('aria-label', 'تمرير للأعلى');
      down.setAttribute('aria-label', 'تمرير للأسفل');
      up.innerHTML = '<i class="fa fa-chevron-up" aria-hidden="true"></i>';
      down.innerHTML = '<i class="fa fa-chevron-down" aria-hidden="true"></i>';
      up.setAttribute('aria-label', 'تمرير للأعلى');
      down.setAttribute('aria-label', 'تمرير للأسفل');
      nav.insertBefore(up, nav.firstChild);
      nav.appendChild(down);
    }
    ensureScrollButtons();

    function visibleBottom(el){
      if (!el) return 0;
      try {
        const cs = window.getComputedStyle(el);
        if (!cs || cs.display === 'none' || cs.visibility === 'hidden') return 0;
      } catch(e) {}
      const rect = el.getBoundingClientRect();
      if (!rect || rect.height < 1) return 0;
      return Math.round(rect.bottom + window.scrollY);
    }
    function contentHeight(){
      return Math.max(
        scroller.scrollHeight || 0,
        document.body.scrollHeight || 0,
        document.documentElement.scrollHeight || 0,
        page ? (page.getBoundingClientRect().top + window.scrollY + page.scrollHeight) : 0
      );
    }
    function maxScroll(){
      return Math.max(0, contentHeight() - window.innerHeight);
    }
    function trackBox(){
      const box = nav.getBoundingClientRect();
      return {
        top: box.top + arrowSize,
        bottom: box.bottom - arrowSize,
        height: Math.max(1, box.height - (arrowSize * 2)),
        left: box.left,
        right: box.right,
        width: box.width
      };
    }
    function setHidden(){
      const hidden = maxScroll() < 8;
      nav.classList.toggle('is-hidden', hidden);
      nav.setAttribute('aria-hidden', hidden ? 'true' : 'false');
    }
    function currentTop(){
      return window.pageYOffset || scroller.scrollTop || document.documentElement.scrollTop || document.body.scrollTop || 0;
    }
    function setTop(v){
      const t = Math.max(0, Math.min(maxScroll(), v));
      window.scrollTo(0, t);
      scroller.scrollTop = t;
      document.documentElement.scrollTop = t;
      document.body.scrollTop = t;
    }
    function centerThumbX(){
      // Final centering strategy: absolute left/right = 0 + auto margins.
      // This is stable in RTL/LTR and is not affected by translateX or logical inset conflicts.
      thumb.style.setProperty('left', '0', 'important');
      thumb.style.setProperty('right', '0', 'important');
      thumb.style.setProperty('inset-inline-start', '0', 'important');
      thumb.style.setProperty('inset-inline-end', '0', 'important');
      thumb.style.setProperty('margin-left', 'auto', 'important');
      thumb.style.setProperty('margin-right', 'auto', 'important');
      thumb.style.setProperty('margin-inline-start', 'auto', 'important');
      thumb.style.setProperty('margin-inline-end', 'auto', 'important');
      thumb.style.setProperty('transform-origin', '50% 0', 'important');
    }
    function setThumbY(y){
      centerThumbX();
      thumb.style.setProperty('transform', 'translateY(' + Math.max(0, Math.round(y || 0)) + 'px)', 'important');
    }
    function update(){
      const max = maxScroll();
      setHidden();
      const box = trackBox();
      centerThumbX();
      if (max < 8) {
        thumb.style.height = '120px';
        thumb.style.top = '0px';
        setThumbY(0);
        return;
      }
      const h = Math.max(120, Math.min(box.height, (window.innerHeight / Math.max(contentHeight(), 1)) * box.height));
      const travel = Math.max(1, box.height - h);
      const centerStart = Math.round(travel / 2);
      const y = Math.round(centerStart + ((currentTop() / max) * (travel - centerStart)));
      thumb.style.height = h + 'px';
      thumb.style.top = '0px';
      setThumbY(y);
      nav.setAttribute('aria-valuenow', String(Math.round((currentTop() / max) * 100)));
      nav.setAttribute('aria-valuemin', '0');
      nav.setAttribute('aria-valuemax', '100');
    }
    function scrollToClientY(clientY, center){
      const box = trackBox();
      const h = thumb.offsetHeight || 120;
      const travel = Math.max(1, box.height - h);
      const centerStart = Math.round(travel / 2);
      const raw = clientY - box.top - (center ? h / 2 : 0);
      const y = Math.max(centerStart, Math.min(travel, raw));
      const ratio = (y - centerStart) / Math.max(1, travel - centerStart);
      setTop(ratio * maxScroll());
      update();
    }

    thumb.addEventListener('pointerdown', function(ev){
      dragging = true;
      thumb.setPointerCapture(ev.pointerId);
      ev.preventDefault();
    });
    window.addEventListener('pointermove', function(ev){
      if (!dragging) return;
      scrollToClientY(ev.clientY, true);
    });
    window.addEventListener('pointerup', function(){ dragging = false; });
    nav.addEventListener('pointerdown', function(ev){
      if (ev.target === thumb) return;
      if (ev.target.closest && ev.target.closest('[data-ua-scroll-dir]')) return;
      scrollToClientY(ev.clientY, true);
    });
    nav.addEventListener('wheel', function(ev){
      ev.preventDefault();
      setTop(currentTop() + ev.deltaY);
      update();
    }, {passive:false});
    nav.addEventListener('keydown', function(ev){
      const step = 80;
      if (ev.key === 'ArrowDown') { setTop(currentTop() + step); ev.preventDefault(); }
      if (ev.key === 'ArrowUp') { setTop(currentTop() - step); ev.preventDefault(); }
      if (ev.key === 'PageDown') { setTop(currentTop() + window.innerHeight * .8); ev.preventDefault(); }
      if (ev.key === 'PageUp') { setTop(currentTop() - window.innerHeight * .8); ev.preventDefault(); }
      if (ev.key === 'Home') { setTop(0); ev.preventDefault(); }
      if (ev.key === 'End') { setTop(maxScroll()); ev.preventDefault(); }
    });
    nav.querySelectorAll('[data-ua-scroll-dir]').forEach(function(btn){
      btn.addEventListener('click', function(ev){
        ev.preventDefault();
        const dir = parseInt(btn.getAttribute('data-ua-scroll-dir') || '0', 10);
        setTop(currentTop() + (dir * Math.max(120, Math.round(window.innerHeight * .32))));
        update();
      });
    });

    window.addEventListener('scroll', update, {passive:true});
    window.addEventListener('resize', update);
    if (window.ResizeObserver) {
      try { new ResizeObserver(update).observe(page); } catch(e) {}
    }
    setTimeout(update, 60);
    setTimeout(update, 700);
    setTimeout(update, 1500);
    update();
  }
})();

</script>



<script>
(function(){
  'use strict';
  function hasOpenWork(){
    try {
      if (document.querySelector('.ua-fix-open, .ua-bulk-active')) return true;
    } catch(e) {}
    return false;
  }
  function clearProgramState(){
    try {
      [
        'ua_window_pages_v5','ua_window_pages_v4','ua_window_pending_target_v1',
        'ua_window_dashboard_return_v1','ua_window_last_shell_url_v1',
        'ua_subscribers_top_v1','ua_shell_counts_v2','ua_shell_traffic_v1'
      ].forEach(function(k){ sessionStorage.removeItem(k); });
    } catch(e) {}
  }
  function ensureModal(){
    var m=document.getElementById('uaLogoutModal');
    if(m) return m;
    m=document.createElement('div');
    m.id='uaLogoutModal';
    m.className='ua-logout-modal';
    m.innerHTML='<div class="ua-logout-card" role="dialog" aria-modal="true" aria-labelledby="uaLogoutTitle"><div class="ua-logout-head"><i class="fa fa-sign-out"></i><span id="uaLogoutTitle">تأكيد تسجيل الخروج</span></div><div class="ua-logout-body" id="uaLogoutText"></div><div class="ua-logout-actions"><button type="button" class="ua-logout-btn ua-logout-btn--yes" id="uaLogoutYes">تسجيل الخروج</button><button type="button" class="ua-logout-btn ua-logout-btn--no" id="uaLogoutNo">إلغاء</button></div></div>';
    document.body.appendChild(m);
    m.querySelector('#uaLogoutNo').onclick=function(){m.classList.remove('is-open');};
    m.addEventListener('click',function(ev){ if(ev.target===m) ev.stopPropagation(); }, true);
    return m;
  }
  function askLogout(href){
    var m=ensureModal();
    var txt=hasOpenWork()
      ? 'هناك صفحات أو عمليات مفتوحة. هل تريد تسجيل الخروج وإنهاء كل العمليات وإغلاق البرنامج؟'
      : 'هل تريد تسجيل الخروج وإغلاق البرنامج؟';
    m.querySelector('#uaLogoutText').textContent=txt;
    m.querySelector('#uaLogoutYes').onclick=function(){ clearProgramState(); window.location.href=href; };
    m.classList.add('is-open');
  }
  document.addEventListener('click', function(ev){
    var a = ev.target && ev.target.closest ? ev.target.closest('a[href*="logout.php"]') : null;
    if (!a) return;
    var href = a.getAttribute('href') || '';
    var isSwitch = a.hasAttribute('data-ua-switch-user') || /[?&]switch_user=1(?:&|$)/.test(href);
    if (isSwitch) return;
    ev.preventDefault();
    ev.stopPropagation();
    askLogout(href);
  }, true);
})();
</script>

<style>
.ua-agent-edit-approval{position:fixed;inset:0;z-index:2147483000;display:none;align-items:center;justify-content:center;padding:24px;background:rgba(2,8,18,.62);backdrop-filter:blur(4px)}
.ua-agent-edit-approval.is-open{display:flex}
.ua-agent-edit-approval__card{width:min(620px,calc(100vw - 24px));direction:rtl;background:#0d1d32;color:#eaf2ff;border:1px solid rgba(250,190,35,.58);border-radius:18px;box-shadow:0 24px 70px rgba(0,0,0,.55);overflow:hidden;transform:translateY(0)}
.ua-agent-edit-approval__head{display:flex;gap:12px;align-items:center;padding:16px 18px;border-bottom:1px solid rgba(148,163,184,.16)}
.ua-agent-edit-approval__icon{display:grid;place-items:center;width:42px;height:42px;border-radius:13px;background:rgba(250,190,35,.13);color:#fabe23;font-size:19px}
.ua-agent-edit-approval__head div{flex:1}.ua-agent-edit-approval__head strong{display:block;font-size:17px}.ua-agent-edit-approval__head small{color:#93a7bf}
.ua-agent-edit-approval__close{border:0;background:transparent;color:#91a3b8;font-size:24px;cursor:pointer}
.ua-agent-edit-approval__body{padding:16px 18px}.ua-agent-edit-approval__body p{margin:0 0 8px;font-size:15px}.ua-agent-edit-approval__note{padding:10px 12px;border-radius:11px;background:rgba(255,255,255,.045);color:#b8c7d9;font-size:13px}
.ua-agent-edit-approval__actions{display:flex;gap:10px;padding:0 18px 18px}.ua-agent-edit-approval__actions button{flex:1;border-radius:11px;border:1px solid rgba(148,163,184,.25);padding:11px 14px;font-weight:800;cursor:pointer}
.ua-agent-edit-approval__approve{background:#fabe23;color:#111827;border-color:#fabe23!important}.ua-agent-edit-approval__reject{background:#17283d;color:#f8fafc}.ua-agent-edit-approval__actions button:disabled{opacity:.55;cursor:wait}
</style>
<script>
(function(){
  'use strict';
  if (!document.body.classList.contains('ua-authed') || window.top !== window) return;
  var currentId = 0, csrf = '', busy = false, canDecide = false;
  function modal(){
    var root = document.getElementById('uaAgentEditApproval');
    if (root) return root;
    root = document.createElement('div');
    root.id = 'uaAgentEditApproval';
    root.className = 'ua-agent-edit-approval';
    root.innerHTML = '<section class="ua-agent-edit-approval__card" role="dialog" aria-modal="true" aria-labelledby="uaAgentEditApprovalTitle">'
      + '<header class="ua-agent-edit-approval__head"><span class="ua-agent-edit-approval__icon"><i class="fa fa-user-edit fa-pencil-square-o"></i></span><div><strong id="uaAgentEditApprovalTitle">طلب تعديل مشترك</strong><small>عملية محمية تتطلب موافقة الإدارة</small></div><button class="ua-agent-edit-approval__close" type="button" aria-label="إغلاق">×</button></header>'
      + '<div class="ua-agent-edit-approval__body"><p id="uaAgentEditApprovalText"></p><div class="ua-agent-edit-approval__note" id="uaAgentEditApprovalNote" hidden></div></div>'
      + '<footer class="ua-agent-edit-approval__actions"><button class="ua-agent-edit-approval__approve" type="button"><i class="fa fa-check"></i> موافقة لمدة 30 دقيقة</button><button class="ua-agent-edit-approval__reject" type="button"><i class="fa fa-times"></i> رفض</button></footer></section>';
    document.body.appendChild(root);
    root.querySelector('.ua-agent-edit-approval__close').onclick = function(){
      root.classList.remove('is-open');
      currentId = 0;
    };
    root.querySelector('.ua-agent-edit-approval__approve').onclick = function(){ decide('APPROVED'); };
    root.querySelector('.ua-agent-edit-approval__reject').onclick = function(){ decide('REJECTED'); };
    return root;
  }
  function show(request){
    if (!request || !request.id) return;
    var root = modal();
    if (Number(request.id) === currentId && root.classList.contains('is-open')) return;
    currentId = Number(request.id);
    root.querySelector('#uaAgentEditApprovalText').textContent =
      request.request_scope === 'PORTAL_EDIT'
        ? 'المعتمد «' + (request.agent_name || '-') + '» يطلب صلاحية مؤقتة للبحث عن المشتركين وتعديل بياناتهم.'
        : 'المعتمد «' + (request.agent_name || '-') + '» يطلب تعديل بيانات المشترك «' + (request.subscriber_name || ('#' + request.subscriber_id)) + '».';
    var note = root.querySelector('#uaAgentEditApprovalNote');
    note.textContent = request.request_note || '';
    note.hidden = !request.request_note;
    root.querySelector('.ua-agent-edit-approval__actions').hidden = !canDecide;
    if (!canDecide) {
      note.hidden = false;
      note.textContent = (request.request_note ? request.request_note + ' — ' : '') + 'تحتاج صلاحية تعديل المشترك لاتخاذ القرار.';
    }
    root.classList.add('is-open');
  }
  async function load(){
    if (busy || document.hidden) return;
    try {
      var response = await fetch('api/agent_edit_requests.php?_=' + Date.now(), {credentials:'same-origin',cache:'no-store',headers:{'Accept':'application/json'}});
      if (!response.ok) return;
      var data = await response.json();
      if (!data || !data.ok) return;
      csrf = data.csrf || csrf;
      canDecide = data.can_decide !== false;
      if (Array.isArray(data.requests) && data.requests.length) show(data.requests[0]);
    } catch(e) {
      if (window.console && console.warn) console.warn('تعذر تحديث طلبات موافقة المعتمد.');
    }
  }
  async function decide(decision){
    if (busy || !currentId) return;
    busy = true;
    var root = modal(), buttons = root.querySelectorAll('.ua-agent-edit-approval__actions button');
    buttons.forEach(function(button){ button.disabled = true; });
    try {
      var form = new FormData();
      form.append('request_id', String(currentId));
      form.append('decision', decision);
      form.append('ua_csrf', csrf);
      var response = await fetch('api/agent_edit_requests.php', {method:'POST',body:form,credentials:'same-origin',headers:{'X-Requested-With':'XMLHttpRequest','Accept':'application/json'}});
      var data = await response.json();
      if (!response.ok || !data.ok) throw new Error(data.message || 'تعذر معالجة الطلب.');
      root.classList.remove('is-open');
      currentId = 0;
      if (typeof window.uaToast === 'function') window.uaToast(data.message || 'تمت معالجة الطلب.');
      setTimeout(load, 700);
    } catch(error) {
      var note = root.querySelector('#uaAgentEditApprovalNote');
      note.hidden = false;
      note.textContent = error && error.message ? error.message : 'تعذر معالجة الطلب.';
    } finally {
      busy = false;
      buttons.forEach(function(button){ button.disabled = false; });
    }
  }
  load();
  setInterval(load, 7000);
  document.addEventListener('visibilitychange', function(){ if (!document.hidden) load(); });
})();
</script>

<?php if (!empty($logged)): ?><script src="<?= h(ua_asset_versioned_local('assets/js/subscriber_id_scanner.js')) ?>"></script><?php endif; ?>
<?php include __DIR__ . '/footer_ui_cleaner.php'; ?>
</body>
</html>
