/**
 * 1MZ For Artists — Design System
 * design-system.js — Delegator central para componentes interactivos
 *
 * Filosofia: ZERO event listeners por elemento. Todos os componentes do
 * design system são activados por data-attributes, e há UM listener
 * delegate por tipo de evento. Isto significa:
 *
 *   - HTML pode ser injectado dinamicamente (AJAX) e funciona logo
 *   - Não há fugas de memória
 *   - É impossível "esquecer" de fazer bind
 *   - Funciona com CSP estrito (zero inline handlers)
 *
 * API exposta no global window.rmbz:
 *   rmbz.modal.open(id)
 *   rmbz.modal.close(id)         // ou close() para fechar todos
 *   rmbz.toast.show(message, type, options)
 *   rmbz.button.setLoading(button, isLoading)
 *
 * Atributos suportados no HTML:
 *
 *   [data-rmbz-modal-open="my-modal"]      Abre modal (no click)
 *   [data-rmbz-modal]                      Marca um elemento como modal (container)
 *   [data-rmbz-action="close"]             Fecha o modal pai mais próximo
 *   [data-rmbz-pill-group]                 Grupo de pills com toggle
 *   [data-rmbz-pill][data-target="X"]      Pill individual (mostra/esconde alvos)
 *   [data-rmbz-toast="msg|type"]           Trigger toast no click (raro)
 *   [data-rmbz-loading-on-submit]          Form: botão entra em loading no submit
 */

(function () {
  'use strict';

  // Guard contra múltipla inicialização (importante: o script pode ser
  // enqueued duas vezes se o tema fizer asneira)
  if (window.__rmbzDsInit) return;
  window.__rmbzDsInit = true;

  // ─────────────────────────────────────────────────────────────────────────
  // Helpers
  // ─────────────────────────────────────────────────────────────────────────

  const $  = (sel, root = document) => root.querySelector(sel);
  const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel));

  function ensureToastContainer() {
    let c = $('.rmbz-toast-container');
    if (c) return c;
    c = document.createElement('div');
    c.className = 'rmbz-toast-container';
    c.setAttribute('aria-live', 'polite');
    c.setAttribute('aria-atomic', 'true');
    document.body.appendChild(c);
    return c;
  }

  // ─────────────────────────────────────────────────────────────────────────
  // MODAL
  // ─────────────────────────────────────────────────────────────────────────

  const modal = {
    open(id) {
      const el = document.getElementById(id);
      if (!el) return;
      // Fechar outros antes de abrir um novo (evita stacking horrível)
      modal.closeAll();
      // Limpar qualquer style.display inline gravado por código antigo
      // (ex: opener legacy fazia el.style.display='flex' directamente)
      el.style.removeProperty('display');
      el.removeAttribute('hidden');
      // Bloquear scroll do body
      document.body.style.overflow = 'hidden';
      // Focus no primeiro elemento focável
      const firstFocusable = el.querySelector(
        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
      );
      // setTimeout para esperar a animação iniciar
      setTimeout(() => firstFocusable?.focus(), 50);
      el.dispatchEvent(new CustomEvent('rmbz:modal:open', { bubbles: true }));
    },

    close(id) {
      const el = id ? document.getElementById(id) : null;
      if (el) {
        // Limpar style.display inline (pode ter sido gravado por código antigo)
        // antes de pôr o atributo hidden, para garantir que esconde mesmo.
        el.style.removeProperty('display');
        el.setAttribute('hidden', '');
        el.dispatchEvent(new CustomEvent('rmbz:modal:close', { bubbles: true }));
      }
      // Se não há mais modais abertos, libertar scroll
      if (!$$('.rmbz-modal:not([hidden])').length) {
        document.body.style.overflow = '';
      }
    },

    closeAll() {
      $$('.rmbz-modal:not([hidden])').forEach((el) => {
        el.style.removeProperty('display');
        el.setAttribute('hidden', '');
        el.dispatchEvent(new CustomEvent('rmbz:modal:close', { bubbles: true }));
      });
      document.body.style.overflow = '';
    },
  };

  // ─────────────────────────────────────────────────────────────────────────
  // TOAST
  // ─────────────────────────────────────────────────────────────────────────

  const toast = {
    /**
     * Exibe uma notificação flutuante.
     * @param {string} message - Mensagem (pode conter HTML simples)
     * @param {'info'|'success'|'danger'|'warning'} type
     * @param {object} [opts]
     * @param {number} [opts.duration=5000] - ms antes de auto-fechar (0 = nunca)
     * @param {boolean} [opts.dismissible=true]
     */
    show(message, type = 'info', opts = {}) {
      const container = ensureToastContainer();
      const duration = opts.duration ?? 5000;
      const dismissible = opts.dismissible ?? true;

      const el = document.createElement('div');
      el.className = `rmbz-toast rmbz-toast--${type}`;
      el.setAttribute('role', type === 'danger' ? 'alert' : 'status');

      const icon = ({ success: '✓', danger: '✕', warning: '!', info: 'ℹ' })[type] || '•';

      el.innerHTML = `
        <span class="rmbz-toast__icon" aria-hidden="true">${icon}</span>
        <div class="rmbz-toast__body">${message}</div>
        ${dismissible ? '<button type="button" class="rmbz-toast__close" aria-label="Fechar">×</button>' : ''}
      `;

      container.appendChild(el);
      // Trigger reflow + animação
      requestAnimationFrame(() => el.classList.add('is-visible'));

      const dismiss = () => {
        el.classList.remove('is-visible');
        el.classList.add('is-leaving');
        setTimeout(() => el.remove(), 300);
      };

      if (dismissible) {
        el.querySelector('.rmbz-toast__close')?.addEventListener('click', dismiss);
      }

      if (duration > 0) {
        setTimeout(dismiss, duration);
      }

      return { dismiss };
    },

    success(msg, opts) { return toast.show(msg, 'success', opts); },
    danger(msg, opts)  { return toast.show(msg, 'danger', opts); },
    warning(msg, opts) { return toast.show(msg, 'warning', opts); },
    info(msg, opts)    { return toast.show(msg, 'info', opts); },
  };

  // ─────────────────────────────────────────────────────────────────────────
  // BUTTON — loading state
  // ─────────────────────────────────────────────────────────────────────────

  const button = {
    setLoading(btn, isLoading) {
      if (!btn) return;
      if (isLoading) {
        btn.classList.add('rmbz-btn--loading');
        btn.setAttribute('aria-busy', 'true');
        btn.disabled = true;
      } else {
        btn.classList.remove('rmbz-btn--loading');
        btn.removeAttribute('aria-busy');
        btn.disabled = false;
      }
    },
  };

  // ─────────────────────────────────────────────────────────────────────────
  // PILL TOGGLE
  // ─────────────────────────────────────────────────────────────────────────

  function activatePill(pill) {
    const group = pill.closest('[data-rmbz-pill-group]');
    if (!group) return;

    // Toggle visual
    $$('[data-rmbz-pill]', group).forEach((p) => {
      p.classList.toggle('is-active', p === pill);
      p.setAttribute('aria-selected', p === pill ? 'true' : 'false');
    });

    // Mostrar/esconder targets
    const target = pill.dataset.target;
    if (target) {
      const allTargets = $$('[data-rmbz-pill]', group)
        .map((p) => p.dataset.target)
        .filter(Boolean);
      allTargets.forEach((t) => {
        const el = document.getElementById(t);
        if (el) el.toggleAttribute('hidden', t !== target);
      });
    }

    pill.dispatchEvent(new CustomEvent('rmbz:pill:change', {
      bubbles: true,
      detail: { value: pill.dataset.value || target },
    }));
  }

  // ─────────────────────────────────────────────────────────────────────────
  // EVENT DELEGATION — UM listener para todos os clicks
  // ─────────────────────────────────────────────────────────────────────────

  document.addEventListener('click', (e) => {
    // Abrir modal
    const opener = e.target.closest('[data-rmbz-modal-open]');
    if (opener) {
      e.preventDefault();
      modal.open(opener.dataset.rmbzModalOpen);
      return;
    }

    // Fechar modal (botão × ou overlay)
    const closer = e.target.closest('[data-rmbz-action="close"]');
    if (closer) {
      e.preventDefault();
      const m = closer.closest('.rmbz-modal');
      if (m && m.id) modal.close(m.id);
      else modal.closeAll();
      return;
    }

    // Activar pill
    const pill = e.target.closest('[data-rmbz-pill]');
    if (pill) {
      e.preventDefault();
      activatePill(pill);
      return;
    }

    // Trigger de toast (raro mas útil)
    const toastTrigger = e.target.closest('[data-rmbz-toast]');
    if (toastTrigger) {
      e.preventDefault();
      const [msg, type = 'info'] = toastTrigger.dataset.rmbzToast.split('|');
      toast.show(msg, type);
      return;
    }
  });

  // ─────────────────────────────────────────────────────────────────────────
  // KEYBOARD — Escape fecha o modal mais recente
  // ─────────────────────────────────────────────────────────────────────────

  document.addEventListener('keydown', (e) => {
    if (e.key !== 'Escape') return;
    const openModals = $$('.rmbz-modal:not([hidden])');
    if (openModals.length) {
      const last = openModals[openModals.length - 1];
      if (last.id) modal.close(last.id);
    }
  });

  // ─────────────────────────────────────────────────────────────────────────
  // FORM SUBMIT — botão em loading automático
  // ─────────────────────────────────────────────────────────────────────────

  document.addEventListener('submit', (e) => {
    const form = e.target;
    const submitBtn = form.querySelector('[type="submit"][data-rmbz-loading-on-submit]')
                  || form.querySelector('[data-rmbz-loading-on-submit]');
    if (submitBtn) button.setLoading(submitBtn, true);
  }, true);

  // ─────────────────────────────────────────────────────────────────────────
  // ALERT / CONFIRM — substitutos modernos para alert() e confirm() nativos
  //
  // [DS 1.5.62] Os alert()/confirm() do browser são feios (style do SO,
  // fora da identidade do plugin) e bloqueiam a thread (sync). Estes
  // substitutos:
  //
  //   • Visualmente coerentes com o resto do plugin (rmbz-modal)
  //   • Não bloqueiam — confirm devolve Promise<boolean>
  //   • Suportam título, mensagem multi-linha (\n vira <br>), variant de cor
  //   • Auto-destruidos ao fechar (não poluem o DOM)
  //   • Acessíveis (focus trap, ESC fecha, role=alertdialog)
  //
  // API:
  //   rmbz.alert("mensagem")
  //   rmbz.alert("mensagem", { title: "Aviso", variant: "warning" })
  //   rmbz.alert("conteudo<br>HTML", { html: true })  // opt-in HTML cru
  //
  //   rmbz.confirm("Tem a certeza?").then(ok => { if (ok) ... })
  //   rmbz.confirm("Apagar?", {
  //     title: "Confirmar",
  //     variant: "danger",
  //     okLabel: "Apagar",
  //     cancelLabel: "Voltar"
  //   })
  //
  // Fallback: se DOM não disponível ou erro, cai para alert()/confirm() nativo.
  // ─────────────────────────────────────────────────────────────────────────

  let _dialogCounter = 0;

  function escapeHtml(str) {
    const div = document.createElement('div');
    div.textContent = String(str ?? '');
    return div.innerHTML;
  }

  function nl2br(escapedHtml) {
    return escapedHtml.replace(/\n/g, '<br>');
  }

  /**
   * Cria um modal de diálogo dinâmico, abre-o, e devolve uma Promise que
   * resolve quando o utilizador escolhe uma acção. O elemento DOM é destruído
   * automaticamente após fechar.
   *
   * @param {object} opts
   * @param {string} opts.message       - mensagem principal (texto ou HTML)
   * @param {string} [opts.title]       - título opcional
   * @param {'info'|'warning'|'danger'|'success'} [opts.variant='info']
   * @param {string} [opts.okLabel='OK']
   * @param {string} [opts.cancelLabel] - se passado, mostra botão cancelar (= confirm)
   * @param {boolean} [opts.html=false] - opt-in para HTML cru no message
   * @returns {Promise<boolean>} - true=OK, false=cancel/close
   */
  function showDialog(opts) {
    return new Promise((resolve) => {
      try {
        const id = `rmbz-dialog-${++_dialogCounter}-${Date.now()}`;
        const variant = opts.variant || 'info';
        const isConfirm = !!opts.cancelLabel;
        const title = opts.title || '';
        const okLabel = opts.okLabel || 'OK';
        const cancelLabel = opts.cancelLabel || '';

        // Sanitização: por defeito, escapa tudo. Se html=true, confia no chamador.
        const messageHtml = opts.html
          ? String(opts.message ?? '')
          : nl2br(escapeHtml(opts.message));

        // Iconografia por variant — SVG inline, currentColor herda da variant
        const icons = {
          info:    '<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="8.5" stroke="currentColor" stroke-width="1.6"/><path d="M10 9v5M10 6.5v.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',
          warning: '<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M10 2l8.5 15H1.5L10 2z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/><path d="M10 8v4M10 14.5v.01" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',
          danger:  '<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="8.5" stroke="currentColor" stroke-width="1.6"/><path d="M7 7l6 6M13 7l-6 6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/></svg>',
          success: '<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="10" cy="10" r="8.5" stroke="currentColor" stroke-width="1.6"/><path d="M6 10l3 3 5-6" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/></svg>',
        };
        const iconSvg = icons[variant] || icons.info;

        // Construir markup
        const overlay = document.createElement('div');
        // [DS 1.5.64] Sem .rmbz-modal--sm — o .rmbz-dialog__panel define
        // o seu próprio max-width (420px) que é mais confortável que o
        // 360px do --sm. Adicionar --sm comprimia a caixa demasiado.
        overlay.className = 'rmbz-modal rmbz-dialog';
        overlay.id = id;
        overlay.setAttribute('data-rmbz-modal', '');
        overlay.setAttribute('hidden', '');

        overlay.innerHTML = `
          <div class="rmbz-modal__overlay" data-rmbz-action="close" tabindex="-1"></div>
          <div class="rmbz-modal__panel rmbz-dialog__panel rmbz-dialog__panel--${variant}"
               role="alertdialog"
               aria-modal="true"
               ${title ? `aria-labelledby="${id}-title"` : ''}
               aria-describedby="${id}-msg">
            <div class="rmbz-dialog__icon rmbz-dialog__icon--${variant}" aria-hidden="true">
              ${iconSvg}
            </div>
            ${title ? `<h3 class="rmbz-dialog__title" id="${id}-title">${escapeHtml(title)}</h3>` : ''}
            <div class="rmbz-dialog__message" id="${id}-msg">${messageHtml}</div>
            <div class="rmbz-dialog__actions">
              ${isConfirm ? `
                <button type="button" class="rmbz-btn rmbz-btn--ghost" data-rmbz-dialog-action="cancel">
                  ${escapeHtml(cancelLabel)}
                </button>
              ` : ''}
              <button type="button" class="rmbz-btn rmbz-btn--${variant === 'danger' ? 'danger' : 'primary'}" data-rmbz-dialog-action="ok">
                ${escapeHtml(okLabel)}
              </button>
            </div>
          </div>
        `;

        document.body.appendChild(overlay);

        // Settle: ouvinte único para esta instância. Resolve a promise + cleanup.
        let settled = false;
        const settle = (result) => {
          if (settled) return;
          settled = true;
          modal.close(id);
          // Pequeno delay para a animação fechar antes de remover do DOM
          setTimeout(() => overlay.remove(), 200);
          resolve(result);
        };

        overlay.addEventListener('click', (e) => {
          const action = e.target.closest('[data-rmbz-dialog-action]')?.dataset.rmbzDialogAction;
          if (action === 'ok')     settle(true);
          if (action === 'cancel') settle(false);
        });
        overlay.addEventListener('rmbz:modal:close', () => settle(false));

        // ESC fecha (cancel)
        const escHandler = (e) => {
          if (e.key === 'Escape') {
            settle(false);
            document.removeEventListener('keydown', escHandler);
          }
        };
        document.addEventListener('keydown', escHandler);

        // Enter no botão primário (sem precisar de clicar)
        const enterHandler = (e) => {
          if (e.key === 'Enter' && !e.target.matches('textarea, input')) {
            const okBtn = overlay.querySelector('[data-rmbz-dialog-action="ok"]');
            if (okBtn) {
              e.preventDefault();
              okBtn.click();
              document.removeEventListener('keydown', enterHandler);
            }
          }
        };
        document.addEventListener('keydown', enterHandler);

        // Abrir (anima)
        modal.open(id);
      } catch (err) {
        // Fallback — se algo correr mal, não bloquear o utilizador
        console.error('[rmbz.dialog] Fallback para nativo:', err);
        if (opts.cancelLabel) {
          resolve(window.confirm(opts.message));
        } else {
          window.alert(opts.message);
          resolve(true);
        }
      }
    });
  }

  const dialog = {
    /**
     * Substituto moderno para alert(). Fire-and-forget.
     * Devolve Promise<true> para quem quiser saber quando fechou.
     */
    alert(message, opts = {}) {
      return showDialog({ ...opts, message });
    },

    /**
     * Substituto moderno para confirm(). Devolve Promise<boolean>.
     * Use: rmbz.confirm("Apagar?").then(ok => { if (ok) ... })
     */
    confirm(message, opts = {}) {
      return showDialog({
        cancelLabel: 'Cancelar',
        ...opts,
        message,
      });
    },
  };

  // ─────────────────────────────────────────────────────────────────────────
  // EXPOSE API
  // ─────────────────────────────────────────────────────────────────────────

  window.rmbz = window.rmbz || {};
  window.rmbz.modal  = modal;
  window.rmbz.toast  = toast;
  window.rmbz.button = button;
  window.rmbz.alert  = dialog.alert;
  window.rmbz.confirm = dialog.confirm;

})();
