// confirm-dialog.js — Promise-based custom confirm dialog primitive.
//
// Replaces native window.confirm() for actions where the dashboard wants
// a styled, accessible modal. The HTML scaffold lives in layout.html
// (#confirm-dialog) and the styles live in styles.css (.confirm-card,
// .confirm-actions). Both the trigger and the dialog buttons are wired
// to the same Promise so callers can `await confirmDialog({...})`.
//
// Behavior contract (matches WI W-mq5dk1lq):
//   - Escape closes (resolves false)
//   - Backdrop click closes (resolves false)
//   - Enter activates the focused button (default focus is the confirm
//     button, so Enter == confirm in the common case)
//   - Tab / Shift+Tab cycle between Cancel and Confirm (focus trap)
//   - Focus returns to the element that opened the dialog on close
//   - role="dialog", aria-modal="true", aria-labelledby points at the title
//
// API:
//   confirmDialog({title, message, confirmLabel, cancelLabel, danger})
//     -> Promise<boolean>  (true = confirmed, false = cancelled)

(function() {
  let _activeResolve = null;
  let _previousFocus = null;
  let _keyHandler = null;

  function getEl() { return document.getElementById('confirm-dialog'); }

  function getFocusable(scope) {
    return Array.from(scope.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'))
      .filter(el => !el.disabled && el.offsetParent !== null);
  }

  function closeDialog(result) {
    const el = getEl();
    if (!el) return;
    el.classList.remove('open');
    if (_keyHandler) {
      document.removeEventListener('keydown', _keyHandler, true);
      _keyHandler = null;
    }
    const resolver = _activeResolve;
    _activeResolve = null;
    // Restore focus to the trigger element (button/link/etc) on close.
    const prev = _previousFocus;
    _previousFocus = null;
    if (prev && typeof prev.focus === 'function') {
      try { prev.focus(); } catch { /* ignore — element may be gone */ }
    }
    if (resolver) resolver(!!result);
  }

  function confirmDialog(opts) {
    opts = opts || {};
    const el = getEl();
    if (!el) {
      // Defensive: if the HTML scaffold is missing, fall back to native
      // confirm so the calling action still works (e.g. in a test harness
      // that loads the JS without the layout).
      return Promise.resolve(window.confirm(opts.message || opts.title || 'Confirm?'));
    }
    // If a prior dialog is somehow still open, cancel it before reusing
    // the shared scaffold.
    if (_activeResolve) closeDialog(false);

    const titleEl = el.querySelector('#confirm-dialog-title');
    const msgEl = el.querySelector('#confirm-dialog-message');
    const confirmBtn = el.querySelector('#confirm-dialog-confirm');
    const cancelBtn = el.querySelector('#confirm-dialog-cancel');

    titleEl.textContent = opts.title || 'Confirm';
    msgEl.textContent = opts.message || '';
    confirmBtn.textContent = opts.confirmLabel || 'OK';
    cancelBtn.textContent = opts.cancelLabel || 'Cancel';
    // Style the confirm action: red border/text for destructive intent,
    // solid blue for the default reversible/action case. Both reuse the
    // existing .btn primitive in styles.css so the dialog inherits the
    // app's button look.
    confirmBtn.className = 'btn ' + (opts.danger ? 'btn-danger' : 'btn-primary');
    cancelBtn.className = 'btn';

    _previousFocus = document.activeElement;

    return new Promise((resolve) => {
      _activeResolve = resolve;

      el.classList.add('open');
      // Default-focus the confirm button so Enter activates it natively.
      // (Spec: "Enter submits (confirm)".) Defer to next tick so the
      // browser sees the dialog as visible before focus is moved.
      setTimeout(() => { try { confirmBtn.focus(); } catch { /* ignore */ } }, 0);

      _keyHandler = function(ev) {
        if (!el.classList.contains('open')) return;
        if (ev.key === 'Escape') {
          ev.preventDefault();
          closeDialog(false);
          return;
        }
        if (ev.key === 'Tab') {
          // Focus trap: keep tab cycling between the two buttons.
          const focusable = getFocusable(el);
          if (focusable.length === 0) return;
          const first = focusable[0];
          const last = focusable[focusable.length - 1];
          if (ev.shiftKey && document.activeElement === first) {
            ev.preventDefault();
            last.focus();
          } else if (!ev.shiftKey && document.activeElement === last) {
            ev.preventDefault();
            first.focus();
          }
        }
        // Enter / Space are handled natively by whichever button has focus.
      };
      document.addEventListener('keydown', _keyHandler, true);
    });
  }

  window.confirmDialog = confirmDialog;
  // Exposed so the inline onclick handlers on the dialog backdrop /
  // Cancel / Confirm buttons can resolve the promise.
  window._confirmDialogResolve = closeDialog;
})();
