<?php
require_once(dirname(__DIR__) . '/config/db.php');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);

$cdempresa = $_SESSION['cdempresa'] ?? 1;

// exercícios (só pra filtro/listagem e export realizado; import não depende)
$stmt = $pdo->prepare("
  SELECT cdexercicio, anoref
    FROM back.exercicio
   WHERE cdempresa = :emp
     AND flativo = 0
   ORDER BY anoref DESC
");
$stmt->execute([':emp'=>$cdempresa]);
$exercicios = $stmt->fetchAll(PDO::FETCH_ASSOC);

// centros (sem cdempresa)
$stmt = $pdo->prepare("
  SELECT cdcentrocusto, dscentro
    FROM back.centro_custo
   WHERE flativo = 0 and cdcentropai IS NOT NULL
   ORDER BY dscentro
");
$stmt->execute();
$centros = $stmt->fetchAll(PDO::FETCH_ASSOC);

// Buscar moeda da empresa
$stmt = $pdo->prepare("
  SELECT m.simbolo, m.formato
    FROM back.empresa e
    LEFT JOIN back.moeda m ON m.cdmoeda = e.cdmoeda
   WHERE e.cdempresa = :emp
");
$stmt->execute([':emp'=>$cdempresa]);
$moeda = $stmt->fetch(PDO::FETCH_ASSOC) ?? ['simbolo'=>'R$', 'formato'=>'decimal'];
?>

<h4 class="mb-3"><i class="bi bi-receipt"></i> Orçamento Realizado</h4>
<hr>

<div class="d-flex flex-column gap-3">

  <div class="card border-0 shadow-sm">
    <div class="card-body py-3">
      <div class="row g-2 align-items-end">

        <div class="col-md-2">
          <label class="small">Exercício (filtro/export)</label>
          <select class="form-select form-select-sm" id="filtroAno">
            <option value="">Todos...</option>
            <?php foreach ($exercicios as $ex): ?>
              <option value="<?= (int)$ex['anoref'] ?>"><?= htmlspecialchars($ex['anoref']) ?></option>
            <?php endforeach; ?>
          </select>
        </div>

        <div class="col-md-3">
          <label class="small">Centro de Custo (filtro/export)</label>
          <select class="form-select form-select-sm" id="filtroCentro">
            <option value="">Todos...</option>
            <?php foreach ($centros as $c): ?>
              <option value="<?= (int)$c['cdcentrocusto'] ?>"><?= htmlspecialchars($c['dscentro']) ?></option>
            <?php endforeach; ?>
          </select>
        </div>

        <div class="col-md-2">
          <label class="small">Origem</label>
          <select class="form-select form-select-sm" id="filtroOrigem">
            <option value="">Todas</option>
            <option value="1">Excel</option>
            <option value="2">ERP</option>
            <option value="0">Manual</option>
          </select>
        </div>

        <div class="col-md-2">
          <label class="small">Data inicial (opcional)</label>
          <input type="date" class="form-control form-control-sm" id="filtroDataIni">
        </div>

        <div class="col-md-2">
          <label class="small">Data final (opcional)</label>
          <input type="date" class="form-control form-control-sm" id="filtroDataFim">
        </div>

        <div class="col-md-1 d-flex gap-2">
          <button class="btn btn-primary btn-sm flex-grow-1" id="btnBuscar">
            <i class="bi bi-search"></i>
          </button>
        </div>

        <div class="col-12 d-flex gap-2 mt-2">
          <button class="btn btn-outline-secondary btn-sm" id="btnExportModelo">
            <i class="bi bi-download"></i> Exportar Modelo (CSV)
          </button>

          <button class="btn btn-outline-primary btn-sm" id="btnExportRealizado">
            <i class="bi bi-file-earmark-spreadsheet"></i> Exportar Realizado
          </button>

          <button class="btn btn-success btn-sm" id="btnImportar">
            <i class="bi bi-upload"></i> Importar CSV
          </button>

          <button class="btn btn-warning btn-sm" id="btnSyncERP">
            <i class="bi bi-arrow-repeat"></i> Sincronizar ERP (período)
          </button>

          <div class="ms-auto small text-muted d-flex align-items-center" id="importStatus"></div>
        </div>

      </div>
    </div>
  </div>

  <div class="card border-0 shadow-sm">
    <div class="card-body p-0">
      <table class="table table-striped table-hover table-sm align-middle mb-0">
        <thead class="table-dark">
          <tr>
            <th>Exercício</th>
            <th>Descrição</th>
            <th>Origem</th>
            <th>Última sincronização</th>
            <th>Usuário</th>
            <th>Situação</th>
            <th class="text-center" style="width:130px;">Ações</th>
          </tr>
        </thead>
        <tbody id="tabelaLotes">
          <tr><td colspan="8" class="text-center py-3 text-muted">Nenhum registro</td></tr>
        </tbody>
      </table>
    </div>
  </div>

</div>

<!-- Modal Import -->
<div class="modal fade" id="modalImportar" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
  <div class="modal-dialog modal-md modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header bg-success text-white py-2">
        <h6 class="modal-title"><i class="bi bi-upload"></i> Importar CSV</h6>
        <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" id="btnFecharImportar"></button>
      </div>
      <div class="modal-body">
        <div class="alert alert-info small mb-2">
          Formato: <b>CdEmpresa;Ano;CdCentro;Centro;CdContaContabil;CdConta;Conta;Jan..Dez</b>
        </div>
        <input type="file" id="arquivoCSV" class="form-control form-control-sm" accept=".csv,text/csv">
        <div class="mt-3" id="importProgresso" style="display:none;">
          <div class="progress mb-2" style="height: 6px;">
            <div class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%;"></div>
          </div>
          <ul class="small mb-0" id="importEtapas">
            <li data-step="upload">1) Enviando arquivo...</li>
            <li data-step="preview">2) Gerando prévia e validando...</li>
            <li data-step="confirm">3) Gravando dados no banco...</li>
          </ul>
        </div>
        <div class="small text-muted mt-2" id="importResumo"></div>
      </div>
      <div class="modal-footer py-2">
        <button class="btn btn-secondary btn-sm" data-bs-dismiss="modal" id="btnFecharImportarFooter">Fechar</button>
        <button class="btn btn-primary btn-sm" id="btnConfirmarImport">Confirmar</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal Lançamentos -->
<div class="modal fade" id="modalLancamentos" tabindex="-1">
  <div class="modal-dialog modal-fullscreen-lg-down modal-xl" style="max-width: 95vw;">
    <div class="modal-content" style="max-height: 90vh;">
      <div class="modal-header bg-white py-3" style="border-bottom: 1px solid #dee2e6;">
        <h5 class="modal-title text-dark">
          <i class="bi bi-table me-2"></i> Lançamentos Realizados
          <span id="infoExercicioLanc" class="ms-2 small text-muted"></span>
        </h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body p-0" style="flex: 1; overflow: hidden; display: flex; flex-direction: column;">
        <div class="p-2 border-bottom" style="background:#f8f9fa;">
          <div class="input-group input-group-sm" style="max-width: 320px;">
            <span class="input-group-text"><i class="bi bi-search"></i></span>
            <input type="text" class="form-control" id="lancSearch" placeholder="Pesquisar conta (Enter / F3 para próximo)">
          </div>
        </div>
        <div style="flex: 1; overflow-y: auto; display: flex; flex-direction: column;">
          <table class="table table-hover align-middle mb-0" style="font-size: 0.96rem;">
            <thead style="position: sticky; top: 0; background: #f8f9fa; z-index: 100; border-bottom: 2px solid #dee2e6;">
              <tr>
                <th style="padding: 14px 16px; font-size: 0.97rem; color: #495057; font-weight: 600;">Conta</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Jan</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Fev</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Mar</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Abr</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Mai</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Jun</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Jul</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Ago</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Set</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Out</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Nov</th>
                <th class="text-end" style="padding: 14px 10px; font-size: 0.97rem; color: #495057; font-weight: 600;">Dez</th>
                <th class="text-end" style="padding: 14px 10px; background: #e9ecef; font-weight: 700; font-size: 0.97rem; color: #212529; border-left: 2px solid #dee2e6;">Total</th>
              </tr>
            </thead>
            <tbody id="tbLancamentos">
              <tr><td colspan="14" class="text-center py-4 text-muted">Carregando...</td></tr>
            </tbody>
            <tfoot style="background: #f8f9fa; border-top: 2px solid #dee2e6; position: sticky; bottom: 0;">
              <tr>
                <th style="padding: 14px 16px; font-size: 0.97rem; border: none; color: #495057; font-weight: 700;">TOTAL GERAL</th>
                <th class="text-end" id="total_jan" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_fev" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_mar" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_abr" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_mai" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_jun" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_jul" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_ago" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_set" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_out" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_nov" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_dez" style="padding: 14px 10px; font-size: 0.97rem; border: none; color: #212529; font-weight: 600;">0,00</th>
                <th class="text-end" id="total_final" style="padding: 14px 10px; font-size: 1rem; font-weight: 700; border: none; color: #212529; background: #e9ecef; border-left: 2px solid #dee2e6;">0,00</th>
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
      <div class="modal-footer py-2">
        <button class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Fechar</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal Detalhe da Conta -->
<div class="modal fade" id="modalDetalheConta" tabindex="-1" style="z-index: 1065;">
  <div class="modal-dialog modal-lg" style="max-width: 90vw;">
    <div class="modal-content" style="max-height: 90vh;">
      <div class="modal-header bg-white py-3" style="border-bottom: 1px solid #dee2e6;">
        <h5 class="modal-title text-dark"><i class="bi bi-list-ul me-2"></i> Detalhe dos Lançamentos</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body p-0" style="flex: 1; overflow: hidden; display: flex; flex-direction: column;">
        <div class="p-3 border-bottom" style="background:#f8f9fa;">
          <div class="small text-muted mb-2" id="detalheContaInfo"></div>
          <div class="row g-2 align-items-end">
            <div class="col-md-3">
              <label class="small fw-semibold">Data Inicial</label>
              <input type="date" class="form-control form-control-sm" id="detalheDataIni">
            </div>
            <div class="col-md-3">
              <label class="small fw-semibold">Data Final</label>
              <input type="date" class="form-control form-control-sm" id="detalheDataFim">
            </div>
            <div class="col-md-2">
              <button class="btn btn-primary btn-sm" id="btnFiltrarDetalhe">
                <i class="bi bi-search"></i> Filtrar
              </button>
            </div>
          </div>
        </div>
        <div class="p-2 border-bottom" style="background:#ffffff;">
          <div class="small mb-2" id="detalheTotaisResumo"></div>
        </div>
        <div style="flex: 1; overflow-y: auto;">
          <table class="table table-hover align-middle mb-0" style="font-size: 0.95rem;">
            <thead style="position: sticky; top: 0; background: #f8f9fa; z-index: 100; border-bottom: 2px solid #dee2e6;">
              <tr>
                <th style="padding: 12px 16px; font-weight: 600; color: #495057;">Conta</th>
                <th style="padding: 12px 16px; width: 120px; font-weight: 600; color: #495057;">Data</th>
                <th style="padding: 12px 16px; font-weight: 600; color: #495057;">Descrição</th>
                <th style="padding: 12px 16px; width: 90px; font-weight: 600; color: #495057;" class="text-center">Tipo</th>
                <th style="padding: 12px 16px; width: 140px; font-weight: 600; color: #495057;" class="text-end">Valor</th>
              </tr>
            </thead>
            <tbody id="tbDetalheConta">
              <tr><td colspan="5" class="text-center py-3 text-muted">Carregando...</td></tr>
            </tbody>
            <tfoot style="background: #f8f9fa; border-top: 2px solid #dee2e6; position: sticky; bottom: 0;">
              <tr>
                <th colspan="4" class="text-end" style="padding: 12px 16px; border: none; font-weight: 600; color: #495057;">Total</th>
                <th class="text-end" id="detalheTotalValor" style="padding: 12px 16px; border: none; font-weight: 700; color: #212529;">0,00</th>
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
      <div class="modal-footer py-2">
        <button class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Fechar</button>
      </div>
    </div>
  </div>
</div>

<!-- Modal Sincronização ERP -->
<div class="modal fade" id="modalSyncERP" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
  <div class="modal-dialog modal-md modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header bg-warning py-2">
        <h6 class="modal-title"><i class="bi bi-arrow-repeat"></i> Sincronizar ERP (período)</h6>
        <button type="button" class="btn-close" data-bs-dismiss="modal" id="btnFecharSync"></button>
      </div>
      <div class="modal-body">
          <div class="row g-2">
            <div class="col-6">
              <label class="small">Data inicial do período</label>
              <input type="date" class="form-control form-control-sm" id="syncDataIni">
            </div>
            <div class="col-6">
              <label class="small">Data final do período</label>
              <input type="date" class="form-control form-control-sm" id="syncDataFim">
            </div>
          </div>
        <div class="alert alert-warning small mt-3 mb-2">
            Esta ação vai <strong>deletar</strong> e <strong>recarregar</strong> os lançamentos de realizado
            de todos os meses que estiverem dentro do período selecionado, usando o modelo de integração padrão da empresa.
        </div>
        <div class="mt-2" id="syncProgresso" style="display:none;">
          <div class="progress mb-2" style="height: 6px;">
            <div class="progress-bar progress-bar-striped progress-bar-animated bg-warning" role="progressbar" style="width: 0%;"></div>
          </div>
          <ul class="small mb-0" id="syncEtapas">
            <li data-step="preparar">1) Preparando requisição...</li>
            <li data-step="sincronizar">2) Sincronizando com ERP e banco...</li>
            <li data-step="consolidar">3) Consolidando dados...</li>
            <li data-step="atualizar">4) Atualizando tela e totais...</li>
          </ul>
        </div>
        <div id="syncResultado" class="small"></div>
      </div>
      <div class="modal-footer py-2">
        <button class="btn btn-secondary btn-sm" data-bs-dismiss="modal" id="btnFecharSyncFooter">Fechar</button>
        <button class="btn btn-warning btn-sm" id="btnConfirmarSync">Sincronizar agora</button>
      </div>
    </div>
  </div>
</div>

<!-- Overlay global para travar a tela durante importações longas -->
<div id="importOverlay" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.25); z-index:1040; cursor:wait;"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

<script>
// Configurações de moeda
const moedaConfig = {
  simbolo: '<?= htmlspecialchars($moeda['simbolo'] ?? 'R$') ?>',
  formato: '<?= htmlspecialchars($moeda['formato'] ?? 'decimal') ?>'
};

function formatarMoeda(valor) {
  const num = Number(valor) || 0;
  if (moedaConfig.formato === 'inteiro') {
    return moedaConfig.simbolo + ' ' + num.toLocaleString('pt-BR', {minimumFractionDigits: 0, maximumFractionDigits: 0});
  }
  return moedaConfig.simbolo + ' ' + num.toLocaleString('pt-BR', {minimumFractionDigits: 2, maximumFractionDigits: 2});
}

function escapeHtml(text) {
  if (text === null || text === undefined) return '';
  return String(text)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#039;');
}

function normalizarDataValor(valor) {
  if (!valor) return '';
  valor = String(valor).trim();
  if (!valor) return '';

  let dia, mes, ano;

  const anoAtual = new Date().getFullYear();

  // dd/mm (assume ano corrente)
  let m = valor.match(/^(\d{2})\/(\d{2})$/);
  if (m) {
    dia = parseInt(m[1], 10);
    mes = parseInt(m[2], 10);
    ano = anoAtual;
  } else {
    // dd/mm/aaaa
    m = valor.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
  if (m) {
    dia = parseInt(m[1], 10);
    mes = parseInt(m[2], 10);
    ano = parseInt(m[3], 10);
  } else {
    // yyyy-mm-dd
    m = valor.match(/^(\d{4})-(\d{2})-(\d{2})$/);
    if (m) {
      ano = parseInt(m[1], 10);
      mes = parseInt(m[2], 10);
      dia = parseInt(m[3], 10);
    } else {
      return valor; // formato inesperado, não mexe
    }
  }
  }

  if (!ano || !mes || !dia) return '';

  // Ajusta mês para 1..12
  if (mes < 1) mes = 1;
  if (mes > 12) mes = 12;

  // Último dia do mês
  const ultimoDiaMes = new Date(ano, mes, 0).getDate();
  if (dia < 1) dia = 1;
  if (dia > ultimoDiaMes) dia = ultimoDiaMes;

  const a = String(ano).padStart(4, '0');
  const mStr = String(mes).padStart(2, '0');
  const dStr = String(dia).padStart(2, '0');
  return `${a}-${mStr}-${dStr}`;
}

function aplicarNormalizacaoData(selector) {
  $(document).on('change blur', selector, function() {
    const novo = normalizarDataValor(this.value);
    if (novo) this.value = novo;
  });
}

// Quando o usuário informar uma data inicial fora do mês
// corrente, preenche automaticamente a data final com o
// último dia daquele mesmo mês, se a data final estiver vazia.
function configurarAutoPreencherDataFim(selectorInicio, selectorFim) {
  $(document).on('change blur', selectorInicio, function() {
    const val = this.value;
    if (!val) return;

    const dtIni = new Date(val + 'T00:00:00');
    if (isNaN(dtIni.getTime())) return;

    const hoje = new Date();
    if (dtIni.getFullYear() === hoje.getFullYear() && dtIni.getMonth() === hoje.getMonth()) {
      // mês corrente: mantém comportamento atual (não força fim do mês)
      return;
    }

    const ano = dtIni.getFullYear();
    const mesIndex = dtIni.getMonth(); // 0-11
    const ultimoDia = new Date(ano, mesIndex + 1, 0).getDate();

    const mStr = String(mesIndex + 1).padStart(2, '0');
    const dStr = String(ultimoDia).padStart(2, '0');
    const dataFim = `${ano}-${mStr}-${dStr}`;

    const $fim = $(selectorFim);
      $fim.val(dataFim).trigger('change');
  });
}

let modalImportar = new bootstrap.Modal(document.getElementById('modalImportar'));
let modalLanc = new bootstrap.Modal(document.getElementById('modalLancamentos'));
let modalSyncERP = new bootstrap.Modal(document.getElementById('modalSyncERP'));
let modalDetalheConta = new bootstrap.Modal(document.getElementById('modalDetalheConta'));

// Controlar comportamento do ESC entre modais
$('#modalDetalheConta').on('show.bs.modal', function() {
  // Ajustar z-index do backdrop
  setTimeout(() => {
    const backdrop = document.querySelectorAll('.modal-backdrop');
    if (backdrop.length > 1) {
      backdrop[backdrop.length - 1].style.zIndex = '1060';
    }
  }, 50);
});

$('#modalDetalheConta').on('shown.bs.modal', function() {
  // Forçar foco no modal de detalhe para capturar ESC corretamente
  $(this).focus();
  
  // Capturar ESC no modal de detalhe e prevenir propagação
  $(this).off('keydown.escModal').on('keydown.escModal', function(e) {
    if (e.key === 'Escape' || e.keyCode === 27) {
      e.stopPropagation();
      modalDetalheConta.hide();
    }
  });
});

$('#modalDetalheConta').on('hidden.bs.modal', function() {
  // Remover handler de ESC
  $(this).off('keydown.escModal');
});
let idloteAtual = null;
let importEmAndamento = false;
let idloteLancamentosAtual = null;
let totaisServidorRealizado = null;

// Estruturas para árvore do realizado
let raizRealizado = [];
let mapaIdReal = {};
let mapaCdReal = {};
let buscaRealizadoTermo = '';
let buscaRealizadoResultados = [];
let buscaRealizadoIndex = -1;
let buscaRealizadoSelecionadoId = null;

function setImportRunning(running) {
  importEmAndamento = running;
  $('#importProgresso').toggle(running);
  $('#importOverlay').toggle(running);
  $('#arquivoCSV').prop('disabled', running);
  $('#btnFecharImportar, #btnFecharImportarFooter').prop('disabled', running);
  if (running) {
    document.body.style.cursor = 'wait';
  } else {
    document.body.style.cursor = '';
  }
}

function setSyncRunning(running) {
  $('#importOverlay').toggle(running);
  $('#btnFecharSync, #btnFecharSyncFooter').prop('disabled', running);
  if (running) {
    document.body.style.cursor = 'wait';
  } else {
    document.body.style.cursor = '';
  }
}

function setSyncStage(stage) {
  const $bar = $('#syncProgresso .progress-bar');
  const steps = ['preparar', 'sincronizar', 'consolidar', 'atualizar'];
  let idx = steps.indexOf(stage);
  if (idx === -1) idx = 0;

  $('#syncEtapas li').removeClass('fw-bold text-success');
  steps.forEach((s, i) => {
    const $li = $(`#syncEtapas li[data-step="${s}"]`);
    if (i < idx) {
      $li.addClass('text-success fw-bold');
    } else if (i === idx) {
      $li.addClass('fw-bold');
    }
  });

  let width = 0;
  if (stage === 'preparar') width = 15;
  else if (stage === 'sincronizar') width = 50;
  else if (stage === 'consolidar') width = 80;
  else if (stage === 'atualizar') width = 100;
  $bar.css('width', width + '%');
}

function setImportStage(stage) {
  const $bar = $('#importProgresso .progress-bar');
  const steps = ['upload', 'preview', 'confirm'];
  let idx = steps.indexOf(stage);
  if (idx === -1) idx = 0;

  $('#importEtapas li').removeClass('fw-bold text-success');
  steps.forEach((s, i) => {
    const $li = $(`#importEtapas li[data-step="${s}"]`);
    if (i < idx) {
      $li.addClass('text-success fw-bold');
    } else if (i === idx) {
      $li.addClass('fw-bold');
    }
  });

  let width = 0;
  if (stage === 'upload') width = 30;
  else if (stage === 'preview') width = 70;
  else if (stage === 'confirm') width = 100;
  $bar.css('width', width + '%');
}

$('#btnBuscar').on('click', carregarLotes);
$('#btnSyncERP').on('click', abrirModalSyncERP);

function carregarLotes() {
  const params = new URLSearchParams({
    anoref: $('#filtroAno').val(),
    cdcentrocusto: $('#filtroCentro').val(),
    florigem: $('#filtroOrigem').val(),
    dtinicio: $('#filtroDataIni').val(),
    dtfim: $('#filtroDataFim').val()
  });

  fetch('?m=realizado_actions&ajax=listar_lotes&' + params)
    .then(r => r.json())
    .then(dados => {
      const $tb = $('#tabelaLotes').empty();

      if (!dados.length) {
        $tb.append('<tr><td colspan="8" class="text-center py-3 text-muted">Nenhum registro encontrado</td></tr>');
        return;
      }

      dados.forEach(l => {
        const dtUlt = l.dtultima_sync || '';
        const usuario = l.usuario_sync || '';
        const situacao = l.situacao_label || (l.tem_lanc ? 'Com lançamentos' : 'Sem lançamentos');
        const origem = l.origem_label || 'ERP';
        const desc   = l.descricao || '';
        const desabilitarVer = !l.idlote;
        const tr = `
          <tr>
            <td>${l.anoref}</td>
            <td>${escapeHtml(desc)}</td>
            <td>${origem}</td>
            <td class="text-muted small">${dtUlt || '-'}</td>
            <td class="text-muted small">${escapeHtml(usuario || '')}</td>
            <td class="text-muted small">${escapeHtml(situacao)}</td>
            <td class="text-center">
              <button class="btn btn-sm btn-outline-primary ver" ${desabilitarVer ? 'disabled' : ''}><i class="bi bi-eye"></i></button>
              <button class="btn btn-sm btn-outline-danger exc"><i class="bi bi-trash"></i></button>
            </td>
          </tr>
        `;
        const $tr = $(tr);
        if (!desabilitarVer) {
          $tr.find('.ver').on('click', () => abrirLancamentos(l.idlote, l.anoref, desc));
        }
        // Excluir continua usando idlote quando existir
        if (l.idlote) {
          $tr.find('.exc').on('click', () => excluirLote(l.idlote, l));
        } else {
          $tr.find('.exc').prop('disabled', true);
        }
        $tb.append($tr);
      });
    });
}

async function abrirModalSyncERP() {
  $('#syncResultado').empty();
  $('#syncProgresso').hide();
  $('#syncEtapas li').removeClass('fw-bold text-success');
  $('#syncProgresso .progress-bar').css('width', '0%');
  const hoje = new Date();
  const primeiroDia = new Date(hoje.getFullYear(), hoje.getMonth(), 1);
  const ultimoDia   = new Date(hoje.getFullYear(), hoje.getMonth() + 1, 0);

  const toISO = d => new Date(d.getTime() - d.getTimezoneOffset()*60000).toISOString().slice(0, 10);

  $('#syncDataIni').val(toISO(primeiroDia));
  $('#syncDataFim').val(toISO(ultimoDia));

  modalSyncERP.show();
}

$('#btnConfirmarSync').on('click', async function() {
  const dataIni = $('#syncDataIni').val();
  const dataFim = $('#syncDataFim').val();

  if (!dataIni || !dataFim) {
    alert('Informe a data inicial e final do período.');
    return;
  }

  const dtIni = new Date(dataIni + 'T00:00:00');
  const dtFim = new Date(dataFim + 'T00:00:00');
  if (dtFim < dtIni) {
    alert('Data final não pode ser menor que a inicial.');
    return;
  }

  // Regra: intervalo máximo de 30 dias dentro do mesmo mês
  if (dtIni.getFullYear() !== dtFim.getFullYear() || dtIni.getMonth() !== dtFim.getMonth()) {
    alert('O período de sincronização deve estar dentro do mesmo mês.');
    return;
  }

  const diffMs = dtFim - dtIni;
  const diffDias = Math.floor(diffMs / (1000 * 60 * 60 * 24)) + 1; // inclui o dia inicial
  if (diffDias > 31) {
    alert('Selecione um intervalo máximo de 30 dias para sincronizar.');
    return;
  }

  $('#btnConfirmarSync').prop('disabled', true).text('Sincronizando...');
  $('#syncProgresso').show();
  setSyncStage('preparar');
  setSyncRunning(true);
  $('#syncResultado').html(`
    <div class="text-center py-3">
      <div class="spinner-border text-warning" role="status">
        <span class="visually-hidden">Sincronizando...</span>
      </div>
      <p class="mt-2 mb-0">Sincronizando dados do período ${dataIni} até ${dataFim}, aguarde...</p>
    </div>
  `);

  try {
    const body = JSON.stringify({
      dtinicio: dataIni,
      dtfim: dataFim
    });
    setSyncStage('sincronizar');
    const resp = await fetch('?m=realizado_actions&ajax=sincronizar_periodo', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json;charset=UTF-8' },
      body: body
    });

    let json, texto;
    try {
      texto = await resp.text();
      if (!texto) {
        throw new Error('Resposta vazia do servidor');
      }
      json = JSON.parse(texto);
    } catch (parseErr) {
      console.error('Erro ao parsear JSON:', parseErr, 'Resposta:', texto);
      $('#syncResultado').html(`<div class="alert alert-danger mt-2">Erro ao processar resposta do servidor (${resp.status})</div>`);
      $('#btnConfirmarSync').prop('disabled', false).text('Sincronizar agora');
      setSyncRunning(false);
      return;
    }
    
    if (!json.ok) {
      $('#syncResultado').html(`<div class="alert alert-warning mt-2">${json.msg || 'Erro na sincronização'}</div>`);
      $('#btnConfirmarSync').prop('disabled', false).text('Sincronizar agora');
      setSyncRunning(false);
      return;
    }

    let htmlResumo = `
      <div class="mt-2">
        <h6 class="mb-2"><i class="bi bi-check-circle"></i> Sincronização concluída</h6>
        <div class="alert alert-success py-2 px-2 small">${json.msg}</div>
        <div class="alert alert-info py-2 px-2 small mb-0">
          <strong>Totais:</strong> ${json.total || 0} inseridos | ${json.ignorados || 0} ignorados | ${json.erros || 0} erros
        </div>
    `;

    // ✨ Exibir status da consolidação de dados
    if (json.consolidacao) {
      const consolidacao = json.consolidacao;
      const statusClass = consolidacao.ok ? 'alert-success' : 'alert-warning';
      let consolidacaoHtml = `<div class="alert ${statusClass} py-2 px-2 small mt-2 mb-2">
        <strong>📊 Consolidação de Dados:</strong><br>`;
      
      if (consolidacao.mensagens && consolidacao.mensagens.length > 0) {
        consolidacaoHtml += consolidacao.mensagens.join('<br>');
      }
      consolidacaoHtml += '</div>';
      
      htmlResumo += consolidacaoHtml;
    }

    if (json.ignorados_motivos) {
      const m = json.ignorados_motivos;
      const itens = [];
      if (m.empresa_origem_sem_mapeamento) itens.push(`<li>${m.empresa_origem_sem_mapeamento} com empresa de origem sem mapeamento em back.empresa.cdintegracao</li>`);
      if (m.empresa_nao_vinculada_integracao) itens.push(`<li>${m.empresa_nao_vinculada_integracao} de empresas não vinculadas à integração (back.integracao_empresa)</li>`);
      if (m.dtmovimento_vazio) itens.push(`<li>${m.dtmovimento_vazio} sem dtmovimento na query de origem</li>`);
      if (m.dtmovimento_invalido) itens.push(`<li>${m.dtmovimento_invalido} com dtmovimento em formato inválido</li>`);
      if (m.exercicio_nao_criado) itens.push(`<li>${m.exercicio_nao_criado} sem exercício válido para empresa/ano</li>`);

      if (itens.length) {
        htmlResumo += `
          <div class="alert alert-warning py-2 px-2 small mt-2 mb-0">
            <strong>Motivos dos ignorados:</strong>
            <ul class="mb-0">${itens.join('')}</ul>
          </div>
        `;
      }
    }

    htmlResumo += '</div>';

    $('#syncResultado').html(htmlResumo);
    setSyncStage('consolidar');
    // Aguardar um pouco para demonstrar a etapa de consolidação
    await new Promise(resolve => setTimeout(resolve, 500));
    setSyncStage('atualizar');
    carregarLotes();
  } catch (e) {
    console.error(e);
    $('#syncResultado').html(`<div class="alert alert-danger mt-2">${e.message || 'Erro inesperado na sincronização.'}</div>`);
    setSyncRunning(false);
  } finally {
    setSyncRunning(false);
    $('#btnConfirmarSync').prop('disabled', false).text('Sincronizar agora');
  }
});

let detalheContaAtual = null;

function abrirDetalheConta(idlote, cdconta, dsconta, cdplanocontabil, ehSintetica = false) {
  // Salva contexto para refiltrar
  detalheContaAtual = { idlote, cdconta, dsconta, cdplanocontabil, ehSintetica };

  // Define período padrão: mês corrente
  const hoje = new Date();
  const primeiroDia = new Date(hoje.getFullYear(), hoje.getMonth(), 1);
  const ultimoDia = new Date(hoje.getFullYear(), hoje.getMonth() + 1, 0);
  const toISO = d => new Date(d.getTime() - d.getTimezoneOffset()*60000).toISOString().slice(0, 10);

  $('#detalheDataIni').val(toISO(primeiroDia));
  $('#detalheDataFim').val(toISO(ultimoDia));

  $('#detalheContaInfo').html(
    `<strong>Conta:</strong> ${escapeHtml(cdconta)} - ${escapeHtml(dsconta || '')}`
  );

  $('#tbDetalheConta').html('<tr><td colspan="5" class="text-center py-3 text-muted">Carregando...</td></tr>');
  $('#detalheTotalValor').text('0,00');
  modalDetalheConta.show();

  carregarDetalheConta();
}

function carregarDetalheConta() {
  if (!detalheContaAtual) return;

  const { idlote, cdconta, dsconta, cdplanocontabil, ehSintetica } = detalheContaAtual;
  const dtIni = $('#detalheDataIni').val();
  const dtFim = $('#detalheDataFim').val();

  $('#tbDetalheConta').html('<tr><td colspan="5" class="text-center py-3 text-muted">Carregando...</td></tr>');

  const params = new URLSearchParams({
    idlote: idlote,
    cdconta: cdconta,
    cdplanocontabil: cdplanocontabil || '',
    dtinicio: dtIni,
    dtfim: dtFim,
    hierarquia: ehSintetica ? '1' : '0'
  });

  fetch(`?m=realizado_actions&ajax=listar_lancamentos_detalhe_conta&${params.toString()}`)
    .then(r => r.json())
    .then(dados => {
      const $tb = $('#tbDetalheConta').empty();

      if (!Array.isArray(dados)) {
        const msg = dados && dados.msg ? dados.msg : 'Erro ao carregar detalhes da conta.';
        $tb.append(`<tr><td colspan="5" class="text-center py-3 text-danger">${escapeHtml(msg)}</td></tr>`);
        return;
      }

      if (!dados.length) {
        $tb.append('<tr><td colspan="5" class="text-center py-3 text-muted">Nenhum lançamento encontrado para esta conta no período.</td></tr>');
        return;
      }

      let totalDeb = 0;
      let totalCred = 0;

      if (ehSintetica) {
        // Agrupar lançamentos por conta filha (cdplanocontabil)
        const contasMap = {};
        dados.forEach(l => {
          // Usar cdplanocontabil como chave para agrupar corretamente
          const chave = l.cdplanocontabil || l.cdconta || 'sem_conta';
          if (!contasMap[chave]) {
            contasMap[chave] = {
              cdplanocontabil: l.cdplanocontabil,
              cdconta: l.cdconta,
              dsconta: l.dsconta,
              lancamentos: [],
              totalDeb: 0,
              totalCred: 0
            };
          }
          contasMap[chave].lancamentos.push(l);
          
          const valor = Number(l.valor || 0);
          if (l.tpmovimento === 'C') {
            contasMap[chave].totalCred += valor;
            totalCred += valor;
          } else if (l.tpmovimento === 'D') {
            contasMap[chave].totalDeb += valor;
            totalDeb += valor;
          }
        });

        // Ordenar contas por código
        const contas = Object.values(contasMap).sort((a, b) => {
          const codA = a.cdconta || '';
          const codB = b.cdconta || '';
          return codA.localeCompare(codB);
        });

        // Renderizar cada conta filha com seus lançamentos
        contas.forEach((conta, idx) => {
          // Cabeçalho da conta filha
          const saldoConta = conta.totalCred - conta.totalDeb;
          const absSaldoConta = Math.abs(saldoConta);
          const naturezaConta = saldoConta === 0 ? '' : (saldoConta > 0 ? ' (C)' : ' (D)');
          const idConta = `conta_${conta.cdplanocontabil || idx}`;
          
          const trCabecalho = $(`
            <tr style="background: #f8f9fa; font-weight: 600; border-left: 3px solid #6c757d; cursor: pointer;" class="conta-header" data-target="${idConta}">
              <td colspan="5" style="padding: 12px 16px;">
                <i class="bi bi-plus-square me-2 icone-expandir" style="color: #6c757d;"></i>
                <strong style="color: #212529;">${escapeHtml(conta.cdconta)}</strong> <span style="color: #6c757d;">- ${escapeHtml(conta.dsconta || '')}</span>
                <span class="float-end">
                  <small class="text-muted me-3">D: ${formatarMoeda(conta.totalDeb)} | C: ${formatarMoeda(conta.totalCred)}</small>
                  <span class="${saldoConta > 0 ? 'badge bg-success' : (saldoConta < 0 ? 'badge bg-danger' : 'badge bg-secondary')}">
                    ${formatarMoeda(absSaldoConta)}${naturezaConta}
                  </span>
                </span>
              </td>
            </tr>
          `);
          
          trCabecalho.on('click', function() {
            const target = $(this).data('target');
            const $icone = $(this).find('.icone-expandir');
            const estaExpandido = $icone.hasClass('bi-dash-square');
            
            if (estaExpandido) {
              $icone.removeClass('bi-dash-square').addClass('bi-plus-square');
              $(`.${target}`).hide();
            } else {
              $icone.removeClass('bi-plus-square').addClass('bi-dash-square');
              $(`.${target}`).show();
            }
          });
          
          $tb.append(trCabecalho);

          // Ordenar lançamentos por data
          conta.lancamentos.sort((a, b) => {
            const dtA = a.dtmovimento || '';
            const dtB = b.dtmovimento || '';
            return dtA.localeCompare(dtB);
          });

          // Lançamentos da conta filha (inicialmente ocultos)
          conta.lancamentos.forEach(l => {
            const data = l.dtmovimento
              ? new Date(l.dtmovimento + 'T00:00:00').toLocaleDateString('pt-BR')
              : '';
            const tipo = l.tpmovimento === 'D' ? 'D' : (l.tpmovimento === 'C' ? 'C' : '');
            const valor = Number(l.valor || 0);
            const valStr = formatarMoeda(Math.abs(valor));
            const classeValor = l.tpmovimento === 'D' ? 'text-danger' : 'text-success';

            $tb.append(`
              <tr style="background: #ffffff; display: none; border-bottom: 1px solid #f0f0f0;" class="${idConta}">
                <td style="padding-left: 40px; color: #6c757d; font-size: 0.9rem;">
                  <i class="bi bi-arrow-return-right me-1" style="font-size: 0.75rem; color: #adb5bd;"></i> 
                  ${escapeHtml(conta.cdconta)}
                </td>
                <td style="font-size: 0.9rem; color: #495057;">${escapeHtml(data)}</td>
                <td style="font-size: 0.9rem; color: #495057;">${escapeHtml(l.dscomplemento || '')}</td>
                <td class="text-center" style="font-size: 0.9rem;">
                  <span class="badge ${tipo === 'D' ? 'bg-danger' : 'bg-success'} badge-sm">${tipo}</span>
                </td>
                <td class="text-end ${classeValor}" style="font-size: 0.9rem; font-weight: 500;">${valStr}</td>
              </tr>
            `);
          });

          // Linha de subtotal da conta (inicialmente oculta)
          $tb.append(`
            <tr style="background: #f8f9fa; font-weight: 600; border-bottom: 1px solid #dee2e6; border-top: 1px solid #dee2e6; display: none;" class="${idConta}">
              <td colspan="4" class="text-end" style="padding: 8px 16px; font-size: 0.9rem; color: #495057;">
                <i class="bi bi-calculator me-1"></i> Subtotal ${escapeHtml(conta.dsconta || conta.cdconta)}
              </td>
              <td class="text-end ${saldoConta > 0 ? 'text-success' : (saldoConta < 0 ? 'text-danger' : 'text-muted')}" style="padding: 8px 16px; font-size: 0.95rem; font-weight: 600;">
                ${formatarMoeda(absSaldoConta)}${naturezaConta}
              </td>
            </tr>
          `);

          // Separador entre contas (exceto na última)
          if (idx < contas.length - 1) {
            $tb.append(`<tr style="height: 16px; background: #fff;"><td colspan="5"></td></tr>`);
          }
        });

      } else {
        // Conta analítica - exibição simples
        dados.forEach(l => {
          const valor = Number(l.valor || 0);
          if (l.tpmovimento === 'C') {
            totalCred += valor;
          } else if (l.tpmovimento === 'D') {
            totalDeb += valor;
          }

          const data = l.dtmovimento
            ? new Date(l.dtmovimento + 'T00:00:00').toLocaleDateString('pt-BR')
            : '';
          const tipo = l.tpmovimento === 'D' ? 'Débito' : (l.tpmovimento === 'C' ? 'Crédito' : (l.tpmovimento || ''));
          const valStr = formatarMoeda(valor);

          const contaInfo = l.dsconta ? `${escapeHtml(l.cdconta)} - ${escapeHtml(l.dsconta)}` : escapeHtml(l.cdconta || '');

          $tb.append(`
            <tr>
              <td>${contaInfo}</td>
              <td>${escapeHtml(data)}</td>
              <td>${escapeHtml(l.dscomplemento || '')}</td>
              <td class="text-center">${escapeHtml(tipo)}</td>
              <td class="text-end">${valStr}</td>
            </tr>
          `);
        });
      }

      const saldo = totalCred - totalDeb;
      const absSaldo = Math.abs(saldo);
      const naturezaSaldo = saldo === 0 ? '' : (saldo > 0 ? ' (C)' : ' (D)');

      $('#detalheTotalValor').text(formatarMoeda(absSaldo) + naturezaSaldo);

      $('#detalheTotaisResumo').html(
        `<strong>Débito:</strong> ${escapeHtml(formatarMoeda(totalDeb))} (D) &nbsp;|&nbsp; ` +
        `<strong>Crédito:</strong> ${escapeHtml(formatarMoeda(totalCred))} (C) &nbsp;|&nbsp; ` +
        `<strong>Saldo (Crédito − Débito):</strong> ${escapeHtml(formatarMoeda(absSaldo) + naturezaSaldo)}`
      );
    })
    .catch(err => {
      console.error('Erro ao carregar detalhes da conta:', err);
      $('#tbDetalheConta').html('<tr><td colspan="5" class="text-center py-3 text-danger">Erro ao carregar detalhes.</td></tr>');
    });
}

$('#btnFiltrarDetalhe').on('click', carregarDetalheConta);

function montarArvoreRealizado(lista) {
  raizRealizado = [];
  mapaIdReal = {};
  mapaCdReal = {};

  if (!Array.isArray(lista)) lista = [];

  lista.forEach(c => {
    const node = {
      id: Number(c.cdcontacontabil),
      cd: c.cdconta,
      pai: c.cdcontapai || null,
      desc: c.dsconta,
      tipo: c.fltipo,
      valores: Array.isArray(c.valores) ? c.valores.map(x => Number(x) || 0) : Array(12).fill(0),
      filhos: [],
      expanded: false,
      nivel: 0
    };

    mapaIdReal[node.id] = node;
    mapaCdReal[node.cd] = node;
  });

  Object.values(mapaCdReal).forEach(n => {
    if (n.pai && mapaCdReal[n.pai]) {
      const p = mapaCdReal[n.pai];
      n.nivel = (p.nivel || 0) + 1;
      p.filhos.push(n);
    } else {
      raizRealizado.push(n);
    }
  });

  raizRealizado.sort((a, b) => a.cd.localeCompare(b.cd));
  Object.values(mapaCdReal).forEach(n => n.filhos.sort((a, b) => a.cd.localeCompare(b.cd)));
}

function somarArvoreRealizado() {
  function somarNode(n) {
    if (n.tipo === 'A') return n.valores;

    const soma = Array(12).fill(0);
    n.filhos.forEach(f => {
      const vf = somarNode(f);
      for (let i = 0; i < 12; i++) soma[i] += Number(vf[i]) || 0;
    });
    n.valores = soma;
    return soma;
  }

  raizRealizado.forEach(r => somarNode(r));
}

function atualizarTotaisRealizado(nodesRaiz) {
  // Se já temos os totais vindos do backend para este lote,
  // sempre os reaplicamos no rodapé para manter o valor
  // idêntico ao da listagem, mesmo ao expandir/colapsar a
  // árvore na tela.
  if (totaisServidorRealizado) {
    aplicarTotaisServidor(totaisServidorRealizado);
    return;
  }

  const mesesIds = ['', 'jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];
  const totaisMes = Array(13).fill(0);

  const nodes = nodesRaiz && nodesRaiz.length ? nodesRaiz : raizRealizado;

  nodes.forEach(n => {
    for (let i = 0; i < 12; i++) {
      totaisMes[i + 1] += Number(n.valores[i]) || 0;
    }
  });

  for (let mes = 1; mes <= 12; mes++) {
    const valor = totaisMes[mes] || 0;
    const absVal = Math.abs(valor);
    const marcador = valor === 0 ? '' : (valor > 0 ? ' (C)' : ' (D)');
    const valStr = formatarMoeda(absVal) + marcador;
    const classe = valor > 0 ? 'text-success fw-semibold' : (valor < 0 ? 'text-danger fw-semibold' : 'text-muted');
    const $cel = $(`#total_${mesesIds[mes]}`);
    $cel.removeClass('text-success fw-semibold text-danger text-muted');
    $cel.addClass(classe);
    $cel.text(valStr);
  }

  const totalGeral = totaisMes.reduce((acc, v) => acc + v, 0);
  const absTotal = Math.abs(totalGeral);
  const marcadorTotal = totalGeral === 0 ? '' : (totalGeral > 0 ? ' (C)' : ' (D)');
  const totalStr = formatarMoeda(absTotal) + marcadorTotal;
  const classeTotal = totalGeral > 0 ? 'text-success fw-bold' : (totalGeral < 0 ? 'text-danger fw-bold' : 'text-muted fw-bold');
  const $celTotal = $('#total_final');
  $celTotal.removeClass('text-success fw-bold text-danger text-muted');
  $celTotal.addClass(classeTotal);
  $celTotal.text(totalStr);
}

// Aplica totais vindos do backend (garante que o rodapé
// sempre bata exatamente com o total do lote da listagem).
function aplicarTotaisServidor(totais) {
  if (!totais || !totais.meses) {
    totaisServidorRealizado = null;
    return;
  }

  totaisServidorRealizado = totais;

  const mesesIds = ['', 'jan','fev','mar','abr','mai','jun','jul','ago','set','out','nov','dez'];
  const totaisMes = totais.meses || {};

  let totalGeral = 0;

  for (let mes = 1; mes <= 12; mes++) {
    const bruto = Number(totaisMes[mes] || 0);
    totalGeral += bruto;

    const absVal = Math.abs(bruto);
    const marcador = bruto === 0 ? '' : (bruto > 0 ? ' (C)' : ' (D)');
    const valStr = formatarMoeda(absVal) + marcador;
    const classe = bruto > 0 ? 'text-success fw-semibold' : (bruto < 0 ? 'text-danger fw-semibold' : 'text-muted');
    const $cel = $(`#total_${mesesIds[mes]}`);
    $cel.removeClass('text-success fw-semibold text-danger text-muted');
    $cel.addClass(classe);
    $cel.text(valStr);
  }

  const absTotal = Math.abs(totalGeral);
  const marcadorTotal = totalGeral === 0 ? '' : (totalGeral > 0 ? ' (C)' : ' (D)');
  const totalStr = formatarMoeda(absTotal) + marcadorTotal;
  const classeTotal = totalGeral > 0 ? 'text-success fw-bold' : (totalGeral < 0 ? 'text-danger fw-bold' : 'text-muted fw-bold');
  const $celTotal = $('#total_final');
  $celTotal.removeClass('text-success fw-bold text-danger text-muted');
  $celTotal.addClass(classeTotal);
  $celTotal.text(totalStr);
}

function renderTabelaRealizado() {
  const $tb = $('#tbLancamentos').empty();

  if (!raizRealizado.length) {
    $tb.append('<tr><td colspan="14" class="text-center py-4 text-muted">Nenhum lançamento encontrado</td></tr>');
    atualizarTotaisRealizado([]);
    return;
  }

  raizRealizado.forEach(n => renderLinhaRealizado($tb, n));
  atualizarTotaisRealizado(raizRealizado);

  // aplicar destaque e scroll para item selecionado na busca
  if (buscaRealizadoSelecionadoId !== null) {
    const $row = $(`#tbLancamentos tr[data-id="${buscaRealizadoSelecionadoId}"]`);
    if ($row.length) {
      $('#tbLancamentos tr').removeClass('table-info');
      $row.addClass('table-info');
      const el = $row.get(0);
      if (el && typeof el.scrollIntoView === 'function') {
        el.scrollIntoView({block: 'center'});
      }
    }
  }
}

function renderLinhaRealizado(tbody, n) {
  const tr = $('<tr></tr>').attr('data-id', n.id);
  const indent = (n.nivel || 0) * 20;

  let expandBtn = '';
  if (n.tipo === 'S') {
    expandBtn = `
      <span class="tree-btn" data-id="${n.id}" style="font-weight:bold; cursor:pointer; margin-right:6px;">
        ${n.expanded ? '−' : '+'}
      </span>`;
  } else {
    expandBtn = '<span class="tree-leaf" style="color:#888; margin-right:6px;">•</span>';
  }

  const descHtml = n.tipo === 'S' ? `<strong>${escapeHtml(n.desc)}</strong>` : escapeHtml(n.desc);

  tr.append(`
  <td style="position:sticky; left:0; background:white; z-index:10; white-space:nowrap; padding:10px 16px; border-left:4px solid #667eea;">
    <span class="tree-indent" style="display:inline-block; width:${indent}px"></span>
    ${expandBtn}
    ${descHtml} <span class="text-muted">(${n.id})</span>
    <span class="ms-1 text-primary detalhe-btn" data-id="${n.id}" title="Ver detalhes de cálculo" style="cursor:pointer;"><i class="bi bi-search"></i></span>
  </td>
  `);

  let total = 0;
  for (let i = 0; i < 12; i++) {
    const valor = Number(n.valores[i]) || 0;
    total += valor;
    const isCred = valor >= 0;
    const absVal = Math.abs(valor);
    const valStrBase = formatarMoeda(absVal);
    const marcador = valor === 0 ? '' : (isCred ? ' (C)' : ' (D)');
    const valStr = valStrBase + marcador;
    let classe = 'text-muted';
    if (valor > 0) classe = 'text-success fw-semibold';
    else if (valor < 0) classe = 'text-danger fw-semibold';
    tr.append(`<td class="text-end ${classe}" style="padding:10px 10px; vertical-align:middle;">${valStr}</td>`);
  }

  const isTotalCred = total >= 0;
  const absTotal = Math.abs(total);
  const totalStrBase = formatarMoeda(absTotal);
  const marcadorTotal = total === 0 ? '' : (isTotalCred ? ' (C)' : ' (D)');
  const totalStr = totalStrBase + marcadorTotal;
  const totalClasse = total > 0 ? 'text-success fw-bold' : (total < 0 ? 'text-danger fw-bold' : 'text-muted fw-bold');
  tr.append(`<td class="text-end ${totalClasse}" style="padding:10px 10px; background:rgba(102,126,234,0.1); border-right:4px solid #667eea; vertical-align:middle;">${totalStr}</td>`);

  // Ícone dedicado para abrir o detalhe da conta (analítica ou sintética)
  if (n.tipo === 'A' || n.tipo === 'S') {
    const cdplanocontabil = n.tipo === 'A' ? n.id : null;
    const ehSintetica = n.tipo === 'S';

    tr.find('.detalhe-btn').on('click', (ev) => {
      ev.stopPropagation();
      abrirDetalheConta(idloteLancamentosAtual, n.cd, n.desc, cdplanocontabil, ehSintetica);
    });

    // Comportamento da linha inteira:
    // - Sintética: clicar na linha expande/recolhe (como o '+')
    // - Analítica: clicar na linha abre o detalhe
    tr.css('cursor', 'pointer');
    tr.on('click', (ev) => {
      // Se clicou diretamente no botão de detalhe, já tratamos acima
      if ($(ev.target).closest('.detalhe-btn').length) return;

      if (n.tipo === 'S') {
        toggleExpandRealizado(n.id);
      } else {
        abrirDetalheConta(idloteLancamentosAtual, n.cd, n.desc, cdplanocontabil, ehSintetica);
      }
    });
  }

  tbody.append(tr);

  if (n.expanded) {
    n.filhos.forEach(f => renderLinhaRealizado(tbody, f));
  }
}

function toggleExpandRealizado(id) {
  if (!mapaIdReal[id]) return;
  mapaIdReal[id].expanded = !mapaIdReal[id].expanded;
  renderTabelaRealizado();
}

function recomputarBuscaRealizado() {
  buscaRealizadoTermo = ($('#lancSearch').val() || '').trim();
  buscaRealizadoResultados = [];
  buscaRealizadoIndex = -1;
  buscaRealizadoSelecionadoId = null;

  const termo = buscaRealizadoTermo.toLowerCase();
  if (!termo) {
    renderTabelaRealizado();
    return;
  }

  Object.values(mapaIdReal).forEach(n => {
    const desc = (n.desc || '').toLowerCase();
    const cd   = (n.cd || '').toLowerCase();
    if (desc.includes(termo) || cd.includes(termo)) {
      buscaRealizadoResultados.push(n.id);
    }
  });

  if (buscaRealizadoResultados.length) {
    buscarRealizadoIrPara(0);
  } else {
    renderTabelaRealizado();
  }
}

function buscarRealizadoIrPara(index) {
  if (!buscaRealizadoResultados.length) return;

  if (index < 0) index = 0;
  if (index >= buscaRealizadoResultados.length) index = buscaRealizadoResultados.length - 1;

  buscaRealizadoIndex = index;
  const id = buscaRealizadoResultados[buscaRealizadoIndex];
  const node = mapaIdReal[id];
  if (!node) return;

  // expandir ancestrais
  let atual = node;
  while (atual && atual.pai) {
    const pai = mapaCdReal[atual.pai];
    if (!pai) break;
    pai.expanded = true;
    atual = pai;
  }

  buscaRealizadoSelecionadoId = id;
  renderTabelaRealizado();
}

function buscarRealizadoProximo(delta) {
  if (!buscaRealizadoResultados.length) return;
  if (buscaRealizadoIndex === -1) {
    buscarRealizadoIrPara(0);
    return;
  }

  const len = buscaRealizadoResultados.length;
  let idx = (buscaRealizadoIndex + delta) % len;
  if (idx < 0) idx = len - 1;
  buscarRealizadoIrPara(idx);
}

// eventos de busca
$(document).on('input', '#lancSearch', function() {
  recomputarBuscaRealizado();
});

$(document).on('keydown', '#lancSearch', function(e) {
  if (e.key === 'Enter') {
    e.preventDefault();
    if (!buscaRealizadoTermo.trim()) {
      recomputarBuscaRealizado();
    } else {
      buscarRealizadoProximo(1);
    }
  }
});

$(document).on('keydown', function(e) {
  if (e.key === 'F3' && $('#modalLancamentos').hasClass('show')) {
    e.preventDefault();
    if (!buscaRealizadoTermo.trim()) {
      recomputarBuscaRealizado();
    } else {
      buscarRealizadoProximo(1);
    }
  }
});

function abrirLancamentos(idlote, anoref = null, descEx = '') {
  $('#tbLancamentos').html('<tr><td colspan="14" class="text-center py-4 text-muted">Carregando...</td></tr>');
  modalLanc.show();

  idloteLancamentosAtual = idlote;
  totaisServidorRealizado = null;

  // Atualiza indicação de exercício/descrição no cabeçalho do modal
  let info = '';
  if (anoref) info = 'Exercício ' + anoref;
  if (descEx) info += (info ? ' - ' : '') + descEx;
  $('#infoExercicioLanc').text(info);

   // reset busca ao abrir o modal
  buscaRealizadoTermo = '';
  buscaRealizadoResultados = [];
  buscaRealizadoIndex = -1;
  buscaRealizadoSelecionadoId = null;
  $('#lancSearch').val('');

  const params = new URLSearchParams({
    idlote: idlote,
    anoref: $('#filtroAno').val(),
    cdcentrocusto: $('#filtroCentro').val(),
    florigem: $('#filtroOrigem').val(),
    dtinicio: $('#filtroDataIni').val(),
    dtfim: $('#filtroDataFim').val()
  });

  fetch(`?m=realizado_actions&ajax=listar_lancamentos_lote_arvore&${params.toString()}`)
    .then(r => r.json())
    .then(ret => {
      const $tb = $('#tbLancamentos').empty();

      if (!ret || !ret.ok) {
        const msg = ret && ret.msg ? ret.msg : 'Erro ao carregar lançamentos.';
        $tb.append(`<tr><td colspan="14" class="text-center py-4 text-danger">${escapeHtml(msg)}</td></tr>`);
        return;
      }

      if (!ret.dados || !ret.dados.length) {
        $tb.append('<tr><td colspan="14" class="text-center py-4 text-muted">Nenhum lançamento encontrado</td></tr>');
        atualizarTotaisRealizado([]);
        return;
      }

      montarArvoreRealizado(ret.dados);
      somarArvoreRealizado();
      renderTabelaRealizado();

      // Se o backend mandar os totais já calculados, aplica
      // direto no rodapé para garantir consistência com a
      // listagem de lotes.
      if (ret.totais) {
        aplicarTotaisServidor(ret.totais);
      }
    })
    .catch(err => {
      console.error('Erro ao carregar lançamentos do lote:', err);
      $('#tbLancamentos').html('<tr><td colspan="14" class="text-center py-4 text-danger">Erro ao carregar lançamentos.</td></tr>');
    });
}

function excluirLote(idlote, info) {
  const dtIni = $('#filtroDataIni').val();
  const dtFim = $('#filtroDataFim').val();

  if (!dtIni || !dtFim) {
    alert('Para excluir um lote, informe o período nas datas (inicial e final) do filtro.');
    return;
  }

  if (!confirm(`Excluir lote do realizado no período ${dtIni} a ${dtFim}?\nExercício: ${info.anoref}\nCentro: ${info.dscentro}\nOrigem: ${info.origem_label}`)) return;
  fetch(`?m=realizado_actions&ajax=cancelar_lote&idlote=${encodeURIComponent(idlote)}`)
    .then(r => r.json())
    .then(resp => { alert(resp.msg); if (resp.ok) carregarLotes(); });
}

// Export modelo exige ano+centro (é geração do template)
$('#btnExportModelo').on('click', () => {
  const ano = $('#filtroAno').val();
  const cc  = $('#filtroCentro').val();
  if (!ano || !cc) { alert('Selecione Exercício e Centro de Custo para gerar o modelo.'); return; }
  window.location.href = `?m=realizado_actions&ajax=export_modelo_csv&anoref=${encodeURIComponent(ano)}&cdcentrocusto=${encodeURIComponent(cc)}`;
});

$('#btnExportRealizado').on('click', () => {
  const ano = $('#filtroAno').val();
  if (!ano) { alert('Selecione o exercício para exportar o realizado.'); return; }
  window.location.href = `?m=realizado_actions&ajax=export_realizado_csv&anoref=${encodeURIComponent(ano)}`;
});

$('#btnImportar').on('click', () => {
  idloteAtual = null;
  $('#arquivoCSV').val('');
  $('#importResumo').html('');
   $('#importProgresso').hide();
   $('#importEtapas li').removeClass('fw-bold text-success');
   $('#importProgresso .progress-bar').css('width', '0%');
   $('#btnFecharImportar, #btnFecharImportarFooter').prop('disabled', false);
  $('#btnConfirmarImport').prop('disabled', false);
  modalImportar.show();
});

// New flow: single Confirmar button will upload, preview and confirm
$('#btnConfirmarImport').on('click', async () => {
  const file = $('#arquivoCSV')[0].files[0];
  if (!file) { alert('Selecione um CSV.'); return; }

  $('#btnConfirmarImport').prop('disabled', true);
  $('#importResumo').html('Enviando arquivo para o servidor, aguarde...');
  setImportStage('upload');
  setImportRunning(true);

  // Upload to temp
  const fd = new FormData();
  fd.append('arquivo', file);
  let respTxt;
  try {
    const resp = await fetch('?m=realizado_actions&ajax=importar_csv', { method:'POST', body: fd });
    respTxt = await resp.text();
  } catch (err) {
    console.error('Erro no upload:', err);
    alert('Falha ao enviar o arquivo. Verifique a conexão.');
    setImportRunning(false);
    $('#btnConfirmarImport').prop('disabled', false);
    return;
  }

  let data;
  try { data = JSON.parse(respTxt); }
  catch(e) {
    console.error('Resposta não-JSON:', respTxt);
    alert('Resposta inválida do servidor. Veja o console.');
    setImportRunning(false);
    $('#btnConfirmarImport').prop('disabled', false);
    return;
  }

  if (!data.ok) {
    $('#importResumo').html(`<span class="text-danger">${data.msg}</span>`);
    $('#arquivoCSV').val('');
    setImportRunning(false);
    // keep disabled until user selects a new file
    return;
  }

  idloteAtual = data.idlote;

  // Get preview
  setImportStage('preview');
  $('#importResumo').html('Gerando prévia e validando registros, aguarde...');
  let pv = null;
  try {
    const pvResp = await fetch(`?m=realizado_actions&ajax=preview_lote&idlote=${encodeURIComponent(idloteAtual)}`);
    const pvTxt = await pvResp.text();
    pv = JSON.parse(pvTxt);
  } catch(e) { console.error('Prévia não-JSON ou erro:', e); }

  const ctx = data.contexto || {};
  const rs = data.resumo || {};

  let html = `
    <div class="mb-2">
      <b>Lote:</b> ${idloteAtual}<br>
      <b>Arquivo:</b> ${file.name}<br>
      <b>Exercício detectado:</b> ${ctx.anoref ?? '-'}<br>
      <b>Centro detectado:</b> ${ctx.cdcentrocusto ?? '-'} - ${ctx.dscentro ?? ''}<br>
    </div>
    <div class="mb-2">
      <b>Linhas lidas:</b> ${rs.linhas_lidas ?? '-'} |
      <b>Registros temp:</b> ${rs.registros_temp ?? '-'}<br>
      <b>Válidos:</b> ${rs.validos ?? '-'} |
      <b>Inválidos:</b> ${rs.invalidos ?? '-'}
    </div>
  `;

  if (pv && pv.ok && pv.invalidos && pv.invalidos.length) {
    html += `<div class="alert alert-warning small mb-0">
      <b>Importação com Erros , Verifique:</b><br>` +
      pv.invalidos.map(x => `• ${x.erro}`).join('<br>') +
    `</div>`;
    $('#importResumo').html(html);
    setImportRunning(false);
    // Keep button disabled — user must pick a new file after fixing
    return;
  }

  // No errors on preview: confirm import immediately
  html += `<div class="alert alert-success small mb-0">✓ Prévia pronta e sem erros. Confirmando importação...</div>`;
  $('#importResumo').html(html);

  setImportStage('confirm');

  try {
    const confResp = await fetch(`?m=realizado_actions&ajax=confirmar_importacao&idlote=${encodeURIComponent(idloteAtual)}`);
    const conf = await confResp.json();
    alert(conf.msg);
    if (conf.ok) {
      modalImportar.hide();
      carregarLotes();
      $('#importStatus').text(`Última importação: ${idloteAtual}`);
    } else {
      $('#importResumo').html(`<span class="text-danger">${conf.msg}</span>`);
      $('#arquivoCSV').val('');
      setImportRunning(false);
      $('#btnConfirmarImport').prop('disabled', false);
    }
  } catch (e) {
    console.error('Erro confirmando importação:', e);
    $('#importResumo').html('<span class="text-danger">Erro ao confirmar importação.</span>');
    setImportRunning(false);
    $('#btnConfirmarImport').prop('disabled', false);
  } finally {
    // se ok, modal já foi fechado; se erro, já reabilitamos acima
  }
});

// Allow file reselection to re-enable confirm button
$('#arquivoCSV').on('change', () => {
  $('#btnConfirmarImport').prop('disabled', false);
});

// init
carregarLotes();

// Normalização de datas digitadas (corrige dias inválidos para último dia do mês)
aplicarNormalizacaoData('#filtroDataIni');
aplicarNormalizacaoData('#filtroDataFim');
aplicarNormalizacaoData('#syncDataIni');
aplicarNormalizacaoData('#syncDataFim');
aplicarNormalizacaoData('#detalheDataIni');
aplicarNormalizacaoData('#detalheDataFim');

// Auto-preenchimento de data final com último dia do mês
configurarAutoPreencherDataFim('#filtroDataIni', '#filtroDataFim');
configurarAutoPreencherDataFim('#syncDataIni', '#syncDataFim');
configurarAutoPreencherDataFim('#detalheDataIni', '#detalheDataFim');
</script>
