/**
 * Controle de acesso — delega ao Access Control Hub
 * Spec 040 · DS-FE-005
 */
(function () {
  'use strict';

  const ROLE_CODES = {
    super_admin: 'SU',
    ops_lead: 'CO',
    technician: 'TEC',
    noc: 'NOC',
    sales_admin: 'SAD',
    sales_support: 'SSU',
    finance: 'FIN',
    marketing: 'MKT',
    seo: 'SEO',
    developer: 'DEV',
    devops: 'DVO',
    security_analyst: 'SOC',
    content_editor: 'CMS',
    agentic_operator: 'AIO',
    partner: 'PTR',
    root: 'RO',
  };

  const ACCESS_ACTIONS = [
    { id: 'create_user', actionId: 'desk.auth.user.create', label: 'Criar usuário', hint: 'Provisionar conta directa' },
    { id: 'edit_user', actionId: 'desk.auth.user.edit', label: 'Editar usuário', hint: 'Nome, perfil e metadados' },
    { id: 'freeze_user', actionId: 'desk.auth.user.freeze', label: 'Congelar conta', hint: 'Bloquear login — SSU nunca' },
    { id: 'approve_registration', actionId: 'desk.auth.user.approve_registration', label: 'Aprovar pedidos de cadastro', hint: 'SU + CO' },
    { id: 'manage_passwords', actionId: 'desk.auth.user.password.reset', label: 'Gerenciar senhas', hint: 'Reset admin' },
    { id: 'reset_2fa', actionId: 'desk.auth.user.2fa.reset', label: 'Resetar 2FA', hint: 'Recuperação autenticador' },
    { id: 'manage_modules', actionId: 'desk.auth.modules.toggle', label: 'Módulos Desk ON/OFF', hint: 'Feature flags' },
    { id: 'purge_domain', actionId: 'vm112.domain.purge', label: 'Purge domínio', hint: 'Irreversível' },
    { id: 'openpanel_delete', actionId: 'vm123_openpanel.site.delete', label: 'Deletar instância OpenPanel', hint: 'SU + CO' },
    { id: 'validate_billing', actionId: 'desk.billing.state.validate', label: 'Validar billing', hint: 'billing_state' },
    { id: 'agent_approve', actionId: 'desk.agent.runbook.approve', label: 'Aprovar remediação A7', hint: 'Agentes' },
  ];

  let levelsCache = null;
  let levelsRole = null;
  let catalogEditable = false;

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

  async function loadLevelsForRole(roleId) {
    if (levelsCache && levelsRole === roleId) return levelsCache;
    const r = await fetchWithTimeout('/api/v1/rbac/actions', { headers: authHeaders() });
    if (!r.ok) throw new Error(String(r.status));
    const data = await r.json();
    catalogEditable = !!data.editable;
    const map = {};
    (data.actions || []).forEach((a) => {
      map[a.id] = {
        effective: a.effective?.[roleId] || 'none',
        default: a.defaults?.[roleId] || 'none',
        overridden: a.overridden_roles?.includes(roleId),
      };
    });
    levelsCache = map;
    levelsRole = roleId;
    return map;
  }

  function actionOn(level) {
    return level === 'full' || level === 'approve' || level === 'api' || level === 'system';
  }

  function renderPermToggles(selectedRole, roleMeta, levels, editable) {
    const code = ROLE_CODES[selectedRole] || selectedRole?.slice(0, 3).toUpperCase() || '—';
    const rows = ACCESS_ACTIONS.map((a) => {
      const lv = levels[a.actionId]?.effective || 'none';
      const on = actionOn(lv);
      const partial = on && lv !== 'full';
      const ro = !editable ? ' acs-toggle--readonly' : '';
      const dis = editable ? '' : ' disabled';
      return `
        <div class="acs-perm-row" title="${esc(a.hint)} · ${esc(lv)}">
          <span class="acs-perm-label">${esc(a.label)}${partial ? ` <em class="acs-partial">(${esc(lv)})</em>` : ''}</span>
          <label class="acs-toggle${ro}" aria-label="${esc(a.label)}" data-acs-action="${esc(a.actionId)}">
            <input type="checkbox" ${on ? 'checked' : ''}${dis} data-acs-toggle="${esc(a.actionId)}"/>
            <span class="acs-toggle-slider"></span>
          </label>
        </div>`;
    }).join('');

    const editHint = editable
      ? 'Toggles ligados ao catálogo Spec 039 — alterações gravam na Matriz «Quem faz o quê».'
      : 'Modo consulta — use a aba «Quem faz o quê» com edição activa para alterar.';

    return `
      <div class="acs-perms-card acs-card lb-card" style="padding:16px">
        <header class="acs-perms-head">
          <span class="acs-role-code" title="Código da função">${esc(code)}</span>
          <div>
            <h3>Capacidades da função</h3>
            <p class="acs-perms-desc">Função <strong>${esc(roleMeta?.label || selectedRole)}</strong>. ${editHint}</p>
          </div>
        </header>
        <div class="acs-perm-list">${rows}</div>
        <p class="ticket-meta"><a href="#" class="acs-goto-exec" data-goto-exec>Abrir mapa completo «Quem faz o quê»</a></p>
      </div>`;
  }

  async function patchToggle(actionId, roleId, checked) {
    const level = checked ? 'full' : 'none';
    const r = await fetchWithTimeout('/api/v1/rbac/actions/override', {
      method: 'PATCH',
      headers: authHeaders({ 'Content-Type': 'application/json' }),
      body: JSON.stringify({ action_id: actionId, role_id: roleId, level, reset: !checked }),
    });
    if (!r.ok) throw new Error(await r.text());
    levelsCache = null;
    return r.json();
  }

  async function paintCapabilitiesOnly(host, opts = {}) {
    if (!host) return;
    const selectedRole = opts.selectedRole || 'super_admin';
    const roleMeta = opts.roleMeta || {};
    const editable = !!opts.editable;
    host.innerHTML = '<p class="loading">Carregando capacidades…</p>';
    let levels = {};
    try {
      levels = await loadLevelsForRole(selectedRole);
    } catch (e) {
      host.innerHTML = `<p class="loading">Catálogo indisponível: ${esc(e.message)}</p>`;
      return;
    }
    const canEdit = editable && catalogEditable;
    host.innerHTML = renderPermToggles(selectedRole, roleMeta, levels, canEdit);
    host.querySelector('[data-goto-exec]')?.addEventListener('click', (e) => {
      e.preventDefault();
      document.querySelector('[data-am-tab="quem-faz-o-que"]')?.click();
    });
    host.querySelectorAll('[data-acs-toggle]').forEach((inp) => {
      inp.addEventListener('change', async () => {
        if (!canEdit) return;
        const actionId = inp.dataset.acsToggle;
        try {
          await patchToggle(actionId, selectedRole, inp.checked);
        } catch (err) {
          inp.checked = !inp.checked;
          window.alert(`Erro ao gravar: ${err.message}`);
        }
      });
    });
  }

  async function paint(host, opts = {}) {
    if (!host) return;
    if (window.DeskAccessControlHub?.paint) {
      return window.DeskAccessControlHub.paint(host, opts);
    }
    return paintCapabilitiesOnly(host, opts);
  }

  window.DeskAccessControlPanel = {
    ROLE_CODES,
    ACCESS_ACTIONS,
    paint,
    paintCapabilitiesOnly,
    invalidateCache: () => { levelsCache = null; levelsRole = null; },
    resetUserMgmt: () => window.DeskUserManagement?.reset?.(),
  };
})();
