<?php
/**
 * Produtos / Catálogo — shell instantâneo.
 * KPIs e grid de produtos carregados via fetch após DOM pronto.
 */
?>
<div class="pbi-page-header">
    <h1 class="pbi-page-title"><i class="bi bi-grid me-2 text-accent"></i>Produtos</h1>
</div>
<?php include __DIR__ . '/_submenu.php' ?>

<!-- ── KPIs skeleton ──────────────────────────────────────────────────────── -->
<div class="pbi-kpi-grid mb-4" id="kpi-grid">
    <?php for ($i = 0; $i < 5; $i++): ?>
    <div class="pbi-kpi-card">
        <div class="pbi-kpi-label pbi-skeleton" style="width:60%;height:.8rem;border-radius:4px">&nbsp;</div>
        <div class="pbi-kpi-value pbi-skeleton mt-2" style="width:75%;height:1.6rem;border-radius:4px">&nbsp;</div>
    </div>
    <?php endfor; ?>
</div>

<div class="pbi-hint mb-3" style="margin-top:0"><strong>Catálogo</strong> = todos os produtos cadastrados. <strong>Valor Total Estoque</strong> = quanto vale tudo que você tem guardado. <strong>Estoque Baixo</strong> = itens abaixo do mínimo, que podem faltar.</div>

<!-- ── Busca + Filtros ───────────────────────────────────────────────────── -->
<div class="pbi-card mb-4 p-3">
    <div class="pbi-hint mb-2" style="margin-top:0">Busque por nome/código, ou digite o <strong>Código de barras</strong> (pode bipar com leitor). Filtre por marca, ou use <strong>Ler Código</strong> pra ler pela câmera.</div>
    <div class="d-flex gap-2 flex-wrap align-items-center">
        <input type="text" id="busca-catalogo" class="form-control form-control-sm"
               style="max-width:280px;background:#0f1117;border-color:#2d3452;color:#e2e8f0"
               placeholder="🔍 Buscar produto ou código…">
        <span class="d-inline-flex align-items-center" title="Digite ou bipe o código de barras e pressione Enter"
              style="border:1.5px solid #4ade80;border-radius:8px;background:#0f1117;overflow:hidden;max-width:240px;box-shadow:0 0 0 2px rgba(74,222,128,.12)">
            <span style="padding:.35rem .6rem;color:#4ade80;display:flex;align-items:center;border-right:1px solid #2d3452;background:#16261a">
                <i class="bi bi-upc-scan" style="font-size:1.15rem"></i>
            </span>
            <input type="text" id="barra-catalogo" class="form-control form-control-sm border-0"
                   inputmode="numeric"
                   style="background:#0f1117;color:#e2e8f0;box-shadow:none;min-width:150px"
                   placeholder="Código de barras + Enter">
        </span>
        <select id="filtro-marca" class="form-select form-select-sm"
                style="max-width:180px;background:#0f1117;border-color:#2d3452;color:#e2e8f0">
            <option value="">Todas as marcas</option>
        </select>
        <label class="d-flex align-items-center gap-1 small text-muted" style="cursor:pointer">
            <input type="checkbox" id="chk-foto"> Só com foto
        </label>

        <!-- Scanner — destaque visual -->
        <button onclick="abrirScanner()" title="Ler código de barras com câmera"
                style="background:#1a2640;border:1px solid #4ade80;color:#4ade80;border-radius:8px;
                       padding:.35rem .85rem;font-size:.85rem;cursor:pointer;white-space:nowrap;
                       display:flex;align-items:center;gap:.4rem;transition:background .15s"
                onmouseover="this.style.background='#1f3520'" onmouseout="this.style.background='#1a2640'">
            <i class="bi bi-upc-scan" style="font-size:1.1rem"></i>
            <span>Ler Código</span>
        </button>

        <span id="catalogo-info" class="small text-muted ms-auto"></span>
    </div>
</div>

<!-- ── Grid de produtos ──────────────────────────────────────────────────── -->
<div id="catalogo-grid" class="row g-3 mb-4">
    <?php for ($i = 0; $i < 12; $i++): ?>
    <div class="col-6 col-sm-4 col-md-3 col-lg-2">
        <div class="pbi-card h-100" style="overflow:hidden">
            <div class="pbi-skeleton" style="width:100%;padding-bottom:100%;border-radius:4px 4px 0 0">&nbsp;</div>
            <div class="p-2">
                <div class="pbi-skeleton mb-1" style="width:80%;height:.7rem;border-radius:3px">&nbsp;</div>
                <div class="pbi-skeleton" style="width:50%;height:.7rem;border-radius:3px">&nbsp;</div>
            </div>
        </div>
    </div>
    <?php endfor; ?>
</div>

<!-- ── Paginação ─────────────────────────────────────────────────────────── -->
<div id="catalogo-paginacao" class="d-flex justify-content-center gap-2 mb-4"></div>

<!-- ── Modal Scanner de Código de Barras ────────────────────────────────── -->
<div class="modal fade" id="modalScanner" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered" style="max-width:480px">
    <div class="modal-content" style="background:#0f1117;border:1px solid #2d3452;color:#e2e8f0">
      <div class="modal-header" style="border-color:#2d3452">
        <h5 class="modal-title"><i class="bi bi-upc-scan me-2 text-accent"></i>Scanner de Código de Barras</h5>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" onclick="pararScanner()"></button>
      </div>
      <div class="modal-body p-0" style="position:relative">
        <!-- Vídeo da câmera (oculto quando em modo HTTP-IP fallback) -->
        <div id="scannerCameraWrap" style="position:relative;background:#000;overflow:hidden;border-radius:0">
          <video id="scannerVideo" autoplay playsinline muted style="width:100%;max-height:300px;object-fit:cover;display:block"></video>
          <!-- Mira central -->
          <div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none">
            <div style="width:220px;height:120px;border:2px solid #4ade80;border-radius:8px;box-shadow:0 0 0 9999px rgba(0,0,0,0.45)"></div>
          </div>
          <!-- Status da detecção (câmera ao vivo) -->
          <div id="scannerStatusCamera" style="position:absolute;bottom:8px;left:0;right:0;text-align:center">
            <span class="badge" style="background:rgba(0,0,0,.6);font-size:.8rem">Aponte para o código de barras</span>
          </div>
        </div>
        <!-- Status unificado (visível em ambos os modos) -->
        <div id="scannerStatus" style="min-height:28px;padding:4px 8px;text-align:center;display:none"></div>
        <!-- Fallback HTTP+IP: foto via input nativo -->
        <div id="scannerFotoFallback" style="display:none;padding:2rem 1.5rem;text-align:center;background:#0b0e16;min-height:200px;flex-direction:column;align-items:center;justify-content:center;gap:.75rem">
          <i class="bi bi-camera" style="font-size:3rem;color:#4ade80"></i>
          <p class="small mb-1" style="color:#94a3b8;line-height:1.5">
            Câmera ao vivo indisponível via HTTP.<br>Fotografe o código de barras para escanear.
          </p>
          <button id="btnFotografar" onclick="document.getElementById('scannerFotoInput').click()"
                  style="background:#1a2640;border:2px solid #4ade80;color:#4ade80;border-radius:8px;
                         padding:.55rem 1.4rem;font-size:.9rem;cursor:pointer;display:flex;align-items:center;gap:.5rem">
            <i class="bi bi-camera-fill"></i><span>Fotografar Código</span>
          </button>
          <input type="file" id="scannerFotoInput" accept="image/*" capture="environment" style="display:none">
          <p class="text-muted" style="font-size:.72rem;margin:0">ou digite o código abaixo manualmente</p>
        </div>
        <!-- Input manual -->
        <div class="p-3">
          <div class="d-flex gap-2">
            <input type="text" id="scannerInput" class="form-control form-control-sm"
                   style="background:#1a1f2e;border-color:#2d3452;color:#e2e8f0"
                   placeholder="Ou digite o código manualmente…" autocomplete="off">
            <button class="btn btn-sm btn-accent" onclick="buscarCodigoManual()">
              <i class="bi bi-search"></i>
            </button>
          </div>
          <div id="scannerResultado" class="mt-3"></div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- ── Modal Câmera para Foto ────────────────────────────────────────────── -->
<div class="modal fade" id="modalFoto" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-dialog-centered" style="max-width:480px">
    <div class="modal-content" style="background:#0f1117;border:1px solid #2d3452;color:#e2e8f0">
      <div class="modal-header" style="border-color:#2d3452">
        <h5 class="modal-title"><i class="bi bi-camera me-2 text-accent"></i>Atualizar Foto do Produto</h5>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" onclick="pararCameraFoto()"></button>
      </div>
      <div class="modal-body">
        <p class="small text-muted mb-3" id="fotoModalNome"></p>
        <!-- Abas: Câmera / Arquivo -->
        <ul class="nav nav-tabs mb-3" style="border-color:#2d3452">
          <li class="nav-item">
            <button class="nav-link active" id="tabCameraBtn" style="color:#e2e8f0;border-color:#2d3452;background:#1a1f2e" onclick="mostrarAbaCamera()">
              <i class="bi bi-camera me-1"></i>Câmera
            </button>
          </li>
          <li class="nav-item">
            <button class="nav-link" id="tabArquivoBtn" style="color:#8892b0;border-color:transparent;background:transparent" onclick="mostrarAbaArquivo()">
              <i class="bi bi-folder me-1"></i>Arquivo
            </button>
          </li>
        </ul>

        <!-- Aba câmera -->
        <div id="abaCamera">
          <div style="position:relative;background:#000;border-radius:8px;overflow:hidden;min-height:200px">
            <video id="fotoVideo" autoplay playsinline muted style="width:100%;max-height:300px;object-fit:cover;display:block"></video>
          </div>
          <canvas id="fotoCanvas" style="display:none"></canvas>
          <div class="d-flex gap-2 justify-content-center mt-3">
            <button class="btn btn-accent" id="btnCapturar" onclick="capturarFoto()">
              <i class="bi bi-camera-fill me-1"></i>Tirar Foto
            </button>
          </div>
        </div>

        <!-- Aba arquivo -->
        <div id="abaArquivo" style="display:none">
          <label class="d-block border border-dashed rounded p-4 text-center" style="border-color:#2d3452!important;cursor:pointer" for="inputFotoArquivo">
            <i class="bi bi-cloud-upload fs-2 text-accent d-block mb-2"></i>
            <span class="small">Clique para selecionar imagem ou arraste aqui</span>
            <input type="file" id="inputFotoArquivo" accept="image/*" capture="environment" style="display:none" onchange="previewArquivo(this)">
          </label>
        </div>

        <!-- Preview -->
        <div id="fotoPreviewWrap" style="display:none;margin-top:1rem">
          <p class="small text-muted mb-2">Preview:</p>
          <img id="fotoPreview" style="width:100%;max-height:220px;object-fit:contain;border-radius:8px;background:#1a1f2e">
          <div class="d-flex gap-2 justify-content-center mt-3">
            <button class="btn btn-accent" id="btnSalvarFoto" onclick="salvarFoto()">
              <i class="bi bi-check-lg me-1"></i>Salvar Foto
            </button>
            <button class="btn btn-outline-secondary" onclick="descartarFoto()">
              <i class="bi bi-x me-1"></i>Descartar
            </button>
          </div>
          <div id="fotoMsg" class="mt-2 text-center"></div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- ── Modal Detalhe Produto ─────────────────────────────────────────────── -->
<div class="modal fade" id="modalProduto" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-scrollable">
    <div class="modal-content" style="background:#0f1117;border:1px solid #2d3452;color:#e2e8f0">
      <div class="modal-header" style="border-color:#2d3452">
        <div>
          <h5 class="modal-title mb-0" id="modalProdNome">—</h5>
          <small class="text-muted" id="modalProdCod"></small>
        </div>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body" id="modalProdBody">
        <div class="text-center py-5"><div class="spinner-border text-accent"></div></div>
      </div>
    </div>
  </div>
</div>

<!-- Input global: scanner HTTP direto (sem modal) -->
<input type="file" id="scannerInputDireto" accept="image/*" capture="environment" style="display:none">
<!-- Toast flutuante de feedback do scanner -->
<div id="scannerToast"
     style="position:fixed;bottom:32px;left:50%;transform:translateX(-50%);
            background:#1a2640;border:1px solid #2d4a7a;border-radius:12px;
            padding:.65rem 1.3rem;color:#e2e8f0;font-size:.88rem;z-index:10000;
            box-shadow:0 4px 28px rgba(0,0,0,.75);align-items:center;gap:.6rem;
            white-space:nowrap;display:none;pointer-events:none"></div>

<style>
.produto-card { cursor:pointer; transition: transform .15s, box-shadow .15s; }
.produto-card:hover { transform:translateY(-3px); box-shadow:0 6px 20px rgba(0,0,0,.4); }
.produto-img { width:100%; aspect-ratio:1/1; object-fit:contain; background:#1a1f2e; border-radius:4px 4px 0 0; }
.produto-img-placeholder { width:100%; aspect-ratio:1/1; background:#1a1f2e; border-radius:4px 4px 0 0;
    display:flex;align-items:center;justify-content:center;color:#3d4466;font-size:2rem; }
.pbi-skeleton { background:var(--pbi-border,#e2e8f0); animation:pbi-pulse 1.4s ease-in-out infinite;
    pointer-events:none; color:transparent!important; display:block; }
@keyframes pbi-pulse { 0%,100%{opacity:1} 50%{opacity:.4} }

/* Modal detalhe */
#modalProduto .table { color:#e2e8f0; }
#modalProduto .table th { color:#8892b0; font-weight:500; font-size:.78rem; text-transform:uppercase; }
#modalProduto .table td { font-size:.88rem; vertical-align:middle; }
#modalProduto .table-dark-row { background:#151823; }
.preco-edit-wrap { background:#1a1f2e; border-radius:8px; padding:1rem; border:1px solid #2d3452; }
.preco-edit-wrap label { font-size:.8rem; color:#8892b0; }
.preco-badge { display:inline-block; background:#1a2640; border:1px solid #2d4a7a; border-radius:6px;
    padding:.2rem .6rem; font-size:.8rem; color:#7eb3f5; }
.stock-bar-wrap { height:6px; background:#1a1f2e; border-radius:3px; overflow:hidden; margin-top:4px; }
.stock-bar { height:100%; border-radius:3px; background:#4ade80; }
.stock-bar.baixo { background:#f87171; }
.stock-bar.medio { background:#fbbf24; }
.btn-accent { background:#3b5bdb; border-color:#3b5bdb; color:#fff; }
.btn-accent:hover { background:#2f4ac4; border-color:#2f4ac4; color:#fff; }
.btn-outline-accent { color:#7eb3f5; border-color:#2d4a7a; }
.btn-outline-accent:hover { background:#1a2640; color:#a8d4ff; border-color:#3d6aa0; }
/* Scanner e câmera */
#scannerVideo { display:block; }
.border-dashed { border-style:dashed!important; }
</style>

<!-- Quagga2: decodifica código de barras 1D de imagem (fallback HTTP+IP) -->
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/lib/quagga.min.js"></script>

<script>
// ── Helpers e funções globais (acessíveis por onclick inline) ─────────────
function pbiImgErr(img){
    var ph = document.createElement('div');
    ph.className = 'produto-img-placeholder';
    ph.innerHTML = '<i class="bi bi-image"></i>';
    if (img.parentNode) img.parentNode.replaceChild(ph, img);
}
function fmtR(v){ return 'R$ '+parseFloat(v||0).toLocaleString('pt-BR',{minimumFractionDigits:2,maximumFractionDigits:2}); }
function fmtN(v){ return parseFloat(v||0).toLocaleString('pt-BR',{maximumFractionDigits:0}); }
function escHtml(s){ var d=document.createElement('div'); d.textContent=s||''; return d.innerHTML; }
function fmtData(s){
    if (!s) return '—';
    s = String(s);
    var m = s.match(/^(\d{4})-(\d{2})-(\d{2})/);
    return m ? m[3]+'/'+m[2]+'/'+m[1] : s.substring(0,10);
}

// Dados do form de preço
var _fpCod='', _fpEmpresa=0;

// ════════════════════════════════════════════════════════════════
// SCANNER DE CÓDIGO DE BARRAS
// ════════════════════════════════════════════════════════════════
var _scanStream=null, _scanTimer=null, _scanModal=null, _scanDetector=null;

function abrirScanner(){
    // HTTP + IP: sem modal — câmera nativa abre direto
    if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== 'function') {
        var inp = document.getElementById('scannerInputDireto');
        inp.value = '';
        inp.onchange = processarFotoScannerDireto;
        inp.click();
        return;
    }
    // HTTPS / localhost: modal com câmera ao vivo
    _scanModal = _scanModal || new bootstrap.Modal(document.getElementById('modalScanner'));
    document.getElementById('scannerResultado').innerHTML='';
    document.getElementById('scannerInput').value='';
    _scanModal.show();
    document.getElementById('modalScanner').addEventListener('shown.bs.modal', iniciarScanner, {once:true});
}

// ── Redimensiona imagem para canvas (max 1600px) ──────────────────────────
async function redimensionarParaCanvas(file, maxPx){
    maxPx = maxPx || 1600;
    var bmp = await createImageBitmap(file);
    var w = bmp.width, h = bmp.height;
    var scale = Math.min(1, maxPx / Math.max(w, h));
    var cw = Math.round(w * scale), ch = Math.round(h * scale);
    var canvas = document.createElement('canvas');
    canvas.width = cw; canvas.height = ch;
    canvas.getContext('2d').drawImage(bmp, 0, 0, cw, ch);
    bmp.close();
    return canvas;
}

// ── Decodifica código de barras de um File ────────────────────────────────
async function decodificarImagem(file, _statusCb){
    var status = _statusCb || function(){};

    // ── BarcodeDetector nativo (Chrome Android — não precisa de HTTPS) ────
    if ('BarcodeDetector' in window){
        status('BarcodeDetector: processando…');
        try {
            // Reduz resolução antes (foto de celular pode ter 12MP+)
            var canvas = await redimensionarParaCanvas(file, 1600);
            var bmp = await createImageBitmap(canvas);
            var det = new BarcodeDetector({
                formats:['ean_13','ean_8','code_128','code_39','qr_code','upc_a','upc_e','itf']
            });
            var codes = await det.detect(bmp);
            bmp.close();
            if (codes.length > 0) return codes[0].rawValue;
            status('BarcodeDetector: não leu → tentando Quagga…');
        } catch(e){
            status('BarcodeDetector erro: '+e.message+' → tentando Quagga…');
        }
    } else {
        status('BarcodeDetector: indisponível → usando Quagga…');
    }

    // ── Quagga2 fallback ──────────────────────────────────────────────────
    if (typeof Quagga === 'undefined') throw new Error('nao_encontrado');
    status('Quagga: processando…');
    return new Promise(function(resolve, reject){
        var url = URL.createObjectURL(file);
        var timeout = setTimeout(function(){
            URL.revokeObjectURL(url);
            reject(new Error('nao_encontrado'));
        }, 10000);
        Quagga.decodeSingle({
            src: url,
            numOfWorkers: 0,
            inputStream: { size: 1200 },
            decoder: {
                readers: ['ean_reader','ean_8_reader','upc_reader','upc_e_reader',
                          'code_128_reader','code_39_reader','itf_reader'],
                multiple: false
            },
            locate: true
        }, function(result){
            clearTimeout(timeout);
            URL.revokeObjectURL(url);
            if (result && result.codeResult && result.codeResult.code){
                resolve(result.codeResult.code);
            } else {
                reject(new Error('nao_encontrado'));
            }
        });
    });
}

// ── Scanner HTTP direto (sem modal) ───────────────────────────────────────
async function processarFotoScannerDireto(e){
    var file = e.target.files[0];
    if (!file) return;
    e.target.value = '';

    var toast = document.getElementById('scannerToast');
    function showToast(html, dur){
        toast.innerHTML = html;
        toast.style.display = 'flex';
        if (dur) setTimeout(function(){ toast.style.display = 'none'; }, dur);
    }
    showToast('<span class="spinner-border spinner-border-sm" style="width:.9rem;height:.9rem;flex-shrink:0"></span><span>Lendo código…</span>');

    try {
        var cod = await decodificarImagem(file, function(msg){
            showToast('<span class="spinner-border spinner-border-sm" style="width:.8rem;height:.8rem;flex-shrink:0"></span><span style="font-size:.8rem">'+escHtml(msg)+'</span>');
        });
        showToast('<i class="bi bi-check-circle-fill" style="color:#4ade80"></i><span>'+escHtml(cod)+'</span>', 2500);
        if (typeof window.abrirDetalhe === 'function') window.abrirDetalhe(cod);
    } catch(err) {
        var semCod = (err.message === 'nao_encontrado');
        var dispBD = ('BarcodeDetector' in window) ? 'BD:sim' : 'BD:não';
        var dispQ  = (typeof Quagga !== 'undefined') ? 'Q:sim' : 'Q:não';
        showToast(
            semCod
                ? '<i class="bi bi-exclamation-triangle" style="color:#fbbf24;flex-shrink:0"></i><span>Não lido ['+dispBD+' '+dispQ+']. Enquadre o código na horizontal, perto e com boa luz.</span>'
                : '<i class="bi bi-x-circle" style="color:#f87171;flex-shrink:0"></i><span>'+escHtml(err.message||'Erro')+'</span>',
            5000
        );
    }
}

async function iniciarScanner(){
    var v = document.getElementById('scannerVideo');
    var statusCamera = document.getElementById('scannerStatusCamera'); // dentro do vídeo
    var statusEl     = document.getElementById('scannerStatus');       // abaixo (fallback)
    var cameraWrap   = document.getElementById('scannerCameraWrap');
    var fallbackWrap = document.getElementById('scannerFotoFallback');

    // ── Detecta HTTP + IP (mediaDevices indisponível) ──────────────────────
    if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== 'function') {
        // Esconde vídeo, mostra fallback de foto
        cameraWrap.style.display = 'none';
        fallbackWrap.style.display = 'flex';
        statusEl.style.display = 'block';
        statusEl.innerHTML = '<span class="small" style="color:#94a3b8">Acesse via HTTPS para câmera ao vivo</span>';
        // Registra handler do input de arquivo
        var fi = document.getElementById('scannerFotoInput');
        fi.onchange = processarFotoScanner;
        return;
    }

    // ── Câmera disponível (HTTPS ou localhost) ────────────────────────────
    // Tenta câmera traseira (celular), depois frontal, depois qualquer uma
    var tentativas = [
        { facingMode:'environment', width:{ideal:1280}, height:{ideal:720} },
        { facingMode:'user' },
        true  // qualquer câmera disponível
    ];

    for (var i = 0; i < tentativas.length; i++) {
        try {
            _scanStream = await navigator.mediaDevices.getUserMedia({ video: tentativas[i] });
            break; // sucesso
        } catch(e) {
            if (i === tentativas.length - 1) {
                // Todas falharam — mostra erro real e instrução
                var msg = e.name === 'NotAllowedError'
                    ? 'Permissão de câmera negada. Clique no cadeado da barra de endereço e permita a câmera.'
                    : e.name === 'NotFoundError'
                    ? 'Nenhuma câmera encontrada neste dispositivo.'
                    : 'Câmera indisponível: ' + e.message;
                statusCamera.innerHTML = '<span class="badge bg-danger px-3 py-2" style="white-space:normal;max-width:260px">'+escHtml(msg)+'</span>';
                return;
            }
        }
    }

    v.srcObject = _scanStream;
    await v.play();
    statusCamera.innerHTML = '<span class="badge" style="background:rgba(0,0,0,.6)">Aponte para o código de barras</span>';

    // Usa BarcodeDetector nativo se disponível (Chrome/Edge desktop e Android)
    if ('BarcodeDetector' in window){
        _scanDetector = new BarcodeDetector({formats:['ean_13','ean_8','code_128','code_39','qr_code','upc_a','upc_e','itf']});
        _scanTimer = setInterval(async function(){
            if (!v.videoWidth) return;
            try {
                var codes = await _scanDetector.detect(v);
                if (codes.length > 0) {
                    var cod = codes[0].rawValue;
                    statusCamera.innerHTML = '<span class="badge bg-success">Detectado: '+escHtml(cod)+'</span>';
                    clearInterval(_scanTimer);
                    await processarCodigo(cod);
                }
            } catch(e){}
        }, 400);
    } else {
        statusCamera.innerHTML = '<span class="badge" style="background:rgba(0,0,0,.7);color:#fbbf24">'
            + 'Câmera ativa — digite o código manualmente (scanner automático não suportado neste browser)'
            + '</span>';
    }
}

function pararScanner(){
    clearInterval(_scanTimer); _scanTimer=null;
    if (_scanStream){ _scanStream.getTracks().forEach(function(t){t.stop();}); _scanStream=null; }
    var v = document.getElementById('scannerVideo');
    if (v) v.srcObject=null;
    // Restaura estado dos wrappers (para reabertura do modal)
    var cw = document.getElementById('scannerCameraWrap');
    var fw = document.getElementById('scannerFotoFallback');
    if (cw) cw.style.display = '';
    if (fw) fw.style.display = 'none';
    var fi = document.getElementById('scannerFotoInput');
    if (fi) { fi.value=''; fi.onchange=null; }
}

// ── Fallback HTTP+IP: decodifica código de barras de foto capturada ───────
async function processarFotoScanner(e){
    var file = (e.target||e).files[0];
    if (!file) return;
    var statusEl = document.getElementById('scannerStatus'); // div unificado (visível no fallback)
    var btn = document.getElementById('btnFotografar');
    var btnOrig = btn.innerHTML;
    btn.disabled = true;
    btn.innerHTML = '<span class="spinner-border spinner-border-sm" style="width:1rem;height:1rem"></span> Analisando…';
    statusEl.style.display = 'block';
    statusEl.innerHTML = '<span class="small" style="color:#94a3b8">Decodificando imagem…</span>';
    e.target.value = ''; // reset para permitir nova foto

    try {
        var cod = await decodificarImagem(file);
        btn.disabled = false;
        btn.innerHTML = btnOrig;
        statusEl.innerHTML = '<span class="badge bg-success">✓ '+escHtml(cod)+'</span>';
        abrirDoProdutoScanner(cod);
    } catch(err) {
        btn.disabled = false;
        btn.innerHTML = btnOrig;
        var semCod = (err.message === 'nao_encontrado');
        statusEl.innerHTML = semCod
            ? '<span class="small" style="color:#fbbf24">⚠ Não lido. Enquadre o código na horizontal e tire de perto.</span>'
            : '<span class="small" style="color:#f87171">✗ '+escHtml(err.message||String(err))+'</span>';
    }
}

function buscarCodigoManual(){
    var cod = document.getElementById('scannerInput').value.trim();
    if (!cod) return;
    processarCodigo(cod);
}

document.addEventListener('DOMContentLoaded', function(){
    var inp = document.getElementById('scannerInput');
    if (inp) inp.addEventListener('keydown', function(e){ if(e.key==='Enter') buscarCodigoManual(); });
    document.getElementById('modalScanner').addEventListener('hidden.bs.modal', pararScanner);
});

async function processarCodigo(cod){
    document.getElementById('scannerResultado').innerHTML =
        '<div class="text-center py-2"><div class="spinner-border spinner-border-sm text-accent"></div></div>';
    try {
        var r = await fetch('/api/produtos/buscar-barras?cod='+encodeURIComponent(cod),{credentials:'same-origin'});
        var d = await r.json();
        if (d.nao_encontrado || !d.COD_ITEM){
            document.getElementById('scannerResultado').innerHTML =
                '<div class="alert alert-warning small mb-0">Código <b>'+escHtml(cod)+'</b> não encontrado.</div>';
            document.getElementById('scannerStatusCamera').innerHTML =
                '<span class="badge" style="background:rgba(0,0,0,.6)">Aponte para o código de barras</span>';
            if(_scanDetector && _scanStream){
                _scanTimer = setInterval(async function(){
                    var v=document.getElementById('scannerVideo');
                    try{ var codes=await _scanDetector.detect(v); if(codes.length>0){clearInterval(_scanTimer);await processarCodigo(codes[0].rawValue);} }catch(e){}
                },400);
            }
            return;
        }
        // Produto encontrado
        document.getElementById('scannerResultado').innerHTML =
            '<div class="d-flex align-items-center gap-3 p-2" style="background:#1a1f2e;border-radius:8px">'
            + (d.TEM_FOTO==1 ? '<img src="/api/produtos/foto?cod='+encodeURIComponent(d.COD_ITEM)+'" style="width:60px;height:60px;object-fit:contain;border-radius:6px;background:#0f1117">' : '<div style="width:60px;height:60px;background:#0f1117;border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:#3d4466"><i class="bi bi-image"></i></div>')
            + '<div class="flex-fill">'
            + '<div class="fw-bold small">'+escHtml(d.DESCRICAO||'')+'</div>'
            + '<div class="text-muted" style="font-size:.75rem">Cód: '+escHtml(d.COD_ITEM||'')+' | '+escHtml(d.MARCA||'')+'</div>'
            + '</div>'
            + '<button class="btn btn-sm btn-accent" onclick="abrirDoProdutoScanner(\''+escHtml(d.COD_ITEM)+'\')">'
            + '<i class="bi bi-box-arrow-up-right me-1"></i>Abrir</button>'
            + '</div>';
    } catch(e){
        document.getElementById('scannerResultado').innerHTML='<div class="alert alert-danger small mb-0">Erro: '+escHtml(e.message)+'</div>';
    }
}

function abrirDoProdutoScanner(cod){
    if(_scanModal) _scanModal.hide();
    pararScanner();
    setTimeout(function(){ abrirDetalhe(cod); }, 300);
}

// ════════════════════════════════════════════════════════════════
// CÂMERA PARA FOTO DO PRODUTO
// ════════════════════════════════════════════════════════════════
var _fotoStream=null, _fotoModal=null, _fotoCodItem='', _fotoBlobUrl=null, _fotoBlob=null;

function abrirModalFoto(codItem, nome){
    _fotoCodItem = codItem;
    _fotoModal = _fotoModal || new bootstrap.Modal(document.getElementById('modalFoto'));
    document.getElementById('fotoModalNome').textContent = nome || codItem;
    document.getElementById('fotoPreviewWrap').style.display='none';
    document.getElementById('fotoMsg').innerHTML='';
    document.getElementById('inputFotoArquivo').value='';
    _fotoBlob=null;
    _fotoModal.show();
    document.getElementById('modalFoto').addEventListener('shown.bs.modal', function(){
        mostrarAbaCamera();
    },{once:true});
    document.getElementById('modalFoto').addEventListener('hidden.bs.modal', pararCameraFoto, {once:true});
}

async function mostrarAbaCamera(){
    document.getElementById('tabCameraBtn').classList.add('active');
    document.getElementById('tabArquivoBtn').classList.remove('active');
    document.getElementById('tabCameraBtn').style.cssText='color:#e2e8f0;border-color:#2d3452;background:#1a1f2e';
    document.getElementById('tabArquivoBtn').style.cssText='color:#8892b0;border-color:transparent;background:transparent';
    document.getElementById('abaCamera').style.display='';
    document.getElementById('abaArquivo').style.display='none';
    if (!_fotoStream){
        var tentativas = [
            { facingMode:'environment', width:{ideal:1280}, height:{ideal:720} },
            { facingMode:'user' },
            true
        ];
        var ok = false;
        for (var i = 0; i < tentativas.length; i++){
            try {
                _fotoStream = await navigator.mediaDevices.getUserMedia({ video: tentativas[i] });
                ok = true; break;
            } catch(e){ if (i === tentativas.length-1){
                var msg = e.name==='NotAllowedError'
                    ? 'Permissão negada. Clique no cadeado da barra de endereço e permita a câmera.'
                    : e.name==='NotFoundError' ? 'Nenhuma câmera encontrada.'
                    : 'Câmera indisponível: '+e.message;
                document.getElementById('abaCamera').innerHTML=
                    '<div class="alert alert-warning small"><i class="bi bi-camera-video-off me-2"></i>'+escHtml(msg)+'<br><small class="text-muted mt-1 d-block">Use a aba <b>Arquivo</b> para selecionar uma foto.</small></div>';
            }}
        }
        if (ok){
            var v=document.getElementById('fotoVideo');
            v.srcObject=_fotoStream; await v.play();
        }
    }
}

function mostrarAbaArquivo(){
    pararCameraFoto();
    document.getElementById('tabArquivoBtn').classList.add('active');
    document.getElementById('tabCameraBtn').classList.remove('active');
    document.getElementById('tabArquivoBtn').style.cssText='color:#e2e8f0;border-color:#2d3452;background:#1a1f2e';
    document.getElementById('tabCameraBtn').style.cssText='color:#8892b0;border-color:transparent;background:transparent';
    document.getElementById('abaArquivo').style.display='';
    document.getElementById('abaCamera').style.display='none';
}

function pararCameraFoto(){
    if(_fotoStream){ _fotoStream.getTracks().forEach(function(t){t.stop();}); _fotoStream=null; }
    var v=document.getElementById('fotoVideo');
    if(v) v.srcObject=null;
}

function capturarFoto(){
    var v=document.getElementById('fotoVideo');
    var canvas=document.getElementById('fotoCanvas');
    canvas.width=v.videoWidth; canvas.height=v.videoHeight;
    canvas.getContext('2d').drawImage(v,0,0);
    canvas.toBlob(function(blob){
        _fotoBlob=blob;
        var url=URL.createObjectURL(blob);
        document.getElementById('fotoPreview').src=url;
        document.getElementById('fotoPreviewWrap').style.display='';
        document.getElementById('fotoMsg').innerHTML='';
    },'image/jpeg',0.92);
}

function previewArquivo(input){
    if(!input.files[0]) return;
    _fotoBlob=input.files[0];
    var reader=new FileReader();
    reader.onload=function(e){
        document.getElementById('fotoPreview').src=e.target.result;
        document.getElementById('fotoPreviewWrap').style.display='';
        document.getElementById('fotoMsg').innerHTML='';
    };
    reader.readAsDataURL(_fotoBlob);
}

function descartarFoto(){
    _fotoBlob=null;
    document.getElementById('fotoPreviewWrap').style.display='none';
    document.getElementById('fotoMsg').innerHTML='';
}

function salvarFoto(){
    if(!_fotoBlob){ document.getElementById('fotoMsg').innerHTML='<small class="text-warning">Nenhuma foto capturada.</small>'; return; }
    var btn=document.getElementById('btnSalvarFoto');
    btn.disabled=true; btn.innerHTML='<span class="spinner-border spinner-border-sm"></span>';
    var fd=new FormData();
    fd.append('cod',_fotoCodItem);
    fd.append('foto',_fotoBlob,'foto.jpg');
    fetch('/api/produtos/atualizar-foto',{method:'POST',credentials:'same-origin',body:fd})
        .then(function(r){return r.json();})
        .then(function(d){
            btn.disabled=false; btn.innerHTML='<i class="bi bi-check-lg me-1"></i>Salvar Foto';
            if(d.ok){
                document.getElementById('fotoMsg').innerHTML='<small class="text-success"><i class="bi bi-check-circle me-1"></i>Foto salva com sucesso!</small>';
                // Atualiza a imagem no modal de detalhe sem recarregar tudo
                var imgDetalhe=document.getElementById('modalFotoImg');
                if(imgDetalhe) imgDetalhe.src='/api/produtos/foto?cod='+encodeURIComponent(_fotoCodItem)+'&t='+Date.now();
                setTimeout(function(){ if(_fotoModal) _fotoModal.hide(); pararCameraFoto(); abrirDetalhe(_fotoCodItem); },1500);
            } else {
                document.getElementById('fotoMsg').innerHTML='<small class="text-danger">'+(d.erro||'Erro ao salvar.')+'</small>';
            }
        })
        .catch(function(e){
            btn.disabled=false; btn.innerHTML='<i class="bi bi-check-lg me-1"></i>Salvar Foto';
            document.getElementById('fotoMsg').innerHTML='<small class="text-danger">'+escHtml(e.message)+'</small>';
        });
}

function editarPreco(cod, empresa, precoAtual){
    _fpCod = cod;
    _fpEmpresa = empresa;
    var wrap = document.getElementById('formPrecoWrap');
    // Descobre nome da empresa pelo badge na linha
    var empNome = 'Empresa '+empresa;
    document.querySelectorAll('#modalProduto tbody tr').forEach(function(r){
        var btn = r.querySelector('button[onclick^="editarPreco"]');
        if (btn && btn.getAttribute('onclick').indexOf(','+empresa+',') > 0){
            var badge = r.querySelector('.badge');
            if (badge) empNome = badge.textContent;
        }
    });
    document.getElementById('fpEmpresaNome').textContent = empNome;
    document.getElementById('fpPrecoAtual').textContent  = fmtR(precoAtual);
    document.getElementById('fpNovoPreco').value = precoAtual.toFixed(2).replace('.',',');
    document.getElementById('fpMsg').innerHTML = '';
    wrap.style.display = 'block';
    wrap.scrollIntoView({behavior:'smooth', block:'nearest'});
    document.getElementById('fpNovoPreco').focus();
    document.getElementById('fpNovoPreco').select();
}

function salvarPreco(){
    var novoRaw = document.getElementById('fpNovoPreco').value.replace(/\./g,'').replace(',','.');
    var novo = parseFloat(novoRaw);
    if (isNaN(novo)||novo<=0){ document.getElementById('fpMsg').innerHTML='<small class="text-danger">Preço inválido.</small>'; return; }
    var btn = document.getElementById('fpSalvarBtn');
    btn.disabled = true;
    btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
    var fd = new FormData();
    fd.append('cod',_fpCod); fd.append('empresa',_fpEmpresa); fd.append('preco',novo.toFixed(2));
    fetch('/api/produtos/atualizar-preco',{method:'POST',credentials:'same-origin',body:fd})
        .then(function(r){ return r.json(); })
        .then(function(d){
            btn.disabled=false; btn.innerHTML='<i class="bi bi-check-lg me-1"></i>Salvar';
            if(d.ok){
                document.getElementById('fpMsg').innerHTML='<small class="text-success"><i class="bi bi-check-circle me-1"></i>Preço atualizado!</small>';
                setTimeout(function(){ abrirDetalhe(_fpCod); },1200);
            } else {
                document.getElementById('fpMsg').innerHTML='<small class="text-warning">'+(d.erro||'Nenhum registro atualizado.')+'</small>';
            }
        })
        .catch(function(e){
            btn.disabled=false; btn.innerHTML='<i class="bi bi-check-lg me-1"></i>Salvar';
            document.getElementById('fpMsg').innerHTML='<small class="text-danger">'+escHtml(e.message)+'</small>';
        });
}

(function(){
'use strict';

var pagina = 1, totalPaginas = 1, marcasCarregadas = false;
var buscaTimer = null;
function qs(sel){ return document.querySelector(sel); }

function params(){
    var b = encodeURIComponent((qs('#busca-catalogo')||{}).value||'');
    var m = encodeURIComponent((qs('#filtro-marca')||{}).value||'');
    var f = (qs('#chk-foto')||{}).checked ? 1 : 0;
    return '?pagina='+pagina+'&busca='+b+'&marca='+m+'&foto='+f;
}

// ── KPIs ─────────────────────────────────────────────────────────────────
function carregarKpis(){
    fetch('/api/produtos/catalogo-kpis', {credentials:'same-origin'})
        .then(function(r){ return r.json(); })
        .then(function(d){
            var kpis = d.kpis || {};
            var html = [
                {label:'Total de Produtos', val: fmtN(kpis.TOTAL_PRODUTOS), cls:''},
                {label:'Categorias',        val: fmtN(kpis.TOTAL_CATEGORIAS), cls:''},
                {label:'Marcas',            val: fmtN(kpis.TOTAL_MARCAS), cls:''},
                {label:'Valor Total Estoque', val: fmtR(kpis.VALOR_ESTOQUE), cls:'text-accent'},
                {label:'Estoque Baixo',     val: fmtN(kpis.ESTOQUE_BAIXO), cls:'text-warning'},
            ].map(function(k){
                return '<div class="pbi-kpi-card">'
                     + '<div class="pbi-kpi-label">'+k.label+'</div>'
                     + '<div class="pbi-kpi-value '+k.cls+'">'+k.val+'</div>'
                     + '</div>';
            }).join('');
            qs('#kpi-grid').innerHTML = html;
        })
        .catch(function(){ qs('#kpi-grid').innerHTML = '<div class="text-muted small p-3">Erro ao carregar KPIs.</div>'; });
}

// ── Marcas para o select ──────────────────────────────────────────────────
function carregarMarcas(){
    if (marcasCarregadas) return;
    fetch('/api/produtos/marcas', {credentials:'same-origin'})
        .then(function(r){ return r.json(); })
        .then(function(d){
            var sel = qs('#filtro-marca');
            (d.marcas||[]).forEach(function(m){
                var opt = document.createElement('option');
                opt.value = m.NOME || '';
                opt.textContent = m.NOME || '(sem marca)';
                sel.appendChild(opt);
            });
            marcasCarregadas = true;
        });
}

// ── Grid de produtos ──────────────────────────────────────────────────────
function carregarGrid(){
    var grid = qs('#catalogo-grid');
    grid.innerHTML = '<div class="col-12 text-center py-5"><div class="spinner-border text-accent"></div></div>';
    fetch('/api/produtos/catalogo'+params(), {credentials:'same-origin'})
        .then(function(r){ return r.json(); })
        .then(function(d){
            totalPaginas = d.paginas || 1;
            var total = d.total || 0;
            var de = ((pagina-1)*d.limite)+1, ate = Math.min(pagina*d.limite, total);
            qs('#catalogo-info').textContent = 'Exibindo '+de+' — '+ate+' de '+fmtN(total)+' produtos (Página '+pagina+' de '+fmtN(totalPaginas)+')';

            if (!(d.produtos||[]).length){
                grid.innerHTML = '<div class="col-12 text-center text-muted py-5">Nenhum produto encontrado.</div>';
                renderPaginacao();
                return;
            }

            grid.innerHTML = (d.produtos||[]).map(function(p){
                var temFoto = p.TEM_FOTO == '1' || p.TEM_FOTO === true || p.TEM_FOTO == 1;
                var imgHtml = temFoto
                    ? '<img class="produto-img" src="/api/produtos/foto?cod='+encodeURIComponent(p.COD_ITEM)+'" loading="lazy" onerror="pbiImgErr(this)">'
                    : '<div class="produto-img-placeholder"><i class="bi bi-image"></i></div>';
                return '<div class="col-6 col-sm-4 col-md-3 col-lg-2">'
                     + '<div class="pbi-card h-100 produto-card" data-cod="'+escHtml(p.COD_ITEM||'')+'" style="overflow:hidden">'
                     + imgHtml
                     + '<div class="p-2">'
                     + '<div class="small fw-bold text-truncate" style="font-size:.78rem" title="'+escHtml(p.DESCRICAO||'')+'">'+escHtml((p.DESCRICAO||'').substring(0,40))+'</div>'
                     + '<div class="text-muted" style="font-size:.72rem">Cód: '+escHtml(p.COD_ITEM||'')+'</div>'
                     + (p.PRECO_VENDA ? '<div class="text-accent fw-bold mt-1" style="font-size:.82rem">'+fmtR(p.PRECO_VENDA)+'</div>' : '')
                     + (p.MARCA ? '<div class="text-muted" style="font-size:.7rem">'+escHtml(p.MARCA)+'</div>' : '')
                     + '</div></div></div>';
            }).join('');

            // Clique no card → abre modal
            qs('#catalogo-grid').querySelectorAll('.produto-card').forEach(function(card){
                card.addEventListener('click', function(){ abrirDetalhe(this.dataset.cod); });
            });
            renderPaginacao();
        })
        .catch(function(e){
            grid.innerHTML = '<div class="col-12 alert alert-warning small">Erro ao carregar produtos: '+e.message+'</div>';
        });
}

// ── Paginação ─────────────────────────────────────────────────────────────
function renderPaginacao(){
    var el = qs('#catalogo-paginacao');
    if (totalPaginas <= 1){ el.innerHTML=''; return; }
    var btns = [], min = Math.max(1,pagina-3), max = Math.min(totalPaginas,pagina+3);
    if (pagina > 1) btns.push(btnPag('&laquo;', pagina-1));
    if (min > 1){ btns.push(btnPag('1',1)); if(min>2) btns.push('<span class="text-muted">…</span>'); }
    for(var p2=min;p2<=max;p2++) btns.push(btnPag(p2,p2,p2===pagina));
    if (max < totalPaginas){ if(max<totalPaginas-1) btns.push('<span class="text-muted">…</span>'); btns.push(btnPag(totalPaginas,totalPaginas)); }
    if (pagina < totalPaginas) btns.push(btnPag('&raquo;', pagina+1));
    el.innerHTML = btns.join('');
    el.querySelectorAll('[data-p]').forEach(function(b){
        b.addEventListener('click',function(){ pagina=parseInt(this.dataset.p); carregarGrid(); window.scrollTo(0,0); });
    });
}
function btnPag(lbl,p2,ativo){
    return '<button class="btn btn-sm '+(ativo?'btn-accent text-white':'btn-outline-secondary')+'" data-p="'+p2+'">'+lbl+'</button>';
}

// ── Modal Detalhe ─────────────────────────────────────────────────────────
var modalBS = null;
function getModal(){
    if (!modalBS) modalBS = new bootstrap.Modal(document.getElementById('modalProduto'));
    return modalBS;
}

function abrirDetalhe(cod){
    var m = getModal();
    document.getElementById('modalProdNome').textContent = 'Carregando…';
    document.getElementById('modalProdCod').textContent = cod;
    document.getElementById('modalProdBody').innerHTML =
        '<div class="text-center py-5"><div class="spinner-border text-accent"></div></div>';
    m.show();

    fetch('/api/produtos/detalhe?cod='+encodeURIComponent(cod), {credentials:'same-origin'})
        .then(function(r){ return r.json(); })
        .then(function(d){
            if (d.erro){ document.getElementById('modalProdBody').innerHTML='<div class="alert alert-danger">'+escHtml(d.erro)+'</div>'; return; }
            renderModal(d);
        })
        .catch(function(e){
            document.getElementById('modalProdBody').innerHTML='<div class="alert alert-warning small">'+escHtml(e.message)+'</div>';
        });
}
window.abrirDetalhe = abrirDetalhe; // expõe para scanner global

function renderModal(d){
    var item = d.item || {};
    var estoques = d.estoques || [];
    var vendas = d.vendas || [];

    document.getElementById('modalProdNome').textContent = item.DESCRICAO || '—';
    document.getElementById('modalProdCod').textContent  = 'Cód: '+(item.COD_ITEM||'');

    // ── Imagem ───────────────────────────────────────────────────────────────
    var fotoHtml = (item.TEM_FOTO == 1
        ? '<img id="modalFotoImg" src="/api/produtos/foto?cod='+encodeURIComponent(item.COD_ITEM)+'&t='+Date.now()+'" onerror="pbiImgErr(this)" '
          + 'style="width:100%;max-height:220px;object-fit:contain;background:#1a1f2e;border-radius:8px 8px 0 0">'
        : '<div style="width:100%;height:160px;background:#1a1f2e;border-radius:8px 8px 0 0;display:flex;align-items:center;justify-content:center;color:#3d4466;font-size:3rem"><i class="bi bi-image"></i></div>')
      + '<button class="btn btn-sm w-100" style="border-radius:0 0 8px 8px;background:#1a2640;border:1px solid #2d4a7a;border-top:none;color:#7eb3f5" '
      + 'onclick="abrirModalFoto(\''+escHtml(item.COD_ITEM)+'\',\''+escHtml((item.DESCRICAO||'').substring(0,40))+'\')">'
      + '<i class="bi bi-camera me-1"></i>'+(item.TEM_FOTO==1?'Atualizar Foto':'Adicionar Foto')+'</button>';

    // ── Info básica ───────────────────────────────────────────────────────────
    var rows = [
        ['Marca',      item.MARCA       || '—'],
        ['Tipo',       item.TIPO_PRODUTO || '—'],
        ['Unidade',    item.COD_UNIDADE  || '—'],
        ['Referência', item.REFERENCIA   || '—'],
        ['NCM',        item.NCM          || '—'],
        ['Estoque Mín',fmtN(item.ESTOQ_MINIMO||0)],
        ['Estoque Máx',fmtN(item.ESTOQUE_MAXIMO||0)],
        ['Qtd Embal.', fmtN(item.QTD_EMBALAGEM||0)],
    ];
    var infoHtml = '<table class="table table-sm mb-0">'
        + rows.map(function(r){
            return '<tr><th style="width:40%">'+escHtml(r[0])+'</th><td>'+escHtml(r[1])+'</td></tr>';
        }).join('')
        + '</table>';

    // ── Estoque por empresa ───────────────────────────────────────────────────
    var estHead = '<thead><tr>'
        + '<th>Empresa</th><th class="text-end">Estoque</th><th class="text-end">Reservado</th>'
        + '<th class="text-end">Preço Venda</th><th class="text-end">Atacado</th>'
        + '<th class="text-end">Custo Final</th><th class="text-end">Custo Médio</th>'
        + '<th></th></tr></thead>';
    var estRows = estoques.map(function(e){
        var min = parseFloat(item.ESTOQ_MINIMO||0);
        var qtd = parseFloat(e.QTD||0);
        var pct = min > 0 ? Math.min(100, qtd/min*100) : 100;
        var barCls = pct < 30 ? 'baixo' : (pct < 80 ? 'medio' : '');
        var qtdHtml = '<div style="white-space:nowrap">'
            + '<span class="'+(qtd<=0?'text-danger':(qtd<min?'text-warning':'text-success'))+'">'+fmtN(qtd)+'</span>'
            + (min>0?'<div class="stock-bar-wrap"><div class="stock-bar '+barCls+'" style="width:'+pct+'%"></div></div>':'')
            + '</div>';
        return '<tr>'
            + '<td><span class="badge" style="background:#1a2640;color:#7eb3f5">'+escHtml(e.EMPRESA||e.COD_EMPRESA)+'</span></td>'
            + '<td class="text-end">'+qtdHtml+'</td>'
            + '<td class="text-end text-muted">'+fmtN(e.QTD_RESERVADA||0)+'</td>'
            + '<td class="text-end text-accent fw-bold">'+fmtR(e.PRECO_VENDA||0)+'</td>'
            + '<td class="text-end text-muted">'+fmtR(e.PRECO_ATACADO||0)+'</td>'
            + '<td class="text-end">'+fmtR(e.CUSTO_FINAL||0)+'</td>'
            + '<td class="text-end">'+fmtR(e.CUSTO_MEDIO||0)+'</td>'
            + '<td><button class="btn btn-sm btn-outline-accent py-0 px-2" onclick="editarPreco(\''+escHtml(item.COD_ITEM)+'\','+e.COD_EMPRESA+','+parseFloat(e.PRECO_VENDA||0)+')" title="Alterar preço"><i class="bi bi-pencil"></i></button></td>'
            + '</tr>'
            // Histórico de preços como sub-linha
            + (e.PRECO_ANT1 ? '<tr style="background:#0d1019"><td colspan="8" class="py-1 ps-4">'
                + '<span class="text-muted small">Histórico: </span>'
                + (e.PRECO_ANT1 ? '<span class="preco-badge me-1">'+fmtR(e.PRECO_ANT1)+' <small>'+fmtData(e.DT_ANT1)+'</small></span>' : '')
                + (e.PRECO_ANT2 ? '<span class="preco-badge me-1">'+fmtR(e.PRECO_ANT2)+' <small>'+fmtData(e.DT_ANT2)+'</small></span>' : '')
                + (e.PRECO_ANT3 ? '<span class="preco-badge">'+fmtR(e.PRECO_ANT3)+' <small>'+fmtData(e.DT_ANT3)+'</small></span>' : '')
                + '</td></tr>' : '');
    }).join('');
    var estHtml = '<div class="table-responsive"><table class="table table-sm table-hover mb-0">'+estHead+'<tbody>'+estRows+'</tbody></table></div>';

    // ── Últimas vendas ────────────────────────────────────────────────────────
    var vendHtml = '';
    if (vendas.length) {
        vendHtml = '<h6 class="mt-3 mb-2 text-muted small text-uppercase">Últimas Vendas</h6>'
            + '<div class="table-responsive"><table class="table table-sm mb-0"><thead><tr>'
            + '<th>Data</th><th class="text-end">Qtd</th><th class="text-end">Preço Unit.</th><th>Cliente</th>'
            + '</tr></thead><tbody>'
            + vendas.map(function(v){
                return '<tr>'
                    + '<td>'+fmtData(v.DATA_EMISSAO)+'</td>'
                    + '<td class="text-end">'+fmtN(v.QTD)+'</td>'
                    + '<td class="text-end text-accent">'+fmtR(v.PRECO_UNIT)+'</td>'
                    + '<td class="text-muted small text-truncate" style="max-width:180px">'+escHtml((v.CLIENTE||'').substring(0,30))+'</td>'
                    + '</tr>';
            }).join('')
            + '</tbody></table></div>';
    }

    // ── Form editar preço (hidden, aparece via editarPreco()) ─────────────────
    var formHtml = '<div id="formPrecoWrap" class="preco-edit-wrap mt-3" style="display:none">'
        + '<h6 class="mb-3"><i class="bi bi-tag me-1"></i>Alterar Preço de Venda</h6>'
        + '<div class="row g-2 align-items-end">'
        + '<div class="col-auto"><label>Empresa</label><div id="fpEmpresaNome" class="fw-bold mt-1"></div></div>'
        + '<div class="col-auto"><label>Preço Atual</label><div id="fpPrecoAtual" class="text-accent fw-bold mt-1"></div></div>'
        + '<div class="col-auto">'
        + '<label>Novo Preço (R$)</label>'
        + '<input type="text" id="fpNovoPreco" class="form-control form-control-sm mt-1" style="background:#0f1117;border-color:#2d3452;color:#e2e8f0;width:140px" placeholder="0,00">'
        + '</div>'
        + '<div class="col-auto">'
        + '<button class="btn btn-sm btn-accent mt-1" id="fpSalvarBtn" onclick="salvarPreco()"><i class="bi bi-check-lg me-1"></i>Salvar</button>'
        + '<button class="btn btn-sm btn-outline-secondary mt-1 ms-1" onclick="document.getElementById(\'formPrecoWrap\').style.display=\'none\'">Cancelar</button>'
        + '</div>'
        + '</div>'
        + '<div id="fpMsg" class="mt-2"></div>'
        + '</div>';

    // Botão de foto separado (sempre visível, full-width)
    var btnFotoLabel = item.TEM_FOTO == 1 ? 'Atualizar Foto' : 'Adicionar Foto';
    var btnFotoHtml = '<button class="btn btn-sm w-100 mb-3" '
        + 'style="background:#1a2640;border:1px solid #2d4a7a;color:#7eb3f5;border-radius:8px;padding:.45rem 1rem" '
        + 'onclick="abrirModalFoto(\''+escHtml(item.COD_ITEM)+'\',\''+escHtml((item.DESCRICAO||'').substring(0,40))+'\')">'
        + '<i class="bi bi-camera me-2"></i>'+btnFotoLabel+'</button>';

    document.getElementById('modalProdBody').innerHTML =
        // Foto + botão (linha completa)
        '<div class="row g-2 mb-3">'
        + '<div class="col-4 col-md-3">'
        + (item.TEM_FOTO == 1
            ? '<img id="modalFotoImg" src="/api/produtos/foto?cod='+encodeURIComponent(item.COD_ITEM)+'&t='+Date.now()+'" onerror="pbiImgErr(this)" style="width:100%;aspect-ratio:1/1;object-fit:contain;background:#1a1f2e;border-radius:8px">'
            : '<div style="width:100%;aspect-ratio:1/1;background:#1a1f2e;border-radius:8px;display:flex;align-items:center;justify-content:center;color:#3d4466;font-size:2rem"><i class="bi bi-image"></i></div>')
        + '</div>'
        + '<div class="col-8 col-md-9">'+infoHtml+'</div>'
        + '</div>'
        // Botão foto full-width sempre visível
        + btnFotoHtml
        + '<h6 class="mb-2 text-muted small text-uppercase">Estoque</h6>'
        + estHtml
        + formHtml
        + vendHtml;

    // Scroll para o topo do modal body
    var body = document.getElementById('modalProdBody');
    if (body) body.scrollTop = 0;
}

// ── Eventos ───────────────────────────────────────────────────────────────
qs('#busca-catalogo').addEventListener('input', function(){
    clearTimeout(buscaTimer);
    buscaTimer = setTimeout(function(){ pagina=1; carregarGrid(); }, 500);
});
// Código de barras: ao dar Enter (ou bipar), acha o produto pelo resolvedor rapido
// (/api/produtos/buscar-barras) e abre o detalhe direto — sem varrer o catalogo.
function buscarPorBarraCatalogo(){
    var cod  = ((qs('#barra-catalogo')||{}).value||'').trim();
    var info = qs('#catalogo-info');
    if(!cod) return;
    if(info) info.textContent = 'Buscando código ' + cod + '…';
    fetch('/api/produtos/buscar-barras?cod=' + encodeURIComponent(cod), {credentials:'same-origin'})
        .then(function(r){ return r.json(); })
        .then(function(d){
            if(d && d.COD_ITEM){
                if(info) info.textContent = '';
                abrirDetalhe(d.COD_ITEM);
                var el = qs('#barra-catalogo'); if(el) el.value = '';
            } else {
                if(info) info.textContent = '✗ Código de barras não encontrado.';
            }
        })
        .catch(function(){ if(info) info.textContent = 'Erro ao buscar o código.'; });
}
qs('#barra-catalogo').addEventListener('keydown', function(e){ if(e.key === 'Enter'){ e.preventDefault(); buscarPorBarraCatalogo(); } });
qs('#filtro-marca').addEventListener('change', function(){ pagina=1; carregarGrid(); });
qs('#chk-foto').addEventListener('change', function(){ pagina=1; carregarGrid(); });

// ── Init ──────────────────────────────────────────────────────────────────
carregarKpis();
carregarMarcas();
carregarGrid();

})();
</script>
