<?php /** @var string $title */ ?>
<div class="card">
  <div class="header" style="justify-content: space-between; align-items:center;">
    <h1 style="margin:0;"><?= htmlspecialchars($title ?? 'Permissões (RBAC)') ?></h1>
    <div style="display:flex; gap:.5rem;">
      <button id="rbac_new_role" class="btn-outline">Novo papel</button>
      <button id="rbac_save" class="btn">Salvar</button>
      <button id="rbac_cancel" class="btn-outline">Cancelar</button>
    </div>
  </div>

  <div class="tabs">
    <button class="tab active" data-tab="user">Dados do usuário</button>
    <button class="tab" data-tab="access">Horários de acesso</button>
  </div>

  <section id="tab_user" class="card">
    <div class="form-row cols-2">
      <div class="form-group">
        <label>Login (e-mail)</label>
        <input id="user_login" type="email" placeholder="joelson@empresa.com" />
      </div>
      <div class="form-group">
        <label>Nome</label>
        <input id="user_name" type="text" placeholder="Joelson" />
      </div>
      <div class="form-group">
        <label>Departamento</label>
        <input id="user_department" type="text" placeholder="Direção" />
      </div>
      <div class="form-group">
        <label><input id="user_change_password" type="checkbox" /> Alterar Senha</label>
        <div class="form-row cols-2" style="margin-top:.5rem;">
          <input id="user_password" type="password" placeholder="Senha (mínimo 6 caracteres)" disabled />
          <input id="user_password_repeat" type="password" placeholder="Repita a senha" disabled />
        </div>
      </div>
    </div>
    <div style="margin:.5rem 0; display:flex; gap:.5rem; align-items:center; flex-wrap:wrap;">
      <button id="rbac_copy" class="btn-outline">Selecionar papel de outro usuário</button>
      <button id="rbac_copy_perms" class="btn-outline">Copiar permissões do usuário</button>
      <label class="muted" style="display:inline-flex; align-items:center; gap:.25rem;">
        Modo de cópia:
        <select id="rbac_copy_mode">
          <option value="merge" selected>Mesclar</option>
          <option value="overwrite">Sobrescrever</option>
        </select>
      </label>
    </div>
    <div class="form-row cols-2">
      <div class="form-group">
        <label>Papel do usuário</label>
        <select id="rbac_user_role"></select>
      </div>
      <div class="form-group">
        <label>Filtrar por funcionalidade</label>
        <input id="rbac_filter" type="text" placeholder="Buscar..." />
      </div>
    </div>
    <div id="rbac_tree" style="border:1px solid #ddd; border-radius:6px; max-height:420px; overflow:auto; padding:.5rem;"></div>
  </section>

  <section id="tab_access" class="card" style="display:none;">
    <div style="border:1px solid #ddd; border-radius:6px; padding:.5rem;">
      <div style="display:flex; align-items:center; gap:.5rem; flex-wrap:wrap;">
        <label style="display:inline-flex; align-items:center; gap:.25rem;">Horário Inicial
          <input id="ctrl_start" type="time" value="08:00" />
        </label>
        <label style="display:inline-flex; align-items:center; gap:.25rem;">Horário Final
          <input id="ctrl_end" type="time" value="17:30" />
        </label>
        <label class="muted">D <input id="ctrl_day_0" type="checkbox" /></label>
        <label class="muted">S <input id="ctrl_day_1" type="checkbox" /></label>
        <label class="muted">T <input id="ctrl_day_2" type="checkbox" /></label>
        <label class="muted">Q <input id="ctrl_day_3" type="checkbox" /></label>
        <label class="muted">Q <input id="ctrl_day_4" type="checkbox" /></label>
        <label class="muted">S <input id="ctrl_day_5" type="checkbox" /></label>
        <label class="muted">S <input id="ctrl_day_6" type="checkbox" /></label>
        <button id="access_add_row" class="btn" style="margin-left:auto;">Adicionar horário permitido</button>
      </div>
      <div id="access_table" style="margin-top:.5rem;"></div>
    </div>

    <div class="form-row cols-3" style="align-items:end; margin-top:.75rem;">
      <div class="form-group">
        <label>Login (e-mail) do usuário</label>
        <input id="access_user_login" type="email" placeholder="joelson@empresa.com" />
      </div>
      <div class="form-group">
        <label>Status atual</label>
        <div id="access_status" class="badge">—</div>
      </div>
      <div class="form-group" style="display:flex; gap:.5rem;">
        <button id="access_load" class="btn-outline">Carregar horários</button>
        <button id="access_save" class="btn">Salvar horários</button>
      </div>
    </div>
  </section>
</div>

<script>
document.addEventListener('DOMContentLoaded', () => {
  const $ = (id) => document.getElementById(id);
  // Tab switching
  document.querySelectorAll('.tab').forEach(btn => {
    btn.addEventListener('click', () => {
      document.querySelectorAll('.tab').forEach(b => b.classList.remove('active'));
      btn.classList.add('active');
      const tab = btn.getAttribute('data-tab');
      $('tab_user').style.display = tab==='user' ? '' : 'none';
      $('tab_access').style.display = tab==='access' ? '' : 'none';
    });
  });

  $('user_change_password').addEventListener('change', (e) => {
    const on = e.target.checked;
    $('user_password').disabled = !on;
    $('user_password_repeat').disabled = !on;
  });

  const api = {
    roles: '/api/auth/roles',
    permissions: '/api/auth/permissions',
    rolePerms: (role) => `/api/auth/role-permissions?role=${encodeURIComponent(role)}`,
    rolePermsPut: '/api/auth/role-permissions',
    userRolesGet: (userId) => `/api/auth/user-roles?user_id=${userId}`,
    userRolesPut: '/api/auth/user-roles',
    users: (q) => `/api/cadastros/usuarios?q=${encodeURIComponent(q||'')}`,
    me: '/api/auth/me',
    accessSchedulesGet: (userId) => `/api/auth/access-schedules?user_id=${userId}`,
    accessSchedulesPut: '/api/auth/access-schedules',
    accessStatusGet: (userId) => `/api/auth/access-schedules/status?user_id=${userId}`
  };

  let allPerms = [];
  let grouped = {};
  let selectedRole = '';
  let selectedUserId = null;
  let isAdminSelected = false;
  let currentUserPerms = [];
  let allowedPrefixes = new Set();
  const DAYS = [
    { idx:0, name:'Domingo', abbr:'D' },
    { idx:1, name:'Segunda', abbr:'S' },
    { idx:2, name:'Terça', abbr:'T' },
    { idx:3, name:'Quarta', abbr:'Q' },
    { idx:4, name:'Quinta', abbr:'Q' },
    { idx:5, name:'Sexta', abbr:'S' },
    { idx:6, name:'Sábado', abbr:'S' }
  ];
  let scheduleRows = []; // [{ start_minute, end_minute, days:[idx,...] }]

  function groupLabel(p) {
    if (p.startsWith('pdv.')) return 'Frente de Caixa';
    if (p.startsWith('clientes.')) return 'Clientes';
    if (p.startsWith('produtos.')) return 'Produtos';
    if (p.startsWith('vendas.')) return 'Vendas';
    if (p.startsWith('estoque.')) return 'Estoque';
    if (p.startsWith('compras.')) return 'Compras';
    if (p.startsWith('cotacoes.')) return 'Cotações';
    if (p.startsWith('wms.')) return 'WMS';
    if (p.startsWith('fiscal.') || p.startsWith('nfe.')) return 'Nota Fiscal';
    if (p.startsWith('cadastros.')) return 'Cadastros';
    if (p.startsWith('settings.')) return 'Configurações';
    if (p.startsWith('rbac.')) return 'Segurança';
    if (p.startsWith('modules.')) return 'Módulos';
    return 'Outros';
  }

  // Util: prefixo do módulo (antes do último ponto)
  function permPrefix(p) {
    const i = p.lastIndexOf('.');
    return i > 0 ? p.substring(0, i) : p;
  }

  // Constroi definição de módulos com listas de leitura/edição por prefixo
  function buildModuleDefs() {
    const defs = {}; // { prefix: { label, group, readPerms:[], editPerms:[] } }
    const suffixIsRead = (s) => s === 'read' || s === 'access';
    const suffixIsEdit = (s) => s === 'create' || s === 'update' || s === 'delete' || s === 'manage';
    allPerms.forEach(p => {
      const i = p.lastIndexOf('.');
      const prefix = i > 0 ? p.substring(0, i) : p;
      const suffix = i > 0 ? p.substring(i+1) : '';
      const group = groupLabel(prefix + '.');
      const label = (function() {
        // map amigável
        const map = {
          'clientes': 'Clientes', 'produtos': 'Produtos', 'compras': 'Compras', 'cotacoes': 'Cotações',
          'estoque': 'Estoque', 'wms': 'WMS', 'vendas': 'Vendas', 'pdv': 'Frente de Caixa',
          'fiscal': 'Fiscal', 'nfe': 'Nota Fiscal', 'addons.asaas': 'Asaas', 'integrations.googlecalendar': 'Google Calendar',
          'settings': 'Configurações', 'modules': 'Módulos', 'rbac': 'Segurança (RBAC)',
          'cadastros.fornecedores': 'Cadastros: Fornecedores', 'cadastros.empresas': 'Cadastros: Empresas',
          'cadastros.transportadoras': 'Cadastros: Transportadoras', 'cadastros.usuarios': 'Cadastros: Usuários',
          'cadastros.vendedores': 'Cadastros: Vendedores', 'cadastros.tecnicos': 'Cadastros: Técnicos'
        };
        return map[prefix] || prefix.charAt(0).toUpperCase() + prefix.slice(1);
      })();
      const def = (defs[prefix] ||= { label, group, readPerms: [], editPerms: [] });
      if (suffixIsRead(suffix)) def.readPerms.push(p);
      else if (suffixIsEdit(suffix)) def.editPerms.push(p);
    });
    return defs;
  }

  // Render com radios: Nenhum / Ler / Editar / Ambos
  function renderTree(currentPerms) {
    const defs = buildModuleDefs();
    const filter = $('rbac_filter').value.trim().toLowerCase();
    const container = $('rbac_tree');
    container.innerHTML = '';
    if (isAdminSelected) {
      const note = document.createElement('div');
      note.className = 'muted';
      note.style.margin = '.25rem 0 .5rem 0';
      note.textContent = 'Edição desabilitada para o papel "admin".';
      container.appendChild(note);
    }

    // Agrupar por área amigável
    const byGroup = {};
    Object.entries(defs).forEach(([prefix, def]) => {
      // ocultar módulos sem nenhuma permissão conhecida
      if ((def.readPerms.length + def.editPerms.length) === 0) return;
      // filtrar por perfil do usuário atual: só mostrar prefixos permitidos
      if (allowedPrefixes.size > 0 && !allowedPrefixes.has(prefix)) return;
      const matchesFilter = !filter || prefix.toLowerCase().includes(filter) || def.label.toLowerCase().includes(filter);
      if (!matchesFilter) return;
      (byGroup[def.group] ||= []).push({ prefix, def });
    });

    Object.keys(byGroup).sort().forEach(groupName => {
      const groupDiv = document.createElement('div');
      groupDiv.style.marginBottom = '.75rem';

      // Cabeçalho do grupo com aplicador global
      const header = document.createElement('div');
      header.style.display = 'flex'; header.style.alignItems = 'center'; header.style.gap = '.6rem';
      const ttl = document.createElement('strong'); ttl.textContent = groupName;
      header.appendChild(ttl);
      const applyAll = document.createElement('div'); applyAll.className = 'muted'; applyAll.style.marginLeft = 'auto';
      applyAll.textContent = 'Aplicar a todos:';
      const opts = ['none','read','edit','both'];
      const labels = { none: 'Nenhum', read: 'Ler', edit: 'Editar', both: 'Ambos' };
      const applyWrap = document.createElement('div'); applyWrap.style.display='inline-flex'; applyWrap.style.gap='.4rem'; applyWrap.style.marginLeft='.4rem';
      opts.forEach(o => {
        const lab = document.createElement('label'); lab.className = 'muted'; lab.style.display='inline-flex'; lab.style.alignItems='center'; lab.style.gap='.25rem';
        const r = document.createElement('input'); r.type = 'radio'; r.name = `grp_${groupName}_apply`; r.value = o; r.disabled = isAdminSelected;
        lab.appendChild(r); lab.appendChild(document.createTextNode(labels[o])); applyWrap.appendChild(lab);
      });
      applyAll.appendChild(applyWrap); header.appendChild(applyAll);
      groupDiv.appendChild(header);

      const list = document.createElement('div'); list.style.marginLeft = '1rem';
      byGroup[groupName].sort((a,b)=> a.prefix.localeCompare(b.prefix)).forEach(({prefix, def}) => {
        const row = document.createElement('div'); row.style.display='flex'; row.style.alignItems='center'; row.style.gap='.6rem'; row.style.margin='.2rem 0';
        const name = document.createElement('div'); name.style.minWidth='180px'; name.textContent = def.label;
        row.appendChild(name);
        const choiceWrap = document.createElement('div'); choiceWrap.style.display='inline-flex'; choiceWrap.style.gap='.6rem';
        const hasRead = def.readPerms.some(p => currentPerms.includes(p));
        const hasEdit = def.editPerms.some(p => currentPerms.includes(p));
        const state = hasRead && hasEdit ? 'both' : (hasRead ? 'read' : (hasEdit ? 'edit' : 'none'));
        ['none','read','edit','both'].forEach(o => {
          const lab = document.createElement('label'); lab.style.display='inline-flex'; lab.style.alignItems='center'; lab.style.gap='.25rem';
          const r = document.createElement('input'); r.type = 'radio'; r.name = `mod_${prefix}`; r.value = o; r.checked = (o === state); r.disabled = isAdminSelected;
          lab.appendChild(r); lab.appendChild(document.createTextNode(labels[o])); choiceWrap.appendChild(lab);
        });
        row.appendChild(choiceWrap);
        list.appendChild(row);
      });

      // Listener: aplicar opção a todos módulos do grupo
      applyWrap.querySelectorAll('input[type=radio]').forEach(r => {
        r.addEventListener('change', () => {
          const val = r.value;
          list.querySelectorAll('input[type=radio]').forEach(ir => {
            if (ir.name.startsWith('mod_') && !ir.disabled) {
              ir.checked = (ir.value === val);
            }
          });
        });
      });

      container.appendChild(groupDiv);
    });

    // Nota para admin
    const saveBtn = $('rbac_save');
    saveBtn.disabled = isAdminSelected;
  }

  async function loadRoles() {
    const resp = await apiRequest(api.roles, { headers: { 'Accept': 'application/json' } });
    if (!resp || !resp.ok) {
      try {
        const err = await resp.json();
        alert('Falha ao carregar papéis: ' + (err?.error || resp.status));
      } catch(_) {
        alert('Falha ao carregar papéis (status ' + (resp ? resp.status : 'desconhecido') + '). Verifique permissão rbac.manage.');
      }
    }
    const json = await resp.json(); const roles = json.data || [];
    const sel = $('rbac_user_role'); sel.innerHTML = '';
    roles.forEach(r => { const opt = document.createElement('option'); opt.value = r.name; opt.textContent = r.name; sel.appendChild(opt); });
    const nonAdmin = roles.find(r => r.name !== 'admin');
    selectedRole = nonAdmin ? nonAdmin.name : (roles[0]?.name || '');
    isAdminSelected = (selectedRole === 'admin');
    if (selectedRole) sel.value = selectedRole;
  }

  async function loadPerms() {
    const resp = await apiRequest(api.permissions, { headers: { 'Accept': 'application/json' } });
    const json = await resp.json(); allPerms = (json.data || []).map(r => r.name);
  }

  async function loadMe() {
    try {
      const resp = await apiRequest(api.me, { headers: { 'Accept': 'application/json' } });
      const json = await resp.json();
      currentUserPerms = (json.user?.permissions) || [];
      const roles = (json.user?.roles) || [];
      const hasManage = currentUserPerms.includes('rbac.manage');
      const isAdminUser = roles.includes('admin');
      // Se admin ou com rbac.manage, liberar visualização completa
      if (hasManage || isAdminUser) {
        allowedPrefixes = new Set();
      } else {
        allowedPrefixes = new Set(currentUserPerms.map(p => { const i = p.lastIndexOf('.'); return i>0 ? p.substring(0,i) : p; }));
      }
    } catch (e) { currentUserPerms = []; allowedPrefixes = new Set(); }
  }

  async function refreshRolePerms() {
    if (!selectedRole) return;
    const resp = await apiRequest(api.rolePerms(selectedRole), { headers: { 'Accept': 'application/json' } });
    const json = await resp.json(); const cur = json.data || [];
    renderTree(cur);
  }

  $('rbac_user_role').addEventListener('change', async (e) => {
    selectedRole = e.target.value; isAdminSelected = (selectedRole === 'admin'); await refreshRolePerms();
  });
  $('rbac_filter').addEventListener('input', async () => {
    const resp = await apiRequest(api.rolePerms(selectedRole), { headers: { 'Accept': 'application/json' } });
    const json = await resp.json(); renderTree(json.data || []);
  });

  $('rbac_save').addEventListener('click', async () => {
    // Carregar permissões atuais para preservar especiais fora de módulos
    const curRes = await apiRequest(api.rolePerms(selectedRole), { headers: { 'Accept': 'application/json' } });
    const curJson = await curRes.json(); const current = curJson.data || [];
    const defs = buildModuleDefs();
    const isModulePerm = (p) => {
      return Object.values(defs).some(def => def.readPerms.includes(p) || def.editPerms.includes(p));
    };
    const specialPerms = current.filter(p => !isModulePerm(p));

    // Construir a partir dos radios
    const selectedPerms = [];
    Object.entries(defs).forEach(([prefix, def]) => {
      const chosen = document.querySelector(`input[type=radio][name="mod_${prefix}"]:checked`);
      const val = chosen ? chosen.value : 'none';
      if (val === 'read' || val === 'both') {
        def.readPerms.forEach(p => selectedPerms.push(p));
      }
      if (val === 'edit' || val === 'both') {
        def.editPerms.forEach(p => selectedPerms.push(p));
      }
    });

    const finalPerms = [...specialPerms, ...selectedPerms];
    const res = await apiRequest(api.rolePermsPut, {
      method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
      body: JSON.stringify({ role: selectedRole, permissions: finalPerms })
    });
    if (res.ok) { alert('Permissões salvas'); await refreshRolePerms(); }
    else { const err = await res.json().catch(()=>({})); alert('Erro ao salvar: ' + (err.error || res.status)); }
  });

  $('rbac_cancel').addEventListener('click', () => { window.location.reload(); });

  $('rbac_new_role').addEventListener('click', async () => {
    const name = prompt('Nome do novo papel');
    if (!name) return;
    try {
      const res = await apiRequest(api.roles, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
        body: JSON.stringify({ name: name.trim() })
      });
      if (res && (res.status === 201 || res.ok)) {
        alert('Papel criado com sucesso');
        await loadRoles();
        const sel = $('rbac_user_role');
        sel.value = name.trim(); selectedRole = name.trim(); isAdminSelected = (selectedRole === 'admin');
        await refreshRolePerms();
      } else {
        const err = await res.json().catch(()=>({}));
        alert('Falha ao criar papel: ' + (err.error || (res ? res.status : 'desconhecido')));
      }
    } catch (e) {
      alert('Erro ao criar papel: ' + (e && e.message ? e.message : 'desconhecido'));
    }
  });

  $('rbac_copy').addEventListener('click', async () => {
    const q = ($('user_login').value || '').trim();
    if (!q) { alert('Informe o e-mail do usuário de origem em "Login (e-mail)"'); return; }
    // Encontrar usuário por e-mail
    const respUsers = await apiRequest(api.users(q), { headers: { 'Accept': 'application/json' } });
    const jsUsers = await respUsers.json(); const list = jsUsers.data || [];
    const src = list.find(u => (u.email||'').toLowerCase() === q.toLowerCase());
    if (!src) { alert('Usuário não encontrado'); return; }
    const respUR = await apiRequest(api.userRolesGet(src.id), { headers: { 'Accept': 'application/json' } });
    const jsUR = await respUR.json(); const roles = jsUR.data || [];
    if (!roles.length) { alert('Usuário origem sem roles'); return; }
    // Define o primeiro role como seleção e recarrega permissões
    $('rbac_user_role').value = roles[0]; selectedRole = roles[0]; await refreshRolePerms();
    alert('Papel selecionado a partir do usuário de origem: ' + roles[0]);
  });

  // Botão para copiar permissões agregadas de outro usuário (mesclar ou sobrescrever)
  $('rbac_copy_perms').addEventListener('click', async () => {
    const q = ($('user_login').value || '').trim();
    if (!q) { alert('Informe o e-mail do usuário de origem em "Login (e-mail)"'); return; }
    try {
      // Encontrar usuário por e-mail
      const respUsers = await apiRequest(api.users(q), { headers: { 'Accept': 'application/json' } });
      const jsUsers = await respUsers.json(); const list = jsUsers.data || [];
      const src = list.find(u => (u.email||'').toLowerCase() === q.toLowerCase());
      if (!src) { alert('Usuário não encontrado'); return; }
      // Obter roles do usuário
      const respUR = await apiRequest(api.userRolesGet(src.id), { headers: { 'Accept': 'application/json' } });
      const jsUR = await respUR.json(); const roles = jsUR.data || [];
      if (!roles.length) { alert('Usuário sem papéis para copiar permissões'); return; }
      // Agregar permissões de todos os papéis do usuário origem
      const permsSets = await Promise.all(roles.map(r => apiRequest(api.rolePerms(r), { headers: { 'Accept': 'application/json' } }).then(rs => rs.json()).then(j => (j.data||[]))));
      const union = new Set(); permsSets.forEach(arr => arr.forEach(p => union.add(p)));
      // Decidir modo via seletor na UI
      const modeSel = document.getElementById('rbac_copy_mode');
      const overwrite = (modeSel && modeSel.value === 'overwrite');
      let finalPerms = Array.from(union);
      if (!overwrite) {
        // Mesclar com permissões atuais do papel selecionado
        const curRes = await apiRequest(api.rolePerms(selectedRole), { headers: { 'Accept': 'application/json' } });
        const curJson = await curRes.json(); const current = curJson.data || [];
        current.forEach(p => union.add(p));
        finalPerms = Array.from(union);
      }
      // Aplicar permissões ao papel selecionado
      const put = await apiRequest(api.rolePermsPut, {
        method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
        body: JSON.stringify({ role: selectedRole, permissions: finalPerms })
      });
      if (put && put.ok) { alert('Permissões copiadas com sucesso'); await refreshRolePerms(); }
      else {
        const err = await (put ? put.json() : Promise.resolve({}));
        alert('Falha ao copiar permissões: ' + (err?.error || (put ? put.status : 'desconhecido')));
      }
    } catch (e) {
      alert('Erro ao copiar permissões: ' + (e && e.message ? e.message : 'desconhecido'));
    }
  });

  // Botão para atribuir o papel selecionado ao usuário informado
  (function addAssignRoleButton(){
    const userSection = document.getElementById('tab_user');
    if (!userSection) return;
    const btnWrap = document.createElement('div'); btnWrap.style.margin = '.5rem 0';
    const assignBtn = document.createElement('button'); assignBtn.id = 'rbac_assign_role'; assignBtn.className = 'btn-outline'; assignBtn.textContent = 'Atribuir papel ao usuário';
    btnWrap.appendChild(assignBtn);
    // Inserir após o botão de copiar
    const copyBtn = document.getElementById('rbac_copy');
    if (copyBtn && copyBtn.parentElement) { copyBtn.parentElement.insertAdjacentElement('afterend', btnWrap); } else { userSection.appendChild(btnWrap); }
    assignBtn.addEventListener('click', async () => {
      const q = ($('user_login').value || '').trim();
      if (!q) { alert('Informe o e-mail do usuário em "Login (e-mail)"'); return; }
      if (!selectedRole) { alert('Selecione um papel antes de atribuir.'); return; }
      try {
        const respUsers = await apiRequest(api.users(q), { headers: { 'Accept': 'application/json' } });
        const jsUsers = await respUsers.json(); const list = jsUsers.data || [];
        const src = list.find(u => (u.email||'').toLowerCase() === q.toLowerCase());
        if (!src) { alert('Usuário não encontrado'); return; }
        const put = await apiRequest(api.userRolesPut, {
          method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
          body: JSON.stringify({ user_id: src.id, roles: [selectedRole] })
        });
        if (put && put.ok) { alert('Papel atribuído ao usuário: ' + selectedRole); }
        else {
          const err = await (put ? put.json() : Promise.resolve({}));
          alert('Falha ao atribuir papel: ' + (err?.error || (put ? put.status : 'desconhecido')));
        }
      } catch(e) {
        alert('Erro ao atribuir papel: ' + (e && e.message ? e.message : 'desconhecido'));
      }
    });
  })();

  // ----- Horários de acesso -----
  function minutesFromTimeStr(str) {
    const [h,m] = (str||'').split(':').map(x=>parseInt(x,10));
    if (isNaN(h) || isNaN(m)) return null; return h*60 + m;
  }
  function timeStrFromMinutes(min) {
    const h = Math.floor(min/60); const m = min%60; const pad = (n)=>String(n).padStart(2,'0');
    return `${pad(h)}:${pad(m)}`;
  }
  function renderAccessTable() {
    const container = document.getElementById('access_table');
    container.innerHTML = '';
    const table = document.createElement('table'); table.className = 'table'; table.style.width='100%';
    const thead = document.createElement('thead');
    const hr = document.createElement('tr');
    ['Início','Fim',...DAYS.map(d=>d.abbr),''].forEach(h => { const th = document.createElement('th'); th.textContent = h; hr.appendChild(th); });
    thead.appendChild(hr); table.appendChild(thead);
    const tbody = document.createElement('tbody');
    scheduleRows.forEach((row, idx) => {
      const tr = document.createElement('tr');
      const tdStart = document.createElement('td'); const inpStart = document.createElement('input'); inpStart.type='time'; inpStart.value=timeStrFromMinutes(row.start_minute);
      inpStart.addEventListener('change', () => { const v=minutesFromTimeStr(inpStart.value); if (v!==null) row.start_minute=v; }); tdStart.appendChild(inpStart); tr.appendChild(tdStart);
      const tdEnd = document.createElement('td'); const inpEnd = document.createElement('input'); inpEnd.type='time'; inpEnd.value=timeStrFromMinutes(row.end_minute);
      inpEnd.addEventListener('change', () => { const v=minutesFromTimeStr(inpEnd.value); if (v!==null) row.end_minute=v; }); tdEnd.appendChild(inpEnd); tr.appendChild(tdEnd);
      DAYS.forEach(d => {
        const td = document.createElement('td'); const cb = document.createElement('input'); cb.type='checkbox'; cb.checked = row.days.includes(d.idx);
        cb.addEventListener('change', () => {
          if (cb.checked) { if (!row.days.includes(d.idx)) row.days.push(d.idx); }
          else { row.days = row.days.filter(x=>x!==d.idx); }
        }); td.appendChild(cb); tr.appendChild(td);
      });
      const tdActions = document.createElement('td'); const del = document.createElement('button'); del.className='btn-outline'; del.title='Remover'; del.textContent='🗑';
      del.addEventListener('click', () => { scheduleRows.splice(idx,1); renderAccessTable(); }); tdActions.appendChild(del); tr.appendChild(tdActions);
      tbody.appendChild(tr);
    });
    table.appendChild(tbody);
    container.appendChild(table);
  }

  async function findUserIdByEmail(email) {
    const respUsers = await apiRequest(api.users(email), { headers: { 'Accept': 'application/json' } });
    const jsUsers = await respUsers.json(); const list = jsUsers.data || [];
    const src = list.find(u => (u.email||'').toLowerCase() === email.toLowerCase());
    return src ? src.id : null;
  }

  async function loadAccessSchedules() {
    const email = (document.getElementById('access_user_login').value || '').trim();
    if (!email) { alert('Informe o e-mail do usuário'); return; }
    const uid = await findUserIdByEmail(email);
    if (!uid) { alert('Usuário não encontrado'); return; }
    selectedUserId = uid;
    const res = await apiRequest(api.accessSchedulesGet(uid), { headers: { 'Accept': 'application/json' } });
    const js = await res.json(); const data = js.data || [];
    // Agrupar por (start,end) para formar linhas com checkboxes de dias
    const map = new Map();
    data.forEach(r => {
      if ((r.allow ?? 1) != 1) return;
      const key = `${r.start_minute}-${r.end_minute}`;
      if (!map.has(key)) map.set(key, { start_minute: r.start_minute, end_minute: r.end_minute, days: [] });
      const row = map.get(key);
      if (!row.days.includes(r.day_of_week)) row.days.push(r.day_of_week);
    });
    scheduleRows = Array.from(map.values());
    renderAccessTable();
    await refreshAccessStatus();
  }

  async function refreshAccessStatus() {
    if (!selectedUserId) { document.getElementById('access_status').textContent = '—'; return; }
    const res = await apiRequest(api.accessStatusGet(selectedUserId), { headers: { 'Accept': 'application/json' } });
    const js = await res.json(); const ok = !!js.allowed;
    const el = document.getElementById('access_status');
    el.textContent = ok ? 'Permitido agora' : 'Bloqueado agora';
    el.className = ok ? 'badge success' : 'badge danger';
  }

  async function saveAccessSchedules() {
    if (!selectedUserId) { alert('Carregue um usuário primeiro'); return; }
    const payload = { user_id: selectedUserId, schedules: [] };
    scheduleRows.forEach(row => {
      const s = Math.max(0, Math.min(1439, parseInt(row.start_minute, 10)));
      const e = Math.max(1, Math.min(1440, parseInt(row.end_minute, 10)));
      if (!isFinite(s) || !isFinite(e) || s >= e) return;
      (row.days||[]).forEach(d => {
        payload.schedules.push({ day_of_week: d, start_minute: s, end_minute: e, allow: 1 });
      });
    });
    const res = await apiRequest(api.accessSchedulesPut, {
      method: 'PUT', headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
      body: JSON.stringify(payload)
    });
    if (res.ok) { alert('Horários salvos'); await refreshAccessStatus(); }
    else { const err = await res.json().catch(()=>({})); alert('Erro ao salvar: ' + (err.error || res.status)); }
  }

  // conectar handlers
  document.getElementById('access_load').addEventListener('click', loadAccessSchedules);
  document.getElementById('access_save').addEventListener('click', saveAccessSchedules);
  document.getElementById('access_add_row').addEventListener('click', () => {
    const sStr = document.getElementById('ctrl_start').value;
    const eStr = document.getElementById('ctrl_end').value;
    const s = minutesFromTimeStr(sStr); const e = minutesFromTimeStr(eStr);
    if (s===null || e===null || s>=e) { alert('Informe horários válidos'); return; }
    const daysSel = DAYS.map(d => ({idx:d.idx, checked: !!document.getElementById(`ctrl_day_${d.idx}`).checked})).filter(x=>x.checked).map(x=>x.idx);
    if (daysSel.length === 0) { alert('Selecione pelo menos um dia'); return; }
    const existing = scheduleRows.find(r => r.start_minute===s && r.end_minute===e);
    if (existing) {
      const set = new Set(existing.days); daysSel.forEach(d => set.add(d)); existing.days = Array.from(set);
    } else {
      scheduleRows.push({ start_minute: s, end_minute: e, days: daysSel });
    }
    renderAccessTable();
  });

  // Sugestão: copiar o e-mail do campo da aba usuário
  const userEmailInput = document.getElementById('user_login');
  const accessEmailInput = document.getElementById('access_user_login');
  if (userEmailInput && accessEmailInput) {
    userEmailInput.addEventListener('input', () => { accessEmailInput.value = userEmailInput.value; });
  }

  (async function init(){ await loadMe(); await loadRoles(); await loadPerms(); await refreshRolePerms(); })();
});
</script>