/* ============================================================
   AdminDialog — shared themed dialogs for the AliothPress admin
   ------------------------------------------------------------
   Replaces native window.alert / confirm / prompt everywhere in
   the admin panel: browser dialogs ignore the admin theme
   entirely (white chrome popups over a dark admin) and cannot be
   styled or translated consistently.

   Third sibling of the same design: AliothEditor.dialog (rich
   text editor) and pbDialog (Page Builder) already use identical
   markup/behaviour on their own token sets. This one is built on
   the ADMIN tokens (--adm-*) + the admin's own .btn classes, so
   it is loaded from base.html and available on every admin page.
   AliothEditor.dialog delegates here when this file is present,
   so the editor and the rest of the admin share one modal.

   API (all Promise-based — native dialogs were synchronous, so
   call sites converted from `if (confirm(x)) y` to
   `AdminDialog.confirm(x).then(ok => ok && y)`):

     AdminDialog.dialog({ title, message, fields, okLabel,
                          cancelLabel, danger, hideCancel })
        -> Promise<{name:value,...} | null>
     AdminDialog.alert(message [, {title}])    -> Promise<void>
     AdminDialog.confirm(message [, {title, okLabel, danger}])
        -> Promise<boolean>
     AdminDialog.prompt(label [, value])       -> Promise<string|null>

   Declarative confirms (replaces onsubmit="return confirm(…)"):

     <form data-confirm="Really delete?" data-confirm-danger
           data-confirm-ok="Delete">…</form>
     <button data-confirm="…">           (submit buttons / links)

   A delegated capture listener intercepts the submit/click,
   shows the themed confirm, and re-triggers on OK.

   Translations for the default OK/Cancel labels come via
   window.AdminDialogI18N (set inline in base.html) so this file
   stays free of Jinja.
   ============================================================ */
(function (global) {
  'use strict';

  function t(key, fallback) {
    var i18n = global.AdminDialogI18N || {};
    return i18n[key] || fallback;
  }

  function esc(s) {
    return String(s == null ? '' : s)
      .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;');
  }

  function dialog(opts) {
    opts = opts || {};
    return new Promise(function (resolve) {
      var overlay = document.createElement('div');
      overlay.className = 'adm-modal-overlay';
      var fieldsHtml = (opts.fields || []).map(function (fld, i) {
        return '<div class="adm-modal-field">' +
          '<label for="adm-dlg-f' + i + '">' + esc(fld.label) + '</label>' +
          '<input id="adm-dlg-f' + i + '" type="' + esc(fld.type || 'text') + '"' +
          ' value="' + esc(fld.value || '') + '"' +
          (fld.placeholder ? ' placeholder="' + esc(fld.placeholder) + '"' : '') +
          (fld.min != null ? ' min="' + esc(fld.min) + '"' : '') +
          (fld.max != null ? ' max="' + esc(fld.max) + '"' : '') +
          ' autocomplete="off">' +
          '</div>';
      }).join('');
      overlay.innerHTML =
        '<div class="adm-modal" role="dialog" aria-modal="true" aria-label="' + esc(opts.title || opts.message || '') + '">' +
          '<div class="adm-modal-head">' +
            '<h3>' + esc(opts.title || '') + '</h3>' +
            '<button type="button" class="adm-modal-x" aria-label="' + esc(t('cancel', 'Cancel')) + '">\u00d7</button>' +
          '</div>' +
          (opts.message ? '<div class="adm-modal-message">' + esc(opts.message) + '</div>' : '') +
          fieldsHtml +
          '<div class="adm-modal-actions">' +
            (opts.hideCancel ? '' :
              '<button type="button" class="btn btn-secondary btn-sm" data-adm-cancel>' +
                esc(opts.cancelLabel || t('cancel', 'Cancel')) + '</button>') +
            '<button type="button" class="btn ' + (opts.danger ? 'btn-danger' : 'btn-primary') + ' btn-sm" data-adm-ok>' +
              esc(opts.okLabel || t('ok', 'OK')) + '</button>' +
          '</div>' +
        '</div>';
      document.body.appendChild(overlay);
      var inputs = overlay.querySelectorAll('.adm-modal-field input');
      function collect() {
        var out = {};
        (opts.fields || []).forEach(function (fld, i) { out[fld.name] = inputs[i].value; });
        return out;
      }
      function close(result) {
        document.removeEventListener('keydown', onKey, true);
        if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
        resolve(result);
      }
      function onKey(e) {
        if (e.key === 'Escape') { e.stopPropagation(); close(null); }
        else if (e.key === 'Enter' && overlay.contains(e.target) &&
                 !e.target.hasAttribute('data-adm-cancel')) {
          e.preventDefault(); e.stopPropagation(); close(collect());
        }
      }
      overlay.addEventListener('mousedown', function (e) { if (e.target === overlay) close(null); });
      overlay.querySelector('.adm-modal-x').addEventListener('click', function () { close(null); });
      var cancelBtn = overlay.querySelector('[data-adm-cancel]');
      if (cancelBtn) cancelBtn.addEventListener('click', function () { close(null); });
      overlay.querySelector('[data-adm-ok]').addEventListener('click', function () { close(collect()); });
      document.addEventListener('keydown', onKey, true);
      if (inputs[0]) { inputs[0].focus(); inputs[0].select(); }
      else { overlay.querySelector('[data-adm-ok]').focus(); }
    });
  }

  function admAlert(message, opts) {
    opts = opts || {};
    return dialog({
      title: opts.title || '',
      message: message,
      hideCancel: true
    }).then(function () { /* resolve void either way */ });
  }

  function admConfirm(message, opts) {
    opts = opts || {};
    return dialog({
      /* Short messages read best as the heading; with an explicit title the
         message drops into the body (multi-line confirms keep their \n via
         white-space: pre-line). */
      title: opts.title || (message.indexOf('\n') === -1 && message.length <= 90 ? message : ''),
      message: (opts.title || message.indexOf('\n') !== -1 || message.length > 90) ? message : '',
      okLabel: opts.okLabel,
      danger: opts.danger
    }).then(function (r) { return r !== null; });
  }

  function admPrompt(label, value) {
    return dialog({
      title: label,
      fields: [{ name: 'v', label: label, value: value || '' }]
    }).then(function (r) { return r ? r.v : null; });
  }

  /* ── Declarative data-confirm ────────────────────────────────
     Forms: intercept submit once, confirm, then re-submit with a
     marker attribute so the second pass falls through. Using
     requestSubmit() keeps normal submit semantics (submitter
     name/value, HTML validation); form.submit() is the fallback. */
  document.addEventListener('submit', function (e) {
    var form = e.target;
    if (!form || !form.hasAttribute || !form.hasAttribute('data-confirm')) return;
    if (form.hasAttribute('data-confirm-passed')) {
      form.removeAttribute('data-confirm-passed');
      return;
    }
    e.preventDefault();
    e.stopImmediatePropagation();
    var submitter = e.submitter || null;
    admConfirm(form.getAttribute('data-confirm'), {
      danger: form.hasAttribute('data-confirm-danger'),
      okLabel: form.getAttribute('data-confirm-ok') || undefined
    }).then(function (ok) {
      if (!ok) return;
      form.setAttribute('data-confirm-passed', '');
      if (form.requestSubmit) form.requestSubmit(submitter || undefined);
      else form.submit();
    });
  }, true);

  /* Buttons & links: <button data-confirm> / <a data-confirm>. */
  document.addEventListener('click', function (e) {
    var el = e.target && e.target.closest ? e.target.closest('[data-confirm]') : null;
    if (!el || el.tagName === 'FORM') return;
    if (el.hasAttribute('data-confirm-passed')) {
      el.removeAttribute('data-confirm-passed');
      return;
    }
    e.preventDefault();
    e.stopImmediatePropagation();
    admConfirm(el.getAttribute('data-confirm'), {
      danger: el.hasAttribute('data-confirm-danger'),
      okLabel: el.getAttribute('data-confirm-ok') || undefined
    }).then(function (ok) {
      if (!ok) return;
      if (el.tagName === 'A' && el.href) { global.location.href = el.href; return; }
      var form = el.form || (el.closest ? el.closest('form') : null);
      if (form && (el.type === 'submit' || !el.type)) {
        /* Mark the FORM too: if it carries its own data-confirm the submit
           listener above must not ask a second time. */
        form.setAttribute('data-confirm-passed', '');
        if (form.requestSubmit) form.requestSubmit(el);
        else form.submit();
      } else {
        el.setAttribute('data-confirm-passed', '');
        el.click();
      }
    });
  }, true);

  global.AdminDialog = {
    dialog: dialog,
    alert: admAlert,
    confirm: admConfirm,
    prompt: admPrompt
  };
})(window);
