<?php /* UI de pré-visualização NFC-e (normalizada e validação cruzada) */ ?>
<style>
@media print {
  /* Ocultar cabeçalho/nav/rodapé da aplicação */
  header, nav, footer, .dropdown-menu { display: none !important; }

  /* Ocultar elementos desnecessários da página */
  .page-header, .card h3, .btn, #totalsPanel, #printHint { display: none !important; }

  /* Exibir apenas a seção visual da NFC-e */
  section.card { display: none !important; }
  #visualSection { display: block !important; }

  /* Configurações gerais de impressão */
  body {
    margin: 0;
    padding: 0;
    font-size: 12px;
    line-height: 1.2;
    background: #fff !important;
  }

  /* Container principal da NFC-e */
  #visualOut {
    border: none !important;
    background: white !important;
    padding: 0 !important;
    margin: 0 auto !important;
    max-width: none !important;
    width: 80mm; /* Largura padrão de cupom fiscal */
  }

  /* Ajustes específicos para o cupom */
  #visualOut > div {
    max-width: none !important;
    font-family: 'Courier New', monospace !important;
    font-size: 10px !important;
  }

  /* QR Code na impressão */
  #qrCodeContainer { margin-top: 8px !important; }
  #qrCodeDiv canvas { max-width: 60px !important; max-height: 60px !important; }

  /* Quebra de página após o cupom */
  .card:last-child { page-break-after: always; }
}
</style>
<div class="page-header" style="display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;">
  <div>
    <h1>Prévia NFC-e</h1>
    <p class="muted">Calcular preview com ambiente e comparar motores 2024/2026</p>
  </div>
  <div class="card" style="display:flex;gap:0.5rem;align-items:center;">
    <div class="muted">Ambiente atual:</div>
    <select id="envSelect" class="input" aria-label="Ambiente">
      <option value="homolog">Homologação</option>
      <option value="prod">Produção</option>
    </select>
    <button id="envSave" class="btn btn-secondary">Salvar</button>
  </div>
</div>

<section class="card" aria-labelledby="inputTitle" style="display:flex;flex-direction:column;gap:0.75rem;">
  <h3 id="inputTitle" style="margin:0;">Itens</h3>
  <p class="muted">Preencha os campos dos itens. As validações são em tempo real.</p>
  <div id="itemsContainer" style="display:flex;flex-direction:column;gap:0.75rem;"></div>
  <div style="display:flex;gap:0.5rem;flex-wrap:wrap;">
    <button id="btnAddItem" class="btn btn-secondary" type="button">Adicionar item</button>
    <!-- Botões de preview/cross removidos conforme solicitação: foco na visualização -->
  </div>

  
</section>

<section class="card" id="totalsPanel" aria-labelledby="totalsTitle" style="margin-top:0.75rem;">
  <h3 id="totalsTitle" style="margin:0;">Totais</h3>
  <div style="display:flex; gap:1rem; flex-wrap:wrap; align-items:center;">
    <div><span class="muted">Itens:</span> <strong id="totalsItemsCount">0</strong></div>
    <div><span class="muted">Subtotal:</span> <strong id="totalsSubtotal">R$ 0,00</strong></div>
    <div id="totalsTaxesLegacyBox"><span class="muted">Tributos (estim.):</span> <strong id="totalsTaxes">R$ 0,00</strong></div>
    <div id="totalsIbsBox" style="display:none;"><span class="muted">IBS:</span> <strong id="totalsIBS">R$ 0,00</strong></div>
    <div id="totalsCbsBox" style="display:none;"><span class="muted">CBS:</span> <strong id="totalsCBS">R$ 0,00</strong></div>
    <div id="totalsIsBox" style="display:none;"><span class="muted">IS:</span> <strong id="totalsIS">R$ 0,00</strong></div>
    <div><span class="muted">Desconto:</span> <input id="totalsDiscount" class="input" inputmode="decimal" placeholder="R$ 0,00" style="width:8rem;" title="Desconto em reais" /></div>
    <div><span class="muted">Frete:</span> <input id="totalsFreight" class="input" inputmode="decimal" placeholder="R$ 0,00" style="width:8rem;" title="Frete em reais" /></div>
    <div><span class="muted">Total:</span> <strong id="totalsTotal">R$ 0,00</strong></div>
  </div>
</section>

<!-- Seção de resultados JSON removida conforme solicitação -->

<section class="card" id="visualSection" aria-labelledby="visualTitle" style="margin-top:0.75rem;">
  <div style="display:flex; align-items:center; justify-content:space-between; gap:0.5rem; flex-wrap:wrap;">
    <h3 id="visualTitle" style="margin:0;">Visual NFC-e (Modelo)</h3>
    <div style="display:flex; gap:0.5rem; align-items:center;">
      <button id="btnPrintVisual" class="btn btn-secondary" type="button">Imprimir</button>
    </div>
  </div>
  <div id="visualOut" style="padding:0.75rem; border:1px dashed #cbd5e1; border-radius:6px; background:#fff;"></div>
</section>

<script>
document.addEventListener('DOMContentLoaded', async function(){
  // Dados do emissor
  let emitter = { nome: 'Minha Empresa LTDA', cnpj: '00.000.000/0001-00' };

  // Carregar config fiscal para aplicar ambiente atual
  try {
    const resp = await apiRequest('/api/fiscal/config');
    if (resp && resp.ok) {
      const js = await resp.json();
      const opt = (js && js.data && js.data.options) ? js.data.options : {};
      const env = (opt && typeof opt.environment === 'string') ? opt.environment : 'homolog';
      document.getElementById('envSelect').value = (env === 'prod') ? 'prod' : 'homolog';
    }
  } catch (_) {}

  // Carregar empresa/emissor (último registro)
  try {
    const er = await apiRequest('/api/cadastros/empresas?limit=1');
    if (er && er.ok) {
      const ej = await er.json();
      const row = Array.isArray(ej.data) && ej.data.length ? ej.data[0] : null;
      if (row) {
        emitter.nome = String(row.nome || emitter.nome);
        emitter.cnpj = String(row.cnpj || emitter.cnpj);
        // Garantir campos de endereço
        emitter.logradouro = row.logradouro || '';
        emitter.numero = row.numero || '';
        emitter.complemento = row.complemento || '';
        emitter.bairro = row.bairro || '';
        emitter.cidade = row.cidade || '';
        emitter.estado = row.estado || '';
        emitter.cep = row.cep || '';
      }
    }
  } catch(_) {}
  window.emitter = emitter;

  // Salvar ambiente
  document.getElementById('envSave').addEventListener('click', async () => {
    try {
      showLoading();
      const env = document.getElementById('envSelect').value;
      const cfgResp = await apiRequest('/api/fiscal/config');
      if (!cfgResp || !cfgResp.ok) { showAlert('Falha ao carregar configuração', 'error'); hideLoading(); return; }
      const cfg = await cfgResp.json();
      const current = cfg && cfg.data ? cfg.data : {};
      const mv = current.model_version || '2024';
      const options = Object.assign({}, current.options || {}, { environment: env });
      const putResp = await apiRequest('/api/fiscal/config', { method: 'PUT', body: JSON.stringify({ model_version: mv, options }) });
      hideLoading();
      if (putResp && putResp.ok) { showAlert('Ambiente atualizado'); } else { showAlert('Falha ao atualizar ambiente', 'error'); }
    } catch (e) { hideLoading(); showAlert('Erro ao salvar ambiente', 'error'); }
  });

  // ===== Form de Itens =====
  const itemsContainer = document.getElementById('itemsContainer');

  // Máscaras e formatação
  function formatCurrencyBr(value){
    const n = Number(String(value).replace(',', '.'));
    if (!isFinite(n)) return 'R$ 0,00';
    return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL' }).format(n);
  }
  function formatQuantity(value){
    const n = Number(String(value).replace(',', '.'));
    if (!isFinite(n)) return '0';
    return new Intl.NumberFormat('pt-BR', { minimumFractionDigits: 0, maximumFractionDigits: 3 }).format(n);
  }
  function sanitizeDecimalInput(str){
    return String(str||'').replace(/[^\d,\.]/g, '');
  }
  function parseMoney(str){
    const v = String(str||'').replace(/[^\d,\.\,]/g,'').replace(',','.');
    const n = Number(v);
    return isFinite(n) ? n : 0;
  }
  // Formata CNPJ em máscara brasileira
  function formatCnpj(value){
    const d = String(value||'').replace(/\D/g,'');
    if (d.length !== 14) return '';
    return d.replace(/^(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})$/, '$1.$2.$3/$4-$5');
  }
  function setupMasks(row){
    const idx = parseInt(row.dataset.index||'0',10);
    const get = (n)=> row.querySelector(`[name="items[${idx}][${n}]"]`);
    const q = get('quantidade');
    const p = get('preco');
    if (q){
      q.addEventListener('input', ()=>{ q.value = sanitizeDecimalInput(q.value); validateRow(row); recomputeTotals(); });
      q.addEventListener('blur', ()=>{ q.value = formatQuantity(q.value).replace(/\./g,'').replace(',', '.'); validateRow(row); });
    }
    if (p){
      p.addEventListener('input', ()=>{ p.value = sanitizeDecimalInput(p.value); validateRow(row); recomputeTotals(); });
      p.addEventListener('blur', ()=>{ const n = Number(String(p.value).replace(',', '.')); p.value = isFinite(n) ? String(n.toFixed(2)) : ''; validateRow(row); recomputeTotals(); });
    }
  }

  // Totais
  function recomputeTotals(){
    const rows = Array.from(itemsContainer.children);
    let count = rows.length;
    let subtotal = 0;
    rows.forEach((row, idx)=>{
      const get = (n)=> row.querySelector(`[name="items[${idx}][${n}]"]`);
      const q = Number(String((get('quantidade')?.value||'')).replace(',', '.'));
      const p = Number(String((get('preco')?.value||'')).replace(',', '.'));
      if (isFinite(q) && isFinite(p)) subtotal += (q * p);
    });
    document.getElementById('totalsItemsCount').textContent = String(count);
    document.getElementById('totalsSubtotal').textContent = formatCurrencyBr(subtotal);
    // Atualizar UI de preview via backend
    updatePreviewUI();
  }

  function createItemRow(index){
    const row = document.createElement('div');
    row.className = 'card';
    row.style.display = 'grid';
    row.style.gridTemplateColumns = '2fr 1fr 1fr 1fr 1fr 1fr auto auto';
    row.style.gap = '0.5rem';
    row.dataset.index = String(index);

    row.innerHTML = `
      <input name="items[${index}][descricao]" class="input" placeholder="Descrição" aria-label="Descrição" title="Nome/descrição do item na NFC-e" />
      <input name="items[${index}][quantidade]" class="input" placeholder="Qtd" aria-label="Quantidade" inputmode="decimal" title="Quantidade (até 3 casas decimais)" />
      <input name="items[${index}][preco]" class="input" placeholder="Preço" aria-label="Preço" inputmode="decimal" title="Preço unitário (BRL)" />
      <input name="items[${index}][ncm]" class="input" placeholder="NCM (8 dígitos)" aria-label="NCM" maxlength="8" title="Código NCM com 8 dígitos, somente números" />
      <input name="items[${index}][cfop]" class="input" placeholder="CFOP (4 dígitos)" aria-label="CFOP" maxlength="4" title="CFOP (4 dígitos), conforme operação" />
      <input name="items[${index}][csosn]" class="input" placeholder="CSOSN (3 dígitos)" aria-label="CSOSN" maxlength="3" title="CSOSN do Simples Nacional (3 dígitos), se aplicável" />
      <button type="button" class="btn btn-secondary" data-action="product">Buscar produto</button>
      <button type="button" class="btn btn-secondary" data-action="remove">Remover</button>
      <div class="muted" style="grid-column: 1 / -1; font-size: 0.85em;" data-role="errors"></div>
      <div class="card" data-role="product-search" style="grid-column: 1 / -1; display:none; padding:0.5rem;">
        <div style="display:flex; gap:0.5rem; align-items:center;">
          <input type="text" class="input" placeholder="Buscar por código/EAN/NCM ou nome" aria-label="Buscar produto" data-role="search-input" />
          <button type="button" class="btn btn-secondary" data-action="close-search">Fechar</button>
        </div>
        <div class="muted" style="margin-top:0.5rem;">Resultados:</div>
        <div data-role="search-results" style="display:flex; flex-direction:column; gap:0.25rem; max-height:160px; overflow:auto;"></div>
      </div>
    `;

    // Eventos de validação em tempo real
    const inputs = row.querySelectorAll('input');
    inputs.forEach(inp => {
      inp.addEventListener('input', () => validateRow(row));
      inp.addEventListener('blur', () => validateRow(row));
    });

    // Remoção
    const btnRemove = row.querySelector('[data-action="remove"]');
    btnRemove.addEventListener('click', () => {
      itemsContainer.removeChild(row);
      renumberRows();
      recomputeTotals();
    });

    // Buscar produto
    const btnProd = row.querySelector('[data-action="product"]');
    const searchBox = row.querySelector('[data-role="product-search"]');
    const closeSearch = row.querySelector('[data-action="close-search"]');
    const searchInput = row.querySelector('[data-role="search-input"]');
    const resultsBox = row.querySelector('[data-role="search-results"]');
    btnProd.addEventListener('click', ()=>{ searchBox.style.display = 'block'; searchInput.focus(); });
    closeSearch.addEventListener('click', ()=>{ searchBox.style.display = 'none'; resultsBox.innerHTML = ''; });

    let debounceT;
    async function queryProducts(q){
      try{
        const resp = await apiRequest(`/api/produtos?q=${encodeURIComponent(q)}&per_page=5`);
        if (!resp || !resp.ok) { resultsBox.innerHTML = '<div class="muted">Erro na busca</div>'; return; }
        const js = await resp.json();
        const list = js.data || [];
        resultsBox.innerHTML = '';
        if (!Array.isArray(list) || list.length===0){ resultsBox.innerHTML = '<div class="muted">Nenhum resultado</div>'; return; }
        list.forEach(item => {
          const btn = document.createElement('button');
          btn.type = 'button';
          btn.className = 'btn btn-secondary';
          let nome = '';
          try{
            if (item.meta_json){ const m = JSON.parse(String(item.meta_json)); nome = String(m.nome||m.name||m.title||''); item.__meta = m; }
          }catch(_){ }
          btn.textContent = `${nome||item.codigo||('ID '+item.id)} • NCM: ${item.ncm||'-'} • CFOP: ${item.cfop||'-'} • Preço: ${typeof item.preco==='number'? formatCurrencyBr(item.preco): '-'}`;
          btn.addEventListener('click', ()=>{
            applyProductToRow(row, item);
            searchBox.style.display = 'none';
            resultsBox.innerHTML = '';
          });
          resultsBox.appendChild(btn);
        });
      }catch(_){ resultsBox.innerHTML = '<div class="muted">Erro inesperado</div>'; }
    }
    searchInput.addEventListener('input', ()=>{
      const q = String(searchInput.value||'').trim();
      clearTimeout(debounceT);
      if (!q){ resultsBox.innerHTML = ''; return; }
      debounceT = setTimeout(()=> queryProducts(q), 250);
    });

    setupMasks(row);
    return row;
  }

  function renumberRows(){
    const rows = Array.from(itemsContainer.children);
    rows.forEach((row, idx) => {
      row.dataset.index = String(idx);
      const names = [ 'descricao','quantidade','preco','ncm','cfop','csosn' ];
      names.forEach(n => {
        const input = row.querySelector(`[name^="items"][name$="[${n}]"]`);
        if (input) input.name = `items[${idx}][${n}]`;
      });
    });
  }

  function validateRow(row){
    const idx = parseInt(row.dataset.index || '0', 10);
    const get = (n) => row.querySelector(`[name="items[${idx}][${n}]"]`);
    const errors = [];
    const addError = (msg) => errors.push(msg);

    const descricao = (get('descricao').value || '').trim();
    const quantidade = (get('quantidade').value || '').trim();
    const preco = (get('preco').value || '').trim();
    const ncm = (get('ncm').value || '').trim();
    const cfop = (get('cfop').value || '').trim();
    const csosn = (get('csosn').value || '').trim();

    if (!descricao) addError('Descrição é obrigatória');
    const qNum = Number(quantidade.replace(',', '.'));
    if (!quantidade || !(qNum > 0)) addError('Quantidade deve ser maior que 0');
    const pNum = Number(preco.replace(',', '.'));
    if (preco === '' || !(pNum >= 0)) addError('Preço deve ser 0 ou maior');
    if (ncm && !/^\d{8}$/.test(ncm)) addError('NCM deve ter 8 dígitos');
    if (cfop && !/^\d{4}$/.test(cfop)) addError('CFOP deve ter 4 dígitos');
    if (csosn && !/^\d{3}$/.test(csosn)) addError('CSOSN deve ter 3 dígitos');

    const errBox = row.querySelector('[data-role="errors"]');
    if (errors.length) {
      errBox.textContent = errors.join(' • ');
      errBox.className = 'alert-error';
      return false;
    } else {
      errBox.textContent = '';
      errBox.className = 'muted';
      return true;
    }
  }

  function applyProductToRow(row, prod){
    const idx = parseInt(row.dataset.index||'0',10);
    const get = (n)=> row.querySelector(`[name="items[${idx}][${n}]"]`);
    let nome = '';
    try{
      const m = prod.__meta || (prod.meta_json ? JSON.parse(String(prod.meta_json)) : null);
      if (m){ nome = String(m.nome||m.name||m.title||''); const csosn = (m.csosn||'').replace(/\D/g,''); if (csosn) get('csosn').value = csosn; }
    }catch(_){ }
    get('descricao').value = nome || prod.descricao || prod.codigo || `Produto #${prod.id}`;
    if (prod.preco!=null) get('preco').value = String(Number(prod.preco).toFixed(2));
    if (prod.ncm) get('ncm').value = String(prod.ncm).replace(/\D/g,'').slice(0,8);
    if (prod.cfop) get('cfop').value = String(prod.cfop).replace(/\D/g,'').slice(0,4);
    validateRow(row);
    recomputeTotals();
  }

  function addItem(initial){
    const idx = itemsContainer.children.length;
    const row = createItemRow(idx);
    itemsContainer.appendChild(row);
    if (initial) {
      const get = (n) => row.querySelector(`[name="items[${idx}][${n}]"]`);
      get('descricao').value = initial.descricao || '';
      get('quantidade').value = initial.quantidade != null ? String(initial.quantidade) : '';
      get('preco').value = initial.preco != null ? String(initial.preco) : '';
      get('ncm').value = initial.ncm || '';
      get('cfop').value = initial.cfop || '';
      get('csosn').value = initial.csosn || '';
    }
    validateRow(row);
    recomputeTotals();
  }

  function collectFormData(){
    const fd = new FormData();
    const rows = Array.from(itemsContainer.children);
    if (!rows.length) {
      addItem({ descricao: 'Item de teste', quantidade: 1, preco: 10.00, ncm: '00000000', cfop: '5102', csosn: '102' });
    }
    let allValid = true;
    rows.forEach((row, idx) => {
      const ok = validateRow(row);
      if (!ok) allValid = false;
      const get = (n) => row.querySelector(`[name="items[${idx}][${n}]"]`);
      const qNum = Number((get('quantidade').value || '').replace(',', '.'));
      const pNum = Number((get('preco').value || '').replace(',', '.'));
      fd.append(`items[${idx}][descricao]`, (get('descricao').value || '').trim());
      fd.append(`items[${idx}][quantidade]`, isFinite(qNum) ? String(qNum) : '');
      fd.append(`items[${idx}][preco]`, isFinite(pNum) ? String(pNum) : '');
      fd.append(`items[${idx}][ncm]`, (get('ncm').value || '').trim());
      fd.append(`items[${idx}][cfop]`, (get('cfop').value || '').trim());
      fd.append(`items[${idx}][csosn]`, (get('csosn').value || '').trim());
    });
    return { fd, allValid };
  }

  // Botões
  document.getElementById('btnAddItem').addEventListener('click', () => addItem());

  // Carregar com um item padrão
  addItem({ descricao: 'Item de teste', quantidade: 1, preco: 10.00, ncm: '00000000', cfop: '5102', csosn: '102' });
  recomputeTotals();

  // Visual NFC-e (modelo)
  function collectItemsForVisual(){
    const rows = Array.from(itemsContainer.children);
    const items = rows.map((row, idx)=>{
      const get = (n)=> row.querySelector(`[name="items[${idx}][${n}]"]`);
      const descricao = String(get('descricao')?.value||'').trim();
      const quantidade = Number(String(get('quantidade')?.value||'').replace(',', '.'))||0;
      const preco = Number(String(get('preco')?.value||'').replace(',', '.'))||0;
      return { descricao, quantidade, preco, subtotal: quantidade*preco };
    });
    return items;
  }
  function renderNfceVisual(){
    const env = document.getElementById('envSelect')?.value === 'prod' ? 'Produção' : 'Homologação';
    const itemsLocal = collectItemsForVisual();
    const qtd = itemsLocal.length;
    const desconto = parseMoney(document.getElementById('totalsDiscount')?.value||'');
    const frete = parseMoney(document.getElementById('totalsFreight')?.value||'');
    const pv = window.lastPreview || null;
    let subtotal = itemsLocal.reduce((acc, it)=> acc + (it.subtotal||0), 0);
    let taxesLegacy = 0;
    let ibsT = 0, cbsT = 0, isT = 0, totalPreview = 0;
    let mv = '2024';
    if (pv && typeof pv === 'object') {
      mv = String(pv.model_version||'2024');
      if (mv === '2026') {
        subtotal = Number(pv.subtotal||0);
        ibsT = Number(pv.ibs_total||0);
        cbsT = Number(pv.cbs_total||0);
        isT  = Number(pv.is_total||0);
        totalPreview = Number(pv.total||subtotal + ibsT + cbsT + isT);
      } else {
        const t = pv.totals||{};
        subtotal = Number(t.subtotal||subtotal||0);
        taxesLegacy = Number(t.impostos||0);
        totalPreview = Number(t.total||subtotal - Number(t.desconto||0));
      }
    }
    const total = Math.max(0, (totalPreview||subtotal + taxesLegacy) - desconto + frete);
    const now = new Date();
    const fmtDate = new Intl.DateTimeFormat('pt-BR', { dateStyle: 'short', timeStyle: 'short' }).format(now);
    const html = [
      `<div style="max-width:420px; margin:0; font-family: ui-sans-serif, system-ui, -apple-system;">`,
      `<div style="text-align:center; border-bottom:1px solid #e5e7eb; padding-bottom:6px;">`,
      `<div style="font-weight:600;">${escapeHtml(emitter.nome||'Minha Empresa LTDA')}</div>`,
      `<div class="muted" style="font-size:0.9em;">CNPJ ${escapeHtml(formatCnpj(emitter.cnpj)||'00.000.000/0001-00')} • ${env}</div>`,
      emitter.logradouro ? `<div class="muted" style="font-size:0.8em;">${escapeHtml([emitter.logradouro, emitter.numero].filter(Boolean).join(', '))}</div>` : '',
      (emitter.bairro || emitter.cidade) ? `<div class="muted" style="font-size:0.8em;">${escapeHtml([emitter.bairro, emitter.cidade, emitter.estado].filter(Boolean).join(' - '))}</div>` : '',
      emitter.cep ? `<div class="muted" style="font-size:0.8em;">CEP ${escapeHtml(emitter.cep)}</div>` : '',
      `<div class="muted" style="font-size:0.9em;">${fmtDate}</div>`,
      `</div>`,
      `<div style="padding:6px 0; border-bottom:1px dashed #e5e7eb;">`,
      `<div style="display:flex; font-weight:600;">`,
      `<div style="flex:2">Item</div><div style="flex:1;text-align:right">Qtd</div><div style="flex:1;text-align:right">Unit</div><div style="flex:1;text-align:right">Subt</div>`,
      `</div>`,
      itemsLocal.map(it=> {
        return `<div style="display:flex; padding:2px 0;">`
          + `<div style="flex:2;">${escapeHtml(it.descricao||'Item')}</div>`
          + `<div style="flex:1; text-align:right;">${formatQuantity(it.quantidade)}</div>`
          + `<div style="flex:1; text-align:right;">${formatCurrencyBr(it.preco)}</div>`
          + `<div style="flex:1; text-align:right;">${formatCurrencyBr(it.subtotal)}</div>`
          + `</div>`;
      }).join('') || `<div class="muted">Nenhum item</div>`,
      `</div>`,
      `<div style="padding-top:6px;">`,
      `<div class="muted">Itens: ${qtd}</div>`,
      `<div style="display:flex; flex-direction:column; gap:2px; margin-top:4px;">`,
      `<div style="display:flex; justify-content:space-between;"><span>Subtotal</span><span>${formatCurrencyBr(subtotal)}</span></div>`,
      `<div style="display:flex; justify-content:space-between;"><span>Desconto</span><span>${formatCurrencyBr(desconto)}</span></div>`,
      `<div style="display:flex; justify-content:space-between;"><span>Frete</span><span>${formatCurrencyBr(frete)}</span></div>`,
      (mv === '2026'
        ? [`<div style=\"display:flex; justify-content:space-between;\"><span>IBS</span><span>${formatCurrencyBr(ibsT)}</span></div>`,
           `<div style=\"display:flex; justify-content:space-between;\"><span>CBS</span><span>${formatCurrencyBr(cbsT)}</span></div>`,
           `<div style=\"display:flex; justify-content:space-between;\"><span>IS</span><span>${formatCurrencyBr(isT)}</span></div>`].join('')
        : `<div style=\"display:flex; justify-content:space-between;\"><span>Tributos (estim.)</span><span>${formatCurrencyBr(taxesLegacy)}</span></div>`
      ),
      `<div style="display:flex; justify-content:space-between; font-weight:600;"><span>Total</span><span>${formatCurrencyBr(total)}</span></div>`,
      `</div>`,
      `</div>`,
      `<div id="printHint" class="muted" style="margin-top:8px; font-size:0.85em;">Modelo ilustrativo. Não substitui documento fiscal.</div>`,
      `<div id="qrCodeContainer" style="margin-top:12px; text-align:center;">`,
      `<div class="muted" style="font-size:0.8em; margin-bottom:4px;">Chave de Acesso NFC-e</div>`,
      `<div id="qrCodeDiv" style="display:inline-block;"></div>`,
      `<div id="chaveText" style="font-size:0.7em; margin-top:4px; word-break:break-all; color:#666;"></div>`,
      `<div style="margin-top:6px;"><button id="btnCopyChave" class="btn btn-secondary" type="button">Copiar chave</button></div>`,
      `</div>`,
      `</div>`
    ].join('');
    const box = document.getElementById('visualOut');
    if (box) box.innerHTML = html;
    // Bind copiar chave
    const copyBtn = document.getElementById('btnCopyChave');
    if (copyBtn) {
      copyBtn.addEventListener('click', async ()=>{
        const chave = (window.lastNfceKey||'') || (document.getElementById('chaveText')?.textContent||'').replace(/\s+/g,'');
        try {
          await navigator.clipboard.writeText(chave);
          if (typeof showAlert === 'function') showAlert('Chave copiada para a área de transferência');
        } catch (_) {
          try {
            const ta = document.createElement('textarea');
            ta.value = chave;
            document.body.appendChild(ta);
            ta.select();
            document.execCommand('copy');
            document.body.removeChild(ta);
            if (typeof showAlert === 'function') showAlert('Chave copiada');
          } catch(__){ if (typeof showAlert === 'function') showAlert('Falha ao copiar chave', 'error'); }
        }
      });
    }
    
    // Gerar QR Code com chave NFC-e
    generateNfceQrCode();
  }
  function escapeHtml(str){
    return String(str).replace(/[&<>"']/g, s=>({"&":"&amp;","<":"&lt;",">":"&gt;","\"":"&quot;","'":"&#39;"}[s]));
  }
  renderNfceVisual();

  // Removido toggle JSON: foco no espelho visual

  // Imprimir
  document.getElementById('btnPrintVisual').addEventListener('click', ()=>{
  try { PrintControl.safePrint({ copies: 1 }); } catch(_){ try{ window.print(); }catch(__){} }
  });

  // Inputs de desconto/frete
  const disc = document.getElementById('totalsDiscount');
  const frt = document.getElementById('totalsFreight');
  if (disc){
    disc.addEventListener('input', ()=>{ disc.value = sanitizeDecimalInput(disc.value); recomputeTotals(); });
    disc.addEventListener('blur', ()=>{ const n = parseMoney(disc.value); disc.value = String(n.toFixed(2)); recomputeTotals(); });
  }
  if (frt){
    frt.addEventListener('input', ()=>{ frt.value = sanitizeDecimalInput(frt.value); recomputeTotals(); });
    frt.addEventListener('blur', ()=>{ const n = parseMoney(frt.value); frt.value = String(n.toFixed(2)); recomputeTotals(); });
  }

  // Gerar QR Code NFC-e
  async function generateNfceQrCode() {
    try {
      // Gerar chave NFC-e mock usando o serviço existente
      const emitterData = window.emitter || {};
      const cnpj = emitterData.cnpj || '99999999000191';
      
      // Simular geração de chave (baseado no NfceService::generateChaveMockRJ)
      const uf = '33'; // RJ
      const data = new Date().toISOString().slice(2,7).replace('-',''); // AAMM
      const cnpjClean = cnpj.replace(/\D/g, '').padStart(14, '0');
      const model = '65';
      const serie = '001';
      const numero = String(Math.floor(Math.random() * 999999999)).padStart(9, '0');
      const tipoEmis = '1';
      const codigo = String(Math.floor(Math.random() * 99999999)).padStart(8, '0');
      const base = uf + data + cnpjClean + model + serie + numero + tipoEmis + codigo;
      
      // DV módulo 11 simplificado (mock)
      let soma = 0;
      let peso = 2;
      for (let i = base.length - 1; i >= 0; i--) {
        soma += parseInt(base[i]) * peso;
        peso = peso === 9 ? 2 : peso + 1;
      }
      const dv = ((soma % 11) < 2) ? 0 : (11 - (soma % 11));
      const chave = base + dv;
      window.lastNfceKey = chave;
      
      // Exibir chave
      const chaveText = document.getElementById('chaveText');
      if (chaveText) {
        chaveText.textContent = chave.replace(/(.{4})/g, '$1 ').trim();
      }
      
      // Gerar QR Code usando qrcode.js via CDN
      const qrDiv = document.getElementById('qrCodeDiv');
      if (qrDiv && window.QRCode) {
        qrDiv.innerHTML = ''; // Limpar QR anterior
        new QRCode(qrDiv, {
          text: chave,
          width: 120,
          height: 120,
          colorDark: '#000000',
          colorLight: '#ffffff',
          correctLevel: QRCode.CorrectLevel.M
        });
      } else if (qrDiv) {
        qrDiv.innerHTML = '<div style="width:120px;height:120px;border:1px dashed #ccc;display:flex;align-items:center;justify-content:center;font-size:0.7em;color:#999;">QR Code</div>';
      }
    } catch (error) {
      console.error('Erro ao gerar QR Code NFC-e:', error);
    }
  }

  // Preview JSON e comparação removidos: manter cálculo local no visual
  
  // ===== Integração com /api/fiscal/nfce/preview =====
  function collectItemsForApi(){
    const rows = Array.from(itemsContainer.children);
    return rows.map((row, idx)=>{
      const get = (n)=> row.querySelector(`[name="items[${idx}][${n}]"]`);
      return {
        descricao: String(get('descricao')?.value||'').trim() || 'Item',
        quantidade: Number(String(get('quantidade')?.value||'').replace(',', '.')) || 0,
        preco: Number(String(get('preco')?.value||'').replace(',', '.')) || 0,
        ncm: String(get('ncm')?.value||'').replace(/\D/g,'').slice(0,8),
        cfop: String(get('cfop')?.value||'').replace(/\D/g,'').slice(0,4),
        csosn: String(get('csosn')?.value||'').replace(/\D/g,'').slice(0,3)
      };
    });
  }
  async function updatePreviewUI(){
    try{
      const items = collectItemsForApi();
      const resp = await apiRequest('/api/fiscal/nfce/preview', { method: 'POST', body: JSON.stringify({ items }) });
      if (!resp || !resp.ok) { throw new Error('Falha no preview'); }
      const js = await resp.json();
      const pv = js.preview || {};
      window.lastPreview = pv;
      const mv = String(pv.model_version||'2024');
      const desconto = parseMoney(document.getElementById('totalsDiscount')?.value||'');
      const frete = parseMoney(document.getElementById('totalsFreight')?.value||'');
      // Atualizar contadores
      const itemsCount = Array.isArray(pv.items) ? pv.items.length : items.length;
      document.getElementById('totalsItemsCount').textContent = String(itemsCount);
      // Atualizar totais por versão
      if (mv === '2026'){
        const subtotal = Number(pv.subtotal||0);
        const ibsT = Number(pv.ibs_total||0);
        const cbsT = Number(pv.cbs_total||0);
        const isT  = Number(pv.is_total||0);
        const totalPrev = Number(pv.total||subtotal + ibsT + cbsT + isT);
        document.getElementById('totalsSubtotal').textContent = formatCurrencyBr(subtotal);
        // Mostrar IBS/CBS/IS e ocultar legado
        document.getElementById('totalsIbsBox').style.display = '';
        document.getElementById('totalsCbsBox').style.display = '';
        document.getElementById('totalsIsBox').style.display = '';
        document.getElementById('totalsTaxesLegacyBox').style.display = 'none';
        document.getElementById('totalsIBS').textContent = formatCurrencyBr(ibsT);
        document.getElementById('totalsCBS').textContent = formatCurrencyBr(cbsT);
        document.getElementById('totalsIS').textContent = formatCurrencyBr(isT);
        const totalUi = Math.max(0, totalPrev - desconto + frete);
        document.getElementById('totalsTotal').textContent = formatCurrencyBr(totalUi);
      } else {
        const t = pv.totals || {};
        const subtotal = Number(t.subtotal||0);
        const impostos = Number(t.impostos||0);
        const totalPrev = Number(t.total||subtotal - Number(t.desconto||0));
        document.getElementById('totalsSubtotal').textContent = formatCurrencyBr(subtotal);
        // Ocultar IBS/CBS/IS e mostrar legado
        document.getElementById('totalsIbsBox').style.display = 'none';
        document.getElementById('totalsCbsBox').style.display = 'none';
        document.getElementById('totalsIsBox').style.display = 'none';
        document.getElementById('totalsTaxesLegacyBox').style.display = '';
        document.getElementById('totalsTaxes').textContent = formatCurrencyBr(impostos);
        const totalUi = Math.max(0, totalPrev - desconto + frete);
        document.getElementById('totalsTotal').textContent = formatCurrencyBr(totalUi);
      }
      // Re-render visual do cupom com base no preview
      renderNfceVisual();
    } catch(_){
      // Fallback: manter visual local
      renderNfceVisual();
    }
  }
});
</script>

<!-- QR Code Library (real implementation) -->
<script src="/js/qrcode.min.js"></script>
<script src="/js/qrcode-wrapper.js"></script>