<?php
namespace Modules\Financeiro\Controllers;

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Audit\AuditLogger;
use Gestoreasy\Core\Fiscal\TaxConfig;
use PDO;

class RelatoriosController {
    private PDO $db;

    public function __construct() {
        $this->db = ConnectionManager::forTenant();
    }

    /**
     * GET /api/financeiro/relatorios/fluxo
     * Parâmetros: start, end, conta_id (opcional)
     * Retorna agregações de entradas/saídas por dia e totais
     */
    public function fluxo(Request $request): Response {
        $start = (string)$request->getQueryParam('start', '');
        $end = (string)$request->getQueryParam('end', '');
        $contaId = (int)$request->getQueryParam('conta_id', 0);
        if ($start === '' || $end === '') {
            return Response::json(['error' => 'Parâmetros start e end são obrigatórios'], 422);
        }

        if (!$this->tableExists('bank_transactions')) {
            return Response::json(['error' => 'Tabela bank_transactions não encontrada'], 404);
        }

        // Filtros
        $where = ['data >= :start', 'data <= :end'];
        $params = ['start' => $start, 'end' => $end];
        if ($contaId > 0) { $where[] = 'conta_id = :cid'; $params['cid'] = $contaId; }
        $wc = implode(' AND ', $where);

        // Série diária: entradas e saídas por dia
        $sqlSeries = "SELECT data, 
            SUM(CASE WHEN tipo='entrada' THEN valor ELSE 0 END) AS entradas,
            SUM(CASE WHEN tipo='saida' THEN valor ELSE 0 END) AS saidas
          FROM bank_transactions WHERE $wc GROUP BY data ORDER BY data ASC";
        $stSeries = $this->db->prepare($sqlSeries);
        foreach ($params as $k=>$v) { $stSeries->bindValue(":$k", $v); }
        $stSeries->execute();
        $series = $stSeries->fetchAll(PDO::FETCH_ASSOC) ?: [];

        // Totais
        $sqlTotals = "SELECT 
            SUM(CASE WHEN tipo='entrada' THEN valor ELSE 0 END) AS total_entradas,
            SUM(CASE WHEN tipo='saida' THEN valor ELSE 0 END) AS total_saidas
          FROM bank_transactions WHERE $wc";
        $stTotals = $this->db->prepare($sqlTotals);
        foreach ($params as $k=>$v) { $stTotals->bindValue(":$k", $v); }
        $stTotals->execute();
        $tot = $stTotals->fetch(PDO::FETCH_ASSOC) ?: ['total_entradas'=>0,'total_saidas'=>0];
        $saldoPeriodo = (float)($tot['total_entradas'] ?? 0) - (float)($tot['total_saidas'] ?? 0);

        AuditLogger::logRead('relatorios_fluxo', null, ['start'=>$start,'end'=>$end,'conta_id'=>$contaId]);
        return Response::json([
            'period' => ['start' => $start, 'end' => $end],
            'totals' => [
                'entradas' => (float)($tot['total_entradas'] ?? 0),
                'saidas' => (float)($tot['total_saidas'] ?? 0),
                'saldo_periodo' => $saldoPeriodo
            ],
            'series' => $series
        ]);
    }

    /**
     * GET /api/financeiro/relatorios/fluxo/export.csv
     */
    public function exportFluxoCsv(Request $request): Response {
        $resp = $this->fluxo($request);
        if ($resp->status !== 200) return $resp;
        $body = $resp->body;

        // Separador CSV configurável
        $sep = (string)$request->getQueryParam('sep', ';');
        if ($sep === 'tab') { $sep = "\t"; }
        $allowed = [',',';','|',"\t"]; $sep = in_array($sep, $allowed, true) ? $sep : ';';

        $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
        $out = fopen('php://temp', 'r+');
        fputs($out, $bom);
        fputcsv($out, ['Relatório', 'Fluxo de Caixa'], $sep);
        fputcsv($out, ['Período', ($body['period']['start'] ?? '').' a '.($body['period']['end'] ?? '')], $sep);
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Totais'], $sep);
        fputcsv($out, ['Entradas', $body['totals']['entradas'] ?? 0], $sep);
        fputcsv($out, ['Saídas', $body['totals']['saidas'] ?? 0], $sep);
        fputcsv($out, ['Saldo no período', $body['totals']['saldo_periodo'] ?? 0], $sep);
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Data','Entradas','Saídas'], $sep);
        foreach (($body['series'] ?? []) as $row) {
            fputcsv($out, [$row['data'] ?? '', $row['entradas'] ?? 0, $row['saidas'] ?? 0], $sep);
        }
        rewind($out);
        $csv = stream_get_contents($out);
        fclose($out);
        return new Response(200, $csv, ['Content-Type' => 'text/csv; charset=utf-8']);
    }

    /**
     * GET /api/financeiro/relatorios/dre
     * Parâmetros: start, end
     * Retorna DRE (Demonstrativo de Resultados) calculado pelo regime de competência simplificado
     */
    public function dre(Request $request): Response {
        $start = (string)$request->getQueryParam('start', '');
        $end = (string)$request->getQueryParam('end', '');
        if ($start === '' || $end === '') {
            return Response::json(['error' => 'Parâmetros start e end são obrigatórios'], 422);
        }

        // Flags de existência de tabelas
        $hasRec = $this->tableExists('contas_receber');
        $hasPay = $this->tableExists('contas_pagar');
        $hasBankTx = $this->tableExists('bank_transactions');

        // Receita bruta: títulos emitidos no período (contas_receber por data_vencimento)
        $receitaBruta = 0.0;
        if ($hasRec) {
            $sql = "SELECT COALESCE(SUM(valor),0) FROM contas_receber WHERE data_vencimento >= :start AND data_vencimento <= :end";
            $stmt = $this->db->prepare($sql);
            $stmt->execute(['start' => $start, 'end' => $end]);
            $receitaBruta = (float)$stmt->fetchColumn();
        }

        // Deduções/impostos: melhor esforço — se existir coluna 'impostos' em contas_receber, somar; senão 0
        $deducoes = 0.0;
        if ($hasRec && $this->columnExists('contas_receber', 'impostos')) {
            $sql = "SELECT COALESCE(SUM(impostos),0) FROM contas_receber WHERE data_vencimento >= :start AND data_vencimento <= :end";
            $stmt = $this->db->prepare($sql);
            $stmt->execute(['start' => $start, 'end' => $end]);
            $deducoes = (float)$stmt->fetchColumn();
        }

        $receitaLiquida = $receitaBruta - $deducoes;

        // Custo dos produtos/serviços: melhor esforço — se existir coluna 'categoria' em contas_pagar, usar categorias de custo
        $custoProdutos = 0.0;
        if ($hasPay) {
            if ($this->columnExists('contas_pagar', 'categoria')) {
                $sql = "SELECT COALESCE(SUM(valor),0) FROM contas_pagar WHERE data_vencimento >= :start AND data_vencimento <= :end AND categoria IN ('custo','custo_produto','custo_servico')";
                $stmt = $this->db->prepare($sql);
                $stmt->execute(['start' => $start, 'end' => $end]);
                $custoProdutos = (float)$stmt->fetchColumn();
            } else {
                // fallback: se existir coluna 'tipo', filtrar por 'custo'; senão 0
                if ($this->columnExists('contas_pagar', 'tipo')) {
                    $sql = "SELECT COALESCE(SUM(valor),0) FROM contas_pagar WHERE data_vencimento >= :start AND data_vencimento <= :end AND tipo = 'custo'";
                    $stmt = $this->db->prepare($sql);
                    $stmt->execute(['start' => $start, 'end' => $end]);
                    $custoProdutos = (float)$stmt->fetchColumn();
                }
            }
        }

        $lucroBruto = $receitaLiquida - $custoProdutos;

        // Despesas operacionais: contas_pagar que não são custo
        $despesasOperacionais = 0.0;
        if ($hasPay) {
            if ($this->columnExists('contas_pagar', 'categoria')) {
                $sql = "SELECT COALESCE(SUM(valor),0) FROM contas_pagar WHERE data_vencimento >= :start AND data_vencimento <= :end AND (categoria IS NULL OR categoria NOT IN ('custo','custo_produto','custo_servico'))";
                $stmt = $this->db->prepare($sql);
                $stmt->execute(['start' => $start, 'end' => $end]);
                $despesasOperacionais = (float)$stmt->fetchColumn();
            } else {
                // fallback: soma total menos custos identificados
                $sql = "SELECT COALESCE(SUM(valor),0) FROM contas_pagar WHERE data_vencimento >= :start AND data_vencimento <= :end";
                $stmt = $this->db->prepare($sql);
                $stmt->execute(['start' => $start, 'end' => $end]);
                $totalPay = (float)$stmt->fetchColumn();
                $despesasOperacionais = max(0.0, $totalPay - $custoProdutos);
            }
        }

        $resultadoOperacional = $lucroBruto - $despesasOperacionais;

        // Despesas não operacionais: se existir tabela bank_transactions, buscar saídas com source_type = 'tributos' ou 'juros'
        $despNaoOper = 0.0;
        if ($hasBankTx) {
            $sql = "SELECT COALESCE(SUM(valor),0) FROM bank_transactions WHERE data >= :start AND data <= :end AND tipo = 'saida' AND (source_type IN ('tributos','juros','nao_operacional'))";
            $stmt = $this->db->prepare($sql);
            $stmt->execute(['start' => $start, 'end' => $end]);
            $despNaoOper = (float)$stmt->fetchColumn();
        }

        $resultadoAntesImpostos = $resultadoOperacional - $despNaoOper;

        // Impostos: melhor esforço — se existir coluna em contas_receber, já contabilizado em deduções; senão estimar 0
        $impostos = 0.0;
        if ($deducoes > 0) { $impostos = $deducoes; }

        $resultadoLiquido = $resultadoAntesImpostos - $impostos;

        AuditLogger::logRead('relatorios_dre', null, ['start' => $start, 'end' => $end]);

        return Response::json([
            'period' => ['start' => $start, 'end' => $end],
            'dre' => [
                'receita_bruta' => $receitaBruta,
                'deducoes' => $deducoes,
                'receita_liquida' => $receitaLiquida,
                'custo_dos_produtos' => $custoProdutos,
                'lucro_bruto' => $lucroBruto,
                'despesas_operacionais' => $despesasOperacionais,
                'resultado_operacional' => $resultadoOperacional,
                'despesas_nao_operacionais' => $despNaoOper,
                'resultado_antes_impostos' => $resultadoAntesImpostos,
                'impostos' => $impostos,
                'resultado_liquido' => $resultadoLiquido
            ]
        ]);
    }

    /**
     * GET /api/financeiro/relatorios/dre/export.csv
     */
    public function exportDreCsv(Request $request): Response {
        $resp = $this->dre($request);
        if ($resp->status !== 200) return $resp;
        $data = $resp->body['dre'] ?? [];

        // Separador CSV configurável
        $sep = (string)$request->getQueryParam('sep', ';');
        if ($sep === 'tab') { $sep = "\t"; }
        $allowed = [',',';','|',"\t"]; $sep = in_array($sep, $allowed, true) ? $sep : ';';

        // CSV simples com BOM
        $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
        $out = fopen('php://temp', 'r+');
        fputs($out, $bom);
        $headers = ['Conta','Valor'];
        fputcsv($out, $headers, $sep);
        $rows = [
            ['Receita Bruta', $data['receita_bruta'] ?? 0],
            ['Deduções/Impostos', $data['deducoes'] ?? 0],
            ['Receita Líquida', $data['receita_liquida'] ?? 0],
            ['Custo dos Produtos/Serviços', $data['custo_dos_produtos'] ?? 0],
            ['Lucro Bruto', $data['lucro_bruto'] ?? 0],
            ['Despesas Operacionais', $data['despesas_operacionais'] ?? 0],
            ['Resultado Operacional', $data['resultado_operacional'] ?? 0],
            ['Despesas Não Operacionais', $data['despesas_nao_operacionais'] ?? 0],
            ['Resultado Antes dos Impostos', $data['resultado_antes_impostos'] ?? 0],
            ['Impostos', $data['impostos'] ?? 0],
            ['Resultado Líquido', $data['resultado_liquido'] ?? 0],
        ];
        foreach ($rows as $r) { fputcsv($out, $r, $sep); }
        rewind($out);
        $csv = stream_get_contents($out);
        fclose($out);

        $respCsv = new Response(200, $csv, ['Content-Type' => 'text/csv; charset=utf-8']);
        return $respCsv;
    }

    /**
     * GET /api/financeiro/relatorios/dre-completo
     * Parâmetros: start, end
     * Retorna DRE completo com detalhamento de impostos fiscais (ICMS, PIS, COFINS, ISS, IRPJ, CSLL, IPI)
     */
    public function dreCompleto(Request $request): Response {
        $start = (string)$request->getQueryParam('start', '');
        $end = (string)$request->getQueryParam('end', '');
        if ($start === '' || $end === '') {
            return Response::json(['error' => 'Parâmetros start e end são obrigatórios'], 422);
        }

        // Primeiro, aproveita o cálculo simplificado como base
        $base = $this->dre($request);
        if ($base->status !== 200) return $base;
        $dre = $base->body['dre'] ?? [];

        $period = ['start' => $start, 'end' => $end];

        // Detalhamento de impostos (melhor esforço)
        $impostos = [
            'icms' => 0.0,
            'pis' => 0.0,
            'cofins' => 0.0,
            'iss' => 0.0,
            'ipi' => 0.0,
            'irpj' => 0.0,
            'csll' => 0.0,
            // modelo 2026 (ilustrativo)
            'ibs' => 0.0,
            'cbs' => 0.0,
            'is' => 0.0,
        ];

        // Tabelas potenciais
        $hasPos = $this->tableExists('pos_sales') && $this->columnExists('pos_sales', 'tax_data');
        $hasSalesOrders = $this->tableExists('sales_orders') && $this->columnExists('sales_orders', 'tax_data');
        $hasPurchaseInv = $this->tableExists('purchase_invoices') && $this->columnExists('purchase_invoices', 'tax_data');
        $hasNfce = $this->tableExists('nfce_emissions');
        $hasCte = $this->tableExists('cte_emissions');

        // Helper para somar campos conhecidos em tax_data JSON
        $sumTaxData = function(array $row) use (&$impostos) {
            $td = $row['tax_data'] ?? null;
            if (is_string($td) && $td !== '') { $td = json_decode($td, true); }
            if (!is_array($td)) return;
            $map = [
                'pis' => ['pis', 'pis_total'],
                'cofins' => ['cofins', 'cofins_total'],
                'icms' => ['icms', 'icms_total'],
                'iss' => ['iss', 'iss_total'],
                'ipi' => ['ipi', 'ipi_total'],
                'irpj' => ['irpj', 'irpj_total'],
                'csll' => ['csll', 'csll_total'],
                'ibs' => ['ibs', 'ibs_total'],
                'cbs' => ['cbs', 'cbs_total'],
                'is' => ['is', 'is_total'],
            ];
            foreach ($map as $k => $keys) {
                foreach ($keys as $kk) {
                    $val = $td[$kk] ?? null;
                    if ($val !== null) { $impostos[$k] += (float)$val; break; }
                }
            }
        };

        // POS vendas
        if ($hasPos) {
            try {
                $stmt = $this->db->prepare("SELECT tax_data, valor_total, created_at FROM pos_sales WHERE DATE(created_at) BETWEEN :start AND :end");
                $stmt->execute(['start' => $start, 'end' => $end]);
                while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { $sumTaxData($row); }
            } catch (\Throwable $e) { /* tolerante */ }
        }

        // Pedidos de venda
        if ($hasSalesOrders) {
            try {
                $stmt = $this->db->prepare("SELECT tax_data, valor_total, created_at FROM sales_orders WHERE DATE(created_at) BETWEEN :start AND :end");
                $stmt->execute(['start' => $start, 'end' => $end]);
                while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { $sumTaxData($row); }
            } catch (\Throwable $e) { /* tolerante */ }
        }

        // Notas de compra (IPI etc)
        if ($hasPurchaseInv) {
            try {
                $stmt = $this->db->prepare("SELECT tax_data, valor, created_at FROM purchase_invoices WHERE DATE(created_at) BETWEEN :start AND :end");
                $stmt->execute(['start' => $start, 'end' => $end]);
                while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { $sumTaxData($row); }
            } catch (\Throwable $e) { /* tolerante */ }
        }

        // NFCE/CTE: somar ICMS disponível
        if ($hasNfce) {
            try {
                $stmt = $this->db->prepare("SELECT COALESCE(SUM(vl_icms),0) AS s FROM nfce_emissions WHERE DATE(created_at) BETWEEN :start AND :end");
                $stmt->execute(['start' => $start, 'end' => $end]);
                $impostos['icms'] += (float)($stmt->fetchColumn() ?: 0);
            } catch (\Throwable $e) { /* tolerante */ }
        }
        if ($hasCte) {
            try {
                $stmt = $this->db->prepare("SELECT COALESCE(SUM(vl_icms),0) AS s FROM cte_emissions WHERE DATE(created_at) BETWEEN :start AND :end");
                $stmt->execute(['start' => $start, 'end' => $end]);
                $impostos['icms'] += (float)($stmt->fetchColumn() ?: 0);
            } catch (\Throwable $e) { /* tolerante */ }
        }

        // Estimativa quando não há tax_data: aplica TaxConfig default sobre receita líquida
        try {
            $cfg = TaxConfig::get($this->db);
            $opts = is_array($cfg['options'] ?? null) ? $cfg['options'] : [];
            $pisRate = (float)($opts['pis_default_rate'] ?? 0.0165);
            $cofRate = (float)($opts['cofins_default_rate'] ?? 0.076);
            $icmsRate = (float)($opts['icms_default_rate'] ?? 0.18);
            // Somente estima se não houve dados concretos
            if ($impostos['pis'] <= 0 && ($dre['receita_liquida'] ?? 0) > 0) {
                $impostos['pis'] += round((float)$dre['receita_liquida'] * $pisRate, 2);
            }
            if ($impostos['cofins'] <= 0 && ($dre['receita_liquida'] ?? 0) > 0) {
                $impostos['cofins'] += round((float)$dre['receita_liquida'] * $cofRate, 2);
            }
            // ICMS estimado somente para bens; aqui mantemos melhor esforço
            if ($impostos['icms'] <= 0 && ($dre['receita_liquida'] ?? 0) > 0) {
                $impostos['icms'] += round((float)$dre['receita_liquida'] * $icmsRate * 0.2, 2); // fator reduzido (ilustrativo)
            }
        } catch (\Throwable $e) { /* tolerante */ }

        $totalImpostos = array_sum($impostos);

        $body = [
            'period' => $period,
            'dre' => array_merge($dre, [
                'impostos_total' => $totalImpostos,
                'impostos_detail' => $impostos,
                'resultado_liquido' => (float)($dre['resultado_antes_impostos'] ?? 0) - $totalImpostos,
            ])
        ];

        AuditLogger::logRead('relatorios_dre_completo', null, ['start' => $start, 'end' => $end]);
        return Response::json($body);
    }

    /**
     * GET /api/financeiro/relatorios/dre-completo/export.csv
     */
    public function exportDreCompletoCsv(Request $request): Response {
        $resp = $this->dreCompleto($request);
        if ($resp->status !== 200) return $resp;
        $period = $resp->body['period'] ?? [];
        $data = $resp->body['dre'] ?? [];
        $imp = $data['impostos_detail'] ?? [];

        // Separador CSV configurável
        $sep = (string)$request->getQueryParam('sep', ';');
        if ($sep === 'tab') { $sep = "\t"; }
        $allowed = [',',';','|',"\t"]; $sep = in_array($sep, $allowed, true) ? $sep : ';';

        $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
        $out = fopen('php://temp', 'r+');
        fputs($out, $bom);
        fputcsv($out, ['Relatório', 'DRE Completo'], $sep);
        fputcsv($out, ['Período', ($period['start'] ?? '').' a '.($period['end'] ?? '')], $sep);
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Conta','Valor'], $sep);
        foreach ([
            ['Receita Bruta', $data['receita_bruta'] ?? 0],
            ['Deduções', $data['deducoes'] ?? 0],
            ['Receita Líquida', $data['receita_liquida'] ?? 0],
            ['Custo dos Produtos/Serviços', $data['custo_dos_produtos'] ?? 0],
            ['Lucro Bruto', $data['lucro_bruto'] ?? 0],
            ['Despesas Operacionais', $data['despesas_operacionais'] ?? 0],
            ['Despesas Não Operacionais', $data['despesas_nao_operacionais'] ?? 0],
            ['Resultado Antes dos Impostos', $data['resultado_antes_impostos'] ?? 0],
            ['Impostos (Total)', $data['impostos_total'] ?? ($data['impostos'] ?? 0)],
            ['Resultado Líquido', $data['resultado_liquido'] ?? 0],
        ] as $r) { fputcsv($out, $r, $sep); }
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Detalhe de Impostos'], $sep);
        foreach ([
            ['ICMS', $imp['icms'] ?? 0],
            ['PIS', $imp['pis'] ?? 0],
            ['COFINS', $imp['cofins'] ?? 0],
            ['ISS', $imp['iss'] ?? 0],
            ['IPI', $imp['ipi'] ?? 0],
            ['IRPJ', $imp['irpj'] ?? 0],
            ['CSLL', $imp['csll'] ?? 0],
            ['IBS (2026)', $imp['ibs'] ?? 0],
            ['CBS (2026)', $imp['cbs'] ?? 0],
            ['IS (2026)', $imp['is'] ?? 0],
        ] as $r) { fputcsv($out, $r, $sep); }
        rewind($out);
        $csv = stream_get_contents($out);
        fclose($out);
        return new Response(200, $csv, ['Content-Type' => 'text/csv; charset=utf-8']);
    }

    /**
     * GET /api/financeiro/relatorios/receber/resumo
     * Parâmetros: start, end
     * Retorna totais e séries diárias de Contas a Receber
     */
    public function resumoReceber(Request $request): Response {
        $start = (string)$request->getQueryParam('start', '');
        $end = (string)$request->getQueryParam('end', '');
        if ($start === '' || $end === '') {
            return Response::json(['error' => 'Parâmetros start e end são obrigatórios'], 422);
        }

        if (!$this->tableExists('contas_receber')) {
            return Response::json(['error' => 'Tabela contas_receber não encontrada'], 404);
        }

        // Totais por status e geral
        $totais = [
            'total_geral' => 0.0,
            'pendente' => 0.0,
            'vencido' => 0.0,
            'recebido' => 0.0,
        ];
        $stmt = $this->db->prepare("SELECT COALESCE(SUM(valor),0) AS t FROM contas_receber WHERE data_vencimento >= :s AND data_vencimento <= :e");
        $stmt->execute(['s' => $start, 'e' => $end]);
        $totais['total_geral'] = (float)($stmt->fetchColumn() ?: 0);

        foreach (['pendente','vencido'] as $st) {
            $stmt = $this->db->prepare("SELECT COALESCE(SUM(valor),0) AS t FROM contas_receber WHERE status = :st AND data_vencimento >= :s AND data_vencimento <= :e");
            $stmt->execute(['st' => $st, 's' => $start, 'e' => $end]);
            $totais[$st] = (float)($stmt->fetchColumn() ?: 0);
        }
        // Recebidos por valor_recebido no período
        $stmt = $this->db->prepare("SELECT COALESCE(SUM(valor_recebido),0) AS t FROM contas_receber WHERE status = 'recebido' AND data_recebimento IS NOT NULL AND data_recebimento >= :s AND data_recebimento <= :e");
        $stmt->execute(['s' => $start, 'e' => $end]);
        $totais['recebido'] = (float)($stmt->fetchColumn() ?: 0);

        // Contagens auxiliares
        $counts = [
            'overdue_count' => 0,
            'due_today_count' => 0,
        ];
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM contas_receber WHERE status = 'vencido' AND data_vencimento >= :s AND data_vencimento <= :e");
        $stmt->execute(['s' => $start, 'e' => $end]);
        $counts['overdue_count'] = (int)($stmt->fetchColumn() ?: 0);
        $today = date('Y-m-d');
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM contas_receber WHERE status IN ('pendente','vencido') AND data_vencimento = :today");
        $stmt->execute(['today' => $today]);
        $counts['due_today_count'] = (int)($stmt->fetchColumn() ?: 0);

        // Série diária: a receber por vencimento e recebidos por data de recebimento
        $series = [];
        $stV = $this->db->prepare("SELECT data_vencimento AS dia, SUM(valor) AS a_receber FROM contas_receber WHERE data_vencimento >= :s AND data_vencimento <= :e GROUP BY data_vencimento ORDER BY data_vencimento ASC");
        $stV->execute(['s' => $start, 'e' => $end]);
        $serieV = $stV->fetchAll(PDO::FETCH_ASSOC) ?: [];
        $mapV = [];
        foreach ($serieV as $r) { $mapV[$r['dia']] = (float)($r['a_receber'] ?? 0); }

        $stR = $this->db->prepare("SELECT data_recebimento AS dia, SUM(valor_recebido) AS recebidos FROM contas_receber WHERE status='recebido' AND data_recebimento IS NOT NULL AND data_recebimento >= :s AND data_recebimento <= :e GROUP BY data_recebimento ORDER BY data_recebimento ASC");
        $stR->execute(['s' => $start, 'e' => $end]);
        $serieR = $stR->fetchAll(PDO::FETCH_ASSOC) ?: [];
        $mapR = [];
        foreach ($serieR as $r) { $mapR[$r['dia']] = (float)($r['recebidos'] ?? 0); }

        // Mesclar chaves de ambas as séries
        $dias = array_unique(array_merge(array_keys($mapV), array_keys($mapR)));
        sort($dias);
        foreach ($dias as $d) {
            $series[] = ['data' => $d, 'a_receber' => (float)($mapV[$d] ?? 0), 'recebidos' => (float)($mapR[$d] ?? 0)];
        }

        AuditLogger::logRead('relatorios_resumo_receber', null, ['start' => $start, 'end' => $end]);
        return Response::json([
            'period' => ['start' => $start, 'end' => $end],
            'totals' => $totais,
            'counts' => $counts,
            'series' => $series,
        ]);
    }

    /**
     * GET /api/financeiro/relatorios/receber/resumo/export.csv
     */
    public function exportResumoReceberCsv(Request $request): Response {
        $resp = $this->resumoReceber($request);
        if ($resp->status !== 200) return $resp;
        $body = $resp->body;

        // Separador CSV configurável
        $sep = (string)$request->getQueryParam('sep', ';');
        if ($sep === 'tab') { $sep = "\t"; }
        $allowed = [',',';','|',"\t"]; $sep = in_array($sep, $allowed, true) ? $sep : ';';

        $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
        $out = fopen('php://temp', 'r+');
        fputs($out, $bom);
        fputcsv($out, ['Relatório', 'Resumo Contas a Receber'], $sep);
        fputcsv($out, ['Período', ($body['period']['start'] ?? '').' a '.($body['period']['end'] ?? '')], $sep);
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Totais'], $sep);
        fputcsv($out, ['Total Geral', $body['totals']['total_geral'] ?? 0], $sep);
        fputcsv($out, ['Pendentes', $body['totals']['pendente'] ?? 0], $sep);
        fputcsv($out, ['Vencidos', $body['totals']['vencido'] ?? 0], $sep);
        fputcsv($out, ['Recebidos', $body['totals']['recebido'] ?? 0], $sep);
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Data','A Receber','Recebidos'], $sep);
        foreach (($body['series'] ?? []) as $row) {
            fputcsv($out, [$row['data'] ?? '', $row['a_receber'] ?? 0, $row['recebidos'] ?? 0], $sep);
        }
        rewind($out);
        $csv = stream_get_contents($out);
        fclose($out);
        return new Response(200, $csv, ['Content-Type' => 'text/csv; charset=utf-8']);
    }

    /**
     * GET /api/financeiro/relatorios/pagar/resumo
     * Parâmetros: start, end
     * Retorna totais e séries diárias de Contas a Pagar
     */
    public function resumoPagar(Request $request): Response {
        $start = (string)$request->getQueryParam('start', '');
        $end = (string)$request->getQueryParam('end', '');
        if ($start === '' || $end === '') {
            return Response::json(['error' => 'Parâmetros start e end são obrigatórios'], 422);
        }

        if (!$this->tableExists('contas_pagar')) {
            return Response::json(['error' => 'Tabela contas_pagar não encontrada'], 404);
        }

        // Totais por status e geral
        $totais = [
            'total_geral' => 0.0,
            'pendente' => 0.0,
            'vencido' => 0.0,
            'pago' => 0.0,
        ];
        $stmt = $this->db->prepare("SELECT COALESCE(SUM(valor),0) AS t FROM contas_pagar WHERE data_vencimento >= :s AND data_vencimento <= :e");
        $stmt->execute(['s' => $start, 'e' => $end]);
        $totais['total_geral'] = (float)($stmt->fetchColumn() ?: 0);

        foreach (['pendente','vencido'] as $st) {
            $stmt = $this->db->prepare("SELECT COALESCE(SUM(valor),0) AS t FROM contas_pagar WHERE status = :st AND data_vencimento >= :s AND data_vencimento <= :e");
            $stmt->execute(['st' => $st, 's' => $start, 'e' => $end]);
            $totais[$st] = (float)($stmt->fetchColumn() ?: 0);
        }
        // Pagos por valor_pago no período
        $stmt = $this->db->prepare("SELECT COALESCE(SUM(valor_pago),0) AS t FROM contas_pagar WHERE status = 'pago' AND data_pagamento IS NOT NULL AND data_pagamento >= :s AND data_pagamento <= :e");
        $stmt->execute(['s' => $start, 'e' => $end]);
        $totais['pago'] = (float)($stmt->fetchColumn() ?: 0);

        // Contagens auxiliares
        $counts = [
            'overdue_count' => 0,
            'due_today_count' => 0,
        ];
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM contas_pagar WHERE status = 'vencido' AND data_vencimento >= :s AND data_vencimento <= :e");
        $stmt->execute(['s' => $start, 'e' => $end]);
        $counts['overdue_count'] = (int)($stmt->fetchColumn() ?: 0);
        $today = date('Y-m-d');
        $stmt = $this->db->prepare("SELECT COUNT(*) FROM contas_pagar WHERE status IN ('pendente','vencido') AND data_vencimento = :today");
        $stmt->execute(['today' => $today]);
        $counts['due_today_count'] = (int)($stmt->fetchColumn() ?: 0);

        // Série diária: a pagar por vencimento e pagos por data de pagamento
        $series = [];
        $stV = $this->db->prepare("SELECT data_vencimento AS dia, SUM(valor) AS a_pagar FROM contas_pagar WHERE data_vencimento >= :s AND data_vencimento <= :e GROUP BY data_vencimento ORDER BY data_vencimento ASC");
        $stV->execute(['s' => $start, 'e' => $end]);
        $serieV = $stV->fetchAll(PDO::FETCH_ASSOC) ?: [];
        $mapV = [];
        foreach ($serieV as $r) { $mapV[$r['dia']] = (float)($r['a_pagar'] ?? 0); }

        $stP = $this->db->prepare("SELECT data_pagamento AS dia, SUM(valor_pago) AS pagos FROM contas_pagar WHERE status='pago' AND data_pagamento IS NOT NULL AND data_pagamento >= :s AND data_pagamento <= :e GROUP BY data_pagamento ORDER BY data_pagamento ASC");
        $stP->execute(['s' => $start, 'e' => $end]);
        $serieP = $stP->fetchAll(PDO::FETCH_ASSOC) ?: [];
        $mapP = [];
        foreach ($serieP as $r) { $mapP[$r['dia']] = (float)($r['pagos'] ?? 0); }

        $dias = array_unique(array_merge(array_keys($mapV), array_keys($mapP)));
        sort($dias);
        foreach ($dias as $d) {
            $series[] = ['data' => $d, 'a_pagar' => (float)($mapV[$d] ?? 0), 'pagos' => (float)($mapP[$d] ?? 0)];
        }

        AuditLogger::logRead('relatorios_resumo_pagar', null, ['start' => $start, 'end' => $end]);
        return Response::json([
            'period' => ['start' => $start, 'end' => $end],
            'totals' => $totais,
            'counts' => $counts,
            'series' => $series,
        ]);
    }

    /**
     * GET /api/financeiro/relatorios/pagar/resumo/export.csv
     */
    public function exportResumoPagarCsv(Request $request): Response {
        $resp = $this->resumoPagar($request);
        if ($resp->status !== 200) return $resp;
        $body = $resp->body;

        // Separador CSV configurável
        $sep = (string)$request->getQueryParam('sep', ';');
        if ($sep === 'tab') { $sep = "\t"; }
        $allowed = [',',';','|',"\t"]; $sep = in_array($sep, $allowed, true) ? $sep : ';';

        $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
        $out = fopen('php://temp', 'r+');
        fputs($out, $bom);
        fputcsv($out, ['Relatório', 'Resumo Contas a Pagar'], $sep);
        fputcsv($out, ['Período', ($body['period']['start'] ?? '').' a '.($body['period']['end'] ?? '')], $sep);
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Totais'], $sep);
        fputcsv($out, ['Total Geral', $body['totals']['total_geral'] ?? 0], $sep);
        fputcsv($out, ['Pendentes', $body['totals']['pendente'] ?? 0], $sep);
        fputcsv($out, ['Vencidos', $body['totals']['vencido'] ?? 0], $sep);
        fputcsv($out, ['Pagos', $body['totals']['pago'] ?? 0], $sep);
        fputcsv($out, [''], $sep);
        fputcsv($out, ['Data','A Pagar','Pagos'], $sep);
        foreach (($body['series'] ?? []) as $row) {
            fputcsv($out, [$row['data'] ?? '', $row['a_pagar'] ?? 0, $row['pagos'] ?? 0], $sep);
        }
        rewind($out);
        $csv = stream_get_contents($out);
        fclose($out);
        return new Response(200, $csv, ['Content-Type' => 'text/csv; charset=utf-8']);
    }

    private function tableExists(string $table): bool {
        try {
            return $this->db->query("SHOW TABLES LIKE '" . str_replace("'", "''", $table) . "'")->rowCount() > 0;
        } catch (\Throwable $e) { return false; }
    }

    private function columnExists(string $table, string $column): bool {
        try {
            $stmt = $this->db->query("SHOW COLUMNS FROM `" . str_replace("`", "``", $table) . "` LIKE '" . str_replace("'", "''", $column) . "'");
            return $stmt && $stmt->rowCount() > 0;
        } catch (\Throwable $e) { return false; }
    }
}