/* Mersal Suite — shell interactions (vanilla, no deps).
 * Navigation between routes is done in-place (no full page reload): internal
 * links are intercepted, the target page is fetched and only the app shell is
 * swapped in, with the URL kept in sync via the History API. All interactive
 * controls are wired through event delegation on the persistent root node so
 * they keep working across those swaps without any re-binding. */
(function () {
  'use strict';
  var CFG = window.MERSAL_SUITE || {};
  var root = document.querySelector('.mersal-suite-app');
  if (!root) return;

  function post(action, data, cb) {
    var body = new URLSearchParams();
    body.append('action', action);
    for (var k in data) { if (Object.prototype.hasOwnProperty.call(data, k)) { body.append(k, data[k]); } }
    fetch(CFG.ajax, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString() })
      .then(function (r) { return r.json(); })
      .then(function (j) { if (cb) cb(j); })
      .catch(function () { if (cb) cb({ success: false }); });
  }

  /* Centred on the viewport, above the WordPress chrome. A bottom-anchored
     toast disappeared behind the admin menu / collapsed-menu flyout, so a save
     read as if nothing had happened. `inset:0 + margin:auto` centres on both
     axes without a transform, so it is direction-agnostic (RTL and LTR). */
  /* Reveal the icon font once it is genuinely available.
     The stylesheet keeps .msym hidden so the ligature names never flash as
     words; this flips it back on. The timeout matters more than the happy
     path — if the font never arrives we reveal anyway, which is no worse than
     what shipped before, rather than leaving every icon blank. */
  (function () {
    var reveal = function () { document.documentElement.classList.add('ms-fonts-ready'); };
    if (document.fonts && document.fonts.load) {
      var done = false;
      var once = function () { if (!done) { done = true; reveal(); } };
      document.fonts.load('24px "Material Symbols Rounded"').then(once).catch(once);
      document.fonts.ready.then(once).catch(once);
      setTimeout(once, 3000);
    } else {
      reveal();
    }
  })();

  function toast(msg, ok) {
    var t = document.createElement('div');
    t.textContent = msg;
    t.setAttribute('role', 'status');
    t.style.cssText = 'position:fixed; inset:0; margin:auto; z-index:160000; width:max-content; height:max-content; max-width:min(92vw,520px); background:#10241b; color:#fff; padding:14px 24px; border-radius:99px; font-size:14px; font-weight:700; box-shadow:0 18px 48px rgba(0,0,0,.3); font-family:Cairo,Inter,sans-serif; text-align:center;';
    if (ok === false) { t.style.background = '#b42318'; }
    document.body.appendChild(t);
    setTimeout(function () { t.style.transition = 'opacity .3s'; t.style.opacity = '0'; setTimeout(function () { t.remove(); }, 300); }, 1900);
  }

  /* ---- dropdown panels (switcher + notifications) ---- */
  function setPanel(name, open) {
    var panel = root.querySelector('[data-ms-panel="' + name + '"]');
    var back = root.querySelector('[data-ms-backdrop="' + name + '"]');
    if (panel) panel.style.display = open ? 'block' : 'none';
    if (back) back.style.display = open ? 'block' : 'none';
  }
  function closeAll() { setPanel('switch', false); setPanel('notif', false); }

  function applySwitch(sw, on) {
    var rtl = root.getAttribute('dir') === 'rtl';
    sw.setAttribute('data-ms-on', on ? '1' : '0');
    sw.style.background = on ? 'var(--accent)' : 'var(--border-strong)';
    var knob = sw.querySelector('span');
    if (knob) knob.style.transform = 'translateX(' + (on ? (rtl ? '-18px' : '18px') : '0px') + ')';
  }

  /* ------------------------------------------------------------------ */
  /* In-place navigation (no full reload)                               */
  /* ------------------------------------------------------------------ */

  /* A link we should handle ourselves: same-origin, same admin screen
   * (page=mersal-suite), opening in the same tab. Everything else (plugin
   * activation, external downloads, new-tab links) falls through to the
   * browser. */
  function isNavLink(a) {
    if (!a || !a.getAttribute) return false;
    var target = a.getAttribute('target');
    if (target && target !== '_self') return false;
    var href = a.getAttribute('href') || '';
    if (!href || href.charAt(0) === '#') return false;
    var u;
    try { u = new URL(a.href, location.href); } catch (e) { return false; }
    if (u.origin !== location.origin) return false;
    if (!/\/admin\.php$/.test(u.pathname)) return false;
    return u.searchParams.get('page') === 'mersal-suite';
  }

  /* Scripts inside a swapped-in fragment don't run when injected via innerHTML,
   * so we re-create them. Two of the plugin's scripts register global (document)
   * listeners and must run only ONCE per session; everything else (config
   * setters, page-scoped IIFEs) is safe — and required — to run on every swap. */
  var RUN_ONCE = { 'motp-admin-js': true, 'motp-icons-js': true };
  var ranOnce = {};
  Object.keys(RUN_ONCE).forEach(function (id) {
    if (document.getElementById(id)) ranOnce[id] = true; /* already run by the first full load */
  });

  function execScript(old) {
    var s = document.createElement('script');
    for (var i = 0; i < old.attributes.length; i++) {
      s.setAttribute(old.attributes[i].name, old.attributes[i].value);
    }
    s.textContent = old.textContent;
    old.parentNode.replaceChild(s, old);
  }

  function runScripts(container) {
    var fresh = {};
    Array.prototype.slice.call(container.querySelectorAll('script')).forEach(function (old) {
      var type = (old.getAttribute('type') || '').toLowerCase();
      if (['', 'text/javascript', 'application/javascript', 'module'].indexOf(type) === -1) return; /* leave data blocks (e.g. application/json) alone */
      var id = old.id || '';
      if (id && RUN_ONCE[id]) {
        if (ranOnce[id]) return;
        ranOnce[id] = true;
        fresh[id] = true;
      }
      execScript(old);
    });
    return fresh;
  }

  /* Re-bind the plugin's per-DOM interactions to freshly swapped content. When a
   * run-once script executed this swap it already self-initialised, so we skip
   * the matching manual call to avoid double-binding. */
  function reinit(container, fresh) {
    if (!fresh['motp-icons-js'] && window.MOTPicons && window.MOTPicons.swap) {
      window.MOTPicons.swap(container);
    }
    if (!fresh['motp-admin-js'] && window.motpInitAdminShell) {
      window.motpInitAdminShell(container.querySelector('.motp-app') || container);
    }
  }

  var progressEl = null, navToken = 0;
  function progressBar() {
    if (!progressEl) {
      progressEl = document.createElement('div');
      progressEl.className = 'ms-progress';
      progressEl.innerHTML = '<span></span>';
      document.body.appendChild(progressEl);
    }
    return progressEl.firstChild;
  }
  function startProgress() {
    var bar = progressBar();
    root.classList.add('ms-loading');
    bar.style.transition = 'none';
    bar.style.opacity = '1';
    bar.style.width = '0';
    void bar.offsetWidth; /* reflow so the width animation restarts */
    bar.style.transition = 'width 8s cubic-bezier(.12,.7,.3,1), opacity .3s ease';
    bar.style.width = '82%';
  }
  function endProgress() {
    root.classList.remove('ms-loading');
    if (!progressEl) return;
    var bar = progressEl.firstChild;
    bar.style.transition = 'width .2s ease, opacity .35s ease .1s';
    bar.style.width = '100%';
    bar.style.opacity = '0';
  }

  function navigate(url, push) {
    var mine = ++navToken;
    startProgress();
    fetch(url, { credentials: 'same-origin' })
      .then(function (r) { return r.text(); })
      .then(function (html) {
        if (mine !== navToken) return; /* a newer navigation won */
        var doc = new DOMParser().parseFromString(html, 'text/html');
        var fresh = doc.querySelector('.mersal-suite-app');
        if (!fresh) { location.href = url; return; }
        root.innerHTML = fresh.innerHTML;
        if (fresh.getAttribute('dir')) root.setAttribute('dir', fresh.getAttribute('dir'));
        if (fresh.getAttribute('data-dark')) root.setAttribute('data-dark', fresh.getAttribute('data-dark'));
        if (doc.title) document.title = doc.title;
        if (push) history.pushState({ msNav: true }, '', url);
        var ran = runScripts(root); /* re-execute inert <script> nodes the swap injected */
        reinit(root, ran);          /* re-bind plugin per-DOM interactions */
        var main = root.querySelector('main');
        if (main) main.scrollTop = 0;
        closeAll();
        endProgress();
      })
      .catch(function () {
        if (mine !== navToken) return;
        endProgress();
        location.href = url; /* fall back to a hard navigation */
      });
  }

  window.addEventListener('popstate', function () { navigate(location.href, false); });

  /* ------------------------------------------------------------------ */
  /* Delegated interactions (survive shell swaps)                       */
  /* ------------------------------------------------------------------ */

  root.addEventListener('click', function (e) {
    var t = e.target;
    if (!t || !t.closest) return;

    /* One-click install / update of a Mersal plugin from mersal.it. */
    var inst = t.closest('[data-ms-install]');
    if (inst) {
      e.preventDefault();
      if (inst.getAttribute('data-ms-busy') === '1') return;
      var pid = inst.getAttribute('data-ms-install');
      var confirmMsg = CFG.lang === 'en'
        ? 'Install the latest version from mersal.it now?'
        : 'تثبيت أحدث إصدار من mersal.it الآن؟';
      if (!window.confirm(confirmMsg)) return;
      inst.setAttribute('data-ms-busy', '1');
      inst.style.opacity = '.55';
      var oldHtml = inst.innerHTML;
      if (inst.tagName === 'BUTTON') {
        inst.innerHTML = CFG.lang === 'en' ? 'Installing…' : 'جارٍ التثبيت…';
      }
      startProgress();
      toast(CFG.lang === 'en' ? 'Downloading from mersal.it…' : 'جارٍ التحميل من mersal.it…', true);
      post('mersal_suite_install', { nonce: CFG.installNonce, id: pid }, function (j) {
        endProgress();
        if (j && j.success) {
          toast(CFG.lang === 'en' ? 'Installed successfully. Reloading…' : 'تم التثبيت بنجاح. جارٍ التحديث…', true);
          setTimeout(function () { location.reload(); }, 900);
        } else {
          inst.removeAttribute('data-ms-busy');
          inst.style.opacity = '';
          inst.innerHTML = oldHtml;
          var msg = (j && j.data && j.data.message) ? j.data.message : (CFG.lang === 'en' ? 'Installation failed' : 'فشل التثبيت');
          toast(msg, false);
        }
      });
      return;
    }

    /* Dismiss the remote announcement (per-user, remembered server-side). */
    var dism = t.closest('[data-ms-notice-dismiss]');
    if (dism) {
      e.preventDefault();
      var card = dism.closest('[data-ms-notice]');
      if (card) { card.style.transition = 'opacity .25s'; card.style.opacity = '0'; setTimeout(function () { card.remove(); }, 250); }
      post('mersal_suite_dismiss_notice', { nonce: CFG.prefNonce, id: dism.getAttribute('data-ms-notice-dismiss') });
      return;
    }

    /* Internal route link → swap in place. */
    var a = t.closest('a[href]');
    if (a && isNavLink(a)) {
      if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
      e.preventDefault();
      closeAll();
      if (a.href !== location.href) navigate(a.href, true);
      return;
    }

    /* Language switch (still a full reload — flips direction + all labels). */
    var lang = t.closest('[data-ms-lang]');
    if (lang) {
      var code = lang.getAttribute('data-ms-lang');
      if (code === CFG.lang) return;
      post('mersal_suite_pref', { nonce: CFG.prefNonce, lang: code }, function () { location.reload(); });
      return;
    }

    /* Dropdown toggles (switcher / notifications). */
    var tog = t.closest('[data-ms-toggle]');
    if (tog) {
      e.stopPropagation();
      var name = tog.getAttribute('data-ms-toggle');
      var panel = root.querySelector('[data-ms-panel="' + name + '"]');
      var isOpen = panel && panel.style.display === 'block';
      closeAll();
      setPanel(name, !isOpen);
      return;
    }

    /* Backdrop click closes any open dropdown. */
    if (t.closest('[data-ms-backdrop]')) { closeAll(); return; }

    /* Suite-owned toggle switches (optimistic UI). */
    var sw = t.closest('[data-ms-switch]');
    if (sw) {
      var key = sw.getAttribute('data-ms-switch');
      var on = sw.getAttribute('data-ms-on') === '1';
      applySwitch(sw, !on);
      post('mersal_suite_toggle', { nonce: CFG.saveNonce, key: key }, function (j) {
        if (!j || !j.success) { applySwitch(sw, on); toast(CFG.lang === 'en' ? 'Save failed' : 'تعذّر الحفظ', false); return; }
        applySwitch(sw, !!j.data.on);
      });
      return;
    }

    /* Suite settings save buttons. */
    var save = t.closest('[data-ms-save]');
    if (save) {
      var keys = (save.getAttribute('data-ms-save') || '').split(',').map(function (s) { return s.trim(); }).filter(Boolean);
      var fields = {};
      keys.forEach(function (key2) {
        var inp = root.querySelector('[data-ms-field="' + key2 + '"]');
        if (inp) fields['fields[' + key2 + ']'] = inp.value;
      });
      post('mersal_suite_save', Object.assign({ nonce: CFG.saveNonce }, fields), function (j) {
        toast(j && j.success ? (CFG.lang === 'en' ? 'Saved' : 'تم الحفظ') : (CFG.lang === 'en' ? 'Save failed' : 'فشل الحفظ'), j && j.success);
      });
      return;
    }
  });

  /* ------------------------------------------------------------------ */
  /* Sidebar search (client-side nav filter)                            */
  /* ------------------------------------------------------------------ */

  /* Fold Arabic so search ignores diacritics and alef/ya/ta-marbuta variants. */
  function fold(str) {
    str = (str || '').toLowerCase().trim();
    str = str.replace(/[ً-ْٰـ]/g, ''); /* tashkeel + tatweel */
    str = str.replace(/[آأإ]/g, 'ا');  /* آ أ إ → ا */
    str = str.replace(/ى/g, 'ي');                /* ى → ي */
    str = str.replace(/ة/g, 'ه');                /* ة → ه */
    return str;
  }

  function emptyState(nav, show) {
    var el = nav.querySelector('.ms-search-empty');
    if (show) {
      if (!el) {
        el = document.createElement('div');
        el.className = 'ms-search-empty';
        el.style.cssText = 'padding:16px 12px; font-size:12px; color:#6f8a7c; text-align:center;';
        el.textContent = CFG.lang === 'en' ? 'No matching items' : 'لا توجد نتائج مطابقة';
        nav.appendChild(el);
      }
      el.style.display = '';
    } else if (el) {
      el.style.display = 'none';
    }
  }

  function runSearch(raw) {
    var nav = root.querySelector('aside nav');
    if (!nav) return;
    var q = fold(raw);
    var anyMatch = false;
    Array.prototype.forEach.call(nav.children, function (group) {
      if (group.classList && group.classList.contains('ms-search-empty')) return;
      var items = group.querySelectorAll('.ms-nav-item');
      if (!items.length) return;
      var visible = 0;
      Array.prototype.forEach.call(items, function (item) {
        var hit = !q || fold(item.textContent).indexOf(q) !== -1;
        item.style.display = hit ? '' : 'none';
        if (hit) visible++;
      });
      /* Hide the whole group (its heading included) when nothing matches. */
      group.style.display = visible === 0 ? 'none' : '';
      if (visible) anyMatch = true;
    });
    emptyState(nav, !!q && !anyMatch);
  }

  root.addEventListener('input', function (e) {
    var s = e.target.closest ? e.target.closest('[data-ms-search]') : null;
    if (s) runSearch(s.value);
  });

  /* ⌘K / Ctrl+K focuses search; Esc clears it. */
  document.addEventListener('keydown', function (e) {
    var s = root.querySelector('[data-ms-search]');
    if (!s) return;
    if ((e.metaKey || e.ctrlKey) && (e.key === 'k' || e.key === 'K')) {
      e.preventDefault();
      s.focus();
      s.select();
    } else if (e.key === 'Escape' && document.activeElement === s && s.value) {
      s.value = '';
      runSearch('');
    }
  });
})();
