<?php /* Página de Relatórios Financeiros */ ?>
<div class="page-header">
  <h1>Relatórios Financeiros</h1>
  <p class="muted">Gere relatórios detalhados sobre a situação financeira</p>
</div>

<!-- Filtros Gerais -->
<section class="card">
  <h3>Filtros</h3>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1rem;">
    <div class="form-group">
      <label for="dataInicio">Data Início</label>
      <input type="date" id="dataInicio" class="input" />
    </div>
    <div class="form-group">
      <label for="dataFim">Data Fim</label>
      <input type="date" id="dataFim" class="input" />
    </div>
    <div class="form-group">
      <label for="contaId">Conta Bancária</label>
      <select id="contaId" class="input">
        <option value="">Todas</option>
      </select>
    </div>
    <div class="form-group">
      <label for="tipoRelatorio">Tipo de Relatório</label>
      <select id="tipoRelatorio" class="input">
        <option value="geral">Relatório Geral</option>
        <option value="contas_pagar">Contas a Pagar</option>
        <option value="contas_receber">Contas a Receber</option>
        <option value="fluxo_caixa">Fluxo de Caixa</option>
        <option value="dre">DRE Simplificado</option>
        <option value="dre_completo">DRE Completo</option>
      </select>
    </div>
    <div class="form-group">
      <label for="csvSep">Separador CSV</label>
      <select id="csvSep" class="input">
        <option value=";">Ponto e vírgula (;)</option>
        <option value=",">Vírgula (,)</option>
        <option value="tab">Tabulação (\t)</option>
        <option value="|">Pipe (|)</option>
      </select>
    </div>
    <div style="display:flex;align-items:end;gap:0.5rem;">
      <button id="btnGerar" class="btn btn-primary">Gerar Relatório</button>
      <button id="btnExportar" class="btn btn-success">Exportar PDF</button>
      <button id="btnExportarCsv" class="btn">Exportar CSV</button>
    </div>
  </div>
</section>

<!-- Relatório Geral -->
<section id="relatorioGeral" class="card">
  <h3>Resumo Financeiro</h3>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:1rem;margin-bottom:2rem;">
    <div class="stat-card success">
      <h4>Total a Receber</h4>
      <p id="totalReceber">R$ 0,00</p>
      <small id="contasReceber">0 contas</small>
    </div>
    <div class="stat-card danger">
      <h4>Total a Pagar</h4>
      <p id="totalPagar">R$ 0,00</p>
      <small id="contasPagar">0 contas</small>
    </div>
    <div class="stat-card info">
      <h4>Saldo Projetado</h4>
      <p id="saldoProjetado">R$ 0,00</p>
    </div>
    <div class="stat-card warning">
      <h4>Contas Vencidas</h4>
      <p id="contasVencidas">0</p>
      <small>Requer atenção</small>
    </div>
  </div>
</section>

<!-- DRE Simplificado -->
<section id="relatorioDre" class="card" style="display:none;">
  <h3>DRE Simplificado</h3>
  <p class="muted">Período: <span id="drePeriodo"></span></p>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1rem;align-items:start;">
    <div>
      <table class="table" id="dreTable">
        <thead>
          <tr><th>Conta</th><th style="text-align:right;">Valor</th></tr>
        </thead>
        <tbody>
          <tr><td>Receita Bruta</td><td id="dreReceitaBruta" style="text-align:right;">–</td></tr>
          <tr><td>Deduções/Impostos</td><td id="dreDeducoes" style="text-align:right;">–</td></tr>
          <tr><td><strong>Receita Líquida</strong></td><td id="dreReceitaLiquida" style="text-align:right;"><strong>–</strong></td></tr>
          <tr><td>Custo dos Produtos/Serviços</td><td id="dreCusto" style="text-align:right;">–</td></tr>
          <tr><td><strong>Lucro Bruto</strong></td><td id="dreLucroBruto" style="text-align:right;"><strong>–</strong></td></tr>
          <tr><td>Despesas Operacionais</td><td id="dreDespesasOp" style="text-align:right;">–</td></tr>
          <tr><td>Despesas Não Operacionais</td><td id="dreDespesasNaoOp" style="text-align:right;">–</td></tr>
          <tr><td><strong>Resultado Antes dos Impostos</strong></td><td id="dreResultadoAntesImp" style="text-align:right;"><strong>–</strong></td></tr>
          <tr><td>Impostos</td><td id="dreImpostos" style="text-align:right;">–</td></tr>
          <tr><td><strong>Resultado Líquido</strong></td><td id="dreResultadoLiquido" style="text-align:right;"><strong>–</strong></td></tr>
        </tbody>
      </table>
    </div>
    <div>
      <h4>Visualização</h4>
      <div id="dreChart" style="height:220px;display:flex;align-items:flex-end;gap:.5rem;border-bottom:1px solid #eee;padding-bottom:.5rem;">
        <!-- Barras renderizadas via JS -->
      </div>
      <div id="dreChartLegend" class="muted" style="margin-top:.5rem;font-size:.9em;"></div>
      <div style="margin-top:.75rem;display:flex;gap:.5rem;flex-wrap:wrap;">
        <button id="btnDrePng" class="btn">Exportar PNG</button>
      </div>
    </div>
  </div>
  <div class="chip" id="dreNotes" style="margin-top: .5rem;">
    Observação: cálculo por melhor esforço com base nas tabelas disponíveis (contas a receber/pagar, movimentações bancárias).
  </div>
</section>

<!-- DRE Completo -->
<section id="relatorioDreCompleto" class="card" style="display:none;">
  <h3>DRE Completo</h3>
  <p class="muted">Período: <span id="dreCompPeriodo"></span></p>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1rem;align-items:start;">
    <div>
      <table class="table" id="dreCompTable">
        <thead>
          <tr><th>Conta</th><th style="text-align:right;">Valor</th></tr>
        </thead>
        <tbody>
          <tr><td>Receita Bruta</td><td id="dreCompReceitaBruta" style="text-align:right;">–</td></tr>
          <tr><td>Deduções</td><td id="dreCompDeducoes" style="text-align:right;">–</td></tr>
          <tr><td><strong>Receita Líquida</strong></td><td id="dreCompReceitaLiquida" style="text-align:right;"><strong>–</strong></td></tr>
          <tr><td>Custo dos Produtos/Serviços</td><td id="dreCompCusto" style="text-align:right;">–</td></tr>
          <tr><td><strong>Lucro Bruto</strong></td><td id="dreCompLucroBruto" style="text-align:right;"><strong>–</strong></td></tr>
          <tr><td>Despesas Operacionais</td><td id="dreCompDespesasOp" style="text-align:right;">–</td></tr>
          <tr><td>Despesas Não Operacionais</td><td id="dreCompDespesasNaoOp" style="text-align:right;">–</td></tr>
          <tr><td><strong>Resultado Antes dos Impostos</strong></td><td id="dreCompResultadoAntesImp" style="text-align:right;"><strong>–</strong></td></tr>
          <tr><td><strong>Impostos (Total)</strong></td><td id="dreCompImpostosTotal" style="text-align:right;"><strong>–</strong></td></tr>
          <tr><td><strong>Resultado Líquido</strong></td><td id="dreCompResultadoLiquido" style="text-align:right;"><strong>–</strong></td></tr>
        </tbody>
      </table>
      <h4 style="margin-top:.75rem;">Detalhe de Impostos</h4>
      <table class="table" id="dreCompImpTable">
        <thead><tr><th>Imposto</th><th style="text-align:right;">Valor</th></tr></thead>
        <tbody>
          <tr><td>ICMS</td><td id="impIcms" style="text-align:right;">–</td></tr>
          <tr><td>PIS</td><td id="impPis" style="text-align:right;">–</td></tr>
          <tr><td>COFINS</td><td id="impCofins" style="text-align:right;">–</td></tr>
          <tr><td>ISS</td><td id="impIss" style="text-align:right;">–</td></tr>
          <tr><td>IPI</td><td id="impIpi" style="text-align:right;">–</td></tr>
          <tr><td>IRPJ</td><td id="impIrpj" style="text-align:right;">–</td></tr>
          <tr><td>CSLL</td><td id="impCsll" style="text-align:right;">–</td></tr>
          <tr><td>IBS</td><td id="impIbs" style="text-align:right;">–</td></tr>
          <tr><td>CBS</td><td id="impCbs" style="text-align:right;">–</td></tr>
          <tr><td>IS</td><td id="impIs" style="text-align:right;">–</td></tr>
        </tbody>
      </table>
    </div>
    <div>
      <h4>Análise Visual</h4>
      <div id="dreCompChart" style="height:220px;display:flex;align-items:flex-end;gap:.5rem;border-bottom:1px solid #eee;padding-bottom:.5rem;"></div>
      <div id="dreCompChartLegend" class="muted" style="margin-top:.5rem;font-size:.9em;"></div>
      <div style="margin-top:.75rem;display:flex;gap:.5rem;flex-wrap:wrap;">
        <button id="btnDreCompCsv" class="btn">Exportar CSV</button>
        <button id="btnDreCompPrint" class="btn">Imprimir / PDF</button>
      </div>
    </div>
  </div>
</section>

<!-- Fluxo de Caixa -->
<section id="relatorioFluxo" class="card" style="display:none;">
  <h3>Fluxo de Caixa</h3>
  <p class="muted">Entradas e saídas por período. Use os filtros acima.</p>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem;">
    <div class="stat-card success"><h4>Entradas</h4><p id="fluxoTotalEntradas">R$ 0,00</p></div>
    <div class="stat-card danger"><h4>Saídas</h4><p id="fluxoTotalSaidas">R$ 0,00</p></div>
    <div class="stat-card info"><h4>Saldo no período</h4><p id="fluxoSaldoPeriodo">R$ 0,00</p></div>
  </div>
  <h4 style="margin-top:1rem;">Série diária</h4>
  <div id="fluxoChart" style="height:220px;display:flex;align-items:flex-end;gap:.25rem;border-bottom:1px solid #eee;padding-bottom:.5rem;overflow-x:auto;"></div>
  <div id="fluxoLegend" class="muted" style="margin-top:.5rem;font-size:.9em;"></div>
  <div style="margin-top:.75rem;display:flex;gap:.5rem;flex-wrap:wrap;">
    <button id="btnFluxoCsv" class="btn">Exportar CSV</button>
    <button id="btnFluxoPrint" class="btn">Imprimir / PDF</button>
    <button id="btnFluxoPng" class="btn">Exportar PNG</button>
  </div>
</section>

<!-- Contas a Receber (Resumo) -->
<section id="relatorioReceber" class="card" style="display:none;">
  <h3>Contas a Receber (Resumo)</h3>
  <p class="muted">Totais e série diária no período selecionado.</p>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem;">
    <div class="stat-card warning"><h4>Pendentes</h4><p id="recTotalPendentes">R$ 0,00</p><small id="recDueTodayCount" class="muted">Vencem hoje: 0</small></div>
    <div class="stat-card danger"><h4>Vencidos</h4><p id="recTotalVencidos">R$ 0,00</p><small id="recOverdueCount" class="muted">Vencidos: 0</small></div>
    <div class="stat-card success"><h4>Recebidos</h4><p id="recTotalRecebidos">R$ 0,00</p></div>
    <div class="stat-card info"><h4>Total Geral</h4><p id="recTotalGeral">R$ 0,00</p></div>
  </div>
  <h4 style="margin-top:1rem;">Série diária</h4>
  <div id="recChart" style="height:220px;display:flex;align-items:flex-end;gap:.25rem;border-bottom:1px solid #eee;padding-bottom:.5rem;overflow-x:auto;"></div>
  <div id="recLegend" class="muted" style="margin-top:.5rem;font-size:.9em;"></div>
  <div style="margin-top:.75rem;display:flex;gap:.5rem;flex-wrap:wrap;">
    <button id="btnRecCsv" class="btn">Exportar CSV</button>
    <button id="btnRecPrint" class="btn">Imprimir / PDF</button>
    <button id="btnRecPng" class="btn">Exportar PNG</button>
  </div>
 </section>

<!-- Contas a Pagar (Resumo) -->
<section id="relatorioPagar" class="card" style="display:none;">
  <h3>Contas a Pagar (Resumo)</h3>
  <p class="muted">Totais e série diária no período selecionado.</p>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:1rem;">
    <div class="stat-card warning"><h4>Pendentes</h4><p id="payTotalPendentes">R$ 0,00</p><small id="payDueTodayCount" class="muted">Vencem hoje: 0</small></div>
    <div class="stat-card danger"><h4>Vencidos</h4><p id="payTotalVencidos">R$ 0,00</p><small id="payOverdueCount" class="muted">Vencidos: 0</small></div>
    <div class="stat-card success"><h4>Pagos</h4><p id="payTotalPagos">R$ 0,00</p></div>
    <div class="stat-card info"><h4>Total Geral</h4><p id="payTotalGeral">R$ 0,00</p></div>
  </div>
  <h4 style="margin-top:1rem;">Série diária</h4>
  <div id="payChart" style="height:220px;display:flex;align-items:flex-end;gap:.25rem;border-bottom:1px solid #eee;padding-bottom:.5rem;overflow-x:auto;"></div>
  <div id="payLegend" class="muted" style="margin-top:.5rem;font-size:.9em;"></div>
  <div style="margin-top:.75rem;display:flex;gap:.5rem;flex-wrap:wrap;">
    <button id="btnPayCsv" class="btn">Exportar CSV</button>
    <button id="btnPayPrint" class="btn">Imprimir / PDF</button>
    <button id="btnPayPng" class="btn">Exportar PNG</button>
  </div>
 </section>

<script>
function fmtBRL(v){ try { return (new Intl.NumberFormat('pt-BR',{style:'currency',currency:'BRL'})).format(Number(v)); } catch(e){ return 'R$ '+Number(v).toFixed(2); } }
async function apiRequest(url, options){
  const opts=options||{}; const headers=opts.headers||{};
  if(!(opts.body instanceof FormData)) headers['Content-Type']=headers['Content-Type']||'application/json';
  // Se não há Authorization explícito, tenta usar token do cookie (dev)
  if(!headers['Authorization']){
    const tok = (function(){
      try {
        const m = document.cookie.match(/(?:^|; )auth_token_js=([^;]+)/);
        return m ? decodeURIComponent(m[1]) : '';
      } catch(e){ return ''; }
    })();
    if(tok) headers['Authorization'] = 'Bearer ' + tok;
  }
  const resp = await fetch(url,{...opts, headers, credentials:'include'});
  if(resp.status === 401){
    alert('Sessão expirada ou sem permissão (financeiro.read). Faça login novamente.');
    try { window.location.href = '/login'; } catch(e){}
  }
  return resp;
}

function getPeriodo(){
  let s=document.getElementById('dataInicio').value || '';
  let e=document.getElementById('dataFim').value || '';
  const norm = (v)=>{
    if(!v) return v;
    // Aceita DD-MM-YYYY ou DD/MM/YYYY e converte para YYYY-MM-DD
    const m = v.match(/^([0-3]?\d)[-/]([0-1]?\d)[-/](\d{4})$/);
    if(m){ const dd=m[1].padStart(2,'0'); const mm=m[2].padStart(2,'0'); const yyyy=m[3]; return `${yyyy}-${mm}-${dd}`; }
    // Se já vier em YYYY-MM-DD mantém
    const iso = v.match(/^(\d{4})-(\d{2})-(\d{2})$/); if(iso) return v;
    // Tenta parsear data livre
    const d = new Date(v); if(!isNaN(d.getTime())) return d.toISOString().split('T')[0];
    return v; // devolve original se não reconhecido
  };
  s = norm(s); e = norm(e);
  return {start:s, end:e};
}
function getContaId(){
  const v = document.getElementById('contaId')?.value || '';
  const id = Number(v);
  return isNaN(id) || id <= 0 ? '' : String(id);
}
function getCsvSep(){
  const v = document.getElementById('csvSep')?.value || ';';
  // Backend aceita ';', ',', '|', ou 'tab' (convertido internamente para \t)
  return v;
}
async function populateContas(){
  try {
    const resp = await apiRequest('/api/financeiro/bancos/contas?per_page=100&status=ativa');
    if(!resp.ok) return;
    const json = await resp.json();
    const data = Array.isArray(json.data) ? json.data : [];
    const sel = document.getElementById('contaId'); if(!sel) return;
    // mantém a opção "Todas"
    data.forEach(acc=>{
      const opt = document.createElement('option');
      opt.value = String(acc.id);
      const label = `${acc.banco||'Banco'} ${acc.agencia||''} - ${acc.conta||''}`.trim();
      opt.textContent = label;
      sel.appendChild(opt);
    });
  } catch(e) { /* ignore silently */ }
}
function showSection(id){ document.querySelectorAll('section.card').forEach(sec=>{ if(sec.id && sec.id.startsWith('relatorio')) sec.style.display='none'; }); const el=document.getElementById(id); if(el) el.style.display='block'; }

async function loadDre(){
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  const url = `/api/financeiro/relatorios/dre?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`;
  const resp = await apiRequest(url);
  if(!resp.ok){ const t=await resp.text(); alert('Erro ao gerar DRE: '+t); return; }
  const json = await resp.json();
  const d = json.dre || {};
  document.getElementById('drePeriodo').textContent = `${json.period?.start||start} a ${json.period?.end||end}`;
  document.getElementById('dreReceitaBruta').textContent = fmtBRL(d.receita_bruta||0);
  document.getElementById('dreDeducoes').textContent = fmtBRL(d.deducoes||0);
  document.getElementById('dreReceitaLiquida').textContent = fmtBRL(d.receita_liquida||0);
  document.getElementById('dreCusto').textContent = fmtBRL(d.custo_dos_produtos||0);
  document.getElementById('dreLucroBruto').textContent = fmtBRL(d.lucro_bruto||0);
  document.getElementById('dreDespesasOp').textContent = fmtBRL(d.despesas_operacionais||0);
  document.getElementById('dreDespesasNaoOp').textContent = fmtBRL(d.despesas_nao_operacionais||0);
  document.getElementById('dreResultadoAntesImp').textContent = fmtBRL(d.resultado_antes_impostos||0);
  document.getElementById('dreImpostos').textContent = fmtBRL(d.impostos||0);
  document.getElementById('dreResultadoLiquido').textContent = fmtBRL(d.resultado_liquido||0);

  // Render gráfico de barras simples
  const chart = document.getElementById('dreChart'); chart.innerHTML='';
  const legend = document.getElementById('dreChartLegend'); legend.innerHTML='';
  const items = [
    {k:'Receita Líquida', v: Number(d.receita_liquida||0), color:'#2b8a3e'},
    {k:'Custos', v: Number(d.custo_dos_produtos||0), color:'#e8590c'},
    {k:'Despesas Op.', v: Number(d.despesas_operacionais||0), color:'#d6336c'},
    {k:'Impostos', v: Number(d.impostos||0), color:'#364fc7'},
    {k:'Res. Líquido', v: Number(d.resultado_liquido||0), color:'#0b7285'}
  ];
  const max = Math.max(1, ...items.map(i=>Math.abs(i.v)));
  items.forEach(i=>{
    const h = Math.max(8, Math.round((Math.abs(i.v)/max)*200));
    const bar = document.createElement('div');
    bar.style.width='36px'; bar.style.height=h+'px'; bar.style.background=i.color; bar.title=`${i.k}: ${fmtBRL(i.v)}`;
    bar.setAttribute('role','img'); bar.setAttribute('aria-label', `${i.k} ${fmtBRL(i.v)}`);
    chart.appendChild(bar);
    const chip = document.createElement('span'); chip.className='chip'; chip.style.marginRight='.25rem'; chip.textContent=`${i.k}: ${fmtBRL(i.v)}`; legend.appendChild(chip);
  });
}

document.getElementById('btnGerar').addEventListener('click', ()=>{
  const tipo = document.getElementById('tipoRelatorio').value;
  if (tipo === 'dre') { showSection('relatorioDre'); loadDre(); }
  else if (tipo === 'geral') { showSection('relatorioGeral'); loadGeral(); }
  else if (tipo === 'fluxo_caixa') { showSection('relatorioFluxo'); loadFluxo(); }
  else if (tipo === 'contas_pagar') { showSection('relatorioPagar'); loadPagar(); }
  else if (tipo === 'contas_receber') { showSection('relatorioReceber'); loadReceber(); }
  else if (tipo === 'dre_completo') { showSection('relatorioDreCompleto'); loadDreCompleto(); }
});

document.getElementById('btnExportar').addEventListener('click', ()=>{
  const tipo = document.getElementById('tipoRelatorio').value;
  if (tipo === 'dre') { window.print(); }
  else { window.print(); }
});

document.getElementById('btnExportarCsv').addEventListener('click', async ()=>{
  const tipo = document.getElementById('tipoRelatorio').value;
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  let url = '';
  const sep = getCsvSep();
  const contaId = getContaId();
  if (tipo === 'dre') {
    url = `/api/financeiro/relatorios/dre/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&sep=${encodeURIComponent(sep)}`;
  } else if (tipo === 'dre_completo') {
    url = `/api/financeiro/relatorios/dre-completo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&sep=${encodeURIComponent(sep)}`;
  } else if (tipo === 'fluxo_caixa') {
    url = `/api/financeiro/relatorios/fluxo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}${contaId?`&conta_id=${encodeURIComponent(contaId)}`:''}&sep=${encodeURIComponent(sep)}`;
  } else if (tipo === 'contas_receber') {
    url = `/api/financeiro/relatorios/receber/resumo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&sep=${encodeURIComponent(sep)}`;
  } else if (tipo === 'contas_pagar') {
    url = `/api/financeiro/relatorios/pagar/resumo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&sep=${encodeURIComponent(sep)}`;
  } else {
    alert('Selecione um tipo de relatório com exportação CSV.');
    return;
  }
  const resp = await fetch(url, { credentials: 'include' });
  if(!resp.ok){ const t=await resp.text(); alert('Erro ao exportar CSV: '+t); return; }
  const blob = await resp.blob();
  const a = document.createElement('a'); a.href = URL.createObjectURL(blob);
  const name = tipo.replace(/\s+/g,'_');
  a.download = `${name}_${start}_a_${end}.csv`;
  document.body.appendChild(a); a.click(); a.remove();
});

async function loadFluxo(){
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  const contaId = getContaId();
  const url = `/api/financeiro/relatorios/fluxo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}${contaId?`&conta_id=${encodeURIComponent(contaId)}`:''}`;
  const resp = await apiRequest(url);
  if(!resp.ok){ const t=await resp.text(); alert('Erro ao carregar Fluxo: '+t); return; }
  const json = await resp.json();
  const t = json.totals || {};
  document.getElementById('fluxoTotalEntradas').textContent = fmtBRL(t.entradas||0);
  document.getElementById('fluxoTotalSaidas').textContent = fmtBRL(t.saidas||0);
  document.getElementById('fluxoSaldoPeriodo').textContent = fmtBRL(t.saldo_periodo||0);

  // Render barras para série diária: duas barras por dia (entrada/saída)
  const chart = document.getElementById('fluxoChart'); chart.innerHTML='';
  const legend = document.getElementById('fluxoLegend'); legend.innerHTML='';
  const series = json.series || [];
  const max = Math.max(1, ...series.flatMap(r=>[Number(r.entradas||0), Number(r.saidas||0)]));
  series.forEach(r=>{
    const wrap = document.createElement('div'); wrap.style.display='flex'; wrap.style.flexDirection='column'; wrap.style.alignItems='center'; wrap.style.gap='.25rem';
    const bars = document.createElement('div'); bars.style.display='flex'; bars.style.gap='2px'; bars.style.alignItems='flex-end';
    const hIn = Math.max(4, Math.round((Math.abs(Number(r.entradas||0))/max)*180));
    const hOut = Math.max(4, Math.round((Math.abs(Number(r.saidas||0))/max)*180));
    const barIn = document.createElement('div'); barIn.style.width='14px'; barIn.style.height=hIn+'px'; barIn.style.background='#2b8a3e'; barIn.title=`Entradas ${r.data}: ${fmtBRL(r.entradas||0)}`;
    const barOut = document.createElement('div'); barOut.style.width='14px'; barOut.style.height=hOut+'px'; barOut.style.background='#d6336c'; barOut.title=`Saídas ${r.data}: ${fmtBRL(r.saidas||0)}`;
    bars.appendChild(barIn); bars.appendChild(barOut);
    const label = document.createElement('div'); label.style.fontSize='.8em'; label.textContent = r.data;
    wrap.appendChild(bars); wrap.appendChild(label); chart.appendChild(wrap);
  });
  legend.innerHTML = `<span class="chip" style="background:#2b8a3e;color:#fff;">Entradas</span> <span class="chip" style="background:#d6336c;color:#fff;">Saídas</span>`;
}

document.getElementById('btnFluxoCsv').addEventListener('click', async ()=>{
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  const sep = getCsvSep();
  const contaId = getContaId();
  const url = `/api/financeiro/relatorios/fluxo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}${contaId?`&conta_id=${encodeURIComponent(contaId)}`:''}&sep=${encodeURIComponent(sep)}`;
  const resp = await fetch(url, { credentials: 'include' });
  if(!resp.ok){ const t=await resp.text(); alert('Erro ao exportar CSV: '+t); return; }
  const blob = await resp.blob(); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download=`fluxo_${start}_a_${end}.csv`; document.body.appendChild(a); a.click(); a.remove();
});

document.getElementById('btnFluxoPrint').addEventListener('click', ()=>{ window.print(); });
// PNG export listeners (dependem de exportChartAsPng definido mais abaixo)
document.getElementById('btnDrePng')?.addEventListener('click', ()=>{
  const {start,end} = getPeriodo(); exportChartAsPng('dreChart', `dre_simplificado_${start}_a_${end}.png`);
});
document.getElementById('btnFluxoPng')?.addEventListener('click', ()=>{
  const {start,end} = getPeriodo(); exportChartAsPng('fluxoChart', `fluxo_caixa_${start}_a_${end}.png`);
});
document.getElementById('btnRecPng')?.addEventListener('click', ()=>{
  const {start,end} = getPeriodo(); exportChartAsPng('recChart', `contas_receber_${start}_a_${end}.png`);
});
document.getElementById('btnPayPng')?.addEventListener('click', ()=>{
  const {start,end} = getPeriodo(); exportChartAsPng('payChart', `contas_pagar_${start}_a_${end}.png`);
});

async function loadDreCompleto(){
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  const url = `/api/financeiro/relatorios/dre-completo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`;
  const resp = await apiRequest(url);
  if(!resp.ok){ const t=await resp.text(); alert('Erro ao gerar DRE Completo: '+t); return; }
  const json = await resp.json();
  const d = json.dre || {};
  const imp = d.impostos_detail || {};
  document.getElementById('dreCompPeriodo').textContent = `${json.period?.start||start} a ${json.period?.end||end}`;
  document.getElementById('dreCompReceitaBruta').textContent = fmtBRL(d.receita_bruta||0);
  document.getElementById('dreCompDeducoes').textContent = fmtBRL(d.deducoes||0);
  document.getElementById('dreCompReceitaLiquida').textContent = fmtBRL(d.receita_liquida||0);
  document.getElementById('dreCompCusto').textContent = fmtBRL(d.custo_dos_produtos||0);
  document.getElementById('dreCompLucroBruto').textContent = fmtBRL(d.lucro_bruto||0);
  document.getElementById('dreCompDespesasOp').textContent = fmtBRL(d.despesas_operacionais||0);
  document.getElementById('dreCompDespesasNaoOp').textContent = fmtBRL(d.despesas_nao_operacionais||0);
  document.getElementById('dreCompResultadoAntesImp').textContent = fmtBRL(d.resultado_antes_impostos||0);
  document.getElementById('dreCompImpostosTotal').textContent = fmtBRL(d.impostos_total ?? d.impostos ?? 0);
  document.getElementById('dreCompResultadoLiquido').textContent = fmtBRL(d.resultado_liquido||0);

  // Detalhe impostos
  const set = (id, v)=>{ const el=document.getElementById(id); if(el) el.textContent = fmtBRL(v||0); };
  set('impIcms', imp.icms); set('impPis', imp.pis); set('impCofins', imp.cofins); set('impIss', imp.iss);
  set('impIpi', imp.ipi); set('impIrpj', imp.irpj); set('impCsll', imp.csll); set('impIbs', imp.ibs); set('impCbs', imp.cbs); set('impIs', imp.is);

  // Análise Visual — barras re-renderizadas com dados do DRE completo
  const chart = document.getElementById('dreCompChart'); chart.innerHTML='';
  const legend = document.getElementById('dreCompChartLegend'); legend.innerHTML='';
  const items = [
    {k:'Receita Líquida', v: Number(d.receita_liquida||0), color:'#2b8a3e'},
    {k:'Custos', v: Number(d.custo_dos_produtos||0), color:'#e8590c'},
    {k:'Despesas Op.', v: Number(d.despesas_operacionais||0), color:'#d6336c'},
    {k:'Impostos (Total)', v: Number((d.impostos_total ?? d.impostos) || 0), color:'#364fc7'},
    {k:'Res. Líquido', v: Number(d.resultado_liquido||0), color:'#0b7285'}
  ];
  const max = Math.max(1, ...items.map(i=>Math.abs(i.v)));
  items.forEach(i=>{
    const h = Math.max(8, Math.round((Math.abs(i.v)/max)*200));
    const bar = document.createElement('div');
    bar.style.width='36px'; bar.style.height=h+'px'; bar.style.background=i.color; bar.title=`${i.k}: ${fmtBRL(i.v)}`;
    bar.setAttribute('role','img'); bar.setAttribute('aria-label', `${i.k} ${fmtBRL(i.v)}`);
    chart.appendChild(bar);
    const chip = document.createElement('span'); chip.className='chip'; chip.style.marginRight='.25rem'; chip.textContent=`${i.k}: ${fmtBRL(i.v)}`; legend.appendChild(chip);
  });
}

document.getElementById('btnDreCompCsv').addEventListener('click', async ()=>{
  const {start,end} = getPeriodo(); if(!start||!end){ alert('Informe período inicial e final.'); return; }
  const sep = getCsvSep();
  const url = `/api/financeiro/relatorios/dre-completo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&sep=${encodeURIComponent(sep)}`;
  const resp = await fetch(url, { credentials: 'include' }); if(!resp.ok){ const t=await resp.text(); alert('Erro ao exportar CSV: '+t); return; }
  const blob = await resp.blob(); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download=`dre_completo_${start}_a_${end}.csv`; document.body.appendChild(a); a.click(); a.remove();
});
document.getElementById('btnDreCompPrint').addEventListener('click', ()=>{ window.print(); });
document.getElementById('btnDreCompCsv')?.insertAdjacentHTML('afterend', '<button id="btnDreCompPng" class="btn">Exportar PNG</button>');
document.getElementById('btnDreCompPng')?.addEventListener('click', ()=>{
  const {start,end} = getPeriodo(); exportChartAsPng('dreCompChart', `dre_completo_${start}_a_${end}.png`);
});

async function loadReceber(){
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  const url = `/api/financeiro/relatorios/receber/resumo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`;
  const resp = await apiRequest(url);
  if(!resp.ok){ const t=await resp.text(); alert('Erro ao carregar Receber: '+t); return; }
  const json = await resp.json();
  const t = json.totals || {};
  const c = json.counts || {};
  document.getElementById('recTotalPendentes').textContent = fmtBRL(t.pendente||0);
  document.getElementById('recTotalVencidos').textContent = fmtBRL(t.vencido||0);
  document.getElementById('recTotalRecebidos').textContent = fmtBRL(t.recebido||0);
  document.getElementById('recTotalGeral').textContent = fmtBRL(t.total_geral||0);
  const elOver = document.getElementById('recOverdueCount'); if(elOver) elOver.textContent = `Vencidos: ${Number(c.overdue_count||0)}`;
  const elDueToday = document.getElementById('recDueTodayCount'); if(elDueToday) elDueToday.textContent = `Vencem hoje: ${Number(c.due_today_count||0)}`;
  const chart = document.getElementById('recChart'); chart.innerHTML='';
  const legend = document.getElementById('recLegend'); legend.innerHTML='';
  const series = json.series || [];
  const max = Math.max(1, ...series.flatMap(r=>[Number(r.a_receber||0), Number(r.recebidos||0)]));
  series.forEach(r=>{
    const wrap = document.createElement('div'); wrap.style.display='flex'; wrap.style.flexDirection='column'; wrap.style.alignItems='center'; wrap.style.gap='.25rem';
    const bars = document.createElement('div'); bars.style.display='flex'; bars.style.gap='2px'; bars.style.alignItems='flex-end';
    const hA = Math.max(4, Math.round((Math.abs(Number(r.a_receber||0))/max)*180));
    const hR = Math.max(4, Math.round((Math.abs(Number(r.recebidos||0))/max)*180));
    const barA = document.createElement('div'); barA.style.width='14px'; barA.style.height=hA+'px'; barA.style.background='#2b8a3e'; barA.title=`A Receber ${r.data}: ${fmtBRL(r.a_receber||0)}`;
    const barR = document.createElement('div'); barR.style.width='14px'; barR.style.height=hR+'px'; barR.style.background='#364fc7'; barR.title=`Recebidos ${r.data}: ${fmtBRL(r.recebidos||0)}`;
    bars.appendChild(barA); bars.appendChild(barR);
    const label = document.createElement('div'); label.style.fontSize='.8em'; label.textContent = r.data;
    wrap.appendChild(bars); wrap.appendChild(label); chart.appendChild(wrap);
  });
  legend.innerHTML = `<span class="chip" style="background:#2b8a3e;color:#fff;">A Receber</span> <span class="chip" style="background:#364fc7;color:#fff;">Recebidos</span>`;
}

async function loadPagar(){
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  const url = `/api/financeiro/relatorios/pagar/resumo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`;
  const resp = await apiRequest(url);
  if(!resp.ok){ const t=await resp.text(); alert('Erro ao carregar Pagar: '+t); return; }
  const json = await resp.json();
  const t = json.totals || {};
  const c = json.counts || {};
  document.getElementById('payTotalPendentes').textContent = fmtBRL(t.pendente||0);
  document.getElementById('payTotalVencidos').textContent = fmtBRL(t.vencido||0);
  document.getElementById('payTotalPagos').textContent = fmtBRL(t.pago||0);
  document.getElementById('payTotalGeral').textContent = fmtBRL(t.total_geral||0);
  const elOver = document.getElementById('payOverdueCount'); if(elOver) elOver.textContent = `Vencidos: ${Number(c.overdue_count||0)}`;
  const elDueToday = document.getElementById('payDueTodayCount'); if(elDueToday) elDueToday.textContent = `Vencem hoje: ${Number(c.due_today_count||0)}`;
  const chart = document.getElementById('payChart'); chart.innerHTML='';
  const legend = document.getElementById('payLegend'); legend.innerHTML='';
  const series = json.series || [];
  const max = Math.max(1, ...series.flatMap(r=>[Number(r.a_pagar||0), Number(r.pagos||0)]));
  series.forEach(r=>{
    const wrap = document.createElement('div'); wrap.style.display='flex'; wrap.style.flexDirection='column'; wrap.style.alignItems='center'; wrap.style.gap='.25rem';
    const bars = document.createElement('div'); bars.style.display='flex'; bars.style.gap='2px'; bars.style.alignItems='flex-end';
    const hA = Math.max(4, Math.round((Math.abs(Number(r.a_pagar||0))/max)*180));
    const hP = Math.max(4, Math.round((Math.abs(Number(r.pagos||0))/max)*180));
    const barA = document.createElement('div'); barA.style.width='14px'; barA.style.height=hA+'px'; barA.style.background='#d6336c'; barA.title=`A Pagar ${r.data}: ${fmtBRL(r.a_pagar||0)}`;
    const barP = document.createElement('div'); barP.style.width='14px'; barP.style.height=hP+'px'; barP.style.background='#364fc7'; barP.title=`Pagos ${r.data}: ${fmtBRL(r.pagos||0)}`;
    bars.appendChild(barA); bars.appendChild(barP);
    const label = document.createElement('div'); label.style.fontSize='.8em'; label.textContent = r.data;
    wrap.appendChild(bars); wrap.appendChild(label); chart.appendChild(wrap);
  });
  legend.innerHTML = `<span class="chip" style="background:#d6336c;color:#fff;">A Pagar</span> <span class="chip" style="background:#364fc7;color:#fff;">Pagos</span>`;
}

document.getElementById('btnRecCsv').addEventListener('click', async ()=>{
  const {start,end} = getPeriodo(); if(!start||!end){ alert('Informe período inicial e final.'); return; }
  const sep = getCsvSep();
  const url = `/api/financeiro/relatorios/receber/resumo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&sep=${encodeURIComponent(sep)}`;
  const resp = await fetch(url, { credentials: 'include' }); if(!resp.ok){ const t=await resp.text(); alert('Erro ao exportar CSV: '+t); return; }
  const blob = await resp.blob(); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download=`receber_${start}_a_${end}.csv`; document.body.appendChild(a); a.click(); a.remove();
});
document.getElementById('btnRecPrint').addEventListener('click', ()=>{ window.print(); });

document.getElementById('btnPayCsv').addEventListener('click', async ()=>{
  const {start,end} = getPeriodo(); if(!start||!end){ alert('Informe período inicial e final.'); return; }
  const sep = getCsvSep();
  const url = `/api/financeiro/relatorios/pagar/resumo/export.csv?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}&sep=${encodeURIComponent(sep)}`;
  const resp = await fetch(url, { credentials: 'include' }); if(!resp.ok){ const t=await resp.text(); alert('Erro ao exportar CSV: '+t); return; }
  const blob = await resp.blob(); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download=`pagar_${start}_a_${end}.csv`; document.body.appendChild(a); a.click(); a.remove();
});
document.getElementById('btnPayPrint').addEventListener('click', ()=>{ window.print(); });
</script>

<!-- Tabela de Dados -->
<section class="card">
  <h3 id="tabelaTitulo">Dados do Relatório</h3>
  <div style="overflow-x:auto;">
    <table class="table">
      <thead id="tabelaHeader">
        <!-- Cabeçalho será inserido dinamicamente -->
      </thead>
      <tbody id="tabelaBody">
        <tr>
          <td colspan="10" style="text-align:center;padding:2rem;">
            <div class="loading">Selecione um período e clique em "Gerar Relatório"</div>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</section>

<!-- Gráficos -->
<section class="card">
  <h3>Análise Visual</h3>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:2rem;">
    <div>
      <h4>Entradas vs Saídas</h4>
      <div id="graficoEntradaSaida" style="height:200px;display:flex;align-items:flex-end;gap:.5rem;border-bottom:1px solid #eee;padding:.5rem 0;">
        <!-- Barras renderizadas via JS -->
      </div>
      <div id="graficoEntradaSaidaLegend" class="muted" style="margin-top:.5rem;font-size:.9em;"></div>
      <div style="margin-top:.5rem;">
        <button id="btnExportEntradaSaida" class="btn" type="button">Exportar PNG</button>
      </div>
    </div>
    <div>
      <h4>Evolução Mensal</h4>
      <div id="graficoEvolucao" style="height:200px;display:flex;align-items:flex-end;gap:.5rem;border-bottom:1px solid #eee;padding:.5rem 0;overflow-x:auto;">
        <!-- Barras renderizadas via JS -->
      </div>
      <div id="graficoEvolucaoLegend" class="muted" style="margin-top:.5rem;font-size:.9em;"></div>
      <div style="margin-top:.5rem;">
        <button id="btnExportEvolucao" class="btn" type="button">Exportar PNG</button>
      </div>
    </div>
  </div>
</section>

<script>
(function(){
  // Definir datas padrão (último mês)
  const hoje = new Date();
  const umMesAtras = new Date(hoje.getFullYear(), hoje.getMonth() - 1, hoje.getDate());
  document.getElementById('dataInicio').value = umMesAtras.toISOString().split('T')[0];
  document.getElementById('dataFim').value = hoje.toISOString().split('T')[0];
  // Popular contas bancárias
  populateContas();
})();

// Persistência de filtros em localStorage
function restoreSavedFilters(){
  try {
    const s = localStorage.getItem('finRel.filters');
    if(!s) return;
    const obj = JSON.parse(s);
    if(obj.dataInicio) document.getElementById('dataInicio').value = obj.dataInicio;
    if(obj.dataFim) document.getElementById('dataFim').value = obj.dataFim;
    if(obj.contaId) document.getElementById('contaId').value = obj.contaId;
    if(obj.tipoRelatorio) document.getElementById('tipoRelatorio').value = obj.tipoRelatorio;
    if(obj.csvSep) document.getElementById('csvSep').value = obj.csvSep;
  } catch(e) { /* ignore */ }
}
function attachFilterSaveListeners(){
  const save = ()=>{
    try {
      const obj = {
        dataInicio: document.getElementById('dataInicio')?.value || '',
        dataFim: document.getElementById('dataFim')?.value || '',
        contaId: document.getElementById('contaId')?.value || '',
        tipoRelatorio: document.getElementById('tipoRelatorio')?.value || 'geral',
        csvSep: document.getElementById('csvSep')?.value || ';',
      };
      localStorage.setItem('finRel.filters', JSON.stringify(obj));
    } catch(e) { /* ignore */ }
  };
  ['dataInicio','dataFim','contaId','tipoRelatorio','csvSep'].forEach(id=>{
    const el = document.getElementById(id); if(!el) return;
    el.addEventListener('change', save);
    el.addEventListener('input', save);
  });
}

// Renderiza os gráficos globais da seção "Análise Visual"
async function renderAnaliseVisual(){
  const {start,end} = getPeriodo(); if(!start||!end) return;
  try {
    const contaId = getContaId();
    const resp = await apiRequest(`/api/financeiro/relatorios/fluxo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}${contaId?`&conta_id=${encodeURIComponent(contaId)}`:''}`);
    if(!resp.ok){
      // Tenta fallback derivando dados de Receber/Pagar
      await loadFluxoFallback(start, end);
      return;
    }
    const json = await resp.json();
    // Entradas vs Saídas
    const es = document.getElementById('graficoEntradaSaida'); es.innerHTML='';
    const esLeg = document.getElementById('graficoEntradaSaidaLegend'); esLeg.innerHTML='';
    const tot = json.totals || {}; const maxES = Math.max(1, Number(tot.entradas||0), Number(tot.saidas||0));
    const mkBar = (val, color, label)=>{ const h = Math.max(8, Math.round((Math.abs(Number(val))/maxES)*180)); const bar=document.createElement('div'); bar.style.width='40px'; bar.style.height=h+'px'; bar.style.background=color; bar.title=`${label}: ${fmtBRL(val||0)}`; bar.setAttribute('role','img'); bar.setAttribute('aria-label', `${label} ${fmtBRL(val||0)}`); return bar; };
    const vIn = Number(tot.entradas||0); const vOut = Number(tot.saidas||0);
    if (vIn === 0 && vOut === 0) {
      es.innerHTML = '<div class="muted" style="margin:auto;color:#666;">Sem dados para o período</div>';
    } else {
      es.appendChild(mkBar(vIn,'#2b8a3e','Entradas'));
      es.appendChild(mkBar(vOut,'#d6336c','Saídas'));
      esLeg.innerHTML = '<span class="chip" style="background:#2b8a3e;color:#fff;">Entradas</span> <span class="chip" style="background:#d6336c;color:#fff;">Saídas</span>';
    }

    // Evolução Mensal (saldo por mês)
    const ev = document.getElementById('graficoEvolucao'); ev.innerHTML='';
    const evLeg = document.getElementById('graficoEvolucaoLegend'); evLeg.innerHTML='';
    const series = Array.isArray(json.series)? json.series : [];
    if (series.length === 0) {
      ev.innerHTML = '<div class="muted" style="margin:auto;color:#666;">Sem dados para o período</div>';
    } else {
      const porMes = {};
      series.forEach(r=>{ const mes = String(r.data||'').slice(0,7); if(!porMes[mes]) porMes[mes]={entradas:0,saidas:0}; porMes[mes].entradas += Number(r.entradas||0); porMes[mes].saidas += Number(r.saidas||0); });
      const meses = Object.keys(porMes).sort(); const maxEV = Math.max(1, ...meses.flatMap(m=>[porMes[m].entradas, porMes[m].saidas]));
      meses.forEach(m=>{
        const wrap=document.createElement('div'); wrap.style.display='flex'; wrap.style.flexDirection='column'; wrap.style.alignItems='center'; wrap.style.gap='.25rem';
        const bars=document.createElement('div'); bars.style.display='flex'; bars.style.gap='2px'; bars.style.alignItems='flex-end';
        const hIn = Math.max(8, Math.round((Math.abs(porMes[m].entradas)/maxEV)*180));
        const hOut = Math.max(8, Math.round((Math.abs(porMes[m].saidas)/maxEV)*180));
        const barIn=document.createElement('div'); barIn.style.width='14px'; barIn.style.height=hIn+'px'; barIn.style.background='#2b8a3e'; barIn.title=`${m}: Entradas ${fmtBRL(porMes[m].entradas)}`;
        const barOut=document.createElement('div'); barOut.style.width='14px'; barOut.style.height=hOut+'px'; barOut.style.background='#d6336c'; barOut.title=`${m}: Saídas ${fmtBRL(porMes[m].saidas)}`;
        bars.appendChild(barIn); bars.appendChild(barOut);
        const label=document.createElement('div'); label.style.fontSize='.8em'; label.textContent=m;
        wrap.appendChild(bars); wrap.appendChild(label); ev.appendChild(wrap);
      });
      evLeg.innerHTML = '<span class="chip" style="background:#2b8a3e;color:#fff;">Entradas</span> <span class="chip" style="background:#d6336c;color:#fff;">Saídas</span>';
    }
  } catch(e){
    // Fallback em caso de exceção
    const {start,end} = getPeriodo();
    await loadFluxoFallback(start, end);
  }
}

// Fallback: monta dados de fluxo a partir dos endpoints de Resumo Receber/Pagar
async function loadFluxoFallback(start, end){
  try {
    const [recResp, payResp] = await Promise.all([
      apiRequest(`/api/financeiro/relatorios/receber/resumo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`).catch(()=>null),
      apiRequest(`/api/financeiro/relatorios/pagar/resumo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`).catch(()=>null),
    ]);

    let rec = null, pay = null;
    try { if(recResp && recResp.ok) rec = await recResp.json(); } catch(e){}
    try { if(payResp && payResp.ok) pay = await payResp.json(); } catch(e){}

    const seriesMap = {}; // por dia
    const recSeries = Array.isArray(rec?.series) ? rec.series : [];
    const paySeries = Array.isArray(pay?.series) ? pay.series : [];
    recSeries.forEach(r=>{ const d=String(r.data||''); if(!d) return; if(!seriesMap[d]) seriesMap[d]={entradas:0,saidas:0}; seriesMap[d].entradas += Number(r.recebidos||0); });
    paySeries.forEach(r=>{ const d=String(r.data||''); if(!d) return; if(!seriesMap[d]) seriesMap[d]={entradas:0,saidas:0}; seriesMap[d].saidas += Number(r.pagos||0); });

    const series = Object.keys(seriesMap).sort().map(d=>({ data: d, entradas: seriesMap[d].entradas, saidas: seriesMap[d].saidas }));
    const totEntradas = Number(rec?.totals?.recebido || 0);
    const totSaidas = Number(pay?.totals?.pago || 0);
    const saldoPeriodo = totEntradas - totSaidas;

    // Se não houver dados, exibe "Sem dados"
    if (series.length === 0 && totEntradas === 0 && totSaidas === 0) {
      const es = document.getElementById('graficoEntradaSaida'); es.innerHTML='';
      const ev = document.getElementById('graficoEvolucao'); ev.innerHTML='';
      const esLeg = document.getElementById('graficoEntradaSaidaLegend'); esLeg.innerHTML='';
      const evLeg = document.getElementById('graficoEvolucaoLegend'); evLeg.innerHTML='';
      es.innerHTML = '<div class="muted" style="margin:auto;color:#666;">Sem dados para o período</div>';
      ev.innerHTML = '<div class="muted" style="margin:auto;color:#666;">Sem dados para o período</div>';
      return;
    }

    // Renderização reutilizando a mesma lógica dos gráficos
    const es = document.getElementById('graficoEntradaSaida'); es.innerHTML='';
    const esLeg = document.getElementById('graficoEntradaSaidaLegend'); esLeg.innerHTML='';
    const maxES = Math.max(1, Math.abs(totEntradas), Math.abs(totSaidas));
    const mkBar = (val, color, label)=>{ const h = Math.max(8, Math.round((Math.abs(Number(val))/maxES)*180)); const bar=document.createElement('div'); bar.style.width='40px'; bar.style.height=h+'px'; bar.style.background=color; bar.title=`${label}: ${fmtBRL(val||0)}`; bar.setAttribute('role','img'); bar.setAttribute('aria-label', `${label} ${fmtBRL(val||0)}`); return bar; };
    es.appendChild(mkBar(totEntradas,'#2b8a3e','Entradas'));
    es.appendChild(mkBar(totSaidas,'#d6336c','Saídas'));
    esLeg.innerHTML = '<span class="chip" style="background:#2b8a3e;color:#fff;">Entradas</span> <span class="chip" style="background:#d6336c;color:#fff;">Saídas</span>';

    const ev = document.getElementById('graficoEvolucao'); ev.innerHTML='';
    const evLeg = document.getElementById('graficoEvolucaoLegend'); evLeg.innerHTML='';
    if (series.length === 0) {
      ev.innerHTML = '<div class="muted" style="margin:auto;color:#666;">Sem dados para o período</div>';
    } else {
      const porMes = {};
      series.forEach(r=>{ const mes = String(r.data||'').slice(0,7); if(!porMes[mes]) porMes[mes]={entradas:0,saidas:0}; porMes[mes].entradas += Number(r.entradas||0); porMes[mes].saidas += Number(r.saidas||0); });
      const meses = Object.keys(porMes).sort(); const maxEV = Math.max(1, ...meses.flatMap(m=>[porMes[m].entradas, porMes[m].saidas]));
      meses.forEach(m=>{
        const wrap=document.createElement('div'); wrap.style.display='flex'; wrap.style.flexDirection='column'; wrap.style.alignItems='center'; wrap.style.gap='.25rem';
        const bars=document.createElement('div'); bars.style.display='flex'; bars.style.gap='2px'; bars.style.alignItems='flex-end';
        const hIn = Math.max(8, Math.round((Math.abs(porMes[m].entradas)/maxEV)*180));
        const hOut = Math.max(8, Math.round((Math.abs(porMes[m].saidas)/maxEV)*180));
        const barIn=document.createElement('div'); barIn.style.width='14px'; barIn.style.height=hIn+'px'; barIn.style.background='#2b8a3e'; barIn.title=`${m}: Entradas ${fmtBRL(porMes[m].entradas)}`;
        const barOut=document.createElement('div'); barOut.style.width='14px'; barOut.style.height=hOut+'px'; barOut.style.background='#d6336c'; barOut.title=`${m}: Saídas ${fmtBRL(porMes[m].saidas)}`;
        bars.appendChild(barIn); bars.appendChild(barOut);
        const label=document.createElement('div'); label.style.fontSize='.8em'; label.textContent=m;
        wrap.appendChild(bars); wrap.appendChild(label); ev.appendChild(wrap);
      });
      evLeg.innerHTML = '<span class="chip" style="background:#2b8a3e;color:#fff;">Entradas</span> <span class="chip" style="background:#d6336c;color:#fff;">Saídas</span>';
    }
  } catch(err){
    const es = document.getElementById('graficoEntradaSaida'); if(es) es.innerHTML = '<div class="muted" style="margin:auto;color:#666;">Sem dados para o período</div>';
    const ev = document.getElementById('graficoEvolucao'); if(ev) ev.innerHTML = '<div class="muted" style="margin:auto;color:#666;">Sem dados para o período</div>';
    const esLeg = document.getElementById('graficoEntradaSaidaLegend'); if(esLeg) esLeg.innerHTML='';
    const evLeg = document.getElementById('graficoEvolucaoLegend'); if(evLeg) evLeg.innerHTML='';
  }
}

// Atualiza gráficos globais após gerar qualquer relatório
document.getElementById('btnGerar').addEventListener('click', ()=>{ setTimeout(renderAnaliseVisual, 0); });
// Render inicial com período padrão
document.addEventListener('DOMContentLoaded', ()=>{ restoreSavedFilters(); attachFilterSaveListeners(); setTimeout(renderAnaliseVisual, 0); });
</script>

<!-- html2canvas para exportação de gráficos como PNG -->
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
<script>
// Exporta o container do gráfico para PNG
function exportChartAsPng(elementId, filename){
  const el = document.getElementById(elementId);
  if(!el){ alert('Elemento do gráfico não encontrado.'); return; }
  // Evita exportar mensagem de vazio como gráficos
  const hasBars = el.querySelector('div[role="img"], div[style*="height"]');
  if(!hasBars){ alert('Sem dados para exportar neste gráfico.'); return; }
  html2canvas(el, {backgroundColor: '#fff', scale: 2}).then(canvas => {
    const link = document.createElement('a');
    link.download = filename;
    link.href = canvas.toDataURL('image/png');
    link.click();
  }).catch(()=>{
    alert('Falha ao exportar o gráfico.');
  });
}

document.getElementById('btnExportEntradaSaida')?.addEventListener('click', ()=>{
  exportChartAsPng('graficoEntradaSaida', `entradas_vs_saidas_${new Date().toISOString().slice(0,10)}.png`);
});
document.getElementById('btnExportEvolucao')?.addEventListener('click', ()=>{
  exportChartAsPng('graficoEvolucao', `evolucao_mensal_${new Date().toISOString().slice(0,10)}.png`);
});
</script>

<script>
// Utilitário: renderização genérica da tabela "Dados do Relatório"
function setTabelaDados(cols, rows){
  const thead = document.getElementById('tabelaHeader');
  const tbody = document.getElementById('tabelaBody');
  thead.innerHTML = `<tr>${cols.map(c=>`<th>${c}</th>`).join('')}</tr>`;
  if (!rows || rows.length === 0) {
    tbody.innerHTML = `<tr><td colspan="${cols.length}" style="text-align:center;padding:1.25rem;">Sem dados para o período</td></tr>`;
    return;
  }
  tbody.innerHTML = rows.map(r=>`<tr>${r.map(c=>`<td>${c}</td>`).join('')}</tr>`).join('');
}

// Carregar Relatório Geral: agrega Receber, Pagar e Fluxo
async function loadGeral(){
  const {start,end} = getPeriodo();
  if(!start || !end){ alert('Informe período inicial e final.'); return; }
  const urls = {
    receber: `/api/financeiro/relatorios/receber/resumo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`,
    pagar: `/api/financeiro/relatorios/pagar/resumo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}`,
    fluxo: `/api/financeiro/relatorios/fluxo?start=${encodeURIComponent(start)}&end=${encodeURIComponent(end)}${getContaId()?`&conta_id=${encodeURIComponent(getContaId())}`:''}`,
  };
  // dispara em paralelo e trata erros individualmente
  const [recResp, payResp, fluxoResp] = await Promise.all([
    apiRequest(urls.receber).catch(()=>null),
    apiRequest(urls.pagar).catch(()=>null),
    apiRequest(urls.fluxo).catch(()=>null),
  ]);

  let rec = null, pay = null, fluxo = null;
  try { if(recResp && recResp.ok) rec = await recResp.json(); } catch(e){}
  try { if(payResp && payResp.ok) pay = await payResp.json(); } catch(e){}
  try { if(fluxoResp && fluxoResp.ok) fluxo = await fluxoResp.json(); } catch(e){}

  const tRec = rec?.totals || {}; const tPay = pay?.totals || {}; const tFlx = fluxo?.totals || {};

  // Preencher cards do Resumo Financeiro
  document.getElementById('totalReceber').textContent = fmtBRL(tRec.total_geral || 0);
  document.getElementById('totalPagar').textContent = fmtBRL(tPay.total_geral || 0);
  const saldoProj = (Number(tRec.total_geral||0) - Number(tPay.total_geral||0));
  document.getElementById('saldoProjetado').textContent = fmtBRL(saldoProj);

  // Contagens de vencidos e hoje
  const cRec = rec?.counts || {}; const cPay = pay?.counts || {};
  const elRec = document.getElementById('contasReceber'); if (elRec) elRec.textContent = `Vencidas: ${Number(cRec.overdue_count||0)} • Hoje: ${Number(cRec.due_today_count||0)}`;
  const elPay = document.getElementById('contasPagar'); if (elPay) elPay.textContent = `Vencidas: ${Number(cPay.overdue_count||0)} • Hoje: ${Number(cPay.due_today_count||0)}`;
  const vencTotal = Number(cRec.overdue_count||0) + Number(cPay.overdue_count||0);
  const vencEl = document.getElementById('contasVencidas'); if (vencEl) vencEl.textContent = `${vencTotal}`;

  // Montar "Dados do Relatório"
  const cols = ['Métrica','Valor'];
  const rows = [];
  rows.push(['Total a Receber', fmtBRL(tRec.total_geral||0)]);
  rows.push(['Total a Pagar', fmtBRL(tPay.total_geral||0)]);
  rows.push(['Saldo projetado (Receber - Pagar)', fmtBRL(saldoProj)]);
  if (fluxo) {
    rows.push(['Entradas (Fluxo)', fmtBRL(tFlx.entradas||0)]);
    rows.push(['Saídas (Fluxo)', fmtBRL(tFlx.saidas||0)]);
    rows.push(['Saldo no período (Fluxo)', fmtBRL(tFlx.saldo_periodo||0)]);
  }
  if (!rec && !pay && !fluxo) {
    setTabelaDados(cols, []);
  } else {
    setTabelaDados(cols, rows);
  }

  // Atualiza seção visível e gráficos globais
  showSection('relatorioGeral');
  setTimeout(renderAnaliseVisual, 0);
}
</script>