(function () {
  function basePath() {
    return document.body.getAttribute('data-base-path') || '';
  }

  function canEditGlobal() {
    return document.body.getAttribute('data-can-rbac-root') === '1';
  }

  function setStatus(msg, isError) {
    const el = document.getElementById('rbac-status');
    if (!el) return;
    el.textContent = msg;
    el.classList.toggle('error', !!isError);
  }

  async function fetchJson(url, opts) {
    const res = await fetch(url, Object.assign({ credentials: 'same-origin' }, opts || {}));
    const data = await res.json().catch(() => ({}));
    if (!res.ok || data.ok === false) {
      throw new Error(data.error || 'HTTP ' + res.status);
    }
    return data;
  }

  function esc(s) {
    const d = document.createElement('div');
    d.textContent = s == null ? '' : String(s);
    return d.innerHTML;
  }

  function renderPanel(data) {
    const tbody = document.getElementById('rbac-users-tbody');
    if (!tbody) return;
    tbody.innerHTML = '';
    const companies = data.companies || [];
    const companyRoles = data.company_roles || [];
    const globalRoles = data.global_roles || [];
    const sets = [{ key: '', label: '(role defaults only)' }].concat(data.privilege_sets || []);
    const seenAuth = new Set();

    (data.users || []).forEach((u) => {
      (u.memberships || []).forEach((m) => {
        const tr = document.createElement('tr');
        const globalSelect = canEditGlobal()
          ? '<select class="rbac-global-role" data-user-id="' + u.id + '">' +
            globalRoles.map((r) => '<option value="' + esc(r) + '"' + (u.global_role === r ? ' selected' : '') + '>' + esc(r) + '</option>').join('') +
            '</select>'
          : '<code>' + esc(u.global_role) + '</code>';

        const roleSelect =
          '<select class="rbac-company-role" data-user-id="' + u.id + '" data-company-id="' + m.company_id + '">' +
          companyRoles
            .map((r) => '<option value="' + esc(r) + '"' + (m.role === r ? ' selected' : '') + '>' + esc(r) + '</option>')
            .join('') +
          '</select>';

        const setSelect =
          '<select class="rbac-privilege-set" data-user-id="' + u.id + '" data-company-id="' + m.company_id + '">' +
          sets
            .map((s) => {
              const key = s.key != null ? s.key : '';
              const label = s.label || key || '(none)';
              const sel = (m.privilege_set || '') === key ? ' selected' : '';
              return '<option value="' + esc(key) + '"' + sel + '>' + esc(label) + '</option>';
            })
            .join('') +
          (m.privilege_set === 'custom' ? '<option value="" disabled>custom grants (edit via API)</option>' : '') +
          '</select>';

        let authCell = '';
        if (!seenAuth.has(u.id)) {
          seenAuth.add(u.id);
          const fails = Number(u.auth_failures || 0);
          if (canEditGlobal() && fails > 0) {
            authCell =
              '<span class="muted">' + fails + ' fail</span> ' +
              '<button type="button" class="btn btn--secondary rbac-clear-auth" data-user-id="' + u.id + '">Clear lockouts</button>';
          } else if (fails > 0) {
            authCell = '<span class="muted">' + fails + ' recent fail</span>';
          } else {
            authCell = '<span class="muted">—</span>';
          }
        }

        tr.innerHTML =
          '<td>' + esc(u.username) + '</td>' +
          '<td>' + globalSelect + '</td>' +
          '<td><code>' + esc(m.slug) + '</code> ' + esc(m.name) + '</td>' +
          '<td>' + roleSelect + '</td>' +
          '<td>' + setSelect + '</td>' +
          '<td>' + authCell + '</td>';
        tbody.appendChild(tr);
      });
      if (!(u.memberships || []).length && canEditGlobal()) {
        const tr = document.createElement('tr');
        const fails = Number(u.auth_failures || 0);
        let authCell = fails > 0
          ? '<button type="button" class="btn btn--secondary rbac-clear-auth" data-user-id="' + u.id + '">Clear lockouts (' + fails + ')</button>'
          : '<span class="muted">—</span>';
        tr.innerHTML =
          '<td>' + esc(u.username) + '</td>' +
          '<td><code>' + esc(u.global_role) + '</code></td>' +
          '<td colspan="3" class="muted">No company membership</td>' +
          '<td>' + authCell + '</td>';
        tbody.appendChild(tr);
      }
    });

    if (!tbody.children.length) {
      tbody.innerHTML = '<tr><td colspan="6" class="muted">No users in scope.</td></tr>';
    }

    const hint = document.getElementById('rbac-scope-hint');
    if (hint) {
      hint.textContent =
        'Slug admin = company owner/admin (graphs company scope). Root may change global roles. Privilege sets add remote-access grants to members.';
      if (companies.length) {
        hint.textContent += ' Companies: ' + companies.map((c) => c.slug).join(', ');
      }
    }
  }

  async function postAction(action, body) {
    await fetchJson(basePath() + '/api/rbac.php?action=' + encodeURIComponent(action), {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
    });
  }

  function bindChanges() {
    document.addEventListener('click', async (ev) => {
      const btn = ev.target && ev.target.closest ? ev.target.closest('.rbac-clear-auth') : null;
      if (!btn || !canEditGlobal()) return;
      const userId = Number(btn.getAttribute('data-user-id'));
      if (!userId) return;
      try {
        await postAction('clear_auth_lockouts', { user_id: userId });
        setStatus('Auth lockouts cleared.');
        load();
      } catch (e) {
        setStatus(String(e.message || e), true);
      }
    });
    document.addEventListener('change', async (ev) => {
      const t = ev.target;
      if (!t || !t.classList) return;
      try {
        if (t.classList.contains('rbac-global-role') && canEditGlobal()) {
          await postAction('set_global_role', {
            user_id: Number(t.getAttribute('data-user-id')),
            role: t.value,
          });
          setStatus('Global role updated.');
          return;
        }
        if (t.classList.contains('rbac-company-role')) {
          await postAction('set_company_role', {
            user_id: Number(t.getAttribute('data-user-id')),
            company_id: Number(t.getAttribute('data-company-id')),
            role: t.value,
          });
          setStatus('Company role updated.');
          return;
        }
        if (t.classList.contains('rbac-privilege-set')) {
          await postAction('apply_privilege_set', {
            user_id: Number(t.getAttribute('data-user-id')),
            company_id: Number(t.getAttribute('data-company-id')),
            privilege_set: t.value,
          });
          setStatus('Privilege set applied.');
        }
      } catch (e) {
        setStatus(String(e.message || e), true);
      }
    });
  }

  async function load() {
    setStatus('Loading…');
    try {
      const data = await fetchJson(basePath() + '/api/rbac.php?action=panel');
      renderPanel(data);
      setStatus('Ready — changes save on selection.');
    } catch (e) {
      setStatus(String(e.message || e), true);
    }
  }

  document.addEventListener('DOMContentLoaded', function () {
    bindChanges();
    load();
  });
})();
