<?php /* WMS · Armazéns e Operações */ ?>
<nav aria-label="breadcrumb" style="margin-bottom:0.75rem;">
  <ol class="breadcrumb" style="display:flex; gap:0.5rem; list-style:none; padding:0; margin:0;">
    <li><a href="/">ERP</a></li>
    <li>›</li>
    <li><a href="/wms">WMS</a></li>
    <li>›</li>
    <li aria-current="page">Armazéns</li>
  </ol>
  <div class="muted" id="permInfo" style="margin-top:0.25rem;"></div>
  </nav>

<div class="card">
  <div style="display:flex; align-items:center; justify-content:space-between;">
    <h1 style="margin:0;">WMS · Armazéns e Operações</h1>
    <div>
      <button id="kbdHelp" class="btn btn-sm" title="Atalhos (H)">Atalhos</button>
    </div>
  </div>

  <div role="tablist" aria-label="Áreas do WMS" class="tabs" style="display:flex; gap:0.5rem; border-bottom:1px solid #ddd; margin-top:0.75rem;">
    <button role="tab" aria-selected="true" aria-controls="tab-warehouses" id="tabBtn-warehouses" class="tab-btn">Armazéns <span class="badge" id="badge-warehouses" hidden></span></button>
    <button role="tab" aria-selected="false" aria-controls="tab-inventory" id="tabBtn-inventory" class="tab-btn">Inventário <span class="badge" id="badge-inventory" hidden></span></button>
    <button role="tab" aria-selected="false" aria-controls="tab-movements" id="tabBtn-movements" class="tab-btn">Movimentações <span class="badge" id="badge-movements" hidden></span></button>
    <button role="tab" aria-selected="false" aria-controls="tab-reports" id="tabBtn-reports" class="tab-btn">Relatórios <span class="badge" id="badge-reports" hidden></span></button>
    <button role="tab" aria-selected="false" aria-controls="tab-settings" id="tabBtn-settings" class="tab-btn">Configurações <span class="badge" id="badge-settings" hidden></span></button>
  </div>

  <!-- Tab: Armazéns -->
  <section id="tab-warehouses" role="tabpanel" aria-labelledby="tabBtn-warehouses" style="padding-top:0.75rem;">
    <div style="display:flex; gap:0.5rem; align-items:center; margin-bottom:0.75rem; flex-wrap:wrap;">
      <input id="q" type="text" placeholder="Buscar por nome, localização, zona" style="flex:1; padding:0.5rem;" aria-label="Buscar armazéns" list="dlWarehouseQ">
      <select id="filterZone" style="padding:0.5rem;" aria-label="Filtrar por zona">
        <option value="">Todas as zonas</option>
      </select>
      <select id="filterRegion" style="padding:0.5rem;" aria-label="Filtrar por região">
        <option value="">Todas as regiões</option>
      </select>
      <select id="filterStatus" style="padding:0.5rem;" aria-label="Filtrar por status">
        <option value="">Todos os status</option>
      </select>
      <button id="btnNew" class="btn">Novo Armazém (Alt+N)</button>
      <button id="btnInventoryModal" class="btn">Inventários… (Alt+I)</button>
      <div class="right" style="margin-left:auto; display:flex; gap:0.5rem;">
        <button id="btnExportCsv" class="btn btn-sm">CSV</button>
        <button id="btnExportXls" class="btn btn-sm">XLS</button>
        <button id="btnPrint" class="btn btn-sm">PDF/Print</button>
      </div>
    </div>
    <datalist id="dlWarehouseQ"></datalist>
    <div id="feedback" class="muted" aria-live="polite"></div>
    <table class="table" id="tbl" aria-label="Lista de armazéns">
      <thead>
        <tr><th>ID</th><th>Nome</th><th>Localização</th><th>Zonas</th><th style="text-align:right;">Ações</th></tr>
      </thead>
      <tbody id="rows"></tbody>
    </table>
    <div id="whPager" style="display:flex; align-items:center; gap:0.5rem; justify-content:flex-end; margin-top:0.5rem;">
      <label>Registros por página
        <select id="whPageSize" style="padding:0.25rem;">
          <option>10</option>
          <option>25</option>
          <option>50</option>
          <option>100</option>
        </select>
      </label>
      <button id="whPrev" class="btn btn-sm">Anterior</button>
      <span id="whPageInfo" class="muted"></span>
      <button id="whNext" class="btn btn-sm">Próxima</button>
    </div>
  </section>

  <!-- Tab: Inventário -->
  <section id="tab-inventory" role="tabpanel" aria-labelledby="tabBtn-inventory" hidden style="padding-top:0.75rem;">
    <div style="display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap; margin-bottom:0.5rem;">
      <input id="invQuery" type="text" placeholder="Filtrar por produto, endereço, lote" style="flex:2; padding:0.5rem;" list="dlInvQuery">
      <select id="invType" style="padding:0.5rem;">
        <option value="geral">Geral</option>
        <option value="ciclico">Cíclico</option>
        <option value="rotativo">Rotativo</option>
        <option value="amostragem">Amostragem</option>
      </select>
      <input id="invEntries" type="number" min="1" placeholder="Qtd entradas" style="width:10rem; padding:0.5rem;">
      <button id="btnStartInventory" class="btn">Iniciar Inventário</button>
    </div>
    <datalist id="dlInvQuery"></datalist>
    <div id="invFeedback" class="muted" aria-live="polite"></div>
    <table class="table" id="invTable" aria-label="Inventários">
      <thead>
        <tr><th>ID</th><th>Tipo</th><th>Status</th><th>Iniciado</th><th style="text-align:right;">Ações</th></tr>
      </thead>
      <tbody id="invRows"></tbody>
    </table>
    <div id="invPager" style="display:flex; align-items:center; gap:0.5rem; justify-content:flex-end; margin-top:0.5rem;">
      <label>Registros por página
        <select id="invPageSize" style="padding:0.25rem;">
          <option>10</option>
          <option>25</option>
          <option>50</option>
          <option>100</option>
        </select>
      </label>
      <button id="invPrev" class="btn btn-sm">Anterior</button>
      <span id="invPageInfo" class="muted"></span>
      <button id="invNext" class="btn btn-sm">Próxima</button>
    </div>
  </section>

  <!-- Tab: Movimentações -->
  <section id="tab-movements" role="tabpanel" aria-labelledby="tabBtn-movements" hidden style="padding-top:0.75rem;">
    <div style="display:flex; gap:0.5rem; align-items:center; flex-wrap:wrap; margin-bottom:0.5rem;">
      <input id="movQuery" type="text" placeholder="Filtrar por produto, operador, origem/destino" style="flex:2; padding:0.5rem;" list="dlMovQuery">
      <select id="movType" style="padding:0.5rem;">
        <option value="entrada">Entrada</option>
        <option value="saida">Saída</option>
        <option value="transferencia">Transferência</option>
        <option value="ajuste">Ajuste</option>
        <option value="bloqueio">Bloqueio</option>
      </select>
      <button id="btnNewMovement" class="btn">Nova Movimentação</button>
    </div>
    <datalist id="dlMovQuery"></datalist>
    <div id="movFeedback" class="muted" aria-live="polite"></div>
    <table class="table" id="movTable" aria-label="Movimentações">
      <thead>
        <tr><th>ID</th><th>Tipo</th><th>Produto</th><th>Qtd</th><th>Origem</th><th>Destino</th><th>Operador</th><th style="text-align:right;">Ações</th></tr>
      </thead>
      <tbody id="movRows"></tbody>
    </table>
    <div id="movPager" style="display:flex; align-items:center; gap:0.5rem; justify-content:flex-end; margin-top:0.5rem;">
      <label>Registros por página
        <select id="movPageSize" style="padding:0.25rem;">
          <option>10</option>
          <option>25</option>
          <option>50</option>
          <option>100</option>
        </select>
      </label>
      <button id="movPrev" class="btn btn-sm">Anterior</button>
      <span id="movPageInfo" class="muted"></span>
      <button id="movNext" class="btn btn-sm">Próxima</button>
    </div>
  </section>

  <!-- Tab: Relatórios -->
  <section id="tab-reports" role="tabpanel" aria-labelledby="tabBtn-reports" hidden style="padding-top:0.75rem;">
    <div style="display:grid; grid-template-columns:1fr 1fr; gap:0.75rem;">
      <div class="card">
        <div><strong>KPIs de Operação</strong></div>
        <ul class="muted" id="kpiList" style="margin-top:0.5rem;">
          <li>Produtividade dos operadores (últimos 7 dias)</li>
          <li>Taxa de acuracidade de inventário</li>
          <li>Lead time de recebimento e expedição</li>
        </ul>
        <div>
          <button id="btnRefreshKPIs" class="btn btn-sm">Atualizar</button>
        </div>
      </div>
      <div class="card">
        <div><strong>Relatórios</strong></div>
        <div style="display:flex; gap:0.5rem; margin-top:0.5rem;">
          <button class="btn" data-report="movements">Movimentações</button>
          <button class="btn" data-report="inventory">Inventário</button>
          <button class="btn" data-report="receiving">Recebimento</button>
          <button class="btn" data-report="shipping">Expedição</button>
        </div>
        <div style="margin-top:0.75rem;">
          <strong>Histórico de KPIs</strong>
          <table class="table" aria-label="Histórico de KPIs" style="margin-top:0.5rem;">
            <thead>
              <tr><th>Data/Hora</th><th>Descrição</th></tr>
            </thead>
            <tbody id="repRows"></tbody>
          </table>
          <div id="repPager" style="display:flex; align-items:center; gap:0.5rem; justify-content:flex-end; margin-top:0.5rem;">
            <label>Registros por página
              <select id="repPageSize" style="padding:0.25rem;">
                <option>10</option>
                <option>25</option>
                <option>50</option>
                <option>100</option>
              </select>
            </label>
            <button id="repPrev" class="btn btn-sm">Anterior</button>
            <span id="repPageInfo" class="muted"></span>
            <button id="repNext" class="btn btn-sm">Próxima</button>
          </div>
        </div>
      </div>
    </div>
  </section>

  <!-- Tab: Configurações -->
  <section id="tab-settings" role="tabpanel" aria-labelledby="tabBtn-settings" hidden style="padding-top:0.75rem;">
    <div class="card">
      <div><strong>Parâmetros de Integração</strong></div>
      <div class="muted">Configure APIs, WebService, arquivos (XML/EDI) ou DB intermediário</div>
      <div style="display:grid; grid-template-columns:1fr 1fr; gap:0.5rem; margin-top:0.5rem;">
        <label>Endpoint ERP Compras <input id="cfgErpPurch" type="url" placeholder="https://erp.local/api/purchases" /></label>
        <label>Endpoint ERP Vendas <input id="cfgErpSales" type="url" placeholder="https://erp.local/api/sales" /></label>
        <label>Endpoint ERP Fiscal <input id="cfgErpFiscal" type="url" placeholder="https://erp.local/api/fiscal" /></label>
        <label>Chave API <input id="cfgApiKey" type="password" placeholder="********" /></label>
      </div>
      <div style="margin-top:0.5rem; display:flex; gap:0.5rem;">
        <button id="btnSaveCfg" class="btn">Salvar</button>
        <span id="cfgFeedback" class="muted" aria-live="polite"></span>
      </div>
    </div>

    <div class="card" style="margin-top:0.75rem;">
      <div style="display:flex; align-items:center; justify-content:space-between;">
        <strong>Configurações de Estoque</strong>
        <span id="negModeBadgeWms" class="badge" style="display:none; background:#8b0000; color:#fff;">Modo estoque negativo ATIVO</span>
      </div>
      <div class="muted">Controle da política de venda com saldo negativo</div>
      <div style="margin-top:0.5rem;">
        <label style="display:flex; gap:0.5rem; align-items:center;">
          <input id="chkNegStock" type="checkbox">
          Permitir venda com estoque negativo
        </label>
        <p class="muted" style="margin-top:0.25rem;">Quando ativo, o sistema não bloqueia vendas com saldo negativo. Use com cautela.</p>
      </div>
      <div style="margin-top:0.5rem; display:flex; gap:0.5rem; align-items:center;">
        <button id="btnSaveStockCfg" class="btn">Salvar política</button>
        <span id="negCfgFeedback" class="muted" aria-live="polite"></span>
        <span id="negUpdatedAt" class="muted" style="margin-left:auto;"></span>
      </div>
    </div>

    <div class="card" style="margin-top:0.75rem;">
      <div><strong>Integração Coletor Mobile</strong></div>
      <div class="muted">Preparação para conexão futura com o app de coleta de dados (Android/iOS). Estes dados são salvos localmente até a API estar disponível.</div>
      <div style="display:grid; grid-template-columns:1fr 1fr; gap:0.5rem; margin-top:0.5rem;">
        <label>URL Base do Coletor <input id="mobileUrl" type="url" placeholder="https://wms.local/mobile" /></label>
        <label>Chave do Dispositivo <input id="mobileDeviceKey" type="text" placeholder="Ex.: DEV-ABC-123" /></label>
      </div>
      <div style="margin-top:0.5rem; display:flex; gap:0.5rem; align-items:center;">
        <button id="btnSaveMobileCfg" class="btn">Salvar localmente</button>
        <span id="mobileCfgFeedback" class="muted" aria-live="polite"></span>
        <span id="mobileUpdatedAt" class="muted" style="margin-left:auto;"></span>
      </div>
      <div style="margin-top:0.5rem; display:flex; gap:0.5rem; align-items:center;">
        <button id="btnTestMobile" class="btn btn-sm">Testar conexão</button>
        <button id="btnGenMobileQR" class="btn btn-sm">Gerar QR de pareamento</button>
        <button id="btnCopyPairing" class="btn btn-sm">Copiar string de pareamento</button>
        <img id="mobilePairQR" alt="QR de pareamento" style="margin-left:auto; width:120px; height:120px; object-fit:contain;" />
      </div>
    </div>
  </section>
</div>

<!-- Modal de Inventários (Integração Módulo de Inventários) -->
<dialog id="inventoryModal" style="width: min(800px, 95vw);">
  <form method="dialog" style="display:flex; align-items:center; justify-content:space-between;">
    <strong>Inventários</strong>
    <div style="display:flex; gap:0.25rem;">
      <button type="button" class="btn btn-sm" data-win="min" data-dlg="inventoryModal" title="Minimizar">_</button>
      <button type="button" class="btn btn-sm" data-win="max" data-dlg="inventoryModal" title="Maximizar">[]</button>
      <button type="button" class="btn btn-sm" data-win="close" data-dlg="inventoryModal" title="Fechar">×</button>
      <button id="invClose" class="btn btn-sm">Fechar (Esc)</button>
    </div>
  </form>
  <div class="modal-body">
    <div style="display:flex; gap:0.5rem; align-items:center; margin-top:0.5rem;">
      <input id="invModalQuery" type="text" placeholder="Buscar inventários" style="flex:1; padding:0.5rem;">
      <button id="invModalStart" class="btn">Iniciar</button>
    </div>
    <div id="invModalFeedback" class="muted" aria-live="polite" style="margin-top:0.25rem;"></div>
    <table class="table" aria-label="Inventários disponíveis" style="margin-top:0.5rem;">
      <thead>
        <tr><th>ID</th><th>Tipo</th><th>Status</th><th>Atualizado</th><th style="text-align:right;">Ações</th></tr>
      </thead>
      <tbody id="invModalRows"></tbody>
    </table>
  </div>
</dialog>

<!-- Modais adicionais: Armazém (criar/editar) e confirmação de exclusão, e Movimentação -->
<dialog id="warehouseModal" style="width: min(700px, 95vw);">
  <form method="dialog">
    <div style="display:flex; align-items:center; justify-content:space-between;">
      <strong id="whModalTitle">Armazém</strong>
      <div style="display:flex; gap:0.25rem;">
        <button type="button" class="btn btn-sm" data-win="min" data-dlg="warehouseModal" title="Minimizar">_</button>
        <button type="button" class="btn btn-sm" data-win="max" data-dlg="warehouseModal" title="Maximizar">[]</button>
        <button type="button" class="btn btn-sm" data-win="close" data-dlg="warehouseModal" title="Fechar">×</button>
        <button type="button" id="whClose" class="btn btn-sm">Fechar (Esc)</button>
      </div>
    </div>
    <div class="modal-body">
      <div style="display:grid; grid-template-columns:1fr 1fr; gap:0.5rem; margin-top:0.5rem;">
        <label>Nome* <input id="whName" type="text" placeholder="Ex.: Central SP" required /></label>
        <label>Região <input id="whRegion" type="text" placeholder="Sul, Sudeste…" list="dlRegions" /></label>
        <label>Status
          <select id="whStatus">
            <option value="active">Ativo</option>
            <option value="inactive">Inativo</option>
          </select>
        </label>
        <label>Localização <input id="whLocation" type="text" placeholder="Rua/Parque logístico" list="dlLocations" /></label>
        <label style="grid-column:1 / -1;">Zonas (separadas por vírgula)
          <input id="whZones" type="text" placeholder="recebimento, armazenagem, expedicao" list="dlZones" />
        </label>
      </div>
      <div style="display:flex; gap:0.5rem; align-items:center; margin-top:0.75rem;">
        <button type="submit" id="whSave" class="btn">Salvar</button>
        <span id="whFeedback" class="muted" aria-live="polite"></span>
        <span id="whIdHint" class="muted" style="margin-left:auto;"></span>
      </div>
      <datalist id="dlRegions"></datalist>
      <datalist id="dlLocations"></datalist>
      <datalist id="dlZones"></datalist>
    </div>
  </form>
  <form method="dialog" hidden></form>
  
</dialog>

<dialog id="confirmDeleteModal" style="width: min(520px, 95vw);">
  <form method="dialog">
    <div style="display:flex; align-items:center; justify-content:space-between;">
      <strong>Excluir armazém</strong>
      <div style="display:flex; gap:0.25rem;">
        <button type="button" class="btn btn-sm" data-win="min" data-dlg="confirmDeleteModal" title="Minimizar">_</button>
        <button type="button" class="btn btn-sm" data-win="max" data-dlg="confirmDeleteModal" title="Maximizar">[]</button>
        <button type="button" class="btn btn-sm" data-win="close" data-dlg="confirmDeleteModal" title="Fechar">×</button>
        <button type="button" id="delClose" class="btn btn-sm">Fechar</button>
      </div>
    </div>
    <div class="modal-body">
      <p id="delText" style="margin-top:0.5rem;">Confirmar exclusão?</p>
      <div style="display:flex; gap:0.5rem; margin-top:0.5rem;">
        <button type="button" id="delConfirm" class="btn" style="background:#b00020; color:#fff;">Excluir</button>
        <button type="button" id="delCancel" class="btn">Cancelar</button>
        <span id="delFeedback" class="muted" style="margin-left:auto;" aria-live="polite"></span>
      </div>
    </div>
  </form>
</dialog>

<dialog id="movementModal" style="width: min(700px, 95vw);">
  <form method="dialog">
    <div style="display:flex; align-items:center; justify-content:space-between;">
      <strong>Nova Transferência</strong>
      <div style="display:flex; gap:0.25rem;">
        <button type="button" class="btn btn-sm" data-win="min" data-dlg="movementModal" title="Minimizar">_</button>
        <button type="button" class="btn btn-sm" data-win="max" data-dlg="movementModal" title="Maximizar">[]</button>
        <button type="button" class="btn btn-sm" data-win="close" data-dlg="movementModal" title="Fechar">×</button>
        <button type="button" id="movClose" class="btn btn-sm">Fechar (Esc)</button>
      </div>
    </div>
    <div class="modal-body">
      <div style="display:grid; grid-template-columns:1fr 1fr; gap:0.5rem; margin-top:0.5rem;">
        <label>Produto ID <input id="movProductId" type="number" min="1" placeholder="Ex.: 123" list="dlMovProducts" /></label>
        <datalist id="dlMovProducts"></datalist>
        <label>Quantidade <input id="movQty" type="number" step="0.0001" min="0.0001" placeholder="Ex.: 10" /></label>
        <label>Bin Origem
          <select id="movFrom"></select>
        </label>
        <label>Bin Destino
          <select id="movTo"></select>
        </label>
      </div>
      <div style="display:flex; gap:0.5rem; align-items:center; margin-top:0.75rem;">
        <button type="submit" id="movSave" class="btn">Transferir</button>
        <span id="movFeedback" class="muted" aria-live="polite"></span>
      </div>
    </div>
  </form>
  <form method="dialog" hidden></form>
</dialog>

<style>
  .tab-btn[aria-selected="true"]{ border-bottom:2px solid #333; font-weight:bold; }
  .badge{ display:inline-block; min-width:1.25em; padding:0 0.25em; background:#f0ad4e; color:#000; border-radius:10px; font-size:0.75em; text-align:center; }
  .muted{ color:#555; }
  .win-btn{ padding:0.25rem 0.5rem; }
  dialog.modal-max{ width: 95vw !important; height: 90vh; }
  dialog.modal-min .modal-body{ display:none; }
</style>

<script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script>
<script>
// Permissions & audit hooks (stubs)
const currentUserRoles = window.currentUserRoles || ['wms_user'];
function can(perm){
  const map = {
    'wms.create': ['admin','wms_manager'],
    'wms.edit': ['admin','wms_manager'],
    'wms.delete': ['admin'],
    'wms.inventory.start': ['admin','wms_manager','wms_user']
  };
  const needed = map[perm]||[]; return needed.length===0 || needed.some(r=>currentUserRoles.includes(r));
}
async function auditLog(action, payload){
  try{ await fetch('/api/audit', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ module:'wms', action, payload, ts: Date.now() }) }); }catch(e){ /* noop */ }
}

// Generic API
async function apiRequest(url, opts = {}) {
  const res = await fetch(url, { ...opts, headers: { 'Content-Type': 'application/json' } });
  return res;
}

// Toast simples
function showToast(message){
  try{
    const el = document.createElement('div');
    el.textContent = message;
    el.style.position = 'fixed'; el.style.bottom = '1rem'; el.style.right = '1rem';
    el.style.background = '#333'; el.style.color = '#fff'; el.style.padding = '0.5rem 0.75rem';
    el.style.borderRadius = '4px'; el.style.boxShadow = '0 2px 8px rgba(0,0,0,0.25)'; el.style.zIndex = '9999';
    document.body.appendChild(el);
    setTimeout(()=>{ el.remove(); }, 2200);
  }catch(e){ /* noop */ }
}

// Tabs handling
const tabs = ['warehouses','inventory','movements','reports','settings'];
function showTab(name){
  tabs.forEach(t=>{
    document.getElementById('tab-'+t).hidden = (t!==name);
    document.getElementById('tabBtn-'+t).setAttribute('aria-selected', String(t===name));
  });
}
tabs.forEach(t=>{
  document.getElementById('tabBtn-'+t).addEventListener('click',()=>showTab(t));
});

// Warehouses list
let currentRows = [];
let whFilteredRows = [];
let whPage = 1;
let whPageSize = 10;
function renderRows(rows) {
  const tbody = document.getElementById('rows');
  tbody.innerHTML = '';
  for (const r of rows) {
    const tr = document.createElement('tr');
    const zones = Array.isArray(r.zones)? r.zones.join(', ') : (r.zones || '-');
    tr.innerHTML = `
      <td>${r.id}</td>
      <td>${r.name ?? '-'}</td>
      <td>${r.location ?? '-'}</td>
      <td>${zones}</td>
      <td style="text-align:right;">
        <button class="btn btn-sm" data-id="${r.id}" data-action="edit" ${can('wms.edit')?'':'disabled'}>Editar</button>
        <button class="btn btn-sm" data-id="${r.id}" data-action="delete" ${can('wms.delete')?'':'disabled'}>Excluir</button>
      </td>`;
    tbody.appendChild(tr);
  }
}
function renderWarehousePage(){
  const total = whFilteredRows.length;
  const pages = Math.max(1, Math.ceil(total / whPageSize));
  if(whPage>pages) whPage = pages;
  const start = (whPage-1)*whPageSize;
  const slice = whFilteredRows.slice(start, start+whPageSize);
  renderRows(slice);
  document.getElementById('whPageInfo').textContent = `Página ${whPage} de ${pages} — ${slice.length} de ${total} itens`;
}
async function loadWarehouses() {
  const fb = document.getElementById('feedback'); fb.textContent = 'Carregando…';
  try {
    const res = await apiRequest('/api/wms/warehouses');
    if (!res.ok) throw new Error('Falha ao carregar');
    const json = await res.json();
    currentRows = json.data || [];
    whFilteredRows = currentRows.slice();
    renderWarehousePage();
    fb.textContent = `${currentRows.length} armazéns carregados.`;
    document.getElementById('badge-warehouses').hidden = !(json.pending_count>0);
    if(json.pending_count>0){ document.getElementById('badge-warehouses').textContent = json.pending_count; }
    // Autocomplete: nomes, localizações e zonas
    const names = currentRows.map(r=>r.name).filter(Boolean);
    const locs = currentRows.map(r=>r.location).filter(Boolean);
    const zones = currentRows.flatMap(r=> Array.isArray(r.zones)? r.zones : (r.zones? String(r.zones).split(',').map(s=>s.trim()) : []) ).filter(Boolean);
    setDatalistOptions('dlWarehouseQ', [...names, ...locs, ...zones]);
    setDatalistOptions('dlLocations', locs);
    setDatalistOptions('dlZones', zones);
  } catch (e) { fb.textContent = 'Erro: ' + e.message; }
}

// Filters
function applyWarehouseFilters(){
  const q = document.getElementById('q').value.trim().toLowerCase();
  const zone = document.getElementById('filterZone').value;
  const region = document.getElementById('filterRegion').value;
  const status = document.getElementById('filterStatus').value;
  whFilteredRows = currentRows.filter(r=>{
    const text = [r.name, r.location, Array.isArray(r.zones)?r.zones.join(','):r.zones].filter(Boolean).join(' ').toLowerCase();
    const byText = !q || text.includes(q);
    const byZone = !zone || (Array.isArray(r.zones)? r.zones.includes(zone) : String(r.zones||'').toLowerCase().includes(zone.toLowerCase()));
    const byRegion = !region || String(r.region||'') === region;
    const byStatus = !status || String(r.status||'') === status;
    return byText && byZone && byRegion && byStatus;
  });
  whPage = 1;
  renderWarehousePage();
}
document.getElementById('q').addEventListener('input', applyWarehouseFilters);
document.getElementById('filterZone').addEventListener('change', applyWarehouseFilters);
document.getElementById('filterRegion').addEventListener('change', applyWarehouseFilters);
document.getElementById('filterStatus').addEventListener('change', applyWarehouseFilters);
{ const el = document.getElementById('whPageSize'); if(el){ el.addEventListener('change',()=>{ whPageSize = parseInt(el.value,10)||10; whPage=1; renderWarehousePage(); }); } }
{ const el = document.getElementById('whPrev'); if(el){ el.addEventListener('click',()=>{ if(whPage>1){ whPage--; renderWarehousePage(); } }); } }
{ const el = document.getElementById('whNext'); if(el){ el.addEventListener('click',()=>{ const pages = Math.max(1, Math.ceil(whFilteredRows.length/whPageSize)); if(whPage<pages){ whPage++; renderWarehousePage(); } }); } }

// Carregar filtros dinâmicos de armazéns
async function loadWarehouseFilters(){
  try{
    const res = await apiRequest('/api/wms/warehouses/filters'); if(!res.ok) throw new Error('Falha ao carregar filtros');
    const json = await res.json();
    const zones = json.zones || []; const regions = json.regions || []; const statuses = json.statuses || [];
    const zoneEl = document.getElementById('filterZone');
    zoneEl.innerHTML = '<option value="">Todas as zonas</option>' + zones.map(z=>`<option value="${z}">${z}</option>`).join('');
    const regEl = document.getElementById('filterRegion');
    regEl.innerHTML = '<option value="">Todas as regiões</option>' + regions.map(r=>`<option value="${r}">${r}</option>`).join('');
    const stEl = document.getElementById('filterStatus');
    stEl.innerHTML = '<option value="">Todos os status</option>' + statuses.map(s=>`<option value="${s}">${s==='active'?'Ativo':'Inativo'}</option>`).join('');
    // Autocomplete para modais e busca
    setDatalistOptions('dlRegions', regions);
    setDatalistOptions('dlZones', zones);
  }catch(e){ console.warn('Erro carregando filtros WMS:', e); }
}

// Create/Edit/Delete via modais
let whEditingId = null; let delId = null;
const whDlg = document.getElementById('warehouseModal');
const whFields = {
  name: document.getElementById('whName'),
  region: document.getElementById('whRegion'),
  status: document.getElementById('whStatus'),
  location: document.getElementById('whLocation'),
  zones: document.getElementById('whZones'),
  fb: document.getElementById('whFeedback'),
  title: document.getElementById('whModalTitle'),
  idhint: document.getElementById('whIdHint')
};
function openWhModal(mode, row){
  whFields.fb.textContent = '';
  if(mode==='create'){
    whEditingId = null;
    whFields.title.textContent = 'Novo Armazém';
    whFields.idhint.textContent = '';
    whFields.name.value=''; whFields.region.value=''; whFields.status.value='active'; whFields.location.value=''; whFields.zones.value='';
  } else {
    whEditingId = row?.id ?? null;
    whFields.title.textContent = 'Editar Armazém';
    whFields.idhint.textContent = whEditingId? ('ID: '+ whEditingId) : '';
    whFields.name.value = row?.name || '';
    whFields.region.value = row?.region || '';
    whFields.status.value = row?.status || 'active';
    whFields.location.value = row?.location || '';
    const z = Array.isArray(row?.zones)? row.zones.join(', ') : (row?.zones || '');
    whFields.zones.value = z;
  }
  whDlg.showModal();
}
document.getElementById('whClose').addEventListener('click',()=>whDlg.close());
document.getElementById('btnNew').addEventListener('click', ()=>{
  if(!can('wms.create')){ alert('Sem permissão para criar armazéns'); return; }
  openWhModal('create');
});
whDlg.addEventListener('submit', async (ev)=>{
  ev.preventDefault();
  if(!whFields.name.value || whFields.name.value.trim().length<3){ whFields.fb.textContent='Nome inválido (mínimo 3 caracteres)'; return; }
  const zonesArr = (whFields.zones.value||'').split(',').map(s=>s.trim()).filter(Boolean);
  const payload = {
    name: whFields.name.value.trim(),
    region: whFields.region.value.trim(),
    status: whFields.status.value,
    location: whFields.location.value.trim(),
    zones: zonesArr
  };
  whFields.fb.textContent = 'Salvando…';
  try{
    let res;
    if(whEditingId){
      if(!can('wms.edit')){ whFields.fb.textContent='Sem permissão para editar'; return; }
      res = await apiRequest(`/api/wms/warehouses/${whEditingId}`, { method:'PUT', body: JSON.stringify(payload) });
    } else {
      if(!can('wms.create')){ whFields.fb.textContent='Sem permissão para criar'; return; }
      res = await apiRequest('/api/wms/warehouses', { method:'POST', body: JSON.stringify(payload) });
    }
    if(!res.ok){ const txt = await res.text(); whFields.fb.textContent = 'Falha: '+ (txt||'erro'); return; }
    whFields.fb.textContent = 'Salvo com sucesso';
    auditLog(whEditingId? 'warehouse.update':'warehouse.create', { id: whEditingId, ...payload });
    setTimeout(()=>{ whDlg.close(); loadWarehouses(); }, 400);
  }catch(e){ whFields.fb.textContent = 'Erro: '+ e.message; }
});

const delDlg = document.getElementById('confirmDeleteModal');
document.getElementById('delClose').addEventListener('click',()=>delDlg.close());
document.getElementById('delCancel').addEventListener('click',()=>delDlg.close());
document.getElementById('delConfirm').addEventListener('click', async ()=>{
  const fb = document.getElementById('delFeedback');
  if(!can('wms.delete')){ fb.textContent='Sem permissão'; return; }
  if(!delId){ fb.textContent='ID inválido'; return; }
  fb.textContent='Excluindo…';
  try{
    const res = await apiRequest(`/api/wms/warehouses/${delId}`, { method:'DELETE' });
    if(!res.ok){ fb.textContent='Falha ao excluir'; return; }
    auditLog('warehouse.delete',{ id: delId });
    fb.textContent='Excluído'; setTimeout(()=>{ delDlg.close(); loadWarehouses(); }, 300);
  }catch(e){ fb.textContent='Erro: '+e.message; }
});

document.addEventListener('click', async (ev) => {
  const btn = ev.target.closest('button'); if (!btn) return;
  const act = btn.getAttribute('data-action'); const id = btn.getAttribute('data-id');
  if (act === 'delete' && id) {
    if (!can('wms.delete')){ alert('Sem permissão'); return; }
    const row = currentRows.find(r => String(r.id) === String(id));
    delId = id;
    document.getElementById('delText').textContent = `Excluir armazém #${id}${row && row.name? ' — '+row.name : ''}?`;
    document.getElementById('delFeedback').textContent = '';
    delDlg.showModal();
  } else if (act === 'edit' && id) {
    if (!can('wms.edit')){ alert('Sem permissão'); return; }
    const row = currentRows.find(r => String(r.id) === String(id));
    openWhModal('edit', row);
  }
});

// Export helpers
function download(filename, mime, content){
  const blob = new Blob([content], {type:mime}); const url = URL.createObjectURL(blob);
  const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); URL.revokeObjectURL(url);
}
document.getElementById('btnExportCsv').addEventListener('click', ()=>{
  const rows = [['ID','Nome','Localização','Zonas'], ...currentRows.map(r=>[r.id,r.name||'',r.location||'',Array.isArray(r.zones)?r.zones.join('|'):(r.zones||'')])];
  const csv = rows.map(r=>r.map(v=>`"${String(v).replace(/"/g,'""')}"`).join(',')).join('\n'); download('armazens.csv','text/csv',csv);
});
document.getElementById('btnExportXls').addEventListener('click', ()=>{
  const rows = [['ID','Nome','Localização','Zonas'], ...currentRows.map(r=>[r.id,r.name||'',r.location||'',Array.isArray(r.zones)?r.zones.join('|'):(r.zones||'')])];
  const tsv = rows.map(r=>r.join('\t')).join('\n'); download('armazens.xls','application/vnd.ms-excel',tsv);
});
document.getElementById('btnPrint').addEventListener('click', ()=>{ window.print(); });

// Inventory tab & modal
let invRows = [];
let invFilteredRows = [];
let invPage = 1;
let invPageSize = 10;
async function loadInventories(){
  const fb = document.getElementById('invFeedback'); fb.textContent = 'Carregando inventários…';
  try{
    const res = await apiRequest('/api/wms/inventory'); if(!res.ok) throw new Error('Falha');
    const json = await res.json(); invRows = json.data||[]; invFilteredRows = invRows.slice(); renderInvPage(); fb.textContent = `${invRows.length} inventários.`;
    document.getElementById('badge-inventory').hidden = !(json.pending_count>0);
    if(json.pending_count>0){ document.getElementById('badge-inventory').textContent = json.pending_count; }
    // Autocomplete: tipos e status
    const types = invRows.map(r=>r.type).filter(Boolean);
    const stats = invRows.map(r=>r.status).filter(Boolean);
    setDatalistOptions('dlInvQuery', [...types, ...stats]);
  }catch(e){ fb.textContent = 'Erro: '+e.message; }
}
function renderInvRows(rows){
  const tbody = document.getElementById('invRows'); tbody.innerHTML = '';
  rows.forEach(r=>{
    const tr = document.createElement('tr');
    tr.innerHTML = `<td>${r.id}</td><td>${r.type}</td><td>${r.status}</td><td>${r.updated_at ? formatDateTimeBR(r.updated_at) : '-'} </td>
    <td style='text-align:right;'><button class='btn btn-sm' data-act='inv-open' data-id='${r.id}'>Abrir</button></td>`;
    tbody.appendChild(tr);
  });
}
function renderInvPage(){
  const total = invFilteredRows.length;
  const pages = Math.max(1, Math.ceil(total / invPageSize));
  if(invPage>pages) invPage = pages;
  const start = (invPage-1)*invPageSize;
  const slice = invFilteredRows.slice(start, start+invPageSize);
  renderInvRows(slice);
  document.getElementById('invPageInfo').textContent = `Página ${invPage} de ${pages} — ${slice.length} de ${total} itens`;
}
document.getElementById('invQuery').addEventListener('input',()=>{
  const q = document.getElementById('invQuery').value.trim().toLowerCase();
  invFilteredRows = invRows.filter(r=>`${r.type} ${r.status}`.toLowerCase().includes(q));
  invPage = 1; renderInvPage();
});
document.getElementById('btnStartInventory').addEventListener('click', async()=>{
  if(!can('wms.inventory.start')){ alert('Sem permissão'); return; }
  const type = document.getElementById('invType').value;
  const entries = parseInt(document.getElementById('invEntries').value||'0',10);
  if(!entries || entries<=0){ alert('Informe entries_count (>0)'); return; }
  const res = await apiRequest('/api/wms/inventory/start',{method:'POST', body: JSON.stringify({ type, entries_count: entries })});
  if(res.ok){ auditLog('inventory.start',{type, entries_count: entries}); await loadInventories(); } else { alert('Falha ao iniciar inventário'); }
});

// Movements
let movRows = [];
let movFilteredRows = [];
let movPage = 1;
let movPageSize = 10;
async function loadMovements(){
  const fb = document.getElementById('movFeedback'); fb.textContent = 'Carregando movimentações…';
  try{
    const res = await apiRequest('/api/wms/movements'); if(!res.ok) throw new Error('Falha');
    const json = await res.json(); movRows = json.data||[]; movFilteredRows = movRows.slice(); renderMovPage(); fb.textContent = `${movRows.length} registros.`;
    document.getElementById('badge-movements').hidden = !(json.pending_count>0);
    if(json.pending_count>0){ document.getElementById('badge-movements').textContent = json.pending_count; }
    // Autocomplete: tipos, produto, operador, origem, destino
    const types = movRows.map(r=>r.type).filter(Boolean);
    const prods = movRows.map(r=>r.product).filter(Boolean);
    const ops = movRows.map(r=>r.operator).filter(Boolean);
    const froms = movRows.map(r=>r.from).filter(Boolean);
    const tos = movRows.map(r=>r.to).filter(Boolean);
    setDatalistOptions('dlMovQuery', [...types, ...prods, ...ops, ...froms, ...tos]);
    setDatalistOptions('dlMovProducts', prods);
  }catch(e){ fb.textContent = 'Erro: '+e.message; }
}
function renderMovRows(rows){
  const tbody = document.getElementById('movRows'); tbody.innerHTML = '';
  rows.forEach(r=>{
    const tr = document.createElement('tr');
    tr.innerHTML = `<td>${r.id}</td><td>${r.type}</td><td>${r.product}</td><td>${r.quantity}</td><td>${r.from||'-'}</td><td>${r.to||'-'}</td><td>${r.operator||'-'}</td>
    <td style='text-align:right;'><button class='btn btn-sm' data-act='mov-open' data-id='${r.id}'>Detalhes</button></td>`;
    tbody.appendChild(tr);
  });
}
function renderMovPage(){
  const total = movFilteredRows.length;
  const pages = Math.max(1, Math.ceil(total / movPageSize));
  if(movPage>pages) movPage = pages;
  const start = (movPage-1)*movPageSize;
  const slice = movFilteredRows.slice(start, start+movPageSize);
  renderMovRows(slice);
  document.getElementById('movPageInfo').textContent = `Página ${movPage} de ${pages} — ${slice.length} de ${total} itens`;
}
document.getElementById('movQuery').addEventListener('input',()=>{
  const q = document.getElementById('movQuery').value.trim().toLowerCase();
  movFilteredRows = movRows.filter(r=>`${r.type} ${r.product} ${r.operator} ${r.from} ${r.to}`.toLowerCase().includes(q));
  movPage = 1; renderMovPage();
});
document.getElementById('movType').addEventListener('change',()=>{
  const type = document.getElementById('movType').value; movFilteredRows = movRows.filter(r=>!type || r.type===type); movPage=1; renderMovPage();
});
{ const el = document.getElementById('movPageSize'); if(el){ el.addEventListener('change',()=>{ movPageSize = parseInt(el.value,10)||10; movPage=1; renderMovPage(); }); } }
{ const el = document.getElementById('movPrev'); if(el){ el.addEventListener('click',()=>{ if(movPage>1){ movPage--; renderMovPage(); } }); } }
{ const el = document.getElementById('movNext'); if(el){ el.addEventListener('click',()=>{ const pages = Math.max(1, Math.ceil(movFilteredRows.length/movPageSize)); if(movPage<pages){ movPage++; renderMovPage(); } }); } }
// Nova movimentação via modal (transferência)
const movDlg = document.getElementById('movementModal');
const movFields = {
  pid: document.getElementById('movProductId'),
  qty: document.getElementById('movQty'),
  from: document.getElementById('movFrom'),
  to: document.getElementById('movTo'),
  fb: document.getElementById('movFeedback')
};
async function loadBinsForMov(){
  try{ const res = await apiRequest('/api/wms/bins'); const json = await res.json(); const bins = json.data||[];
    const opts = bins.map(b=>`<option value="${b.id}">${b.code} (WH ${b.warehouse_id})</option>`).join('');
    movFields.from.innerHTML = `<option value="">Selecione…</option>`+opts;
    movFields.to.innerHTML = `<option value="">Selecione…</option>`+opts;
  }catch(e){ movFields.fb.textContent='Erro carregando bins: '+e.message; }
}
document.getElementById('movClose').addEventListener('click',()=>movDlg.close());
document.getElementById('btnNewMovement').addEventListener('click', async()=>{ movFields.fb.textContent=''; await loadBinsForMov(); movDlg.showModal(); });
movDlg.addEventListener('submit', async (ev)=>{
  ev.preventDefault(); movFields.fb.textContent='Transferindo…';
  const pid = parseInt(movFields.pid.value||'0',10); const qty = parseFloat(movFields.qty.value||'0');
  const from = parseInt(movFields.from.value||'0',10); const to = parseInt(movFields.to.value||'0',10);
  if(!(pid>0 && qty>0 && from>0 && to>0)){ movFields.fb.textContent='Preencha todos os campos'; return; }
  try{
    const res = await apiRequest('/api/wms/movements/transfer',{ method:'POST', body: JSON.stringify({ product_id: pid, quantity: qty, from_bin_id: from, to_bin_id: to }) });
    if(!res.ok){ const txt = await res.text(); movFields.fb.textContent = 'Falha: '+(txt||'erro'); return; }
    auditLog('movement.transfer',{ product_id: pid, quantity: qty, from_bin_id: from, to_bin_id: to });
    movFields.fb.textContent='Transferido'; setTimeout(()=>{ movDlg.close(); loadMovements(); }, 400);
  }catch(e){ movFields.fb.textContent='Erro: '+e.message; }
});

// Inventory modal integration
document.getElementById('btnInventoryModal').addEventListener('click', async()=>{
  const dlg = document.getElementById('inventoryModal'); dlg.showModal(); document.getElementById('invModalFeedback').textContent='Carregando…';
  try{ const res = await apiRequest('/api/wms/inventory'); const json = await res.json(); const rows = json.data||[]; const tbody = document.getElementById('invModalRows'); tbody.innerHTML='';
    rows.forEach(r=>{ const tr = document.createElement('tr'); tr.innerHTML = `<td>${r.id}</td><td>${r.type}</td><td>${r.status}</td><td>${r.updated_at ? formatDateTimeBR(r.updated_at) : '-'} </td>
      <td style='text-align:right;'><button class='btn btn-sm' data-act='inv-continue' data-id='${r.id}'>Continuar</button></td>`; tbody.appendChild(tr); });
    document.getElementById('invModalFeedback').textContent = `${rows.length} inventários.`;
  }catch(e){ document.getElementById('invModalFeedback').textContent='Erro: '+e.message; }
});
document.getElementById('invModalStart').addEventListener('click', async()=>{
  if(!can('wms.inventory.start')){ alert('Sem permissão'); return; }
  const q = prompt('Quantidade de entradas (entries_count)?'); const entries = parseInt(q||'0',10);
  const type = 'geral';
  if(!entries || entries<=0){ alert('Informe entries_count (>0)'); return; }
  const res = await apiRequest('/api/wms/inventory/start',{method:'POST', body: JSON.stringify({ type, entries_count: entries })});
  if(res.ok){ auditLog('inventory.start',{type, entries_count: entries}); await loadInventories(); document.getElementById('inventoryModal').close(); } else { alert('Falha ao iniciar inventário'); }
});
document.getElementById('invClose').addEventListener('click',()=>{ document.getElementById('inventoryModal').close(); });

// Reports actions
document.querySelectorAll('[data-report]').forEach(btn=>{
  btn.addEventListener('click', async()=>{
    const type = btn.getAttribute('data-report');
    await auditLog('report.generate',{type});
    // Geração local de relatórios (CSV) até que o backend esteja disponível
    if(type==='movements'){
      const rows = [['ID','Tipo','Produto','Qtd','Origem','Destino','Operador'], ...movFilteredRows.map(r=>[r.id,r.type||'',r.product||'',r.quantity||'',r.from||'',r.to||'',r.operator||''])];
      const csv = rows.map(r=>r.map(v=>`"${String(v).replace(/"/g,'""')}"`).join(',')).join('\n');
      download('relatorio_movimentacoes.csv','text/csv',csv);
      showToast('Relatório de Movimentações gerado');
    } else if(type==='inventory'){
      const rows = [['ID','Tipo','Status','Atualizado'], ...invFilteredRows.map(r=>[r.id,r.type||'',r.status||'', r.updated_at? formatDateTimeBR(r.updated_at):'' ])];
      const csv = rows.map(r=>r.map(v=>`"${String(v).replace(/"/g,'""')}"`).join(',')).join('\n');
      download('relatorio_inventario.csv','text/csv',csv);
      showToast('Relatório de Inventário gerado');
    } else if(type==='receiving'){
      const recs = movFilteredRows.filter(r=>r.type==='entrada');
      const rows = [['ID','Produto','Qtd','Origem','Operador','Data'], ...recs.map(r=>[r.id,r.product||'',r.quantity||'',r.from||'',r.operator||'', r.updated_at? formatDateTimeBR(r.updated_at):'' ])];
      const csv = rows.map(r=>r.map(v=>`"${String(v).replace(/"/g,'""')}"`).join(',')).join('\n');
      download('relatorio_recebimento.csv','text/csv',csv);
      showToast('Relatório de Recebimento gerado');
    } else if(type==='shipping'){
      const ships = movFilteredRows.filter(r=>r.type==='saida');
      const rows = [['ID','Produto','Qtd','Destino','Operador','Data'], ...ships.map(r=>[r.id,r.product||'',r.quantity||'',r.to||'',r.operator||'', r.updated_at? formatDateTimeBR(r.updated_at):'' ])];
      const csv = rows.map(r=>r.map(v=>`"${String(v).replace(/"/g,'""')}"`).join(',')).join('\n');
      download('relatorio_expedicao.csv','text/csv',csv);
      showToast('Relatório de Expedição gerado');
    } else {
      showToast('Relatório não suportado');
    }
  });
});
document.getElementById('btnRefreshKPIs').addEventListener('click', async()=>{
  const ul = document.getElementById('kpiList'); ul.insertAdjacentHTML('beforeend', `<li>Atualizado em ${formatDateTimeBR(new Date())}</li>`);
  // Adicionar ao histórico paginado
  kpiHistory.push({ ts: new Date(), desc: 'KPIs atualizados' });
  renderRepPage();
});

// Settings
document.getElementById('btnSaveCfg').addEventListener('click', async()=>{
  const cfg = {
    erp_purchases: document.getElementById('cfgErpPurch').value,
    erp_sales: document.getElementById('cfgErpSales').value,
    erp_fiscal: document.getElementById('cfgErpFiscal').value,
    api_key: document.getElementById('cfgApiKey').value
  };
  const okUrl = (u)=> !u || /^https?:\/\//.test(u);
  if(!okUrl(cfg.erp_purchases)||!okUrl(cfg.erp_sales)||!okUrl(cfg.erp_fiscal)){ document.getElementById('cfgFeedback').textContent='URLs inválidas'; return; }
  try{ const res = await apiRequest('/api/wms/settings',{method:'PUT', body: JSON.stringify(cfg)}); document.getElementById('cfgFeedback').textContent = res.ok? 'Configurações salvas' : 'Falha ao salvar';
    if(res.ok) auditLog('settings.update',cfg);
  }catch(e){ document.getElementById('cfgFeedback').textContent='Erro: '+e.message; }
});

// Estoque negativo (Configurações)
async function loadNegStockSettings(){
  const fb = document.getElementById('negCfgFeedback'); fb.textContent = 'Carregando…';
  try{
    const res = await apiRequest('/api/estoque/configuracoes'); if(!res.ok) throw new Error('Falha ao carregar');
    const json = await res.json(); const data = json.data||{};
    const enabled = !!data.permitir_estoque_negativo;
    document.getElementById('chkNegStock').checked = enabled;
    document.getElementById('negModeBadgeWms').style.display = enabled ? 'inline-block' : 'none';
    document.getElementById('negUpdatedAt').textContent = data.updated_at ? ('Atualizado: '+ formatDateTimeBR(data.updated_at)) : '';
    fb.textContent = '';
  }catch(e){ fb.textContent = 'Erro: '+e.message; }
}
document.getElementById('btnSaveStockCfg').addEventListener('click', async()=>{
  const enabled = document.getElementById('chkNegStock').checked; const fb = document.getElementById('negCfgFeedback');
  fb.textContent = 'Salvando…';
  try{
    const res = await apiRequest('/api/estoque/configuracoes', { method: 'POST', body: JSON.stringify({ permitir_estoque_negativo: enabled }) });
    if(!res.ok){ fb.textContent = 'Falha ao salvar'; return; }
    showToast(enabled ? 'Modo estoque negativo ATIVADO' : 'Modo estoque negativo DESATIVADO');
    await loadNegStockSettings(); fb.textContent = 'Configuração salva';
  }catch(e){ fb.textContent = 'Erro: '+e.message; }
});

// Keyboard shortcuts & help
document.addEventListener('keydown',(ev)=>{
  if(ev.altKey){
    if(ev.key==='1'){ showTab('warehouses'); }
    else if(ev.key==='2'){ showTab('inventory'); }
    else if(ev.key==='3'){ showTab('movements'); }
    else if(ev.key==='4'){ showTab('reports'); }
    else if(ev.key==='5'){ showTab('settings'); }
    else if(ev.key.toLowerCase()==='n'){ document.getElementById('btnNew').click(); }
    else if(ev.key.toLowerCase()==='i'){ document.getElementById('btnInventoryModal').click(); }
  }
  if(ev.key.toLowerCase()==='h'){ alert('Atalhos:\nAlt+1..5: Alternar abas\nAlt+N: Novo armazém\nAlt+I: Inventários'); }
});
document.getElementById('kbdHelp').addEventListener('click',()=>{
  alert('Atalhos:\nAlt+1..5: Alternar abas\nAlt+N: Novo armazém\nAlt+I: Inventários');
});

// Initial load
document.getElementById('permInfo').textContent = 'Permissões: '+ currentUserRoles.join(', ');
showTab('warehouses');
setTimeout(()=>{ loadWarehouseFilters(); loadWarehouses(); loadInventories(); loadMovements(); loadNegStockSettings(); }, 50);
</script>
<script>
// Helpers: datalist e controles de janela
function setDatalistOptions(id, items){
  const dl = document.getElementById(id); if(!dl) return;
  const uniq = Array.from(new Set(items.filter(v=>v && String(v).length>0)));
  dl.innerHTML = uniq.map(v=>`<option value="${String(v).replace(/"/g,'&quot;')}">`).join('');
}
function formatDateBR(d){
  const dt = (d instanceof Date) ? d : new Date(d);
  if(isNaN(dt)) return '-';
  const dd = String(dt.getDate()).padStart(2,'0');
  const mm = String(dt.getMonth()+1).padStart(2,'0');
  const yyyy = dt.getFullYear();
  return `${dd}-${mm}-${yyyy}`;
}
function formatDateTimeBR(d){
  const dt = (d instanceof Date) ? d : new Date(d);
  if(isNaN(dt)) return '-';
  const hh = String(dt.getHours()).padStart(2,'0');
  const mi = String(dt.getMinutes()).padStart(2,'0');
  return `${formatDateBR(dt)} ${hh}:${mi}`;
}
function toggleDialogState(dlg, mode){
  if(mode==='min'){ dlg.classList.add('modal-min'); dlg.classList.remove('modal-max'); }
  else if(mode==='max'){ dlg.classList.add('modal-max'); dlg.classList.remove('modal-min'); }
  else if(mode==='close'){ dlg.close(); }
}
document.addEventListener('click',(ev)=>{
  const btn = ev.target.closest('[data-win]'); if(!btn) return;
  const mode = btn.getAttribute('data-win'); const dlgId = btn.getAttribute('data-dlg'); const dlg = document.getElementById(dlgId);
  if(dlg) toggleDialogState(dlg, mode);
});
// Configuração local do Coletor Mobile
function loadMobileCfg(){
  try{
    const raw = localStorage.getItem('wmsMobileCfg');
    const cfg = raw? JSON.parse(raw) : {};
    document.getElementById('mobileUrl').value = cfg.url||'';
    document.getElementById('mobileDeviceKey').value = cfg.deviceKey||'';
    document.getElementById('mobileUpdatedAt').textContent = cfg.updatedAt? ('Atualizado: '+ formatDateTimeBR(cfg.updatedAt)) : '';
  }catch(e){ /* noop */ }
}
async function testMobileConnection(){
  const url = (document.getElementById('mobileUrl').value||'').trim();
  const deviceKey = (document.getElementById('mobileDeviceKey').value||'').trim();
  const fb = document.getElementById('mobileCfgFeedback');
  const okUrl = (u)=> u && /^https?:\/\//.test(u);
  if(!okUrl(url)){ fb.textContent='URL inválida'; return; }
  try{
    const res = await fetch(`${url.replace(/\/$/,'')}/ping?device_key=${encodeURIComponent(deviceKey)}`, { method: 'GET' });
    if(res.ok){ fb.textContent = 'Conexão OK'; showToast('Conexão com coletor OK'); }
    else { fb.textContent = 'Falha na conexão'; }
  }catch(e){ fb.textContent = 'Erro: '+ e.message; }
}
function generateMobileQR(){
  const url = (document.getElementById('mobileUrl').value||'').trim();
  const deviceKey = (document.getElementById('mobileDeviceKey').value||'').trim();
  const payload = JSON.stringify({ url, deviceKey });
  const img = document.getElementById('mobilePairQR'); if(!img) return;
  if (window.QRCode && QRCode.toDataURL) {
    QRCode.toDataURL(payload, { width: 160, errorCorrectionLevel: 'M' })
      .then(dataUrl => { img.src = dataUrl; showToast('QR de pareamento gerado'); })
      .catch(()=>{
        const data = encodeURIComponent(payload);
        img.src = `https://api.qrserver.com/v1/create-qr-code/?size=160x160&data=${data}`;
        showToast('QR gerado (fallback)');
      });
  } else {
    const data = encodeURIComponent(payload);
    img.src = `https://api.qrserver.com/v1/create-qr-code/?size=160x160&data=${data}`;
    showToast('QR gerado (fallback)');
  }
}
document.getElementById('btnSaveMobileCfg').addEventListener('click',()=>{
  const url = (document.getElementById('mobileUrl').value||'').trim();
  const deviceKey = (document.getElementById('mobileDeviceKey').value||'').trim();
  const fb = document.getElementById('mobileCfgFeedback');
  const okUrl = (u)=> !u || /^https?:\/\//.test(u);
  if(!okUrl(url)){ fb.textContent='URL inválida'; return; }
  const cfg = { url, deviceKey, updatedAt: new Date() };
  try{
    localStorage.setItem('wmsMobileCfg', JSON.stringify(cfg));
    fb.textContent = 'Configuração salva localmente';
    document.getElementById('mobileUpdatedAt').textContent = 'Atualizado: '+ formatDateTimeBR(cfg.updatedAt);
  }catch(e){ fb.textContent = 'Erro ao salvar: '+ e.message; }
});
{ const el = document.getElementById('btnTestMobile'); if(el){ el.addEventListener('click', testMobileConnection); } }
{ const el = document.getElementById('btnGenMobileQR'); if(el){ el.addEventListener('click', generateMobileQR); } }
{ const el = document.getElementById('btnCopyPairing'); if(el){ el.addEventListener('click',()=>{
  const url = (document.getElementById('mobileUrl').value||'').trim();
  const deviceKey = (document.getElementById('mobileDeviceKey').value||'').trim();
  const str = JSON.stringify({ url, deviceKey });
  if(navigator.clipboard){ navigator.clipboard.writeText(str).then(()=> showToast('String copiada')); } else { showToast('Clipboard indisponível'); }
}); } }
// Inicializar seção do coletor após carregar a página
document.addEventListener('DOMContentLoaded', loadMobileCfg);
// Paginação: Relatórios (Histórico KPIs)
let kpiHistory = [];
let repFilteredRows = [];
let repPage = 1;
let repPageSize = 10;
function renderRepRows(rows){
  const tbody = document.getElementById('repRows'); if(!tbody) return; tbody.innerHTML = '';
  rows.forEach(r=>{
    const tr = document.createElement('tr');
    tr.innerHTML = `<td>${formatDateTimeBR(r.ts)}</td><td>${r.desc}</td>`;
    tbody.appendChild(tr);
  });
}
function renderRepPage(){
  repFilteredRows = kpiHistory.slice();
  const total = repFilteredRows.length;
  const pages = Math.max(1, Math.ceil(total / repPageSize));
  if(repPage>pages) repPage = pages;
  const start = (repPage-1)*repPageSize;
  const slice = repFilteredRows.slice(start, start+repPageSize);
  renderRepRows(slice);
  const info = document.getElementById('repPageInfo'); if(info) info.textContent = `Página ${repPage} de ${pages} — ${slice.length} de ${total} itens`;
}
{ const el = document.getElementById('repPageSize'); if(el){ el.addEventListener('change',()=>{ repPageSize = parseInt(el.value,10)||10; repPage=1; renderRepPage(); }); } }
{ const el = document.getElementById('repPrev'); if(el){ el.addEventListener('click',()=>{ if(repPage>1){ repPage--; renderRepPage(); } }); } }
{ const el = document.getElementById('repNext'); if(el){ el.addEventListener('click',()=>{ const pages = Math.max(1, Math.ceil((repFilteredRows||[]).length/repPageSize)); if(repPage<pages){ repPage++; renderRepPage(); } }); } }
// Paginação: Inventário (listeners)
{ const el = document.getElementById('invPageSize'); if(el){ el.addEventListener('change',()=>{ invPageSize = parseInt(el.value,10)||10; invPage=1; renderInvPage(); }); } }
{ const el = document.getElementById('invPrev'); if(el){ el.addEventListener('click',()=>{ if(invPage>1){ invPage--; renderInvPage(); } }); } }
{ const el = document.getElementById('invNext'); if(el){ el.addEventListener('click',()=>{ const pages = Math.max(1, Math.ceil(invFilteredRows.length/invPageSize)); if(invPage<pages){ invPage++; renderInvPage(); } }); } }
</script>