/* assets/js/ua_window_manager.js
   Real in-page tab/window manager for normal pages.
   Dashboard renders the same approved strip as a launcher/mirror from the same registry. */
(function(){
  'use strict';

  const body = document.body;
  if (!body || !body.classList.contains('ua-shell-chrome')) return;
  try {
    if (window.self !== window.top) {
      body.classList.add('ua-tab-iframe-body');
      return;
    }
  } catch(e) {
    body.classList.add('ua-tab-iframe-body');
    return;
  }

  const isDashboard = body.classList.contains('ua-page-dashboard');
  const MAX_TABS = 14;
  const registry = window.UAWorkspaceRegistry || {};
  const STORE_KEY = 'ua_window_pages_v5';
  const LEGACY_STORE_KEY = 'ua_window_pages_v4';
  const PENDING_TARGET_KEY = 'ua_window_pending_target_v1';
  const DASHBOARD_RETURN_KEY = 'ua_window_dashboard_return_v1';
  const LAST_SHELL_KEY = 'ua_window_last_shell_url_v1';
  const UA_TRANSIENT_PROTECTED_PAGES = Object.assign({}, registry.transientProtectedPages || {}, {
    'index.php':1,
    'login.php':1,
    'logout.php':1,
    'setup_first_admin.php':1,
    'install_link.php':1,
    'super_admin_confirm.php':1,
    'subscribers_history.php':1,
    'subscribers_view.php':1,
    'subscribers_edit.php':1,
    'subscribers_distribution.php':1,
    'subscribers_cancel.php':1,
    'subscribers_ppp_toggle.php':1,
    'subscribers_history_clear.php':1
  });
  function isTransientProtectedUrl(url){
    if (registry && typeof registry.isTransientProtected === 'function' && registry.isTransientProtected(url || '')) return true;
    const raw = basenameUrl(url || '');
    if (!raw) return false;
    const path = (raw.split('?')[0] || '').replace(/^\.\//,'');
    return !!UA_TRANSIENT_PROTECTED_PAGES[path];
  }

  function isAuthScreenDocument(doc, frameUrl){
    try {
      const u = new URL(frameUrl || '', location.href);
      const file = (u.pathname.split('/').pop() || '').toLowerCase();
      if (file === 'index.php' || file === 'login.php') return true;
    } catch(e) {}
    try {
      if (doc && doc.body && doc.body.classList.contains('ua-guest')) return true;
      if (doc && doc.querySelector && doc.querySelector('.exa-login-page, form.exa-login-form')) return true;
    } catch(e) {}
    return false;
  }

  function forceTopLogin(){
    try { sessionStorage.removeItem(STORE_KEY); } catch(e) {}
    try { sessionStorage.removeItem(LEGACY_STORE_KEY); } catch(e) {}
    try { sessionStorage.removeItem(PENDING_TARGET_KEY); } catch(e) {}
    try { sessionStorage.removeItem(DASHBOARD_RETURN_KEY); } catch(e) {}
    try { sessionStorage.removeItem(LAST_SHELL_KEY); } catch(e) {}
    try { localStorage.removeItem(LAST_SHELL_KEY); } catch(e) {}
    location.href = 'index.php?login=1';
  }

  function basenameUrl(url){
    try {
      const u = new URL(url, location.href);
      if (u.origin !== location.origin) return '';
      const currentDir = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
      let path = u.pathname;
      if (path.startsWith(currentDir)) path = path.substring(currentDir.length);
      path = path || 'dashboard.php';
      return path + (u.search || '') + (u.hash || '');
    } catch(e) {
      return '';
    }
  }

  const UA_PAGE_TITLE_MAP = Object.assign({
    'mtwatch_allowlist.php': 'قائمة سماح تنبيهات الشبكة',
    'security_alerts.php': 'سجل تنبيهات الأمان',
    'security_monitor.php': 'مراقب الشبكة',
    'dashboard.php': 'لوحة التحكم الرئيسية'
  }, registry.titleMap || {});

  function cleanTitle(value){
    return String(value || '').replace(/\s+/g, ' ').trim() || 'صفحة';
  }

  function mappedTitle(url, fallback){
    const key = normalizeUrl(url || '');
    if (registry && typeof registry.resolveTitle === 'function') {
      const fromRegistry = registry.resolveTitle(key || url || '', fallback || key || 'صفحة');
      if (fromRegistry) return cleanTitle(fromRegistry);
    }
    return cleanTitle(UA_PAGE_TITLE_MAP[key] || fallback || key || 'صفحة');
  }

  function linkTitle(link, href){
    if (registry && typeof registry.titleFromLink === 'function') {
      const fromRegistry = registry.titleFromLink(link, href || '');
      if (fromRegistry) return cleanTitle(fromRegistry);
    }
    return mappedTitle(href, link ? (link.getAttribute('data-ua-title') || link.getAttribute('data-title') || link.textContent || link.getAttribute('title') || href) : href);
  }

  function normalizeUrl(url){
    const raw = basenameUrl(url || '');
    if (!raw) return '';
    if (isTransientProtectedUrl(raw)) return '';

    /*
      Window identity must be page-based, not query-string-based.
      The same program page can be reached from several places with different
      parameters, for example:
        subscribers.php
        subscribers.php?filter=all
        subscribers.php?filter=all&q=...
      These must stay one open window/tab, otherwise the dashboard shortcut
      creates a new tab every time.  Keep only the local page path as the
      window key and reserve query strings for the real page load only.
    */
    const hashIndex = raw.indexOf('#');
    const base = hashIndex >= 0 ? raw.substring(0, hashIndex) : raw;
    const qIndex = base.indexOf('?');
    let path = qIndex >= 0 ? base.substring(0, qIndex) : base;
    path = path.replace(/^\.\//, '').replace(/\/+/g, '/');
    if (!path || path === './') path = 'dashboard.php';
    return path;
  }

  function loadableUrl(url){
    const raw = basenameUrl(url || '');
    if (!raw) return '';
    if (isTransientProtectedUrl(raw)) return '';
    try {
      const u = new URL(raw, location.href);
      if (u.origin !== location.origin) return '';
      u.searchParams.delete('iframe');
      u.searchParams.delete('ua_tab');
      u.searchParams.delete('embed');
      let path = u.pathname;
      const currentDir = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
      if (path.startsWith(currentDir)) path = path.substring(currentDir.length);
      path = (path || 'dashboard.php').replace(/^\.\//, '').replace(/\/+/g, '/');
      return path + (u.search || '') + (u.hash || '');
    } catch(e) {
      return raw;
    }
  }

  function toIframeUrl(url){
    const raw = loadableUrl(url) || normalizeUrl(url);
    if (!raw) return '';
    const hashIndex = raw.indexOf('#');
    const hash = hashIndex >= 0 ? raw.substring(hashIndex) : '';
    const noHash = hashIndex >= 0 ? raw.substring(0, hashIndex) : raw;
    const sep = noHash.includes('?') ? '&' : '?';
    return noHash + sep + 'iframe=1&ua_tab=1' + hash;
  }

  function getCurrentUrl(){
    return normalizeUrl(location.pathname.split('/').pop() + (location.search || '') + (location.hash || '')) || 'dashboard.php';
  }

  function getCurrentLoadUrl(){
    return loadableUrl(location.pathname.split('/').pop() + (location.search || '') + (location.hash || '')) || getCurrentUrl();
  }

  function escapeHtml(v){
    return String(v || '').replace(/[&<>"']/g, ch => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[ch]));
  }

  function cleanStoredPages(pages){
    const seen = new Set();
    return (Array.isArray(pages) ? pages : []).map(p => {
      const rawUrl = (p && (p.url || p.key)) || '';
      if (isTransientProtectedUrl(rawUrl)) return null;
      const url = normalizeUrl(rawUrl);
      if (!url || seen.has(url) || isTransientProtectedUrl(url)) return null;
      seen.add(url);
      return {
        url,
        loadUrl: loadableUrl(p.loadUrl || rawUrl) || url,
        title: mappedTitle(url, p.title || p.name || url),
        minimized: !!p.minimized,
        ts: Number(p.ts || p.touched || Date.now()) || Date.now()
      };
    }).filter(Boolean).slice(-MAX_TABS);
  }

  function loadStoredPages(){
    let pages = [];
    try { pages = JSON.parse(sessionStorage.getItem(STORE_KEY) || '[]') || []; } catch(e) { pages = []; }
    if (!pages.length) {
      try { pages = JSON.parse(sessionStorage.getItem(LEGACY_STORE_KEY) || '[]') || []; } catch(e) { pages = []; }
    }
    return cleanStoredPages(pages);
  }

  function saveStoredPages(pages){
    try { sessionStorage.setItem(STORE_KEY, JSON.stringify(cleanStoredPages(pages))); } catch(e) {}
  }

  function upsertStoredPage(url, title, extra){
    const key = normalizeUrl(url);
    if (!key || key === 'dashboard.php') return;

    /* Keep the original opening order. Updating or activating a tab must not
       move it to the end; the user asked the first opened page to stay first
       after the fixed dashboard shortcut. */
    const pages = loadStoredPages();
    const existing = pages.find(p => p.url === key);
    if (existing) {
      existing.title = mappedTitle(key, title || existing.title || key);
      if (extra && Object.prototype.hasOwnProperty.call(extra, 'minimized')) {
        existing.minimized = !!extra.minimized;
      }
      const nextLoadUrl = (extra && extra.loadUrl) ? loadableUrl(extra.loadUrl) : loadableUrl(url);
      if (nextLoadUrl) existing.loadUrl = nextLoadUrl;
      existing.ts = existing.ts || Date.now();
      saveStoredPages(pages);
      return;
    }

    const loadUrl = (extra && extra.loadUrl) ? loadableUrl(extra.loadUrl) : loadableUrl(url);
    pages.push({
      url: key,
      loadUrl: loadUrl || key,
      title: mappedTitle(key, title || key),
      minimized: !!(extra && extra.minimized),
      ts: Date.now()
    });
    saveStoredPages(pages);
  }

  function removeStoredPage(url){
    const key = normalizeUrl(url);
    if (!key) return;
    saveStoredPages(loadStoredPages().filter(p => p.url !== key));
  }

  function setStoredMinimized(url, minimized){
    const key = normalizeUrl(url);
    if (!key) return;
    saveStoredPages(loadStoredPages().map(p => {
      if (p.url === key) {
        p.minimized = !!minimized;
        p.ts = Date.now();
      }
      return p;
    }));
  }

  function setPendingTarget(url){
    const key = normalizeUrl(url);
    if (!key || key === 'dashboard.php') return false;
    try { sessionStorage.setItem(PENDING_TARGET_KEY, key); } catch(e) {}
    return true;
  }

  function takePendingTarget(){
    let key = '';
    try { key = normalizeUrl(sessionStorage.getItem(PENDING_TARGET_KEY) || ''); sessionStorage.removeItem(PENDING_TARGET_KEY); } catch(e) { key = ''; }
    return key;
  }

  function rememberDashboardReturn(activeUrl){
    const key = normalizeUrl(activeUrl || getCurrentUrl());
    try { sessionStorage.setItem(DASHBOARD_RETURN_KEY, JSON.stringify({url:key, ts:Date.now()})); } catch(e) {}
  }

  function goDashboard(activeUrl){
    rememberDashboardReturn(activeUrl);
    location.href = 'dashboard.php';
  }

  function rememberLastShellUrl(url){
    const key = normalizeUrl(url || getCurrentUrl());
    if (!key || key === 'dashboard.php') return;
    try { sessionStorage.setItem(LAST_SHELL_KEY, key); } catch(e) {}
    try { localStorage.setItem(LAST_SHELL_KEY, key); } catch(e) {}
  }

  function getLastShellUrl(){
    try {
      return normalizeUrl(sessionStorage.getItem(LAST_SHELL_KEY) || localStorage.getItem(LAST_SHELL_KEY) || '');
    } catch(e) {
      return '';
    }
  }

  function forgetClosedPageReferences(url){
    const key = normalizeUrl(url || '');
    if (!key || key === 'dashboard.php') return;

    try {
      const sessionLast = normalizeUrl(sessionStorage.getItem(LAST_SHELL_KEY) || '');
      if (sessionLast === key) sessionStorage.removeItem(LAST_SHELL_KEY);
    } catch(e) {}
    try {
      const localLast = normalizeUrl(localStorage.getItem(LAST_SHELL_KEY) || '');
      if (localLast === key) localStorage.removeItem(LAST_SHELL_KEY);
    } catch(e) {}
    try {
      const pending = normalizeUrl(sessionStorage.getItem(PENDING_TARGET_KEY) || '');
      if (pending === key) sessionStorage.removeItem(PENDING_TARGET_KEY);
    } catch(e) {}
    try {
      const savedReturn = JSON.parse(sessionStorage.getItem(DASHBOARD_RETURN_KEY) || 'null');
      if (savedReturn && normalizeUrl(savedReturn.url || '') === key) {
        sessionStorage.removeItem(DASHBOARD_RETURN_KEY);
      }
    } catch(e) {}
  }

  function isBrowserReload(){
    try {
      const nav = performance.getEntriesByType && performance.getEntriesByType('navigation');
      if (nav && nav[0] && nav[0].type) return nav[0].type === 'reload';
      return performance.navigation && performance.navigation.type === 1;
    } catch(e) {
      return false;
    }
  }

  function clearRestorePending(){
    try { document.documentElement.classList.remove('ua-restore-workspace-pending'); } catch(e) {}
    try { body.classList.remove('ua-restore-workspace-pending'); } catch(e) {}
  }

  /* Dashboard is no longer a separate launcher.
     It participates in the same Workspace manager, while keeping its approved
     dashboard stats/topbar/windowbar outside the pane area. */

  const page = document.querySelector('.ua-page');
  const strip = document.getElementById('uaOpenPagesStrip');
  const titleEl = document.getElementById('uaCurrentPageTitle');
  if (!page || !strip || !titleEl) return;

  const titleHolder = titleEl.closest ? titleEl.closest('.ua-page-windowbar__title') : null;
  if (titleHolder) {
    titleHolder.style.setProperty('display', 'none', 'important');
    titleHolder.setAttribute('aria-hidden', 'true');
  }

  const panes = new Map();
  let activeKey = '';

  function currentWindowScroll(){
    const rec = activeKey ? panes.get(activeKey) : null;
    if (rec && rec.pane && !rec.iframe) return rec.pane.scrollTop || 0;
    return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
  }
  function setWindowScroll(y){
    const top = Math.max(0, Number(y) || 0);
    const rec = activeKey ? panes.get(activeKey) : null;
    if (rec && rec.pane && !rec.iframe) {
      rec.pane.scrollTop = top;
      return;
    }
    window.scrollTo(0, top);
    document.documentElement.scrollTop = top;
    document.body.scrollTop = top;
  }

  function applyBox(el){
    if (!el || !el.style) return el;
    if (!(el.classList && el.classList.contains('ua-wm-pane'))) {
      el.style.setProperty('display', 'block', 'important');
    }
    el.style.setProperty('width', '100%', 'important');
    el.style.setProperty('max-width', '100%', 'important');
    el.style.setProperty('min-width', '0', 'important');
    el.style.setProperty('box-sizing', 'border-box', 'important');
    return el;
  }

  function workspaceViewportHeight(){
    let top = 0;
    /* The visual viewport may report a reduced height on desktop when Chrome
       is zoomed or when an accessibility viewport is active. Using it alone
       shortens iframe panes and leaves the lower part of long pages clipped.
       The layout viewport is the authoritative desktop workspace boundary. */
    const layoutViewportHeight = Math.max(
      Number(window.innerHeight) || 0,
      Number(document.documentElement && document.documentElement.clientHeight) || 0
    );
    const visualViewportHeight = window.visualViewport
      ? ((Number(window.visualViewport.height) || 0) + (Number(window.visualViewport.offsetTop) || 0))
      : 0;
    const viewportHeight = layoutViewportHeight > 0
      ? layoutViewportHeight
      : visualViewportHeight;
    try {
      const ref = stage || getStageHost() || page;
      const rect = ref && ref.getBoundingClientRect ? ref.getBoundingClientRect() : null;
      top = rect ? Math.max(0, rect.top) : 0;
    } catch(e) { top = 0; }
    return Math.max(280, Math.floor(viewportHeight - top - 6));
  }

  function applyFrameBox(iframe){
    applyBox(iframe);
    /* Phase 13: the iframe must fill the active pane exactly.  A computed
       pixel height could become a few pixels taller than the pane and create
       an extra outer scrollbar on the opposite side of the page. */
    iframe.style.setProperty('border', '0', 'important');
    iframe.style.setProperty('background', 'transparent', 'important');
    iframe.style.setProperty('height', '100%', 'important');
    iframe.style.setProperty('min-height', '0', 'important');
    iframe.style.setProperty('max-height', '100%', 'important');
    iframe.style.setProperty('overflow', 'hidden', 'important');
    return iframe;
  }

  function getStageHost(){
    if (isDashboard) {
      const shell = document.querySelector('.nocx-shell');
      /* Phase 4: the dashboard windowbar is no longer inside the dashboard
         topbar.  Keep the dashboard workspace host as .nocx-shell so only
         the real dashboard content moves into panes; the extracted windowbar
         remains a locked row under the stats bar. */
      if (shell && strip) {
        shell.setAttribute('data-ua-dashboard-workspace-shell', '1');
        return shell;
      }
    }
    return page;
  }

  function moveInitialDashboardPaneContent(initialPane, host){
    if (!initialPane || !host) return false;

    const nodes = [];
    const topbar = host.querySelector(':scope > .nocx-topbar--control');

    if (topbar) {
      /* Old dashboard structure: keep the internal dashboard topbar outside
         the movable pane and move only the real dashboard body after it. */
      let node = topbar.nextSibling;
      while (node) {
        const next = node.nextSibling;
        nodes.push(node);
        node = next;
      }
    } else {
      /* New dashboard structure: the duplicated internal topbar has been
         removed.  The workspace host is .nocx-shell, so never fall back to
         moving children from .ua-page; that can attempt to move the shell into
         its own pane and leaves the dashboard blank. */
      Array.from(host.childNodes).forEach(function(node){
        if (node === initialPane) return;
        if (node.nodeType === 1 && node.classList && node.classList.contains('ua-wm-stage')) return;
        nodes.push(node);
      });
    }

    if (!nodes.length) return false;
    nodes.forEach(function(node){ initialPane.appendChild(node); });
    return true;
  }

  function createStage(){
    const host = getStageHost();
    let stage = host.querySelector(':scope > .ua-wm-stage');
    if (stage) {
      applyBox(stage);
      stage.querySelectorAll(':scope > .ua-wm-pane').forEach(applyBox);
      return stage;
    }

    stage = document.createElement('div');
    stage.className = 'ua-wm-stage';
    stage.setAttribute('data-ua-shell-region', isDashboard ? 'dashboard-workspace-stage' : 'workspace-stage');
    applyBox(stage);

    const initialPane = document.createElement('div');
    initialPane.className = 'ua-wm-pane is-current';
    applyBox(initialPane);
    initialPane.dataset.uaWmKey = getCurrentUrl();

    if (isDashboard && host !== page) {
      if (!moveInitialDashboardPaneContent(initialPane, host)) {
        /* Defensive fallback for dashboard only: move children of the selected
           workspace host, not .ua-page, to avoid moving the host into itself. */
        Array.from(host.childNodes).forEach(function(node){
          if (node === stage || node === initialPane) return;
          if (node.nodeType === 1 && node.classList && node.classList.contains('ua-wm-stage')) return;
          initialPane.appendChild(node);
        });
      }
    } else {
      Array.from(page.childNodes).forEach(node => initialPane.appendChild(node));
    }

    stage.appendChild(initialPane);
    host.appendChild(stage);

    const initialTitle = mappedTitle(getCurrentUrl(), titleEl.textContent || document.title);
    const key = initialPane.dataset.uaWmKey;
    panes.set(key, {
      key,
      url: key,
      loadUrl: getCurrentLoadUrl(),
      title: initialTitle,
      pane: initialPane,
      iframe: null,
      loaded: true,
      minimized: false,
      scrollTop: currentWindowScroll(),
      touched: Date.now(),
      lazy: false,
      closed: false
    });
    activeKey = key;
    rememberLastShellUrl(key);
    upsertStoredPage(getCurrentLoadUrl(), initialTitle, {minimized:false, loadUrl:getCurrentLoadUrl()});
    return stage;
  }

  const stage = createStage();
  if (!stage) return;

  function setPaneLoading(rec, loading){
    if (!rec || !rec.pane) return;
    const pane = rec.pane;
    pane.classList.toggle('is-loading', !!loading);
    if (loading) {
      pane.setAttribute('aria-busy', 'true');
      let indicator = pane.querySelector('.ua-wm-pane__loading');
      if (!indicator) {
        indicator = document.createElement('div');
        indicator.className = 'ua-wm-pane__loading';
        indicator.setAttribute('role', 'status');
        indicator.setAttribute('aria-live', 'polite');
        indicator.innerHTML = '<span class="ua-wm-pane__spinner" aria-hidden="true"></span><strong>جارٍ تجهيز الصفحة</strong><small>يتم تحميل البيانات والأدوات…</small>';
        pane.appendChild(indicator);
      }
      return;
    }
    pane.removeAttribute('aria-busy');
    const indicator = pane.querySelector('.ua-wm-pane__loading');
    if (indicator) indicator.remove();
  }

  function bindIframeLoad(rec){
    if (!rec || !rec.iframe || rec._bound) return;
    rec._bound = true;
    rec.iframe.addEventListener('load', function(){
      if (rec.closed || panes.get(rec.key) !== rec) return;
      rec.loaded = true;
      let frameDocument = null;
      try {
        const doc = rec.iframe.contentDocument;
        frameDocument = doc;
        const frameUrl = rec.iframe.contentWindow && rec.iframe.contentWindow.location ? rec.iframe.contentWindow.location.href : rec.iframe.src;
        if (isAuthScreenDocument(doc, frameUrl)) {
          forceTopLogin();
          return;
        }
        const t = mappedTitle(rec.key, (doc && doc.title) || rec.title);
        if (t && t !== 'صفحة') rec.title = t;
        if (doc && doc.body) {
          doc.body.classList.add('ua-tab-iframe-body');
          doc.querySelectorAll('.ua-unified-shell-block,#uaShellStatsBar,#uaShellGoldLine,#uaShellWindowBar,#uaShellScrollNav,.ua-shell-scroll-nav,.nocx-gold-scrollbar,.ua-page-windowbar:not(.ua-subnav),.ua-dashboard-windowbar-host,.nocx-dashboard-windowbar,.nocx-topbar--control,.ua-legacy-windowbar,.ua-legacy-subnav,[data-ua-shared-windowbar]:not(.ua-subnav),.ua-atabs-wrap,.ua-atabs,.ua-page-tabs,.ua-tabs-wrap,.ua-section-tabs,.ua-legacy-page-tabs').forEach(function(el){ try { el.remove(); } catch(_e) {} });
          const firstSubnavBySection = Object.create(null);
          doc.querySelectorAll('.ua-subnav[data-ua-section-nav]').forEach(function(el){
            const k = el.getAttribute('data-ua-section-nav') || 'default';
            const isCanonical = el.getAttribute('data-ua-subnav-canonical') === '1';
            if (!firstSubnavBySection[k] || isCanonical) {
              if (firstSubnavBySection[k] && firstSubnavBySection[k] !== el) {
                try { firstSubnavBySection[k].remove(); } catch(_e) {}
              }
              firstSubnavBySection[k] = el;
              el.setAttribute('data-ua-subnav-canonical','1');
              el.style.marginInlineStart = '0';
              el.style.marginInlineEnd = 'auto';
              return;
            }
            try { el.remove(); } catch(_e) {}
          });
          /* Phase16: keep one canonical page section nav only.
             Previous logic left a second canonical bar alive, so old page-header
             menus could still appear beside the official section nav. */
          let keptAnySubnav = false;
          doc.querySelectorAll('.ua-subnav').forEach(function(el){
            if (el.getAttribute('data-ua-subnav-canonical') === '1' && !keptAnySubnav) {
              keptAnySubnav = true;
              return;
            }
            try { el.remove(); } catch(_e) {}
          });
        }
      } catch(e) {}
      if (rec.closed || panes.get(rec.key) !== rec) return;
      const reveal = function(){
        requestAnimationFrame(function(){
          requestAnimationFrame(function(){
            if (rec.closed || panes.get(rec.key) !== rec) return;
            setPaneLoading(rec, false);
            upsertStoredPage(rec.loadUrl || rec.key, rec.title, {minimized:rec.minimized, loadUrl:rec.loadUrl || rec.key});
            resizeIframe(rec);
            renderTabs();
            updateTitle();
            scheduleResize(rec);
          });
        });
      };
      if (frameDocument && frameDocument.fonts && frameDocument.fonts.ready) {
        frameDocument.fonts.ready.then(reveal, reveal);
      } else {
        reveal();
      }
    });
  }

  function ensureIframe(rec){
    if (!rec || rec.iframe || rec.key === getCurrentUrl()) return;
    const iframe = document.createElement('iframe');
    iframe.className = 'ua-wm-iframe';
    applyFrameBox(iframe);
    iframe.setAttribute('loading', 'eager');
    iframe.setAttribute('referrerpolicy', 'same-origin');
    rec.iframe = iframe;
    rec.loaded = false;
    rec.lazy = false;
    rec.pane.classList.add('has-iframe');
    rec.pane.setAttribute('data-ua-pane-kind', 'iframe');
    bindIframeLoad(rec);
    setPaneLoading(rec, true);
    iframe.src = toIframeUrl(rec.loadUrl || rec.key);
    rec.pane.appendChild(iframe);
    scheduleResize(rec);
  }

  function hydrateStoredPanes(){
    const saved = loadStoredPages();
    saved.forEach(p => {
      if (panes.has(p.url)) return;
      const pane = document.createElement('div');
      pane.className = 'ua-wm-pane';
      applyBox(pane);
      pane.dataset.uaWmKey = p.url;
      pane.hidden = true;
      stage.appendChild(pane);
      panes.set(p.url, {
        key:p.url,
        url:p.url,
        loadUrl:p.loadUrl || p.url,
        title:p.title,
        pane,
        iframe:null,
        loaded:false,
        minimized:!!p.minimized,
        scrollTop:0,
        touched:p.ts || Date.now(),
        lazy:true,
        closed:false
      });
    });
  }

  hydrateStoredPanes();

  function preloadStoredPanes(){
    /* Keep saved tabs lightweight.  Hidden iframes can fan out into several
       DB/API/polling requests after a browser refresh, so load each page only
       when the user activates its tab. */
    return;
  }

  function paneContentHeight(pane){
    const iframe = pane ? pane.querySelector('iframe') : null;
    if (iframe) return workspaceViewportHeight();
    return pane ? pane.scrollHeight : 0;
  }

  function resizeIframe(rec){
    if (!rec || !rec.iframe) return;
    applyBox(rec.pane);
    applyBox(stage);
    applyFrameBox(rec.iframe);
    try {
      const doc = rec.iframe.contentDocument;
      if (!doc) return;
      if (doc.documentElement) doc.documentElement.style.overflowX = 'hidden';
      if (doc.body) doc.body.style.overflowX = 'hidden';
    } catch(e) {}
  }

  function scheduleResize(rec){
    [60, 250, 700, 1400].forEach(t => setTimeout(() => resizeIframe(rec), t));
  }

  let tabOverflowTimer = 0;
  function updateTabOverflowMode(){
    if (!strip || !strip.classList) return;
    const tabs = strip.querySelectorAll('.ua-page-tab').length;
    strip.classList.remove('is-compact', 'is-icon-only', 'is-overflowing');
    if (!tabs) return;
    const hasOverflow = strip.scrollWidth > (strip.clientWidth + 1);
    if (hasOverflow || tabs > 6) strip.classList.add('is-compact');
    requestAnimationFrame(function(){
      if (!strip || !strip.classList) return;
      const stillOverflowing = strip.scrollWidth > (strip.clientWidth + 1);
      strip.classList.toggle('is-icon-only', stillOverflowing || tabs > 10);
      strip.classList.toggle('is-overflowing', stillOverflowing);
    });
  }

  function scheduleTabOverflowMode(){
    if (tabOverflowTimer) cancelAnimationFrame(tabOverflowTimer);
    tabOverflowTimer = requestAnimationFrame(updateTabOverflowMode);
  }

  function renderTabs(){
    closeTabContextMenu();
    /* The page title block is hidden; therefore the active page must stay as a
       normal tab in its original opening position instead of disappearing and
       shifting the remaining tabs. */
    const records = Array.from(panes.values()).filter(rec => rec.key !== 'dashboard.php');
    const dashboardCls = 'ua-page-tab ua-page-tab--dashboard' + (activeKey === 'dashboard.php' ? ' is-current' : '');
    const dashboardTab = '<button type="button" class="' + dashboardCls + '" data-ua-wm-dashboard="dashboard.php" title="لوحة التحكم الرئيسية"><i class="fa fa-tachometer"></i><span>لوحة التحكم الرئيسية</span></button>';
    strip.innerHTML = dashboardTab + records.map(rec => {
      const cls = 'ua-page-tab' + (rec.key === activeKey ? ' is-current' : '') + (rec.minimized ? ' is-minimized' : '');
      const icon = rec.minimized ? 'fa-window-minimize' : 'fa-file-o';
      return '<button type="button" class="' + cls + '" data-ua-wm-tab="' + escapeHtml(rec.key) + '" title="' + escapeHtml(rec.title) + '"><i class="fa ' + icon + '"></i><span>' + escapeHtml(rec.title) + '</span><span class="ua-page-tab__close" data-ua-wm-close-tab="' + escapeHtml(rec.key) + '" title="إغلاق" aria-label="إغلاق">×</span></button>';
    }).join('');
    scheduleTabOverflowMode();
  }

  let tabContextMenu = null;
  function closeTabContextMenu(){
    if (!tabContextMenu) return;
    try { tabContextMenu.remove(); } catch(e) {}
    tabContextMenu = null;
  }

  function closePane(key){
    key = normalizeUrl(key || '');
    if (!key || key === 'dashboard.php') return false;
    const wasActive = key === activeKey;
    const rec = panes.get(key);
    if (rec) {
      rec.closed = true;
      rec.pane.remove();
      panes.delete(key);
    }
    removeStoredPage(key);
    forgetClosedPageReferences(key);
    closeTabContextMenu();
    if (wasActive) {
      const next = Array.from(panes.values()).filter(r => !r.minimized && r.key !== 'dashboard.php').pop()
        || panes.get('dashboard.php')
        || Array.from(panes.values()).pop();
      if (next) showPane(next.key, true);
      else location.href = 'dashboard.php';
    } else {
      renderTabs();
      setCurrentPaneClasses();
    }
    return true;
  }

  function showTabContextMenu(key, clientX, clientY){
    key = normalizeUrl(key || '');
    if (!key || key === 'dashboard.php' || !panes.has(key)) return;
    closeTabContextMenu();

    const rec = panes.get(key);
    const menu = document.createElement('div');
    menu.className = 'ua-wm-context-menu';
    menu.setAttribute('role', 'menu');
    menu.setAttribute('aria-label', 'خيارات الصفحة');

    const title = document.createElement('div');
    title.className = 'ua-wm-context-menu__title';
    title.textContent = rec.title || 'الصفحة';

    const close = document.createElement('button');
    close.type = 'button';
    close.className = 'ua-wm-context-menu__close';
    close.setAttribute('role', 'menuitem');
    close.innerHTML = '<i class="fa fa-times" aria-hidden="true"></i><span>إغلاق الصفحة</span>';
    close.addEventListener('click', function(ev){
      ev.preventDefault();
      ev.stopPropagation();
      closePane(key);
    });

    menu.appendChild(title);
    menu.appendChild(close);
    document.body.appendChild(menu);
    tabContextMenu = menu;

    const rect = menu.getBoundingClientRect();
    const left = Math.max(8, Math.min(Number(clientX) || 8, window.innerWidth - rect.width - 8));
    const top = Math.max(8, Math.min(Number(clientY) || 8, window.innerHeight - rect.height - 8));
    menu.style.left = left + 'px';
    menu.style.top = top + 'px';
  }

  function updateTitle(){
    const rec = panes.get(activeKey);
    if (rec) titleEl.setAttribute('data-active-title', rec.title || '');
  }

  function setCurrentPaneClasses(){
    applyBox(stage);
    const activeRecForBody = panes.get(activeKey);
    if (activeRecForBody) {
      body.setAttribute('data-ua-active-pane', activeRecForBody.key || '');
    }
    panes.forEach(rec => {
      /* IMPORTANT: applyBox() writes display:block!important.  If we leave that
         inline style on inactive panes, the browser ignores the hidden attribute
         and several pages stack vertically in the workspace.  Keep the sizing
         rules, then explicitly force exactly one pane visible. */
      applyBox(rec.pane);
      if (rec.iframe) applyFrameBox(rec.iframe);
      rec.pane.classList.toggle('has-iframe', !!rec.iframe);
      if (rec.iframe) rec.pane.setAttribute('data-ua-pane-kind', 'iframe');
      else rec.pane.removeAttribute('data-ua-pane-kind');
      const isCurrent = rec.key === activeKey && !rec.minimized;
      rec.pane.hidden = !isCurrent;
      rec.pane.style.setProperty('display', isCurrent ? 'block' : 'none', 'important');
      rec.pane.style.setProperty('visibility', isCurrent ? 'visible' : 'hidden', 'important');
      if (rec.iframe && isCurrent) {
        const h = workspaceViewportHeight();
        rec.pane.style.setProperty('height', h + 'px', 'important');
        rec.pane.style.setProperty('max-height', h + 'px', 'important');
        rec.pane.style.setProperty('overflow', 'hidden', 'important');
      } else if (!rec.iframe) {
        rec.pane.style.removeProperty('height');
        rec.pane.style.removeProperty('max-height');
        rec.pane.style.removeProperty('overflow');
      }
      rec.pane.setAttribute('aria-hidden', isCurrent ? 'false' : 'true');
      rec.pane.classList.toggle('is-current', isCurrent);
      rec.pane.classList.toggle('is-minimized', !!rec.minimized);
    });
    body.classList.toggle('ua-page-window-min', !!(panes.get(activeKey) && panes.get(activeKey).minimized));
  }

  function rememberActiveScroll(){
    const rec = panes.get(activeKey);
    if (!rec) return;
    rec.scrollTop = currentWindowScroll();
  }

  function showPane(key, restore){
    const rec = panes.get(key);
    if (!rec) return;
    rememberActiveScroll();
    activeKey = key;
    rememberLastShellUrl(key);
    rec.minimized = false;
    rec.touched = Date.now();
    ensureIframe(rec);
    upsertStoredPage(rec.loadUrl || rec.key, rec.title, {minimized:false, loadUrl:rec.loadUrl || rec.key});
    setCurrentPaneClasses();
    updateTitle();
    renderTabs();
    resizeIframe(rec);
    setTimeout(() => setWindowScroll(restore === false ? 0 : (rec.scrollTop || 0)), 0);
    window.dispatchEvent(new Event('resize'));
  }

  function enforceLimit(){
    const records = Array.from(panes.values()).sort((a,b) => (a.touched || 0) - (b.touched || 0));
    while (records.length > MAX_TABS) {
      const victim = records.shift();
      if (!victim || victim.key === activeKey) continue;
      victim.pane.remove();
      panes.delete(victim.key);
      removeStoredPage(victim.key);
    }
  }

  function openPage(url, title){
    const key = normalizeUrl(url);
    if (!key) return false;
    if (key === 'dashboard.php') {
      if (panes.has('dashboard.php')) {
        showPane('dashboard.php', true);
      } else {
        goDashboard(activeKey || getCurrentUrl());
      }
      return true;
    }
    if (panes.has(key)) {
      const rec = panes.get(key);
      const nextLoadUrl = loadableUrl(url) || key;
      if (rec && nextLoadUrl && rec.loadUrl !== nextLoadUrl) {
        rec.loadUrl = nextLoadUrl;
        rec.loaded = false;
        if (rec.iframe) {
          setPaneLoading(rec, true);
          rec.iframe.src = toIframeUrl(rec.loadUrl);
        }
      }
      showPane(key, true);
      return true;
    }

    rememberActiveScroll();
    const pane = document.createElement('div');
    pane.className = 'ua-wm-pane';
    applyBox(pane);
    pane.dataset.uaWmKey = key;
    pane.hidden = true;
    stage.appendChild(pane);

    const rec = {
      key,
      url: key,
      loadUrl: loadableUrl(url) || key,
      title: mappedTitle(key, title),
      pane,
      iframe: null,
      loaded: false,
      minimized: false,
      scrollTop: 0,
      touched: Date.now(),
      lazy: false,
      closed: false
    };
    panes.set(key, rec);
    ensureIframe(rec);
    activeKey = key;
    rememberLastShellUrl(key);
    upsertStoredPage(rec.loadUrl || key, rec.title, {minimized:false, loadUrl:rec.loadUrl || key});
    setCurrentPaneClasses();
    updateTitle();
    renderTabs();
    enforceLimit();
    setWindowScroll(0);
    scheduleResize(rec);
    return true;
  }

  function shouldManageLink(a, ev){
    if (!a || ev.defaultPrevented) return false;
    if (ev.metaKey || ev.ctrlKey || ev.shiftKey || ev.altKey || ev.button !== 0) return false;
    const href = a.getAttribute('href') || '';
    if (!href || href === '#' || href.startsWith('javascript:') || href.startsWith('mailto:') || href.startsWith('tel:')) return false;
    if (a.target && a.target !== '_self') return false;
    if (a.hasAttribute('download') || a.hasAttribute('data-no-workspace') || a.hasAttribute('data-no-frame')) return false;
    const scope = a.hasAttribute('data-ua-wm-open') ? a : a.closest('.ua-sb3, .ua-sb3-flyout-host, [data-ua-wm-open]');
    if (!scope) return false;
    if (isTransientProtectedUrl(href)) return false;
    const key = normalizeUrl(href);
    if (!key) return false;
    if (/^(api|ajax|cron)\//i.test(key)) return false;
    if (/\.(pdf|zip|rar|7z|xlsx?|csv|docx?|png|jpe?g|webp|gif|svg)(\?|#|$)/i.test(key)) return false;
    return true;
  }

  document.addEventListener('click', function(ev){
    if (isDashboard) {
      const dashSearchItem = ev.target.closest('.nocx-dash-search-item[data-url]');
      if (dashSearchItem) {
        ev.preventDefault();
        ev.stopPropagation();
        const url = dashSearchItem.getAttribute('data-url') || '';
        const label = dashSearchItem.querySelector('.nocx-dash-search-main');
        const title = label ? label.textContent : 'عرض المشتركين';
        const box = document.getElementById('nocSubscriberSearchResults');
        if (box) box.hidden = true;
        if (url) openPage(url, title || 'عرض المشتركين');
        return;
      }
    }

    const closeTab = ev.target.closest('[data-ua-wm-close-tab]');
    if (closeTab) {
      ev.preventDefault();
      ev.stopPropagation();
      const key = normalizeUrl(closeTab.getAttribute('data-ua-wm-close-tab') || '');
      closePane(key);
      return;
    }
    const dashBtn = ev.target.closest('[data-ua-wm-dashboard]');
    if (dashBtn) {
      ev.preventDefault();
      if (panes.has('dashboard.php')) showPane('dashboard.php', true);
      else goDashboard(activeKey || getCurrentUrl());
      return;
    }

    const tabBtn = ev.target.closest('[data-ua-wm-tab]');
    if (tabBtn) {
      ev.preventDefault();
      showPane(tabBtn.getAttribute('data-ua-wm-tab'), true);
      return;
    }

    const link = ev.target.closest('a[href]');
    if (shouldManageLink(link, ev)) {
      ev.preventDefault();
      const rawHref = link.getAttribute('href') || '';
      const label = linkTitle(link, rawHref);
      openPage(rawHref, label);
      return;
    }

    const closeBtn = ev.target.closest('[data-ua-window-close]');
    const maxBtn = ev.target.closest('[data-ua-window-max]');
    const minBtn = ev.target.closest('[data-ua-window-min]');

    if (closeBtn) {
      ev.preventDefault();
      const current = panes.get(activeKey);
      if (!current || current.key === 'dashboard.php') {
        if (panes.has('dashboard.php')) showPane('dashboard.php', true);
        return;
      }
      closePane(activeKey);
      return;
    }
    if (maxBtn) {
      ev.preventDefault();
      body.classList.toggle('ua-page-window-max');
      setTimeout(() => {
        const rec = panes.get(activeKey);
        if (rec) resizeIframe(rec);
        window.dispatchEvent(new Event('resize'));
      }, 60);
      return;
    }
    if (minBtn) {
      ev.preventDefault();
      const rec = panes.get(activeKey);
      if (rec && rec.key !== 'dashboard.php') {
        rec.minimized = true;
        rec.scrollTop = currentWindowScroll();
        setStoredMinimized(rec.key, true);
        setCurrentPaneClasses();
        renderTabs();
        setWindowScroll(0);
      }
      return;
    }
  }, true);

  document.addEventListener('contextmenu', function(ev){
    const tabBtn = ev.target && ev.target.closest ? ev.target.closest('[data-ua-wm-tab]') : null;
    if (!tabBtn) {
      closeTabContextMenu();
      return;
    }
    const key = normalizeUrl(tabBtn.getAttribute('data-ua-wm-tab') || '');
    if (!key || key === 'dashboard.php') return;
    ev.preventDefault();
    ev.stopPropagation();
    showTabContextMenu(key, ev.clientX, ev.clientY);
  }, true);

  document.addEventListener('mousedown', function(ev){
    if (tabContextMenu && !tabContextMenu.contains(ev.target)) closeTabContextMenu();
  }, true);

  document.addEventListener('keydown', function(ev){
    if (ev.key === 'Escape') closeTabContextMenu();
    if (!isDashboard || ev.key !== 'Enter') return;
    const input = ev.target && ev.target.closest ? ev.target.closest('#nocDashboardSearch') : null;
    if (!input) return;
    const q = String(input.value || '').replace(/\s+/g, ' ').trim();
    const box = document.getElementById('nocSubscriberSearchResults');
    const first = box ? box.querySelector('.nocx-dash-search-item[data-url]') : null;
    const url = first ? (first.getAttribute('data-url') || '') : (q ? ('subscribers.php?filter=all&q=' + encodeURIComponent(q)) : 'subscribers.php');
    ev.preventDefault();
    ev.stopPropagation();
    if (box) box.hidden = true;
    openPage(url, 'عرض المشتركين');
  }, true);

  window.addEventListener('resize', function(){
    closeTabContextMenu();
    const rec = panes.get(activeKey);
    if (rec) resizeIframe(rec);
    setCurrentPaneClasses();
    scheduleTabOverflowMode();
  });
  if (window.visualViewport) {
    window.visualViewport.addEventListener('resize', function(){
      const rec = panes.get(activeKey);
      if (rec) resizeIframe(rec);
      setCurrentPaneClasses();
    }, {passive:true});
  }
  window.addEventListener('ua:layout', function(){
    setCurrentPaneClasses();
  });

  function consumePendingTarget(){
    const target = takePendingTarget();
    if (!target || target === 'dashboard.php') return;
    const saved = loadStoredPages().find(p => p.url === target);
    if (panes.has(target)) {
      showPane(target, true);
    } else {
      openPage(target, saved ? saved.title : target);
    }
  }

  function restoreLastWorkAfterDashboardReload(){
    if (!isDashboard || !isBrowserReload()) { clearRestorePending(); return; }
    const target = getLastShellUrl();
    if (!target || target === 'dashboard.php') { clearRestorePending(); return; }
    const saved = loadStoredPages().find(p => p.url === target);
    if (panes.has(target)) {
      showPane(target, true);
    } else {
      openPage(target, saved ? saved.title : target);
    }
    setTimeout(clearRestorePending, 120);
  }

  window.addEventListener('pageshow', function(){ setTimeout(consumePendingTarget, 0); });
  document.addEventListener('DOMContentLoaded', function(){ setTimeout(consumePendingTarget, 0); });

  window.UAWindowManager = {
    open: openPage,
    show: showPane,
    panes: panes,
    loadStoredPages: loadStoredPages
  };

  renderTabs();
  updateTitle();
  setCurrentPaneClasses();
  setTimeout(consumePendingTarget, 0);
  setTimeout(restoreLastWorkAfterDashboardReload, 0);
  setTimeout(preloadStoredPanes, 320);
})();
