/**
 * UserWizard — criar utilizador
 * Spec 040 · DS-FE-003 · mockup Roger · POST /api/v1/governance/users/wizard
 */
(function () {
  'use strict';

  const ROLE_META = [
    { value: 'super_admin', label: 'Super Admin', group: 'Ops', code: 'SU' },
    { value: 'ops_lead', label: 'Chefe Ops', group: 'Ops', code: 'CO' },
    { value: 'technician', label: 'Suporte', group: 'Ops', code: 'TEC' },
    { value: 'noc', label: 'NOC', group: 'Ops', code: 'NOC' },
    { value: 'sales_admin', label: 'Sales Admin', group: 'Comercial', code: 'SAD' },
    { value: 'sales_support', label: 'Sales Support', group: 'Comercial', code: 'SSU' },
    { value: 'finance', label: 'Financeiro', group: 'Negócio', code: 'FIN' },
    { value: 'marketing', label: 'Marketing', group: 'Negócio', code: 'MKT' },
    { value: 'seo', label: 'SEO', group: 'Negócio', code: 'SEO' },
    { value: 'developer', label: 'Developer', group: 'Plataforma', code: 'DEV' },
    { value: 'devops', label: 'DevOps', group: 'Plataforma', code: 'DVO' },
    { value: 'security_analyst', label: 'Segurança / SOC', group: 'Plataforma', code: 'SOC' },
    { value: 'content_editor', label: 'Conteúdo / CMS', group: 'Plataforma', code: 'CMS' },
    { value: 'agentic_operator', label: 'Operador Agentes IA', group: 'Plataforma', code: 'AIO' },
    { value: 'partner', label: 'Partner', group: 'Externo', code: 'PTR' },
  ];

  const MODULES = [
    { id: 'desk', label: 'Desk' },
    { id: 'openpanel', label: 'OpenPanel' },
    { id: 'billing', label: 'Billing' },
    { id: 'api', label: 'API' },
    { id: 'security', label: 'Security' },
    { id: 'ai_agents', label: 'AI Agents' },
  ];

  const LEVELS = [
    { value: 'full', label: 'Total' },
    { value: 'partial', label: 'Parcial' },
    { value: 'read', label: 'Leitura' },
    { value: 'none', label: 'Sem acesso' },
  ];

  const MODULE_TREE = [
    { id: 'desk', label: 'Desk (Help Desk)', actions: ['Criar / editar / remover utilizadores Desk', 'Gerir tickets e filas', 'Ver relatórios operacionais'] },
    { id: 'openpanel', label: 'OpenPanel (Plataforma)', actions: ['Provisionar sites', 'Gerir DNS e SSL'] },
    { id: 'billing', label: 'Faturação & Billing', actions: ['Ver facturas', 'Validar estado billing'] },
    { id: 'ai_agents', label: 'Agentes IA', actions: ['Executar runbooks', 'Aprovar remediação A7'] },
    { id: 'security', label: 'Segurança / SOC', actions: ['Ver incidentes', 'Reset 2FA utilizadores'] },
    { id: 'api', label: 'API & Integrações', actions: ['Gerir tokens API', 'Webhooks inbound'] },
  ];

  const SECONDARY_GROUP_OPTIONS = ['Financeiro', 'Suporte Nível 2', 'Ops', 'Comercial', 'Negócio', 'Plataforma', 'Externo'];

  const GROUP_HINTS = {
    Ops: 'Operações internas — NOC, suporte e administradores.',
    Comercial: 'Equipa comercial, vendas e pós-venda.',
    Negócio: 'Financeiro, marketing e conteúdo.',
    Plataforma: 'Dev, DevOps, segurança e agentes IA.',
    Externo: 'Parceiros e acessos limitados.',
  };

  const PERM_TABS = [
    { id: 'modules', label: 'Módulos e funções' },
    { id: 'special', label: 'Recursos especiais' },
    { id: 'restrictions', label: 'Restrições' },
    { id: 'data', label: 'Acesso a dados' },
  ];

  const STEPS = ['Dados do utilizador', 'Perfil e grupo', 'Permissões', 'Revisão'];

  const STATUS_OPTIONS = [
    { value: 'active', label: 'Ativo' },
    { value: 'pending', label: 'Inativo' },
    { value: 'frozen', label: 'Congelado' },
    { value: 'invited', label: 'Desactivado' },
  ];

  const SVG = {
    userPlus: '<svg viewBox="0 0 24 24"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" y1="8" x2="19" y2="14"/><line x1="22" y1="11" x2="16" y2="11"/></svg>',
    close: '<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
    eye: '<svg viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>',
    whatsapp: '<svg viewBox="0 0 24 24"><path d="M21 11.5a8.38 8.38 0 0 1-3.3 6.7 8.5 8.5 0 0 1-12.7-7.1 8.38 8.38 0 0 1 3.3-6.7A8.5 8.5 0 0 1 21 11.5z"/><path d="M8 12h.01M12 12h.01M16 12h.01"/></svg>',
    info: '<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
    calendar: '<svg viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>',
    shield: '<svg viewBox="0 0 24 24"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>',
    bell: '<svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>',
    key: '<svg viewBox="0 0 24 24"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>',
    arrow: '<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" fill="none" stroke-width="2"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>',
    chevron: '<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" fill="none" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>',
  };

  let open = false;
  let step = 0;
  let saving = false;
  let result = null;
  let onDone = null;
  let defaultRole = 'technician';
  let permTab = 'modules';
  let permSearch = '';
  let expandedModules = new Set(['desk']);
  let confirmOpen = false;
  let groupHintOpen = false;

  const form = {
    display_name: '',
    email: '',
    phone: '',
    document: '',
    birthdate: '',
    password: '',
    password_confirm: '',
    account_status: 'active',
    force_password_change: true,
    mfa_required: true,
    notifications_enabled: true,
    api_access: false,
    role: 'technician',
    main_group: 'Ops',
    secondary_groups: [],
    module_permissions: {},
    notes: '',
    send_invite_email: true,
    activate_account: true,
  };

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

  function roleMeta(id) {
    return ROLE_META.find((r) => r.value === id) || { label: id, group: '—', code: '?' };
  }

  function initials(name) {
    const parts = String(name || '').trim().split(/\s+/).filter(Boolean);
    if (!parts.length) return '—';
    if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
    return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
  }

  function statusLabel(value) {
    return STATUS_OPTIONS.find((s) => s.value === value)?.label || value;
  }

  function statusBadgeClass(value) {
    if (value === 'active') return 'lb-badge lb-badge--active';
    if (value === 'frozen') return 'lb-badge lb-badge--frozen';
    return 'lb-badge lb-badge--warn';
  }

  function defaultPerms(role) {
    const p = {};
    MODULES.forEach((m) => { p[m.id] = 'none'; });
    if (role === 'super_admin') MODULES.forEach((m) => { p[m.id] = 'full'; });
    else if (role === 'ops_lead' || role === 'devops') {
      Object.assign(p, { desk: 'full', openpanel: 'partial', security: 'partial', api: 'read' });
    } else if (role === 'technician') Object.assign(p, { desk: 'partial', openpanel: 'read' });
    else if (role === 'finance') Object.assign(p, { billing: 'full', desk: 'read' });
    else if (role === 'agentic_operator') Object.assign(p, { ai_agents: 'full', desk: 'partial' });
    return p;
  }

  function permStats() {
    const perms = form.module_permissions || {};
    const allowed = MODULES.filter((m) => perms[m.id] && perms[m.id] !== 'none');
    const fullCount = allowed.filter((m) => perms[m.id] === 'full').length;
    const partialCount = allowed.filter((m) => perms[m.id] === 'partial').length;
    const readCount = allowed.filter((m) => perms[m.id] === 'read').length;
    const functionsTotal = 32;
    const functionsReleased = Math.min(functionsTotal, allowed.length * 4 + fullCount * 2 + partialCount + readCount);
    return {
      modules: allowed.length,
      functions: `${functionsReleased} de ${functionsTotal}`,
      special: String(fullCount + partialCount).padStart(2, '0'),
    };
  }

  function resetForm(role) {
    form.display_name = '';
    form.email = '';
    form.phone = '';
    form.document = '';
    form.birthdate = '';
    form.password = '';
    form.password_confirm = '';
    form.account_status = 'active';
    form.force_password_change = true;
    form.mfa_required = true;
    form.notifications_enabled = true;
    form.api_access = false;
    form.role = role || defaultRole;
    form.main_group = roleMeta(form.role).group;
    form.secondary_groups = [];
    form.module_permissions = defaultPerms(form.role);
    form.notes = '';
    form.send_invite_email = true;
    form.activate_account = true;
    step = 0;
    result = null;
    permTab = 'modules';
    permSearch = '';
    expandedModules = new Set(['desk']);
    confirmOpen = false;
    groupHintOpen = false;
  }

  function levelLabel(value) {
    return LEVELS.find((l) => l.value === value)?.label || value;
  }

  function profileSummaryHtml() {
    const stats = permStats();
    return `
      <aside class="lw-summary">
        <h4 class="lw-summary-title">Permissões por perfil (resumo)</h4>
        <div class="lw-summary-stat"><span>Módulos permitidos</span><strong>${stats.modules} módulos</strong></div>
        <div class="lw-summary-stat"><span>Funções libertadas</span><strong>${stats.functions}</strong></div>
        <div class="lw-summary-stat"><span>Recursos especiais</span><strong>${stats.special} habilitados</strong></div>
        <div class="lw-summary-stat"><span>Restrições</span><strong>Nenhuma</strong></div>
        <div class="lw-summary-info">
          ${SVG.info}
          <span>Perfil define o que o utilizador pode fazer. Grupo define onde tem acesso.</span>
        </div>
      </aside>`;
  }

  function toggleRow(name, title, desc, checked) {
    return `
      <label class="lw-access-row">
        <div class="lw-access-main">
          <span class="lw-access-icon">${SVG[name === 'mfa_required' ? 'shield' : name === 'notifications_enabled' ? 'bell' : 'key']}</span>
          <span class="lw-toggle-text">
            <strong>${esc(title)}</strong>
            <span class="lw-toggle-desc">${esc(desc)}</span>
          </span>
        </div>
        <span class="lw-toggle">
          <input type="checkbox" name="${name}"${checked ? ' checked' : ''}/>
          <span class="lw-toggle-slider"></span>
        </span>
      </label>`;
  }

  function summaryHtml() {
    const rm = roleMeta(form.role);
    const stats = permStats();
    const name = form.display_name.trim() || '—';
    const email = form.email.trim() || '—';
    return `
      <aside class="lw-summary">
        <h4 class="lw-summary-title">Resumo do utilizador</h4>
        <div class="lw-summary-preview">
          <div class="lw-summary-avatar">${esc(initials(form.display_name))}</div>
          <div>
            <div class="lw-summary-name">${esc(name)}</div>
            <div class="lw-summary-email">${esc(email)}</div>
            <span class="${statusBadgeClass(form.account_status)}">${esc(statusLabel(form.account_status))}</span>
          </div>
        </div>
        <dl class="lw-summary-kv">
          <dt>Perfil</dt><dd>${esc(rm.label)}</dd>
          <dt>Grupo</dt><dd>${esc(form.main_group)}</dd>
          <dt>Estado</dt><dd>${esc(statusLabel(form.account_status))}</dd>
          <dt>2FA</dt><dd>${form.mfa_required ? 'Activado' : 'Opcional'}</dd>
          <dt>Acesso API</dt><dd>${form.api_access ? 'Permitido' : 'Não permitido'}</dd>
          <dt>Notificações</dt><dd>${form.notifications_enabled ? 'Activas' : 'Desactivadas'}</dd>
        </dl>
        <div class="lw-summary-perms">
          <h5>Permissões iniciais (resumo)</h5>
          <div class="lw-summary-stat"><span>Módulos permitidos</span><strong>${stats.modules}</strong></div>
          <div class="lw-summary-stat"><span>Funções libertadas</span><strong>${stats.functions}</strong></div>
          <div class="lw-summary-stat"><span>Recursos especiais</span><strong>${stats.special} habilitados</strong></div>
        </div>
        <div class="lw-summary-info">
          ${SVG.info}
          <span>Após a criação, o perfil e as permissões podem ser ajustados na gestão de utilizadores.</span>
        </div>
      </aside>`;
  }

  function stepBasic() {
    const statusChips = STATUS_OPTIONS.map((s) =>
      `<button type="button" class="lw-status-chip${form.account_status === s.value ? ' active' : ''}" data-status="${s.value}">${esc(s.label)}</button>`
    ).join('');

    return `
      <div class="lb-wizard-form">
        <section class="lw-section">
          <h3 class="lw-section-title">Dados pessoais</h3>
          <div class="lw-field-grid lw-field-grid--2">
            <div class="lw-field lw-field--full">
              <label class="lw-field__label">Nome completo <span class="lw-req">*</span></label>
              <input name="display_name" value="${esc(form.display_name)}" placeholder="Digite o nome completo" required/>
            </div>
            <div class="lw-field">
              <label class="lw-field__label">E-mail (login) <span class="lw-req">*</span></label>
              <input type="email" name="email" value="${esc(form.email)}" placeholder="ex.: nome@empresa.com" required autocomplete="off"/>
            </div>
            <div class="lw-field">
              <label class="lw-field__label">Telefone <span style="font-weight:400;color:var(--lb-text-muted)">(opcional)</span></label>
              <div class="lw-input-icon">
                <input name="phone" value="${esc(form.phone)}" placeholder="(11) 99999-9999"/>
                <span class="lw-input-trail">${SVG.whatsapp}</span>
              </div>
            </div>
            <div class="lw-field">
              <label class="lw-field__label">Documento <span style="font-weight:400;color:var(--lb-text-muted)">(opcional)</span></label>
              <div class="lw-input-icon">
                <input name="document" value="${esc(form.document)}" placeholder="CPF ou documento"/>
                <span class="lw-input-trail">${SVG.info}</span>
              </div>
            </div>
            <div class="lw-field">
              <label class="lw-field__label">Data de nascimento <span style="font-weight:400;color:var(--lb-text-muted)">(opcional)</span></label>
              <div class="lw-input-icon">
                <input name="birthdate" value="${esc(form.birthdate)}" placeholder="dd/mm/aaaa"/>
                <span class="lw-input-trail">${SVG.calendar}</span>
              </div>
            </div>
          </div>
        </section>

        <section class="lw-section">
          <h3 class="lw-section-title">Segurança e acesso</h3>
          <div class="lw-field-grid lw-field-grid--2">
            <div class="lw-field">
              <label class="lw-field__label">Senha inicial <span class="lw-req">*</span></label>
              <div class="lw-input-icon">
                <input type="password" name="password" minlength="6" required autocomplete="new-password"/>
                <button type="button" class="lw-input-action" data-toggle-pw="password" aria-label="Mostrar senha">${SVG.eye}</button>
              </div>
            </div>
            <div class="lw-field">
              <label class="lw-field__label">Confirmar senha <span class="lw-req">*</span></label>
              <div class="lw-input-icon">
                <input type="password" name="password_confirm" minlength="6" required autocomplete="new-password"/>
                <button type="button" class="lw-input-action" data-toggle-pw="password_confirm" aria-label="Mostrar senha">${SVG.eye}</button>
              </div>
            </div>
          </div>
          <label class="lw-toggle-row" style="margin-top:8px">
            <span class="lw-toggle-text">
              <strong>Forçar alteração no primeiro acesso</strong>
              <span class="lw-toggle-desc">O utilizador terá de definir uma nova senha no primeiro login</span>
            </span>
            <span class="lw-toggle">
              <input type="checkbox" name="force_password_change"${form.force_password_change ? ' checked' : ''}/>
              <span class="lw-toggle-slider"></span>
            </span>
          </label>
          <div class="lw-field" style="margin-top:14px">
            <span class="lw-field__label">Estado da conta</span>
            <div class="lw-status-chips" role="radiogroup" aria-label="Estado da conta">
              ${statusChips}
              <input type="hidden" name="account_status" value="${esc(form.account_status)}"/>
            </div>
          </div>
        </section>

        <section class="lw-section">
          <h3 class="lw-section-title">Acesso adicional</h3>
          ${toggleRow('mfa_required', 'Activar autenticação de dois factores (2FA)', 'Recomendado para perfis administrativos', form.mfa_required)}
          ${toggleRow('notifications_enabled', 'Receber notificações do sistema', 'Alertas operacionais e avisos de segurança', form.notifications_enabled)}
          ${toggleRow('api_access', 'Permitir acesso via API', 'Gera token de API para integrações externas', form.api_access)}
        </section>
      </div>
      ${summaryHtml()}`;
  }

  function stepProfile() {
    const groups = [...new Set(ROLE_META.map((r) => r.group))];
    const opts = ROLE_META.filter((r) => r.value !== 'super_admin' || form.role === 'super_admin')
      .map((r) => `<option value="${r.value}"${r.value === form.role ? ' selected' : ''}>${esc(r.label)} (${r.code})</option>`).join('');
    const addable = SECONDARY_GROUP_OPTIONS.filter((g) => !form.secondary_groups.includes(g));
    const tags = form.secondary_groups.map((g) =>
      `<span class="lw-tag">${esc(g)}<button type="button" data-remove-group="${esc(g)}" aria-label="Remover">×</button></span>`
    ).join('') || '<span class="lb-stat-sub">Nenhum grupo adicional</span>';
    const groupHint = GROUP_HINTS[form.main_group] || 'Grupo organizacional do utilizador.';

    return `
      <div class="lb-wizard-form">
        <section class="lw-section">
          <h3 class="lw-section-title">Perfil e grupo</h3>
          <div class="lw-field-grid lw-field-grid--2">
            <div class="lw-field">
              <label class="lw-field__label">Perfil principal</label>
              <select name="role">${opts}</select>
              <p class="lw-field-hint">Perfil sugerido com base nas permissões seleccionadas.</p>
            </div>
            <div class="lw-field">
              <label class="lw-field__label">Grupo principal</label>
              <select name="main_group">
                ${groups.map((g) => `<option value="${esc(g)}"${form.main_group === g ? ' selected' : ''}>${esc(g)}</option>`).join('')}
              </select>
              <button type="button" class="lw-link-btn" data-toggle-group-hint>${groupHintOpen ? 'Ocultar' : 'Ver'} descrição do grupo</button>
              ${groupHintOpen ? `<p class="lw-field-hint">${esc(groupHint)}</p>` : ''}
            </div>
          </div>
          <div class="lw-field" style="margin-top:12px">
            <label class="lw-field__label">Grupos adicionais</label>
            <select data-add-group ${addable.length ? '' : 'disabled'}>
              <option value="">Seleccionar grupo…</option>
              ${addable.map((g) => `<option value="${esc(g)}">${esc(g)}</option>`).join('')}
            </select>
            <div class="lw-tags" data-group-tags>${tags}</div>
          </div>
          <div class="lw-summary-info" style="margin-top:16px">
            ${SVG.info}
            <span><strong>Perfil</strong> define o que o utilizador pode fazer. <strong>Grupo</strong> define onde tem acesso.</span>
          </div>
        </section>
      </div>
      ${profileSummaryHtml()}`;
  }

  function filteredModules() {
    const q = permSearch.trim().toLowerCase();
    if (!q) return MODULE_TREE;
    return MODULE_TREE.filter((m) =>
      m.label.toLowerCase().includes(q) || m.actions.some((a) => a.toLowerCase().includes(q))
    );
  }

  function moduleLevelSelect(moduleId) {
    const lv = form.module_permissions[moduleId] || 'none';
    const opts = LEVELS.map((l) =>
      `<option value="${l.value}"${lv === l.value ? ' selected' : ''}>${l.label}</option>`).join('');
    return `<select name="perm_${moduleId}" class="lw-module-level" data-module="${moduleId}">${opts}</select>`;
  }

  function stepPermissions() {
    const tabs = PERM_TABS.map((t) =>
      `<button type="button" class="lw-perm-tab${permTab === t.id ? ' active' : ''}" data-perm-tab="${t.id}">${esc(t.label)}</button>`
    ).join('');

    let tabBody = '';
    if (permTab === 'modules') {
      const modules = filteredModules();
      tabBody = `
        <div class="lw-perm-toolbar">
          <input type="search" placeholder="Pesquisar módulos ou funções…" value="${esc(permSearch)}" data-perm-search/>
          <button type="button" class="lb-btn-ghost" data-expand-all>Expandir todos</button>
        </div>
        <div class="lw-module-list">
          ${modules.map((m) => {
            const isOpen = expandedModules.has(m.id);
            const actions = m.actions.map((label, i) => `
              <div class="lw-action-row">
                <span>${esc(label)}</span>
                ${i === 0 ? moduleLevelSelect(m.id) : `<span class="lb-stat-sub">${esc(levelLabel(form.module_permissions[m.id] || 'none'))}</span>`}
              </div>`).join('');
            return `
              <div class="lw-module${isOpen ? ' is-open' : ''}" data-module-id="${m.id}">
                <button type="button" class="lw-module-head" data-toggle-module="${m.id}">
                  <span class="lw-module-chevron">${SVG.chevron}</span>
                  <span class="lw-module-title">${esc(m.label)}</span>
                  <span class="lw-module-count">${m.actions.length} funções</span>
                </button>
                <div class="lw-module-body">${actions}</div>
              </div>`;
          }).join('')}
        </div>`;
    } else if (permTab === 'special') {
      tabBody = `<div class="lw-tab-placeholder">Recursos especiais — ${permStats().special} habilitados pelo perfil <strong>${esc(roleMeta(form.role).label)}</strong>.</div>`;
    } else if (permTab === 'restrictions') {
      tabBody = `<div class="lw-tab-placeholder">Nenhuma restrição adicional configurada para este utilizador.</div>`;
    } else {
      tabBody = `<div class="lw-tab-placeholder">Acesso a dados sensíveis herda do perfil e grupo principal.</div>`;
    }

    return `
      <div class="lb-wizard-form">
        <section class="lw-section">
          <h3 class="lw-section-title">Permissões</h3>
          <p class="lb-stat-sub" style="margin:0 0 12px">Ajuste fino das permissões antes de criar a conta.</p>
          <div class="lw-perm-tabs">${tabs}</div>
          ${tabBody}
        </section>
      </div>
      ${profileSummaryHtml()}`;
  }

  function stepReview() {
    const secGroups = form.secondary_groups.length ? form.secondary_groups.join(', ') : '—';
    const stats = permStats();
    return `
      <div class="lb-wizard-form lb-wizard-form--wide">
        <section class="lw-section">
          <h3 class="lw-section-title">Revisão</h3>
          <p class="lb-stat-sub" style="margin:0 0 14px">Confirme todos os dados antes de criar o utilizador.</p>
          <div class="lw-review-grid">
            <div class="lw-review-col">
              <h4>Dados do utilizador</h4>
              <dl class="lw-review-kv">
                <dt>Nome</dt><dd>${esc(form.display_name)}</dd>
                <dt>E-mail</dt><dd>${esc(form.email)}</dd>
                <dt>Telefone</dt><dd>${esc(form.phone || '—')}</dd>
                <dt>Estado da conta</dt><dd>${esc(statusLabel(form.account_status))}</dd>
                <dt>2FA</dt><dd>${form.mfa_required ? 'Activado' : 'Opcional'}</dd>
              </dl>
            </div>
            <div class="lw-review-col">
              <h4>Perfil e grupo</h4>
              <dl class="lw-review-kv">
                <dt>Perfil principal</dt><dd>${esc(roleMeta(form.role).label)}</dd>
                <dt>Grupo principal</dt><dd>${esc(form.main_group)}</dd>
                <dt>Grupos adicionais</dt><dd>${esc(secGroups)}</dd>
              </dl>
              <h4 style="margin-top:14px">Permissões</h4>
              <dl class="lw-review-kv">
                <dt>Módulos</dt><dd>${stats.modules} módulos</dd>
                <dt>Funções</dt><dd>${stats.functions}</dd>
              </dl>
            </div>
            <div class="lw-review-col">
              <h4>Acessos adicionais</h4>
              <dl class="lw-review-kv">
                <dt>2FA</dt><dd>${form.mfa_required ? 'Activado' : 'Não'}</dd>
                <dt>Acesso API</dt><dd>${form.api_access ? 'Permitido' : 'Não permitido'}</dd>
                <dt>Notificações</dt><dd>${form.notifications_enabled ? 'Activas' : 'Desactivadas'}</dd>
              </dl>
              <div class="lw-field" style="margin-top:12px">
                <label class="lw-field__label">Observações (opcional)</label>
                <textarea name="notes" maxlength="200" rows="3" placeholder="Notas internas sobre este utilizador…">${esc(form.notes)}</textarea>
                <span class="lw-field-hint">${form.notes.length}/200 caracteres</span>
              </div>
              <label style="flex-direction:row;gap:8px;align-items:center;display:flex;font-size:0.78rem;margin-top:10px">
                <input type="checkbox" name="send_invite_email"${form.send_invite_email ? ' checked' : ''}/> Enviar e-mail convite
              </label>
            </div>
          </div>
        </section>
      </div>`;
  }

  function stepSuccess() {
    const email = result?.user?.email || form.email;
    const invite = result?.invite_link || '';
    return `
      <div class="lb-wizard-success">
        <div class="lw-success-icon">✓</div>
        <h2>Utilizador criado com sucesso!</h2>
        <p class="lb-stat-sub">${form.send_invite_email ? `E-mail de convite enviado para ${esc(email)}` : `Conta criada: ${esc(email)}`}</p>
        <p class="lb-stat-sub">ID interno · ${esc(result?.internal_id || '')}</p>
        <div style="display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:20px">
          <button type="button" class="lb-btn-primary" data-wz-view-user>Ver detalhes do utilizador</button>
          <button type="button" class="lb-btn-ghost" data-wz-another>Criar outro utilizador</button>
          <button type="button" class="lb-btn-ghost" data-wz-goto-mgmt>Voltar para a lista</button>
          ${invite ? `<button type="button" class="lb-btn-ghost" data-wz-copy-invite>Copiar link convite</button>` : ''}
        </div>
        ${form.send_invite_email ? `
        <div class="lw-email-preview">
          <div class="lw-email-preview__head">ligbox</div>
          <div class="lw-email-preview__body">
            <p>Olá <strong>${esc(form.display_name)}</strong>,</p>
            <p>Foi criada a sua conta no Ligbox Ops Desk. Clique abaixo para definir a sua senha no primeiro acesso.</p>
            <p style="margin-top:14px"><span class="lb-btn-primary" style="display:inline-block;text-decoration:none">Definir minha senha</span></p>
            <p class="lb-stat-sub" style="margin-top:12px">Link válido por 24 horas · ${esc(email)}</p>
          </div>
        </div>` : ''}
      </div>`;
  }

  function confirmModalHtml() {
    return `
      <div class="lw-confirm-overlay" data-wz-confirm-overlay>
        <div class="lw-confirm-card" role="alertdialog">
          <h3>Confirmar criação do utilizador</h3>
          <p class="lb-stat-sub" style="margin:0 0 10px">O que acontece ao clicar «Criar utilizador»:</p>
          <ul>
            <li>Conta criada na base Desk</li>
            <li>${form.send_invite_email ? 'E-mail de convite enviado' : 'Convite por e-mail não enviado'}</li>
            <li>Utilizador define senha no 1.º acesso${form.force_password_change ? ' (obrigatório)' : ''}</li>
            <li>Permissões RBAC aplicadas conforme revisão</li>
            <li>Registo em audit log</li>
          </ul>
          <div class="lw-confirm-actions">
            <button type="button" class="lb-btn-ghost" data-wz-confirm-cancel>Cancelar</button>
            <button type="button" class="lb-btn-primary" data-wz-confirm-ok ${saving ? 'disabled' : ''}>${saving ? 'A criar…' : 'Criar utilizador'}</button>
          </div>
        </div>
      </div>`;
  }

  function renderSteps() {
    if (step >= 4) return '';
    return STEPS.map((label, i) => {
      const cls = i === step ? 'active' : i < step ? 'done' : '';
      return `<div class="lb-wizard-step ${cls}"><span class="lb-wizard-step-num">${i + 1}</span>${esc(label)}</div>`;
    }).join('');
  }

  function renderBody() {
    if (step === 0) return stepBasic();
    if (step === 1) return stepProfile();
    if (step === 2) return stepPermissions();
    if (step === 3) return stepReview();
    return stepSuccess();
  }

  function syncDom() {
    const root = document.getElementById('lb-user-wizard-root');
    if (!open) {
      if (root) root.innerHTML = '';
      document.body.classList.remove('um-scroll-lock');
      return;
    }
    document.body.classList.add('um-scroll-lock');
    const el = root || (() => {
      const d = document.createElement('div');
      d.id = 'lb-user-wizard-root';
      document.body.appendChild(d);
      return d;
    })();

    const isSuccess = step >= 4;
    const isWide = step === 3 || isSuccess;
    const nextLabel = step === 3 ? 'Criar utilizador' : 'Continuar';

    el.innerHTML = `
      <div class="lb-wizard-root" role="dialog" aria-modal="true" aria-labelledby="lw-title">
        <div class="lb-wizard-card">
          <header class="lb-wizard-head">
            <div class="lb-wizard-head__main">
              <div class="lb-wizard-head__icon">${SVG.userPlus}</div>
              <div>
                <h2 id="lw-title" class="lb-wizard-head__title">Criar utilizador</h2>
                <p class="lb-wizard-head__desc">Crie uma nova conta de utilizador e defina perfil, grupo e permissões iniciais.</p>
              </div>
            </div>
            <div class="lb-wizard-head__right">
              ${!isSuccess ? `<nav class="lb-wizard-steps" aria-label="Passos">${renderSteps()}</nav>` : ''}
              <button type="button" class="lb-wizard-close" data-wz-close aria-label="Fechar">${SVG.close}</button>
            </div>
          </header>
          <div class="lb-wizard-body${isSuccess ? ' lb-wizard-body--success' : ''}${isWide && !isSuccess ? ' lb-wizard-body--wide' : ''}">${renderBody()}</div>
          ${!isSuccess ? `
          <footer class="lb-wizard-foot">
            <button type="button" class="lb-btn-ghost" data-wz-cancel>Cancelar</button>
            <div style="display:flex;gap:8px">
              ${step > 0 ? `<button type="button" class="lb-btn-ghost" data-wz-back>Voltar</button>` : ''}
              <button type="button" class="lb-btn-primary" data-wz-next ${saving ? 'disabled' : ''}>
                ${step === 3 && saving ? 'A criar…' : nextLabel}${step < 3 ? SVG.arrow : ''}
              </button>
            </div>
          </footer>` : ''}
        </div>
        ${confirmOpen ? confirmModalHtml() : ''}
      </div>`;

    bindWizard(el);
  }

  function readForm(container) {
    const g = (n) => container.querySelector(`[name="${n}"]`);
    if (step === 0) {
      form.display_name = g('display_name')?.value?.trim() || '';
      form.email = g('email')?.value?.trim().toLowerCase() || '';
      form.phone = g('phone')?.value?.trim() || '';
      form.document = g('document')?.value?.trim() || '';
      form.birthdate = g('birthdate')?.value?.trim() || '';
      form.password = g('password')?.value || '';
      form.password_confirm = g('password_confirm')?.value || '';
      form.account_status = g('account_status')?.value || 'active';
      form.force_password_change = !!container.querySelector('[name="force_password_change"]')?.checked;
      form.mfa_required = !!container.querySelector('[name="mfa_required"]')?.checked;
      form.notifications_enabled = !!container.querySelector('[name="notifications_enabled"]')?.checked;
      form.api_access = !!container.querySelector('[name="api_access"]')?.checked;
      if (!form.display_name) throw new Error('Nome completo é obrigatório');
      if (!form.email) throw new Error('E-mail é obrigatório');
      if (form.password !== form.password_confirm) throw new Error('Senhas não coincidem');
    } else if (step === 1) {
      form.role = g('role')?.value || form.role;
      form.main_group = g('main_group')?.value || roleMeta(form.role).group;
      form.module_permissions = defaultPerms(form.role);
    } else if (step === 2) {
      MODULES.forEach((m) => {
        form.module_permissions[m.id] = g(`perm_${m.id}`)?.value || 'none';
      });
    } else if (step === 3) {
      form.notes = g('notes')?.value?.trim() || '';
      form.send_invite_email = !!container.querySelector('[name="send_invite_email"]')?.checked;
    }
  }

  function parseApiError(text) {
    try {
      const data = JSON.parse(text);
      if (Array.isArray(data.detail)) {
        return data.detail.map((d) => d.msg || d.message || JSON.stringify(d)).join('\n');
      }
      if (typeof data.detail === 'string') return data.detail;
      return data.message || text;
    } catch (_) {
      return text;
    }
  }

  async function submitWizard() {
    saving = true;
    syncDom();
    try {
      const perms = {};
      MODULES.forEach((m) => { perms[m.id] = form.module_permissions[m.id] || 'none'; });
      const extraNotes = [form.document && `Doc: ${form.document}`, form.birthdate && `Nasc.: ${form.birthdate}`].filter(Boolean).join(' · ');
      const notesRaw = [form.notes, extraNotes].filter(Boolean).join('\n') || null;
      const notes = notesRaw ? notesRaw.slice(0, 200) : null;
      if (form.password.length < 6) throw new Error('Senha inicial: mínimo 6 caracteres');
      const r = await fetchWithTimeout('/api/v1/governance/users/wizard', {
        method: 'POST',
        headers: authHeaders({ 'Content-Type': 'application/json' }),
        body: JSON.stringify({
          display_name: form.display_name,
          email: form.email,
          phone: form.phone || null,
          password: form.password,
          account_status: form.account_status,
          force_password_change: form.force_password_change,
          mfa_required: form.mfa_required,
          notifications_enabled: form.notifications_enabled,
          api_access: form.api_access,
          role: form.role,
          main_group: form.main_group,
          secondary_groups: form.secondary_groups,
          module_permissions: perms,
          notes,
          send_invite_email: form.send_invite_email,
          activate_account: form.account_status === 'active',
        }),
      });
      if (!r.ok) throw new Error(parseApiError(await r.text()));
      result = await r.json();
      step = 4;
      if (typeof onDone === 'function') onDone(result);
    } catch (e) {
      window.alert(e.message);
    } finally {
      saving = false;
      syncDom();
    }
  }

  function bindWizard(root) {
    root.querySelector('[data-wz-close]')?.addEventListener('click', close);
    root.querySelector('[data-wz-cancel]')?.addEventListener('click', close);
    root.querySelector('.lb-wizard-root')?.addEventListener('click', (e) => {
      if (e.target.classList.contains('lb-wizard-root')) close();
    });

    root.querySelectorAll('[data-toggle-pw]').forEach((btn) => {
      btn.addEventListener('click', () => {
        const field = root.querySelector(`[name="${btn.dataset.togglePw}"]`);
        if (!field) return;
        field.type = field.type === 'password' ? 'text' : 'password';
      });
    });

    root.querySelectorAll('[data-status]').forEach((chip) => {
      chip.addEventListener('click', () => {
        form.account_status = chip.dataset.status;
        syncDom();
      });
    });

    root.querySelector('[data-wz-back]')?.addEventListener('click', () => {
      if (step > 0) { step -= 1; syncDom(); }
    });

    root.querySelector('[data-wz-next]')?.addEventListener('click', async () => {
      const body = root.querySelector('.lb-wizard-body');
      try {
        readForm(body);
      } catch (e) {
        window.alert(e.message);
        return;
      }
      if (step === 3) {
        confirmOpen = true;
        syncDom();
        return;
      }
      step += 1;
      syncDom();
    });

    root.querySelector('[data-wz-confirm-cancel]')?.addEventListener('click', () => {
      confirmOpen = false;
      syncDom();
    });
    root.querySelector('[data-wz-confirm-overlay]')?.addEventListener('click', (e) => {
      if (e.target.classList.contains('lw-confirm-overlay')) {
        confirmOpen = false;
        syncDom();
      }
    });
    root.querySelector('[data-wz-confirm-ok]')?.addEventListener('click', async () => {
      confirmOpen = false;
      await submitWizard();
    });

    root.querySelector('[data-toggle-group-hint]')?.addEventListener('click', () => {
      groupHintOpen = !groupHintOpen;
      syncDom();
    });

    root.querySelector('[data-add-group]')?.addEventListener('change', (e) => {
      const val = e.target.value;
      if (val && !form.secondary_groups.includes(val)) {
        form.secondary_groups.push(val);
        syncDom();
      }
    });

    root.querySelectorAll('[data-remove-group]').forEach((btn) => {
      btn.addEventListener('click', () => {
        form.secondary_groups = form.secondary_groups.filter((g) => g !== btn.dataset.removeGroup);
        syncDom();
      });
    });

    root.querySelectorAll('[data-perm-tab]').forEach((btn) => {
      btn.addEventListener('click', () => {
        permTab = btn.dataset.permTab;
        syncDom();
      });
    });

    root.querySelector('[data-perm-search]')?.addEventListener('input', (e) => {
      permSearch = e.target.value;
      clearTimeout(root._permTimer);
      root._permTimer = setTimeout(() => syncDom(), 180);
    });

    root.querySelector('[data-expand-all]')?.addEventListener('click', () => {
      MODULE_TREE.forEach((m) => expandedModules.add(m.id));
      syncDom();
    });

    root.querySelectorAll('[data-toggle-module]').forEach((btn) => {
      btn.addEventListener('click', () => {
        const id = btn.dataset.toggleModule;
        if (expandedModules.has(id)) expandedModules.delete(id);
        else expandedModules.add(id);
        syncDom();
      });
    });

    root.querySelectorAll('.lw-module-level').forEach((sel) => {
      sel.addEventListener('change', (e) => {
        form.module_permissions[e.target.dataset.module] = e.target.value;
        syncDom();
      });
    });

    root.querySelector('[name="notes"]')?.addEventListener('input', (e) => {
      form.notes = e.target.value.slice(0, 200);
      const hint = root.querySelector('.lw-field-hint');
      if (hint) hint.textContent = `${form.notes.length}/200 caracteres`;
    });

    root.querySelector('[name="role"]')?.addEventListener('change', (e) => {
      form.role = e.target.value;
      form.main_group = roleMeta(form.role).group;
      form.module_permissions = defaultPerms(form.role);
      syncDom();
    });

    ['display_name', 'email', 'phone'].forEach((field) => {
      root.querySelector(`[name="${field}"]`)?.addEventListener('input', (e) => {
        form[field] = e.target.value;
        const summary = root.querySelector('.lw-summary');
        if (summary && step === 0) {
          const nameEl = summary.querySelector('.lw-summary-name');
          const emailEl = summary.querySelector('.lw-summary-email');
          const avatarEl = summary.querySelector('.lw-summary-avatar');
          if (nameEl) nameEl.textContent = form.display_name.trim() || '—';
          if (emailEl) emailEl.textContent = form.email.trim() || '—';
          if (avatarEl) avatarEl.textContent = initials(form.display_name);
        }
      });
    });

    root.querySelectorAll('.lw-toggle input[type="checkbox"]').forEach((el) => {
      el.addEventListener('change', () => {
        if (step !== 0) return;
        const body = root.querySelector('.lb-wizard-body');
        form.force_password_change = !!body.querySelector('[name="force_password_change"]')?.checked;
        form.mfa_required = !!body.querySelector('[name="mfa_required"]')?.checked;
        form.notifications_enabled = !!body.querySelector('[name="notifications_enabled"]')?.checked;
        form.api_access = !!body.querySelector('[name="api_access"]')?.checked;
        const old = root.querySelector('.lw-summary');
        if (old) old.outerHTML = summaryHtml();
      });
    });

    root.querySelector('[data-wz-another]')?.addEventListener('click', () => {
      resetForm(defaultRole);
      syncDom();
    });
    root.querySelector('[data-wz-goto-mgmt]')?.addEventListener('click', () => {
      close();
      if (typeof setView === 'function') {
        const ds = window.getDeskState?.();
        if (ds) ds.matrixTab = 'access-control';
        setView('access-matrix');
      }
    });
    root.querySelector('[data-wz-view-user]')?.addEventListener('click', () => {
      const email = result?.user?.username || result?.user?.email;
      close();
      if (email && window.DeskAccessControlHub?.selectUser) {
        window.DeskAccessControlHub.selectUser(email);
        if (typeof onDone === 'function') onDone(result);
      }
    });
    root.querySelector('[data-wz-copy-invite]')?.addEventListener('click', async () => {
      try {
        await navigator.clipboard.writeText(result?.invite_link || '');
        window.alert('Link copiado');
      } catch (_) {
        window.prompt('Copiar link:', result?.invite_link);
      }
    });
  }

  function openWizard(opts = {}) {
    defaultRole = opts.defaultRole || 'technician';
    onDone = opts.onDone || null;
    resetForm(defaultRole);
    open = true;
    syncDom();
  }

  function close() {
    open = false;
    syncDom();
  }

  window.DeskUserWizard = { open: openWizard, close };
})();
