<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Helpers\UrlHelper;
use App\Integrations\ShipayClient;
use Exception;

class EntradasController extends BaseController
{
    public function index(): void
    {
        // Verificar permissão de visualização
        if (!$this->canView('entradas')) {
            $this->response->forbidden('Você não tem permissão para visualizar entradas.');
            return;
        }

        try {
            $companyId = $this->getCompanyId();
            $search = $this->request->get('search', '');
            $status = $this->request->get('status', '');

            $query = "
                SELECT cr.*,
                       p.name as customer_name,
                       ms.nome as status_nome,
                       ms.cor as status_cor,
                       ms.icone as status_icone,
                       mp.name as payment_method_name,
                       cb.bank_name as conta_bancaria_nome
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                LEFT JOIN modulo_status ms ON cr.status_id = ms.id
                LEFT JOIN metodos_pagamento mp ON cr.payment_method = mp.id
                LEFT JOIN contas_bancarias cb ON cr.conta_bancaria_id = cb.id
                WHERE cr.company_id = :company_id
            ";

            $params = ['company_id' => $companyId];

            if (!empty($search)) {
                $query .= " AND (cr.description LIKE :search OR p.name LIKE :search)";
                $params['search'] = "%{$search}%";
            }

            if (!empty($status)) {
                $query .= " AND cr.status_id = :status";
                $params['status'] = $status;
            }

            $query .= " ORDER BY cr.due_date ASC";

            $stmt = $this->db->prepare($query);
            $stmt->execute($params);
            $contas = $stmt->fetchAll();

            // Buscar status disponíveis para o filtro
            $stmtStatus = $this->db->prepare("
                SELECT id, nome, cor
                FROM modulo_status
                WHERE company_id = :company_id
                  AND (modulo = 'entradas' OR modulo = 'contas_receber')
                  AND ativo = 1
                ORDER BY ordem ASC
            ");
            $stmtStatus->execute(['company_id' => $companyId]);
            $statusList = $stmtStatus->fetchAll();

            $this->view('entradas/index', [
                'contas' => $contas,
                'search' => $search,
                'status' => $status,
                'statusList' => $statusList,
                'pageTitle' => 'Contas a Receber',
                'activeMenu' => 'entradas'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao carregar contas a receber: " . $e->getMessage());
            $this->error('Erro ao carregar contas a receber');
        }
    }

    public function create(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Buscar clientes para autocomplete
            $stmt = $this->db->prepare("
                SELECT id, name, trade_name, document, phone, mobile, email
                FROM pessoas
                WHERE company_id = :company_id AND type IN ('cliente', 'ambos') AND is_active = 1
                ORDER BY name ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $clientes = $stmt->fetchAll();

            // Buscar métodos de pagamento
            $metodosPagamento = $this->getMetodosPagamento();

            // Buscar contas bancárias
            $contasBancarias = $this->getContasBancarias();

            // Buscar status do módulo entradas/contas_receber
            $stmt = $this->db->prepare("
                SELECT codigo, nome, descricao, cor, icone, ordem, is_default
                FROM modulo_status
                WHERE company_id = :company_id
                  AND (modulo = 'entradas' OR modulo = 'contas_receber')
                  AND ativo = 1
                ORDER BY ordem ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $statusEntradas = $stmt->fetchAll();

            error_log("Status encontrados para entradas: " . count($statusEntradas));
            if (!empty($statusEntradas)) {
                error_log("Status: " . json_encode($statusEntradas));
            }

            // Buscar plano de contas
            $planoContas = $this->getPlanoContas();
            error_log("DEBUG CREATE - Plano de Contas: " . count($planoContas));
            error_log("DEBUG CREATE - Plano de Contas DATA: " . json_encode($planoContas));

            // Buscar centros de custo
            $centroCustos = $this->getCentroCustos();
            error_log("DEBUG CREATE - Centro de Custos: " . count($centroCustos));

            $this->view('entradas/create', [
                'pessoas' => [],
                'clientes' => $clientes,
                'metodosPagamento' => $metodosPagamento,
                'contasBancarias' => $contasBancarias,
                'planoContas' => $planoContas,
                'centroCustos' => $centroCustos,
                'statusEntradas' => $statusEntradas,
                'pageTitle' => 'Nova Entrada',
                'activeMenu' => 'entradas'
            ]);
        } catch (Exception $e) {
            error_log("Erro ao carregar formulário: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

    public function store(): void
    {
        // Verificar permissão de criação
        if (!$this->canCreate('entradas')) {
            $this->response->forbidden('Você não tem permissão para criar entradas.');
            return;
        }

        try {
            $companyId = $this->getCompanyId();

            $amount = (float) ($this->request->post('amount') ?? 0);
            $amountPaid = (float) ($this->request->post('amount_paid') ?? 0);
            $juros = (float) ($this->request->post('juros') ?? 0);
            $multa = (float) ($this->request->post('multa') ?? 0);
            $desconto = (float) ($this->request->post('desconto') ?? 0);
            $despesa = (float) ($this->request->post('despesa') ?? 0);

            // Calcular valor restante: Valor + Juros + Multa + Despesa - Desconto - Valor Pago
            $amountRemaining = $amount + $juros + $multa + $despesa - $desconto - $amountPaid;

            // Detectar estrutura da tabela
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');

            $campos = ['company_id', 'description', 'amount', 'amount_remaining', 'due_date', 'notes'];
            $valores = [':company_id', ':description', ':amount', ':amount_remaining', ':due_date', ':notes'];

            if (in_array('pessoa_id', $columnNames)) {
                $campos[] = 'pessoa_id';
                $valores[] = ':pessoa_id';
            } elseif (in_array('customer_id', $columnNames)) {
                $campos[] = 'customer_id';
                $valores[] = ':customer_id';
            }
            if (in_array('venda_id', $columnNames)) {
                $campos[] = 'venda_id';
                $valores[] = ':venda_id';
            }
            if (in_array('numero', $columnNames)) {
                $campos[] = 'numero';
                $valores[] = ':numero';
            }
            if (in_array('amount_paid', $columnNames)) {
                $campos[] = 'amount_paid';
                $valores[] = ':amount_paid';
            } elseif (in_array('amount_received', $columnNames)) {
                $campos[] = 'amount_received';
                $valores[] = ':amount_paid';
            }
            if (in_array('payment_date', $columnNames)) {
                $campos[] = 'payment_date';
                $valores[] = ':payment_date';
            }
            if (in_array('payment_method', $columnNames)) {
                $campos[] = 'payment_method';
                $valores[] = ':metodo_pagamento_id';
            } elseif (in_array('metodo_pagamento_id', $columnNames)) {
                $campos[] = 'metodo_pagamento_id';
                $valores[] = ':metodo_pagamento_id';
            } elseif (in_array('payment_method_id', $columnNames)) {
                $campos[] = 'payment_method_id';
                $valores[] = ':metodo_pagamento_id';
            }
            if (in_array('conta_bancaria_id', $columnNames)) {
                $campos[] = 'conta_bancaria_id';
                $valores[] = ':conta_bancaria_id';
            }
            if (in_array('plano_conta_id', $columnNames)) {
                $campos[] = 'plano_conta_id';
                $valores[] = ':plano_conta_id';
            }
            if (in_array('centro_custo_id', $columnNames)) {
                $campos[] = 'centro_custo_id';
                $valores[] = ':centro_custo_id';
            }
            if (in_array('status_id', $columnNames)) {
                $campos[] = 'status_id';
                $valores[] = ':status_id';
            } elseif (in_array('status', $columnNames)) {
                $campos[] = 'status';
                $valores[] = ':status';
            }
            if (in_array('juros', $columnNames)) {
                $campos[] = 'juros';
                $valores[] = ':juros';
            }
            if (in_array('multa', $columnNames)) {
                $campos[] = 'multa';
                $valores[] = ':multa';
            }
            if (in_array('desconto', $columnNames)) {
                $campos[] = 'desconto';
                $valores[] = ':desconto';
            }
            if (in_array('despesa', $columnNames)) {
                $campos[] = 'despesa';
                $valores[] = ':despesa';
            }

            $campos[] = 'created_at';
            $campos[] = 'updated_at';
            $valores[] = 'NOW()';
            $valores[] = 'NOW()';

            $sql = "INSERT INTO contas_receber (" . implode(', ', $campos) . ") VALUES (" . implode(', ', $valores) . ")";
            $stmt = $this->db->prepare($sql);

            $dadosBind = [
                'company_id' => $companyId,
                'description' => $this->request->post('description') ?? '',
                'amount' => $amount,
                'amount_remaining' => $amountRemaining,
                'due_date' => $this->request->post('due_date') ?? '',
                'notes' => $this->request->post('notes') ?: null,
            ];

            // Status - O formulário envia status_id com código do status (ex: "pendente")
            // A tabela pode ter:
            // - status_id (INT) - precisa buscar o ID pelo código na tabela modulo_status
            // - status (VARCHAR) - usa o código diretamente
            $statusValue = $this->request->post('status_id') ?? $this->request->post('status') ?? 'pendente';
            error_log("DEBUG STORE - Status recebido do formulário: " . $statusValue);

            if (in_array('status_id', $columnNames)) {
                // Se status_id é numérico, usar diretamente; senão, buscar ID pelo código
                if (is_numeric($statusValue)) {
                    $dadosBind['status_id'] = (int) $statusValue;
                    error_log("DEBUG STORE - Status é numérico: " . $statusValue);
                } else {
                    // Buscar ID do status pelo código na tabela modulo_status
                    try {
                        $stmtStatus = $this->db->prepare("
                            SELECT id FROM modulo_status
                            WHERE codigo = :codigo
                              AND company_id = :company_id
                              AND (modulo = 'entradas' OR modulo = 'contas_receber')
                            LIMIT 1
                        ");
                        $stmtStatus->execute(['codigo' => $statusValue, 'company_id' => $companyId]);
                        $statusRow = $stmtStatus->fetch();
                        if ($statusRow) {
                            $dadosBind['status_id'] = (int) $statusRow['id'];
                            error_log("DEBUG STORE - Status ID encontrado em modulo_status: " . $statusRow['id']);
                        } else {
                            // Se não encontrou pelo código, usar NULL (vai aceitar qualquer status)
                            $dadosBind['status_id'] = null;
                            error_log("DEBUG STORE - Status não encontrado em modulo_status, usando NULL");
                        }
                    } catch (Exception $e) {
                        // Se a tabela modulo_status não existir, usar NULL
                        error_log("DEBUG STORE - Erro ao buscar status em modulo_status: " . $e->getMessage());
                        $dadosBind['status_id'] = null;
                    }
                }
            } elseif (in_array('status', $columnNames)) {
                // Coluna status aceita texto diretamente
                $dadosBind['status'] = $statusValue;
                error_log("DEBUG STORE - Usando coluna status com valor: " . $statusValue);
            }

            // Cliente/Pessoa - pode ser pessoa_id ou customer_id dependendo da estrutura da tabela
            $pessoaId = $this->request->post('pessoa_id');
            $pessoaIdValue = !empty($pessoaId) && $pessoaId !== '' && $pessoaId !== '0' ? (int) $pessoaId : null;
            error_log("DEBUG STORE - pessoa_id recebido do formulário: " . ($pessoaId ?? 'null'));

            if (in_array('pessoa_id', $columnNames)) {
                $dadosBind['pessoa_id'] = $pessoaIdValue;
                error_log("DEBUG STORE - Salvando em pessoa_id: " . ($pessoaIdValue ?? 'null'));
            } elseif (in_array('customer_id', $columnNames)) {
                $dadosBind['customer_id'] = $pessoaIdValue;
                error_log("DEBUG STORE - Salvando em customer_id: " . ($pessoaIdValue ?? 'null'));
            }
            if (in_array('venda_id', $columnNames)) {
                $dadosBind['venda_id'] = $this->request->post('venda_id') ?: null;
            }
            if (in_array('numero', $columnNames)) {
                $dadosBind['numero'] = $this->request->post('numero') ?: null;
            }
            if (in_array('amount_paid', $columnNames) || in_array('amount_received', $columnNames)) {
                $dadosBind['amount_paid'] = $amountPaid;
            }
            if (in_array('payment_date', $columnNames)) {
                $paymentDate = trim($this->request->post('payment_date') ?? '');
                $dadosBind['payment_date'] = $paymentDate !== '' ? $paymentDate : null;
            }
            if (in_array('payment_method', $columnNames) || in_array('metodo_pagamento_id', $columnNames) || in_array('payment_method_id', $columnNames)) {
                $metodoPagamento = trim($this->request->post('metodo_pagamento_id') ?? '');
                $dadosBind['metodo_pagamento_id'] = $metodoPagamento !== '' && $metodoPagamento !== '0' ? (int) $metodoPagamento : null;
            }
            if (in_array('conta_bancaria_id', $columnNames)) {
                $contaBancaria = trim($this->request->post('conta_bancaria_id') ?? '');
                $dadosBind['conta_bancaria_id'] = $contaBancaria !== '' && $contaBancaria !== '0' ? (int) $contaBancaria : null;
            }
            if (in_array('plano_conta_id', $columnNames)) {
                $dadosBind['plano_conta_id'] = $this->request->post('plano_conta_id') ?: null;
            }
            if (in_array('centro_custo_id', $columnNames)) {
                $dadosBind['centro_custo_id'] = $this->request->post('centro_custo_id') ?: null;
            }
            if (in_array('juros', $columnNames)) {
                $dadosBind['juros'] = $juros;
            }
            if (in_array('multa', $columnNames)) {
                $dadosBind['multa'] = $multa;
            }
            if (in_array('desconto', $columnNames)) {
                $dadosBind['desconto'] = $desconto;
            }
            if (in_array('despesa', $columnNames)) {
                $dadosBind['despesa'] = $despesa;
            }

            $this->db->beginTransaction();

            // Log completo dos dados antes de salvar
            error_log("DEBUG STORE - SQL: " . $sql);
            error_log("DEBUG STORE - Colunas da tabela: " . implode(', ', $columnNames));
            error_log("DEBUG STORE - Dados para bind: " . json_encode($dadosBind, JSON_UNESCAPED_UNICODE));

            $stmt->execute($dadosBind);
            $contaId = (int) $this->db->lastInsertId();

            error_log("DEBUG STORE - Conta criada com ID: " . $contaId);

            $this->logActivity('create', 'contas_receber', $contaId, $dadosBind);

            // Verificar se o status gera financeiro e inserir no fluxo de caixa
            if (!empty($dadosBind['status_id'])) {
                $this->gerarFluxoCaixa($contaId, (int) $dadosBind['status_id'], $companyId);
            }

            $this->db->commit();

            // 🚀 SINCRONIZAÇÃO AUTOMÁTICA: Gerar boleto Inter se a conta bancária for do Inter
            if (!empty($dadosBind['conta_bancaria_id'])) {
                try {
                    $this->tentarGerarBoletoAutomatico($contaId, (int) $dadosBind['conta_bancaria_id'], $companyId);
                } catch (Exception $e) {
                    error_log("Erro ao gerar boleto automático: " . $e->getMessage());
                    // Não interrompe o fluxo - boleto pode ser gerado depois manualmente
                }
            }

            $this->success('Conta a receber criada com sucesso', [
                'id' => $contaId,
                'redirect' => UrlHelper::url('/entradas')
            ]);

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao criar conta a receber: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao criar conta a receber: ' . $e->getMessage());
        }
    }

    public function edit(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('entradas')) {
            $this->response->forbidden('Você não tem permissão para editar entradas.');
            return;
        }

        try {
            $id = (int) $this->request->get('id');
            $conta = $this->getConta($id);

            if (!$conta) {
                $this->response->notFound('Conta a receber não encontrada');
                return;
            }

            $companyId = $this->getCompanyId();

            // Busca clientes para autocomplete
            $stmt = $this->db->prepare("
                SELECT id, name, trade_name, document, phone, mobile, email
                FROM pessoas
                WHERE company_id = :company_id AND type IN ('cliente', 'ambos') AND is_active = 1
                ORDER BY name ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $clientes = $stmt->fetchAll();

            // Buscar métodos de pagamento
            $metodosPagamento = $this->getMetodosPagamento();

            // Buscar contas bancárias
            $contasBancarias = $this->getContasBancarias();

            // Buscar status do módulo entradas/contas_receber
            $stmt = $this->db->prepare("
                SELECT id, codigo, nome, descricao, cor, icone, ordem, is_default
                FROM modulo_status
                WHERE company_id = :company_id
                  AND (modulo = 'entradas' OR modulo = 'contas_receber')
                  AND ativo = 1
                ORDER BY ordem ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $statusEntradas = $stmt->fetchAll();

            // Buscar plano de contas
            $planoContas = $this->getPlanoContas();

            // Buscar centros de custo
            $centroCustos = $this->getCentroCustos();

            $this->view('entradas/edit', [
                'conta' => $conta,
                'pessoas' => [],
                'clientes' => $clientes,
                'metodosPagamento' => $metodosPagamento,
                'contasBancarias' => $contasBancarias,
                'planoContas' => $planoContas,
                'centroCustos' => $centroCustos,
                'statusEntradas' => $statusEntradas,
                'pageTitle' => 'Editar Conta a Receber',
                'activeMenu' => 'entradas'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao editar conta a receber: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

    public function update(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('entradas')) {
            error_log("[EntradasController::update] SEM PERMISSÃO");
            $this->response->forbidden('Você não tem permissão para editar entradas.');
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            error_log("[EntradasController::update] ID recebido: " . $id);
            $conta = $this->getConta($id);

            if (!$conta) {
                $this->error('Conta a receber não encontrada');
                return;
            }

            $companyId = $this->getCompanyId();
            $amount = (float) ($this->request->post('amount') ?? 0);
            $amountPaid = (float) ($this->request->post('amount_paid') ?? 0);
            $juros = (float) ($this->request->post('juros') ?? 0);
            $multa = (float) ($this->request->post('multa') ?? 0);
            $desconto = (float) ($this->request->post('desconto') ?? 0);
            $despesa = (float) ($this->request->post('despesa') ?? 0);

            // Calcular valor restante: Valor + Juros + Multa + Despesa - Desconto - Valor Pago
            $amountRemaining = $amount + $juros + $multa + $despesa - $desconto - $amountPaid;

            // Detectar estrutura da tabela
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');

            $sets = ['description = :description', 'amount = :amount', 'amount_remaining = :amount_remaining', 'due_date = :due_date', 'notes = :notes'];

            if (in_array('pessoa_id', $columnNames)) {
                $sets[] = 'pessoa_id = :pessoa_id';
            } elseif (in_array('customer_id', $columnNames)) {
                $sets[] = 'customer_id = :customer_id';
            }
            if (in_array('venda_id', $columnNames)) {
                $sets[] = 'venda_id = :venda_id';
            }
            if (in_array('numero', $columnNames)) {
                $sets[] = 'numero = :numero';
            }
            if (in_array('amount_paid', $columnNames)) {
                $sets[] = 'amount_paid = :amount_paid';
            } elseif (in_array('amount_received', $columnNames)) {
                $sets[] = 'amount_received = :amount_paid';
            }
            if (in_array('payment_date', $columnNames)) {
                $sets[] = 'payment_date = :payment_date';
            }
            if (in_array('payment_method', $columnNames)) {
                $sets[] = 'payment_method = :metodo_pagamento_id';
            } elseif (in_array('metodo_pagamento_id', $columnNames)) {
                $sets[] = 'metodo_pagamento_id = :metodo_pagamento_id';
            } elseif (in_array('payment_method_id', $columnNames)) {
                $sets[] = 'payment_method_id = :metodo_pagamento_id';
            }
            if (in_array('conta_bancaria_id', $columnNames)) {
                $sets[] = 'conta_bancaria_id = :conta_bancaria_id';
            }
            if (in_array('plano_conta_id', $columnNames)) {
                $sets[] = 'plano_conta_id = :plano_conta_id';
            }
            if (in_array('centro_custo_id', $columnNames)) {
                $sets[] = 'centro_custo_id = :centro_custo_id';
            }
            // Priorizar status_id (melhor prática)
            if (in_array('status_id', $columnNames)) {
                $sets[] = 'status_id = :status_id';
                // Se existe status_id, também limpar o campo status antigo
                if (in_array('status', $columnNames)) {
                    $sets[] = 'status = NULL';
                }
            } elseif (in_array('status', $columnNames)) {
                $sets[] = 'status = :status';
            }
            if (in_array('juros', $columnNames)) {
                $sets[] = 'juros = :juros';
            }
            if (in_array('multa', $columnNames)) {
                $sets[] = 'multa = :multa';
            }
            if (in_array('desconto', $columnNames)) {
                $sets[] = 'desconto = :desconto';
            }
            if (in_array('despesa', $columnNames)) {
                $sets[] = 'despesa = :despesa';
            }

            $sets[] = 'updated_at = NOW()';

            $sql = "UPDATE contas_receber SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";

            $stmt = $this->db->prepare($sql);

            $dadosBind = [
                'id' => $id,
                'company_id' => $companyId,
                'description' => $this->request->post('description') ?? '',
                'amount' => $amount,
                'amount_remaining' => $amountRemaining,
                'due_date' => $this->request->post('due_date') ?? '',
                'notes' => $this->request->post('notes') ?: null,
            ];

            // Status - O formulário envia status_id com código do status (ex: "pendente")
            $statusValue = $this->request->post('status_id') ?? $this->request->post('status') ?? 'pendente';
            error_log("DEBUG UPDATE - Status recebido do formulário: " . $statusValue);

            if (in_array('status_id', $columnNames)) {
                if (is_numeric($statusValue)) {
                    $dadosBind['status_id'] = (int) $statusValue;
                } else {
                    // Buscar ID do status pelo código na tabela modulo_status
                    try {
                        $stmtStatus = $this->db->prepare("
                            SELECT id FROM modulo_status
                            WHERE codigo = :codigo
                              AND company_id = :company_id
                              AND (modulo = 'entradas' OR modulo = 'contas_receber')
                            LIMIT 1
                        ");
                        $stmtStatus->execute(['codigo' => $statusValue, 'company_id' => $companyId]);
                        $statusRow = $stmtStatus->fetch();
                        $dadosBind['status_id'] = $statusRow ? (int) $statusRow['id'] : null;
                        error_log("DEBUG UPDATE - Status ID encontrado: " . ($dadosBind['status_id'] ?? 'null'));
                    } catch (Exception $e) {
                        error_log("DEBUG UPDATE - Erro ao buscar status: " . $e->getMessage());
                        $dadosBind['status_id'] = null;
                    }
                }
            } elseif (in_array('status', $columnNames)) {
                $dadosBind['status'] = $statusValue;
            }

            // Cliente/Pessoa - pode ser pessoa_id ou customer_id
            $pessoaId = $this->request->post('pessoa_id');
            $pessoaIdValue = !empty($pessoaId) && $pessoaId !== '' && $pessoaId !== '0' ? (int) $pessoaId : null;
            error_log("DEBUG UPDATE - pessoa_id recebido: " . ($pessoaId ?? 'null'));

            if (in_array('pessoa_id', $columnNames)) {
                $dadosBind['pessoa_id'] = $pessoaIdValue;
            } elseif (in_array('customer_id', $columnNames)) {
                $dadosBind['customer_id'] = $pessoaIdValue;
            }
            if (in_array('venda_id', $columnNames)) {
                $dadosBind['venda_id'] = $this->request->post('venda_id') ?: null;
            }
            if (in_array('numero', $columnNames)) {
                $dadosBind['numero'] = $this->request->post('numero') ?: null;
            }
            if (in_array('amount_paid', $columnNames) || in_array('amount_received', $columnNames)) {
                $dadosBind['amount_paid'] = $amountPaid;
            }
            if (in_array('payment_date', $columnNames)) {
                $paymentDate = trim($this->request->post('payment_date') ?? '');
                $dadosBind['payment_date'] = $paymentDate !== '' ? $paymentDate : null;
            }
            if (in_array('payment_method', $columnNames) || in_array('metodo_pagamento_id', $columnNames) || in_array('payment_method_id', $columnNames)) {
                $metodoPagamento = trim($this->request->post('metodo_pagamento_id') ?? '');
                $dadosBind['metodo_pagamento_id'] = $metodoPagamento !== '' && $metodoPagamento !== '0' ? (int) $metodoPagamento : null;
            }
            if (in_array('conta_bancaria_id', $columnNames)) {
                $contaBancaria = trim($this->request->post('conta_bancaria_id') ?? '');
                $dadosBind['conta_bancaria_id'] = $contaBancaria !== '' && $contaBancaria !== '0' ? (int) $contaBancaria : null;
            }
            if (in_array('plano_conta_id', $columnNames)) {
                $dadosBind['plano_conta_id'] = $this->request->post('plano_conta_id') ?: null;
            }
            if (in_array('centro_custo_id', $columnNames)) {
                $dadosBind['centro_custo_id'] = $this->request->post('centro_custo_id') ?: null;
            }
            if (in_array('juros', $columnNames)) {
                $dadosBind['juros'] = $juros;
            }
            if (in_array('multa', $columnNames)) {
                $dadosBind['multa'] = $multa;
            }
            if (in_array('desconto', $columnNames)) {
                $dadosBind['desconto'] = $desconto;
            }
            if (in_array('despesa', $columnNames)) {
                $dadosBind['despesa'] = $despesa;
            }

            $this->db->beginTransaction();

            // Log completo dos dados antes de atualizar
            error_log("DEBUG UPDATE - SQL: " . $sql);
            error_log("DEBUG UPDATE - Dados para bind: " . json_encode($dadosBind, JSON_UNESCAPED_UNICODE));

            $result = $stmt->execute($dadosBind);
            $rowsAffected = $stmt->rowCount();

            error_log("DEBUG UPDATE - Execute result: " . ($result ? 'true' : 'false'));
            error_log("DEBUG UPDATE - Rows affected: " . $rowsAffected);
            error_log("DEBUG UPDATE - Conta atualizada com sucesso, ID: " . $id);

            if (!$result || $rowsAffected === 0) {
                throw new \Exception('Nenhuma linha foi atualizada. Verifique se o ID existe e pertence à empresa.');
            }

            $this->logActivity('update', 'contas_receber', $id, $dadosBind);

            // Verificar se o status mudou para PAGO
            $statusMudouParaPago = false;
            $statusAnteriorPago = false;

            // Verificar status anterior
            if (!empty($conta['status_id'])) {
                $stmtStatusAnt = $this->db->prepare("
                    SELECT codigo FROM modulo_status
                    WHERE id = :status_id AND company_id = :company_id
                ");
                $stmtStatusAnt->execute([
                    'status_id' => $conta['status_id'],
                    'company_id' => $companyId
                ]);
                $statusAntInfo = $stmtStatusAnt->fetch();
                if ($statusAntInfo && strtolower($statusAntInfo['codigo']) === 'pago') {
                    $statusAnteriorPago = true;
                }
            } elseif (!empty($conta['status']) && strtolower($conta['status']) === 'pago') {
                $statusAnteriorPago = true;
            }

            // Verificar novo status
            if (!empty($dadosBind['status_id'])) {
                // Buscar código do status para verificar se é "pago"
                $stmtStatusCheck = $this->db->prepare("
                    SELECT codigo FROM modulo_status
                    WHERE id = :status_id AND company_id = :company_id
                ");
                $stmtStatusCheck->execute([
                    'status_id' => $dadosBind['status_id'],
                    'company_id' => $companyId
                ]);
                $statusInfo = $stmtStatusCheck->fetch();

                if ($statusInfo && strtolower($statusInfo['codigo']) === 'pago' && !$statusAnteriorPago) {
                    $statusMudouParaPago = true;
                }

                // Verificar se o status gera financeiro e inserir no fluxo de caixa
                $this->gerarFluxoCaixa($id, (int) $dadosBind['status_id'], $companyId);
            } elseif (!empty($dadosBind['status']) && strtolower($dadosBind['status']) === 'pago' && !$statusAnteriorPago) {
                $statusMudouParaPago = true;
            }

            $this->db->commit();

            // Se mudou para PAGO, gerar entrada no fluxo de caixa (igual ao botão receber)
            if ($statusMudouParaPago) {
                // Buscar dados atualizados da conta
                $contaAtualizada = $this->getConta($id);
                if ($contaAtualizada) {
                    $this->inserirFluxoCaixa($contaAtualizada, 'entrada');
                }
            }

            // 🚀 SINCRONIZAÇÃO AUTOMÁTICA: Gerar boleto Inter se conta bancária mudou para o Inter
            // (apenas se não tem boleto ainda)
            if (!empty($dadosBind['conta_bancaria_id']) && empty($conta['nosso_numero_boleto'])) {
                try {
                    $this->tentarGerarBoletoAutomatico($id, (int) $dadosBind['conta_bancaria_id'], $companyId);
                } catch (Exception $e) {
                    error_log("Erro ao gerar boleto automático: " . $e->getMessage());
                    // Não interrompe o fluxo
                }
            }

            // Se for AJAX/Fetch, retornar JSON
            if ($this->request->isAjax() || isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
                $this->response->json([
                    'success' => true,
                    'message' => 'Conta a receber atualizada com sucesso!',
                    'data' => [
                        'redirect' => UrlHelper::url('/entradas')
                    ]
                ]);
                return;
            }

            // Se for submit tradicional, redirecionar com flash message
            $this->session->set('flash_success', 'Conta a receber atualizada com sucesso!');
            $this->redirect('/entradas');

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao atualizar conta a receber: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());

            // Se for AJAX/Fetch, retornar JSON de erro
            if ($this->request->isAjax() || isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Erro ao atualizar conta a receber: ' . $e->getMessage()
                ]);
                return;
            }

            // Se for submit tradicional, redirecionar com flash message de erro
            $this->session->set('flash_error', 'Erro ao atualizar conta a receber: ' . $e->getMessage());
            $this->redirect('/entradas');
        }
    }

    /**
     * Atualiza e redireciona (form tradicional sem AJAX)
     */
    public function updateAndRedirect(): void
    {
        try {
            $id = (int) $this->request->post('id');
            $companyId = $this->getCompanyId();
            $isAjax = $this->request->isAjax();

            if (!$id) {
                if ($isAjax) {
                    $this->response->json(['success' => false, 'message' => 'ID não informado']);
                    return;
                }
                $this->session->set('flash_error', 'ID não informado');
                $this->redirect('/entradas');
                return;
            }

            // Verificar se a conta existe
            $conta = $this->getConta($id);
            if (!$conta) {
                if ($isAjax) {
                    $this->response->json(['success' => false, 'message' => 'Conta a receber não encontrada']);
                    return;
                }
                $this->session->set('flash_error', 'Conta a receber não encontrada');
                $this->redirect('/entradas');
                return;
            }

            // Detectar estrutura da tabela
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');

            // Montar campos para atualizar
            $sets = [];
            $params = [
                'id' => $id,
                'company_id' => $companyId
            ];

            // Campos básicos
            if (in_array('description', $columnNames)) {
                $sets[] = 'description = :description';
                $params['description'] = $this->request->post('description') ?? '';
            }

            if (in_array('due_date', $columnNames)) {
                $sets[] = 'due_date = :due_date';
                $params['due_date'] = $this->request->post('due_date') ?? date('Y-m-d');
            }

            if (in_array('notes', $columnNames)) {
                $sets[] = 'notes = :notes';
                $params['notes'] = $this->request->post('notes') ?: null;
            }

            // Campos opcionais
            if (in_array('numero', $columnNames)) {
                $numero = $this->request->post('numero');
                if ($numero !== null) {
                    $sets[] = 'numero = :numero';
                    $params['numero'] = $numero;
                }
            }

            if (in_array('status_id', $columnNames)) {
                $statusId = $this->request->post('status_id');
                if ($statusId !== null) {
                    $sets[] = 'status_id = :status_id';
                    $params['status_id'] = $statusId;
                }
            }

            if (in_array('payment_method', $columnNames)) {
                $paymentMethod = $this->request->post('payment_method');
                if ($paymentMethod !== null) {
                    $sets[] = 'payment_method = :payment_method';
                    $params['payment_method'] = $paymentMethod;
                }
            }

            if (in_array('metodo_pagamento_id', $columnNames)) {
                $metodoPagamentoId = $this->request->post('metodo_pagamento_id');
                if ($metodoPagamentoId !== null) {
                    $sets[] = 'metodo_pagamento_id = :metodo_pagamento_id';
                    $params['metodo_pagamento_id'] = $metodoPagamentoId ?: null;
                }
            }

            if (in_array('conta_bancaria_id', $columnNames)) {
                $contaBancariaId = $this->request->post('conta_bancaria_id');
                if ($contaBancariaId !== null) {
                    $sets[] = 'conta_bancaria_id = :conta_bancaria_id';
                    $params['conta_bancaria_id'] = $contaBancariaId ?: null;
                }
            }

            if (in_array('plano_conta_id', $columnNames)) {
                $planoContaId = $this->request->post('plano_conta_id');
                if ($planoContaId !== null) {
                    $sets[] = 'plano_conta_id = :plano_conta_id';
                    $params['plano_conta_id'] = $planoContaId ?: null;
                }
            }

            if (in_array('plano_contas_id', $columnNames)) {
                $planoContasId = $this->request->post('plano_contas_id');
                if ($planoContasId !== null) {
                    $sets[] = 'plano_contas_id = :plano_contas_id';
                    $params['plano_contas_id'] = $planoContasId ?: null;
                }
            }

            if (in_array('centro_custo_id', $columnNames)) {
                $centroCustoId = $this->request->post('centro_custo_id');
                if ($centroCustoId !== null) {
                    $sets[] = 'centro_custo_id = :centro_custo_id';
                    $params['centro_custo_id'] = $centroCustoId ?: null;
                }
            }

            if (in_array('payment_date', $columnNames)) {
                $paymentDate = $this->request->post('payment_date');
                if ($paymentDate !== null && $paymentDate !== '') {
                    $sets[] = 'payment_date = :payment_date';
                    $params['payment_date'] = $paymentDate;
                }
            }

            if (in_array('amount_received', $columnNames)) {
                $amountReceived = $this->request->post('amount_received');
                if ($amountReceived !== null) {
                    $sets[] = 'amount_received = :amount_received';
                    $params['amount_received'] = (float) $amountReceived;
                }
            }

            if (in_array('amount_paid', $columnNames)) {
                $amountPaid = $this->request->post('amount_paid');
                if ($amountPaid !== null) {
                    $sets[] = 'amount_paid = :amount_paid';
                    $params['amount_paid'] = (float) $amountPaid;
                }
            }

            // Sempre atualizar updated_at
            if (in_array('updated_at', $columnNames)) {
                $sets[] = 'updated_at = NOW()';
            }

            if (empty($sets)) {
                throw new \Exception('Nenhum campo para atualizar');
            }

            $sql = "UPDATE contas_receber SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";

            error_log("[EntradasController::updateAndRedirect] SQL: " . $sql);
            error_log("[EntradasController::updateAndRedirect] Params: " . json_encode($params));

            $stmt = $this->db->prepare($sql);
            $result = $stmt->execute($params);

            $rowsAffected = $stmt->rowCount();
            error_log("[EntradasController::updateAndRedirect] Linhas afetadas: " . $rowsAffected);

            if (!$result || $rowsAffected === 0) {
                throw new \Exception('Nenhuma linha foi atualizada. Verifique se o ID existe e pertence à empresa.');
            }

            if ($isAjax) {
                $this->response->json([
                    'success' => true,
                    'message' => 'Entrada atualizada com sucesso!',
                    'redirect' => url('/entradas')
                ]);
                return;
            }

            $this->session->set('flash_success', 'Entrada atualizada com sucesso!');
            $this->redirect('/entradas');

        } catch (Exception $e) {
            error_log("Erro no updateAndRedirect: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());

            if ($this->request->isAjax()) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Erro ao atualizar: ' . $e->getMessage()
                ]);
                return;
            }

            $this->session->set('flash_error', 'Erro ao atualizar: ' . $e->getMessage());
            $this->redirect('/entradas');
        }
    }

    public function show(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $conta = $this->getConta($id);

            if (!$conta) {
                $this->error('Conta a receber não encontrada');
                return;
            }

            // Se for requisição AJAX, retornar JSON
            if ($this->request->isAjax()) {
                // Buscar email do cliente
                $stmtCliente = $this->db->prepare("SELECT email FROM pessoas WHERE id = :id");
                $stmtCliente->execute(['id' => $conta['customer_id'] ?? 0]);
                $cliente = $stmtCliente->fetch();

                $this->success('Conta encontrada', [
                    'id' => $conta['id'],
                    'pessoa_id' => $conta['customer_id'],
                    'pessoa_email' => $cliente['email'] ?? '',
                    'valor' => $conta['amount'],
                    'descricao' => $conta['description']
                ]);
                return;
            }

            // Buscar cliente
            $stmtCliente = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id");
            $stmtCliente->execute(['id' => $conta['customer_id'] ?? 0]);
            $cliente = $stmtCliente->fetch();

            $this->view('entradas/show', [
                'conta' => $conta,
                'cliente' => $cliente,
                'pageTitle' => 'Visualizar Conta a Receber',
                'activeMenu' => 'entradas'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao visualizar conta: " . $e->getMessage());
            $this->error('Erro ao visualizar conta');
        }
    }

    public function receive(): void
    {
        try {
            $id = (int) $this->request->post('id');
            $conta = $this->getConta($id);

            if (!$conta) {
                $this->error('Conta a receber não encontrada');
                return;
            }

            $this->db->beginTransaction();

            // Detectar estrutura da tabela
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');

            $sets = ["amount_remaining = 0", "updated_at = NOW()"];

            if (in_array('amount_paid', $columnNames)) {
                $sets[] = 'amount_paid = amount';
            } elseif (in_array('amount_received', $columnNames)) {
                $sets[] = 'amount_received = amount';
            }

            if (in_array('payment_date', $columnNames)) {
                $sets[] = 'payment_date = CURDATE()';
            }

            // Atualizar status para pago (ID ou código)
            if (in_array('status_id', $columnNames)) {
                // Buscar ID do status "pago"
                $stmtStatus = $this->db->prepare("SELECT id FROM modulo_status WHERE company_id = :company_id AND modulo IN ('entradas', 'contas_receber') AND codigo = 'pago' LIMIT 1");
                $stmtStatus->execute(['company_id' => $this->getCompanyId()]);
                $statusPago = $stmtStatus->fetch();
                if ($statusPago) {
                    $sets[] = "status_id = " . $statusPago['id'];
                }
            } elseif (in_array('status', $columnNames)) {
                $sets[] = "status = 'pago'";
            }

            $sql = "UPDATE contas_receber SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmt = $this->db->prepare($sql);
            $stmt->execute(['id' => $id, 'company_id' => $this->getCompanyId()]);

            // Inserir entrada no fluxo de caixa
            $this->inserirFluxoCaixa($conta, 'entrada');

            $this->logActivity('receive', 'contas_receber', $id, $conta);
            $this->db->commit();

            $this->success('Conta marcada como recebida com sucesso');

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao marcar conta como recebida: " . $e->getMessage());
            $this->error('Erro ao marcar conta como recebida');
        }
    }

    public function delete(): void
    {
        // Verificar permissão de exclusão
        if (!$this->canDelete('entradas')) {
            $this->response->forbidden('Você não tem permissão para excluir entradas.');
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            $conta = $this->getConta($id);

            if (!$conta) {
                $this->error('Conta a receber não encontrada');
                return;
            }

            $this->db->beginTransaction();

            $stmt = $this->db->prepare("DELETE FROM contas_receber WHERE id = :id AND company_id = :company_id");
            $stmt->execute(['id' => $id, 'company_id' => $this->getCompanyId()]);

            $this->logActivity('delete', 'contas_receber', $id, $conta);
            $this->db->commit();

            $this->success('Conta a receber excluída com sucesso');

        } catch (Exception $e) {
            $this->db->rollBack();
            error_log("Erro ao excluir conta a receber: " . $e->getMessage());
            $this->error('Erro ao excluir conta a receber');
        }
    }

    private function getConta(int $id): ?array
    {
        $stmt = $this->db->prepare("
            SELECT cr.*,
                   p.name as customer_name,
                   p.document as customer_document
            FROM contas_receber cr
            LEFT JOIN pessoas p ON cr.customer_id = p.id
            WHERE cr.id = :id AND cr.company_id = :company_id
        ");
        $stmt->execute(['id' => $id, 'company_id' => $this->getCompanyId()]);
        return $stmt->fetch() ?: null;
    }

    /**
     * Inserir movimento no fluxo de caixa
     */
    private function inserirFluxoCaixa(array $conta, string $tipo = 'entrada'): void
    {
        try {
            $companyId = $this->getCompanyId();
            $userId = $this->session->get('user')['id'] ?? null;

            // Verificar se já existe lançamento para esta conta a receber
            $stmtCheck = $this->db->prepare("
                SELECT id FROM fluxo_caixa
                WHERE reference_type = 'contas_receber'
                AND reference_id = :reference_id
                AND company_id = :company_id
            ");
            $stmtCheck->execute([
                'reference_id' => $conta['id'],
                'company_id' => $companyId
            ]);

            if ($stmtCheck->fetch()) {
                error_log("[EntradasController] Lançamento de fluxo de caixa já existe para conta ID: {$conta['id']}");
                return; // Já existe lançamento, não criar duplicado
            }

            // Buscar valores da conta
            $peopleId = $conta['customer_id'] ?? null;
            $amount = (float) ($conta['amount'] ?? $conta['valor'] ?? 0);
            $description = $conta['description'] ?? $conta['descricao'] ?? 'Recebimento de conta';
            $planoContasId = $conta['plano_contas_id'] ?? null;
            $centroCustoId = $conta['centro_custo_id'] ?? null;

            // Calcular saldo atual (último saldo do fluxo de caixa)
            $stmtSaldo = $this->db->prepare("
                SELECT balance FROM fluxo_caixa
                WHERE company_id = :company_id
                ORDER BY date DESC, id DESC
                LIMIT 1
            ");
            $stmtSaldo->execute(['company_id' => $companyId]);
            $ultimoSaldo = (float) ($stmtSaldo->fetchColumn() ?: 0);

            // Calcular novo saldo (entrada aumenta o saldo)
            $novoSaldo = $ultimoSaldo + $amount;

            // Inserir no fluxo de caixa
            $stmt = $this->db->prepare("
                INSERT INTO fluxo_caixa (
                    people_id,
                    responsible_id,
                    company_id,
                    date,
                    type,
                    category,
                    plano_contas_id,
                    centro_custo_id,
                    description,
                    amount,
                    balance,
                    reference_type,
                    reference_id,
                    created_at
                ) VALUES (
                    :people_id,
                    :responsible_id,
                    :company_id,
                    CURDATE(),
                    :type,
                    :category,
                    :plano_contas_id,
                    :centro_custo_id,
                    :description,
                    :amount,
                    :balance,
                    'contas_receber',
                    :reference_id,
                    NOW()
                )
            ");

            $stmt->execute([
                'people_id' => $peopleId,
                'responsible_id' => $userId,
                'company_id' => $companyId,
                'type' => $tipo,
                'category' => 'Recebimento',
                'plano_contas_id' => $planoContasId,
                'centro_custo_id' => $centroCustoId,
                'description' => $description,
                'amount' => $amount,
                'balance' => $novoSaldo,
                'reference_id' => $conta['id']
            ]);

            error_log("[EntradasController] Fluxo de caixa inserido - Tipo: {$tipo}, Valor: {$amount}, Saldo: {$novoSaldo}, Conta ID: {$conta['id']}");

        } catch (Exception $e) {
            error_log("Erro ao inserir fluxo de caixa: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            // Não lança exceção para não interromper o processo principal
        }
    }

    /**
     * Busca pessoas (clientes) para select
     */
    private function getPessoas(): array
    {
        try {
            $stmt = $this->db->prepare("
                SELECT id, name, nome, document
                FROM pessoas
                WHERE company_id = :company_id AND is_active = 1 AND type IN ('cliente', 'ambos')
                ORDER BY COALESCE(name, nome) ASC
            ");
            $stmt->execute(['company_id' => $this->getCompanyId()]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar pessoas: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca métodos de pagamento
     */
    private function getMetodosPagamento(): array
    {
        try {
            $stmt = $this->db->prepare("
                SELECT id, name, type
                FROM metodos_pagamento
                WHERE company_id = :company_id AND is_active = 1
                ORDER BY name ASC
            ");
            $stmt->execute(['company_id' => $this->getCompanyId()]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar métodos de pagamento: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca contas bancárias
     */
    private function getContasBancarias(): array
    {
        try {
            $stmt = $this->db->prepare("
                SELECT id, bank_name, agency, account_number, account_type
                FROM contas_bancarias
                WHERE company_id = :company_id AND is_active = 1
                ORDER BY bank_name ASC, agency ASC
            ");
            $stmt->execute(['company_id' => $this->getCompanyId()]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar contas bancárias: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca plano de contas
     */
    private function getPlanoContas(): array
    {
        try {
            // Detectar estrutura da tabela
            $stmtColumns = $this->db->query("SHOW COLUMNS FROM plano_contas");
            $columns = $stmtColumns->fetchAll();
            $columnNames = array_column($columns, 'Field');

            // Detectar nome da coluna de código
            $colCodigo = in_array('codigo', $columnNames) ? 'codigo' : (in_array('code', $columnNames) ? 'code' : 'id');

            // Detectar nome da coluna de nome
            $colNome = in_array('nome', $columnNames) ? 'nome' : (in_array('name', $columnNames) ? 'name' : 'id');

            // Detectar coluna ativo
            $colAtivo = in_array('ativo', $columnNames) ? 'ativo' : (in_array('is_active', $columnNames) ? 'is_active' : null);

            // Montar WHERE
            $where = "company_id = :company_id";
            if ($colAtivo) {
                $where .= " AND {$colAtivo} = 1";
            }

            $sql = "SELECT id, {$colCodigo} as codigo, {$colNome} as nome FROM plano_contas WHERE {$where} ORDER BY {$colCodigo} ASC";

            $stmt = $this->db->prepare($sql);
            $stmt->execute(['company_id' => $this->getCompanyId()]);
            $result = $stmt->fetchAll();

            error_log("Plano de Contas SQL: {$sql}");
            error_log("Plano de Contas encontrados: " . count($result));

            return $result;
        } catch (Exception $e) {
            error_log("Erro ao buscar plano de contas: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca centros de custo para select
     */
    private function getCentroCustos(): array
    {
        try {
            $stmt = $this->db->prepare("
                SELECT id, code, name
                FROM centro_custos
                WHERE company_id = :company_id AND is_active = 1
                ORDER BY code ASC
            ");
            $stmt->execute(['company_id' => $this->getCompanyId()]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar centros de custo: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Gera lançamento no fluxo de caixa se o status gerar financeiro
     */
    private function gerarFluxoCaixa(int $contaReceberId, int $statusId, int $companyId): void
    {
        try {
            // Buscar informações do status
            $stmtStatus = $this->db->prepare("
                SELECT gera_financeiro
                FROM modulo_status
                WHERE id = :id AND company_id = :company_id
            ");
            $stmtStatus->execute(['id' => $statusId, 'company_id' => $companyId]);
            $status = $stmtStatus->fetch();

            // Se o status não gera financeiro, não faz nada
            if (!$status || empty($status['gera_financeiro'])) {
                return;
            }

            // Buscar informações da conta a receber
            $stmtConta = $this->db->prepare("
                SELECT
                    payment_date,
                    amount_received,
                    description,
                    plano_conta_id,
                    centro_custo_id
                FROM contas_receber
                WHERE id = :id AND company_id = :company_id
            ");
            $stmtConta->execute(['id' => $contaReceberId, 'company_id' => $companyId]);
            $conta = $stmtConta->fetch();

            if (!$conta) {
                error_log("Conta a receber #{$contaReceberId} não encontrada para gerar fluxo de caixa");
                return;
            }

            // Se não tem data de pagamento, não gera fluxo
            if (empty($conta['payment_date'])) {
                error_log("Conta a receber #{$contaReceberId} sem data de pagamento, não gera fluxo");
                return;
            }

            // Se não tem valor recebido, não gera fluxo
            if (empty($conta['amount_received']) || $conta['amount_received'] <= 0) {
                error_log("Conta a receber #{$contaReceberId} sem valor recebido, não gera fluxo");
                return;
            }

            // Verificar se já existe lançamento no fluxo para esta conta
            $stmtCheck = $this->db->prepare("
                SELECT id
                FROM fluxo_caixa
                WHERE reference_type = 'contas_receber'
                  AND reference_id = :reference_id
                  AND company_id = :company_id
            ");
            $stmtCheck->execute([
                'reference_id' => $contaReceberId,
                'company_id' => $companyId
            ]);

            if ($stmtCheck->fetch()) {
                // Já existe lançamento, não cria duplicado
                return;
            }

            // Inserir no fluxo de caixa
            $stmtInsert = $this->db->prepare("
                INSERT INTO fluxo_caixa (
                    company_id,
                    date,
                    type,
                    category,
                    plano_contas_id,
                    centro_custo_id,
                    description,
                    amount,
                    balance,
                    reference_type,
                    reference_id,
                    created_at
                ) VALUES (
                    :company_id,
                    :date,
                    :type,
                    :category,
                    :plano_contas_id,
                    :centro_custo_id,
                    :description,
                    :amount,
                    :balance,
                    :reference_type,
                    :reference_id,
                    NOW()
                )
            ");

            $stmtInsert->execute([
                'company_id' => $companyId,
                'date' => $conta['payment_date'],
                'type' => 'entrada',
                'category' => 'Contas a Receber',
                'plano_contas_id' => $conta['plano_conta_id'] ?: null,
                'centro_custo_id' => $conta['centro_custo_id'] ?: null,
                'description' => $conta['description'] ?? 'Recebimento',
                'amount' => $conta['amount_received'],
                'balance' => 0,
                'reference_type' => 'contas_receber',
                'reference_id' => $contaReceberId
            ]);

            error_log("✅ Fluxo de caixa gerado para conta a receber #{$contaReceberId}");

        } catch (Exception $e) {
            error_log("Erro ao gerar fluxo de caixa: " . $e->getMessage());
            // Não lança exceção para não interromper o fluxo principal
        }
    }

    /**
     * Gera recibo em PDF
     */
    public function recibo(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $conta = $this->getConta($id);

            if (!$conta) {
                $this->error('Conta a receber não encontrada');
                return;
            }

            // Buscar dados da empresa
            $stmtEmpresa = $this->db->prepare("SELECT * FROM empresas WHERE company_id = :company_id LIMIT 1");
            $stmtEmpresa->execute(['company_id' => $this->getCompanyId()]);
            $empresa = $stmtEmpresa->fetch();

            // Buscar dados do cliente
            $stmtCliente = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id");
            $stmtCliente->execute(['id' => $conta['pessoa_id'] ?? $conta['customer_id'] ?? 0]);
            $cliente = $stmtCliente->fetch();

            // Renderizar view de recibo
            $this->view('entradas/recibo', [
                'conta' => $conta,
                'empresa' => $empresa,
                'cliente' => $cliente
            ]);

        } catch (Exception $e) {
            error_log("Erro ao gerar recibo: " . $e->getMessage());
            $this->error('Erro ao gerar recibo');
        }
    }

    /**
     * Gera duplicata em PDF
     */
    public function duplicata(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $conta = $this->getConta($id);

            if (!$conta) {
                $this->error('Conta a receber não encontrada');
                return;
            }

            // Buscar dados da empresa
            $stmtEmpresa = $this->db->prepare("SELECT * FROM empresas WHERE company_id = :company_id LIMIT 1");
            $stmtEmpresa->execute(['company_id' => $this->getCompanyId()]);
            $empresa = $stmtEmpresa->fetch();

            // Buscar dados do cliente
            $stmtCliente = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id");
            $stmtCliente->execute(['id' => $conta['pessoa_id'] ?? $conta['customer_id'] ?? 0]);
            $cliente = $stmtCliente->fetch();

            // Renderizar view de duplicata
            $this->view('entradas/duplicata', [
                'conta' => $conta,
                'empresa' => $empresa,
                'cliente' => $cliente
            ]);

        } catch (Exception $e) {
            error_log("Erro ao gerar duplicata: " . $e->getMessage());
            $this->error('Erro ao gerar duplicata');
        }
    }

    /**
     * Gerar cobrança no Banco Inter
     */
    public function gerarBoletoInter(): void
    {
        try {
            $id = (int) $this->request->post('id');
            $companyId = $this->getCompanyId();

            // Buscar conta a receber
            $stmt = $this->db->prepare("
                SELECT cr.*, p.*,
                       cr.id as conta_id,
                       cr.description as conta_description,
                       cr.notes as conta_notes
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                WHERE cr.id = :id AND cr.company_id = :company_id
            ");
            $stmt->execute(['id' => $id, 'company_id' => $companyId]);
            $conta = $stmt->fetch();

            if (!$conta) {
                $this->error('Conta a receber não encontrada');
                return;
            }

            // Se já tem boleto emitido
            if (!empty($conta['nosso_numero_boleto']) || !empty($conta['boleto_status'])) {
                // Verificar se dados estão vazios (pendente de consulta)
                $dadosVazios = empty($conta['nosso_numero_boleto']) &&
                    empty($conta['linha_digitavel']) &&
                    empty($conta['codigo_barras']);

                // Se está pendente ou com dados vazios, tentar consultar na API
                if ($dadosVazios) {
                    // Continuar para tentar consultar via API
                    error_log("Boleto sem dados completos, tentando consultar na API do Inter...");
                } else {
                    // Tem dados completos - verificar se tem PDF
                    $pdfUrl = $conta['boleto_pdf_url'];

                    // Se não tem PDF ainda, buscar na API usando codigo_solicitacao
                    if (empty($pdfUrl) && !empty($conta['codigo_solicitacao_boleto'])) {
                        error_log("Buscando PDF do boleto na API do Inter...");

                        try {
                            // Buscar conta bancária
                            $stmtBanco = $this->db->prepare("
                                SELECT * FROM contas_bancarias
                                WHERE company_id = :company_id AND bank_code = '077' AND is_active = 1
                                LIMIT 1
                            ");
                            $stmtBanco->execute(['company_id' => $companyId]);
                            $contaBanco = $stmtBanco->fetch();

                            if ($contaBanco) {
                                require_once ROOT_PATH . '/src/Integrations/BancoInter.php';

                                $certPath = ROOT_PATH . '/' . ltrim($contaBanco['certificado_path'], '/');
                                $keyPath = ROOT_PATH . '/' . ltrim($contaBanco['chave_privada_path'], '/');

                                $bancoInter = new \App\Integrations\BancoInter(
                                    $contaBanco['chave_api'],
                                    $contaBanco['token_webhook'],
                                    $contaBanco['account_number'],
                                    true,
                                    $certPath,
                                    $keyPath,
                                    $contaBanco['certificado_senha'] ?? null
                                );

                                $pdfBase64 = $bancoInter->obterPdfBoleto($conta['codigo_solicitacao_boleto']);

                                if ($pdfBase64) {
                                    $pdfUrl = 'data:application/pdf;base64,' . $pdfBase64;

                                    // Salvar no banco
                                    $stmtPdf = $this->db->prepare("
                                        UPDATE contas_receber SET boleto_pdf_url = :pdf_url
                                        WHERE id = :id AND company_id = :company_id
                                    ");
                                    $stmtPdf->execute([
                                        'pdf_url' => $pdfUrl,
                                        'id' => $id,
                                        'company_id' => $companyId
                                    ]);

                                    error_log("PDF obtido e salvo com sucesso!");
                                }
                            }
                        } catch (Exception $e) {
                            error_log("Erro ao buscar PDF: " . $e->getMessage());
                            // Continuar sem PDF
                        }
                    }

                    // Retornar dados salvos completos
                    $this->success('Boleto já foi emitido anteriormente', [
                        'boleto' => [
                            'nosso_numero' => $conta['nosso_numero_boleto'],
                            'linha_digitavel' => $conta['linha_digitavel'],
                            'codigo_barras' => $conta['codigo_barras'],
                            'pdf_url' => $pdfUrl,
                            'qrcode' => $conta['pix_qrcode'],
                            'tx_id' => $conta['pix_txid'],
                            'status' => $conta['boleto_status'],
                            'emitido_em' => $conta['boleto_emitido_em']
                        ]
                    ]);
                    return;
                }
            }

            // Buscar conta bancária do Banco Inter
            $stmtBanco = $this->db->prepare("
                SELECT * FROM contas_bancarias
                WHERE company_id = :company_id
                  AND bank_code = '077'
                  AND is_active = 1
                LIMIT 1
            ");
            $stmtBanco->execute(['company_id' => $companyId]);
            $contaBanco = $stmtBanco->fetch();

            if (!$contaBanco) {
                $this->error('Conta bancária do Banco Inter não encontrada ou inativa');
                return;
            }

            if (empty($contaBanco['chave_api']) || empty($contaBanco['token_webhook'])) {
                $this->error('Conta bancária do Banco Inter sem credenciais (Client ID/Secret). Configure em Contas Bancárias.');
                return;
            }

            // Buscar dados da empresa (cedente)
            $stmtEmpresa = $this->db->prepare("SELECT * FROM empresas WHERE id = :id");
            $stmtEmpresa->execute(['id' => $companyId]);
            $empresa = $stmtEmpresa->fetch();

            if (!$empresa) {
                $this->error('Empresa não encontrada');
                return;
            }

            // Preparar dados para a API do Inter
            $dadosCobranca = [
                'numero_documento' => str_pad((string) $id, 10, '0', STR_PAD_LEFT),
                'valor' => $conta['amount'],
                'data_vencimento' => $conta['due_date'],
                'dias_agenda' => 60,
                'pagador' => [
                    'documento' => preg_replace('/\D/', '', $conta['document'] ?? ''),  // Remove formatação
                    'nome' => $conta['name'] ?? '',
                    'email' => $conta['email'] ?? '',
                    'telefone' => preg_replace('/\D/', '', $conta['mobile'] ?? $conta['phone'] ?? ''),  // Remove formatação
                    'endereco' => $conta['address'] ?? '',
                    'numero' => '',
                    'complemento' => '',
                    'bairro' => '',
                    'cidade' => $conta['city'] ?? '',
                    'uf' => $conta['state'] ?? '',
                    'cep' => preg_replace('/\D/', '', $conta['zip_code'] ?? '')  // Remove formatação e usar zip_code
                ]
            ];

            // Instanciar integração Banco Inter
            require_once ROOT_PATH . '/src/Integrations/BancoInter.php';

            // 🔐 Preparar caminhos dos certificados mTLS
            $certificadoPath = null;
            $chavePrivadaPath = null;

            if (!empty($contaBanco['certificado_path'])) {
                $certificadoPath = ROOT_PATH . '/' . ltrim($contaBanco['certificado_path'], '/');
            }

            if (!empty($contaBanco['chave_privada_path'])) {
                $chavePrivadaPath = ROOT_PATH . '/' . ltrim($contaBanco['chave_privada_path'], '/');
            }

            // Validar certificados
            if (!$certificadoPath || !file_exists($certificadoPath)) {
                $this->error('Certificado digital (.crt) não configurado. Configure em Contas Bancárias → Editar → Dados de Boleto.');
                return;
            }

            if (!$chavePrivadaPath || !file_exists($chavePrivadaPath)) {
                $this->error('Chave privada (.key) não configurada. Configure em Contas Bancárias → Editar → Dados de Boleto.');
                return;
            }

            $bancoInter = new \App\Integrations\BancoInter(
                $contaBanco['chave_api'],
                $contaBanco['token_webhook'],
                $contaBanco['account_number'],
                true,  // 🚀 PRODUÇÃO
                $certificadoPath,
                $chavePrivadaPath,
                $contaBanco['certificado_senha'] ?? null
            );

            // Criar cobrança
            try {
                $boleto = $bancoInter->criarCobranca($dadosCobranca);
            } catch (Exception $e) {
                // Verificar se é erro de duplicação
                if (
                    strpos($e->getMessage(), 'existe uma cobrança emitida') !== false ||
                    strpos($e->getMessage(), 'código de solicitação') !== false
                ) {

                    // Extrair código de solicitação se houver
                    preg_match('/código de solicitação:\s*([a-f0-9-]+)/i', $e->getMessage(), $matches);

                    // Tentar consultar o boleto pelo seuNumero
                    try {
                        $seuNumero = $dadosCobranca['numero_documento'];
                        $token = $bancoInter->getAccessToken();

                        // Usar reflection para acessar método privado
                        $reflection = new \ReflectionClass($bancoInter);
                        $method = $reflection->getMethod('consultarCobrancaPorSeuNumero');
                        $method->setAccessible(true);
                        $boletoExistente = $method->invoke($bancoInter, $seuNumero, $token);

                        if ($boletoExistente) {
                            // Converter para formato esperado (já vem no formato correto da BancoInter)
                            $boleto = [
                                'codigo_solicitacao' => $boletoExistente['codigoSolicitacao'] ?? '',
                                'nosso_numero' => $boletoExistente['nossoNumero'] ?? '',
                                'codigo_barras' => $boletoExistente['codigoBarras'] ?? '',
                                'linha_digitavel' => $boletoExistente['linhaDigitavel'] ?? '',
                                'pdf_base64' => $boletoExistente['pdf_base64'] ?? '',
                                'qrcode' => $boletoExistente['pixCopiaECola'] ?? '',
                                'tx_id' => $boletoExistente['txId'] ?? '',
                                'status' => $boletoExistente['situacao'] ?? 'EMITIDO'
                            ];

                            error_log("Boleto encontrado na consulta: nossoNumero = " . $boleto['nosso_numero'] . ", codigoSolicitacao = " . $boleto['codigo_solicitacao']);
                        } else {
                            throw $e; // Se não conseguir consultar, lançar erro original
                        }
                    } catch (Exception $e2) {
                        // Se não conseguir consultar via API, verificar se já temos dados salvos no banco
                        error_log("Erro ao consultar boleto duplicado via API: " . $e2->getMessage());

                        // Verificar novamente os dados da conta (pode ter sido salvo em tentativa anterior)
                        $stmtCheck = $this->db->prepare("
                            SELECT codigo_solicitacao_boleto, nosso_numero_boleto, linha_digitavel, codigo_barras,
                                   boleto_pdf_url, pix_qrcode, pix_txid, boleto_status
                            FROM contas_receber
                            WHERE id = :id AND company_id = :company_id
                        ");
                        $stmtCheck->execute(['id' => $id, 'company_id' => $companyId]);
                        $dadosSalvos = $stmtCheck->fetch();

                        if (!empty($dadosSalvos['nosso_numero_boleto'])) {
                            // Usar dados salvos
                            $boleto = [
                                'codigo_solicitacao' => $dadosSalvos['codigo_solicitacao_boleto'] ?? '',
                                'nosso_numero' => $dadosSalvos['nosso_numero_boleto'],
                                'linha_digitavel' => $dadosSalvos['linha_digitavel'],
                                'codigo_barras' => $dadosSalvos['codigo_barras'],
                                'pdf_url' => $dadosSalvos['boleto_pdf_url'],
                                'qrcode' => $dadosSalvos['pix_qrcode'],
                                'tx_id' => $dadosSalvos['pix_txid'],
                                'status' => $dadosSalvos['boleto_status'] ?? 'EMITIDO'
                            ];
                            error_log("Usando dados salvos do banco de dados");
                        } else {
                            // Marcar como emitido mesmo sem dados completos
                            // O usuário pode consultar depois ou via painel do Inter
                            $boleto = [
                                'codigo_solicitacao' => '',
                                'nosso_numero' => '',
                                'linha_digitavel' => '',
                                'codigo_barras' => '',
                                'pdf_url' => '',
                                'qrcode' => '',
                                'tx_id' => '',
                                'status' => 'EMITIDO_PENDENTE'
                            ];

                            // Salvar marcador no banco
                            $this->db->beginTransaction();
                            $stmtMark = $this->db->prepare("
                                UPDATE contas_receber SET
                                    boleto_status = 'EMITIDO_PENDENTE',
                                    boleto_emitido_em = NOW(),
                                    updated_at = NOW()
                                WHERE id = :id AND company_id = :company_id
                            ");
                            $stmtMark->execute(['id' => $id, 'company_id' => $companyId]);
                            $this->db->commit();

                            error_log("Boleto marcado como EMITIDO_PENDENTE - dados serão consultados posteriormente");
                        }
                    }
                } else {
                    throw $e; // Re-lançar se não for erro de duplicação
                }
            }

            // Atualizar conta a receber com dados do boleto
            $this->db->beginTransaction();

            $stmtUpdate = $this->db->prepare("
                UPDATE contas_receber SET
                    codigo_solicitacao_boleto = :codigo_solicitacao,
                    nosso_numero_boleto = :nosso_numero,
                    linha_digitavel = :linha_digitavel,
                    codigo_barras = :codigo_barras,
                    boleto_pdf_url = :pdf_url,
                    pix_qrcode = :pix_qrcode,
                    pix_txid = :pix_txid,
                    boleto_status = :boleto_status,
                    boleto_emitido_em = NOW(),
                    updated_at = NOW()
                WHERE id = :id AND company_id = :company_id
            ");

            // Salvar PDF em base64 se disponível (será usado no frontend)
            $pdfUrl = !empty($boleto['pdf_base64']) ? 'data:application/pdf;base64,' . $boleto['pdf_base64'] : '';

            $stmtUpdate->execute([
                'codigo_solicitacao' => $boleto['codigo_solicitacao'] ?? '',
                'nosso_numero' => $boleto['nosso_numero'],
                'linha_digitavel' => $boleto['linha_digitavel'],
                'codigo_barras' => $boleto['codigo_barras'],
                'pdf_url' => $pdfUrl,
                'pix_qrcode' => $boleto['qrcode'],
                'pix_txid' => $boleto['tx_id'],
                'boleto_status' => $boleto['status'],
                'id' => $id,
                'company_id' => $companyId
            ]);

            // Adicionar pdf_base64 na resposta para o frontend
            if (!empty($boleto['pdf_base64'])) {
                $boleto['pdf_url'] = 'data:application/pdf;base64,' . $boleto['pdf_base64'];
            }

            // Verificar se os dados do boleto estão vazios (API retornou sem body)
            $dadosVazios = empty($boleto['nosso_numero']) &&
                empty($boleto['linha_digitavel']) &&
                empty($boleto['codigo_barras']);

            if ($dadosVazios && $boleto['status'] !== 'EMITIDO_PENDENTE') {
                // Marcar como pendente se os dados estão vazios
                $boleto['status'] = 'EMITIDO_PENDENTE';

                // Verificar se já não estava marcado como pendente antes (para não atualizar timestamp)
                if (empty($conta['boleto_status']) || $conta['boleto_status'] !== 'EMITIDO_PENDENTE') {
                    $stmtUpdate->execute([
                        'codigo_solicitacao' => '',
                        'nosso_numero' => '',
                        'linha_digitavel' => '',
                        'codigo_barras' => '',
                        'pdf_url' => '',
                        'pix_qrcode' => '',
                        'pix_txid' => '',
                        'boleto_status' => 'EMITIDO_PENDENTE',
                        'id' => $id,
                        'company_id' => $companyId
                    ]);

                    error_log("API retornou resposta vazia - marcando como EMITIDO_PENDENTE (primeira vez)");
                } else {
                    error_log("Boleto já estava marcado como EMITIDO_PENDENTE - mantendo timestamp original");
                }
            }

            $this->logActivity('boleto_inter', 'contas_receber', $id, $boleto);

            $this->db->commit();

            // Verificar se é um boleto pendente (criado mas sem dados)
            if (isset($boleto['status']) && $boleto['status'] === 'EMITIDO_PENDENTE') {
                $this->success('Boleto criado com sucesso no Banco Inter! Os dados estão sendo processados e estarão disponíveis em breve. Aguarde alguns minutos e clique em "Boleto Inter" novamente para consultar.', [
                    'boleto' => $boleto,
                    'pendente' => true
                ]);
            } else {
                $this->success('Boleto gerado com sucesso no Banco Inter!', [
                    'boleto' => $boleto
                ]);
            }

        } catch (Exception $e) {
            if ($this->db && $this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao gerar boleto Inter: " . $e->getMessage());
            error_log("Stack: " . $e->getTraceAsString());
            $this->error('Erro ao gerar boleto: ' . $e->getMessage());
        }
    }

    /**
     * Tentar gerar boleto automaticamente (chamado ao salvar conta a receber)
     */
    private function tentarGerarBoletoAutomatico(int $contaReceberId, int $contaBancariaId, int $companyId): void
    {
        // Verificar se a conta bancária é do Banco Inter
        $stmtBanco = $this->db->prepare("
            SELECT bank_code FROM contas_bancarias
            WHERE id = :id AND company_id = :company_id AND is_active = 1
        ");
        $stmtBanco->execute(['id' => $contaBancariaId, 'company_id' => $companyId]);
        $banco = $stmtBanco->fetch();

        if ($banco && $banco['bank_code'] === '077') {
            error_log("Conta bancária do Inter detectada - gerando boleto automaticamente para conta_receber #{$contaReceberId}");

            // Simular requisição POST para o método gerarBoletoInter
            $_POST['id'] = $contaReceberId;
            $this->gerarBoletoInter();
            unset($_POST['id']);
        }
    }

    /**
     * Gerar boletos em lote para contas do Banco Inter
     */
    public function gerarBoletosEmLote(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Buscar contas do Banco Inter
            $stmtBanco = $this->db->prepare("
                SELECT id FROM contas_bancarias
                WHERE company_id = :company_id
                  AND bank_code = '077'
                  AND is_active = 1
            ");
            $stmtBanco->execute(['company_id' => $companyId]);
            $contasInter = $stmtBanco->fetchAll();

            if (empty($contasInter)) {
                $this->error('Nenhuma conta do Banco Inter encontrada');
                return;
            }

            $contaBancariaIds = array_column($contasInter, 'id');
            $placeholders = str_repeat('?,', count($contaBancariaIds) - 1) . '?';

            // Buscar contas a receber pendentes do Inter (sem boleto emitido)
            $sql = "
                SELECT id, conta_bancaria_id
                FROM contas_receber
                WHERE company_id = ?
                  AND conta_bancaria_id IN ({$placeholders})
                  AND (nosso_numero_boleto IS NULL OR nosso_numero_boleto = '')
                  AND (boleto_status IS NULL OR boleto_status = '' OR boleto_status = 'EMITIDO_PENDENTE')
                ORDER BY due_date ASC
            ";

            $stmt = $this->db->prepare($sql);
            $params = array_merge([$companyId], $contaBancariaIds);
            $stmt->execute($params);
            $contasPendentes = $stmt->fetchAll();

            if (empty($contasPendentes)) {
                $this->success('Não há contas pendentes para gerar boletos', [
                    'total' => 0,
                    'processadas' => 0
                ]);
                return;
            }

            $total = count($contasPendentes);
            $sucesso = 0;
            $erros = 0;
            $pendentes = 0;
            $detalhes = [];

            foreach ($contasPendentes as $conta) {
                try {
                    // Simular requisição para gerarBoletoInter
                    $_POST['id'] = $conta['id'];

                    // Capturar resposta
                    ob_start();
                    $this->gerarBoletoInter();
                    $response = ob_get_clean();

                    $responseData = json_decode($response, true);

                    if ($responseData && $responseData['success']) {
                        if (isset($responseData['data']['pendente']) && $responseData['data']['pendente']) {
                            $pendentes++;
                            $detalhes[] = [
                                'id' => $conta['id'],
                                'status' => 'pendente',
                                'mensagem' => 'Boleto criado, aguardando dados'
                            ];
                        } else {
                            $sucesso++;
                            $detalhes[] = [
                                'id' => $conta['id'],
                                'status' => 'sucesso',
                                'mensagem' => 'Boleto gerado com sucesso'
                            ];
                        }
                    } else {
                        $erros++;
                        $detalhes[] = [
                            'id' => $conta['id'],
                            'status' => 'erro',
                            'mensagem' => $responseData['message'] ?? 'Erro desconhecido'
                        ];
                    }

                    unset($_POST['id']);

                } catch (Exception $e) {
                    $erros++;
                    $detalhes[] = [
                        'id' => $conta['id'],
                        'status' => 'erro',
                        'mensagem' => $e->getMessage()
                    ];
                    error_log("Erro ao processar conta #{$conta['id']}: " . $e->getMessage());
                }
            }

            $this->success("Processamento em lote concluído", [
                'total' => $total,
                'sucesso' => $sucesso,
                'pendentes' => $pendentes,
                'erros' => $erros,
                'detalhes' => $detalhes
            ]);

        } catch (Exception $e) {
            error_log("Erro ao gerar boletos em lote: " . $e->getMessage());
            $this->error('Erro ao processar boletos em lote: ' . $e->getMessage());
        }
    }

    /**
     * Envia boleto por email
     */
    public function enviarBoletoEmail(): void
    {
        try {
            $contaId = (int) $this->request->post('conta_id');
            $email = trim($this->request->post('email'));

            if (!$contaId || !$email) {
                $this->error('Dados inválidos');
                return;
            }

            // Validar email
            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $this->error('Email inválido');
                return;
            }

            $companyId = $this->getCompanyId();

            // Buscar dados da conta
            $stmt = $this->db->prepare("
                SELECT
                    cr.*,
                    p.name as pessoa_nome,
                    p.document as pessoa_documento,
                    cb.bank_name
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                LEFT JOIN contas_bancarias cb ON cr.conta_bancaria_id = cb.id
                WHERE cr.id = :id AND cr.company_id = :company_id
            ");
            $stmt->execute([
                'id' => $contaId,
                'company_id' => $companyId
            ]);
            $conta = $stmt->fetch();

            if (!$conta) {
                $this->error('Conta não encontrada');
                return;
            }

            // Verificar se tem boleto PDF
            if (empty($conta['boleto_pdf_url'])) {
                $this->error('Boleto ainda não foi gerado ou não tem PDF disponível');
                return;
            }

            // Extrair base64 do data URI (se necessário)
            $pdfBase64 = $conta['boleto_pdf_url'];
            if (strpos($pdfBase64, 'data:application/pdf;base64,') === 0) {
                $pdfBase64 = substr($pdfBase64, strlen('data:application/pdf;base64,'));
            }

            $pdfContent = base64_decode($pdfBase64);
            if ($pdfContent === false) {
                $this->error('Erro ao decodificar PDF');
                return;
            }

            // Salvar PDF temporário
            $tempFile = sys_get_temp_dir() . '/boleto_' . $contaId . '_' . time() . '.pdf';
            file_put_contents($tempFile, $pdfContent);

            // Preparar corpo do email
            $valorFormatado = 'R$ ' . number_format((float) $conta['amount'], 2, ',', '.');
            $vencimento = date('d/m/Y', strtotime($conta['due_date']));

            $body = "
                <html>
                <head>
                    <style>
                        body { font-family: Arial, sans-serif; color: #333; }
                        .header { background-color: #007bff; color: white; padding: 20px; text-align: center; }
                        .content { padding: 20px; }
                        .info { background-color: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0; }
                        .footer { text-align: center; color: #6c757d; font-size: 12px; margin-top: 30px; }
                    </style>
                </head>
                <body>
                    <div class='header'>
                        <h2>Boleto de Cobrança</h2>
                    </div>
                    <div class='content'>
                        <p>Prezado(a) <strong>{$conta['pessoa_nome']}</strong>,</p>
                        <p>Segue em anexo o boleto para pagamento:</p>
                        <div class='info'>
                            <p><strong>Valor:</strong> {$valorFormatado}</p>
                            <p><strong>Vencimento:</strong> {$vencimento}</p>
                            <p><strong>Nosso Número:</strong> {$conta['nosso_numero_boleto']}</p>
                            <p><strong>Linha Digitável:</strong> {$conta['linha_digitavel']}</p>
                        </div>
                        <p>Você pode pagar este boleto:</p>
                        <ul>
                            <li>Em qualquer banco, casa lotérica ou agência dos Correios</li>
                            <li>Através do internet banking</li>
                            <li>Via PIX usando o QR Code no boleto</li>
                        </ul>
                        <p>O boleto está em anexo (arquivo PDF).</p>
                    </div>
                    <div class='footer'>
                        <p>Este é um e-mail automático, por favor não responda.</p>
                    </div>
                </body>
                </html>
            ";

            // Enviar email
            $result = \App\Helpers\MailHelper::sendWithAttachment(
                $email,
                'Boleto de Cobrança - Vencimento: ' . $vencimento,
                $body,
                $tempFile,
                'boleto_' . $conta['nosso_numero_boleto'] . '.pdf'
            );

            // Remover arquivo temporário
            if (file_exists($tempFile)) {
                unlink($tempFile);
            }

            if ($result['success']) {
                // Registrar envio no log
                error_log("Boleto #{$contaId} enviado por email para: {$email}");

                $this->success('Email enviado com sucesso!', [
                    'email' => $email
                ]);
            } else {
                throw new \Exception($result['message']);
            }

        } catch (\Exception $e) {
            error_log("Erro ao enviar boleto por email: " . $e->getMessage());
            $this->error('Erro ao enviar email: ' . $e->getMessage());
        }
    }

    /**
     * Upload de anexo para conta a receber
     */
    public function uploadAnexo(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $contaId = (int) $this->request->post('conta_id');
            $descricao = $this->request->post('descricao', '');

            if (empty($contaId)) {
                $this->error('ID da conta não informado');
                return;
            }

            // Verificar se a conta existe
            $stmt = $this->db->prepare("SELECT id FROM contas_receber WHERE id = :id AND company_id = :company_id");
            $stmt->execute(['id' => $contaId, 'company_id' => $companyId]);
            if (!$stmt->fetch()) {
                $this->error('Conta não encontrada');
                return;
            }

            if (!isset($_FILES['arquivo']) || $_FILES['arquivo']['error'] !== UPLOAD_ERR_OK) {
                $this->error('Nenhum arquivo enviado ou erro no upload');
                return;
            }

            $arquivo = $_FILES['arquivo'];
            $extensao = strtolower(pathinfo($arquivo['name'], PATHINFO_EXTENSION));

            // Extensões permitidas
            $extensoesPermitidas = ['jpg', 'jpeg', 'png', 'pdf'];
            if (!in_array($extensao, $extensoesPermitidas)) {
                $this->error('Formato de arquivo não permitido. Permitidos: JPG, JPEG, PNG e PDF');
                return;
            }

            // Tamanho máximo: 10MB
            $tamanhoMax = 10 * 1024 * 1024;
            if ($arquivo['size'] > $tamanhoMax) {
                $this->error('Arquivo muito grande. Tamanho máximo: 10MB');
                return;
            }

            // Criar diretório se não existir
            $uploadDir = \ROOT_PATH . '/storage/uploads/anexos/entradas/';
            if (!is_dir($uploadDir)) {
                mkdir($uploadDir, 0755, true);
            }

            // Nome único para o arquivo
            $nomeArquivo = uniqid() . '_' . time() . '.' . $extensao;
            $caminhoCompleto = $uploadDir . $nomeArquivo;

            // Mover arquivo
            if (!move_uploaded_file($arquivo['tmp_name'], $caminhoCompleto)) {
                $this->error('Erro ao salvar arquivo');
                return;
            }

            // Verificar se a tabela de anexos existe
            $stmtCheck = $this->db->query("SHOW TABLES LIKE 'anexos'");
            if (!$stmtCheck->fetch()) {
                // Criar tabela se não existir
                $sql = file_get_contents(\ROOT_PATH . '/database/migration_create_anexos_table.sql');
                $this->db->exec($sql);
            }

            // Salvar no banco
            $caminhoRelativo = 'storage/uploads/anexos/entradas/' . $nomeArquivo;
            $userId = $this->session->get('user_id');

            $stmt = $this->db->prepare("
                INSERT INTO anexos (
                    company_id, tipo, conta_id, nome_original, nome_arquivo,
                    caminho, tamanho, tipo_mime, descricao, created_by
                ) VALUES (
                    :company_id, 'entrada', :conta_id, :nome_original, :nome_arquivo,
                    :caminho, :tamanho, :tipo_mime, :descricao, :created_by
                )
            ");

            $stmt->execute([
                'company_id' => $companyId,
                'conta_id' => $contaId,
                'nome_original' => $arquivo['name'],
                'nome_arquivo' => $nomeArquivo,
                'caminho' => $caminhoRelativo,
                'tamanho' => $arquivo['size'],
                'tipo_mime' => $arquivo['type'],
                'descricao' => $descricao,
                'created_by' => $userId
            ]);

            $anexoId = $this->db->lastInsertId();

            $this->success('Anexo enviado com sucesso', [
                'anexo_id' => $anexoId,
                'nome' => $arquivo['name']
            ]);

        } catch (\Exception $e) {
            error_log("Erro ao fazer upload de anexo: " . $e->getMessage());
            $this->error('Erro ao fazer upload: ' . $e->getMessage());
        }
    }

    /**
     * Listar anexos de uma conta
     */
    public function listarAnexos(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $contaId = (int) $this->request->get('conta_id');

            if (empty($contaId)) {
                $this->error('ID da conta não informado');
                return;
            }

            // Verificar se a tabela existe
            $stmtCheck = $this->db->query("SHOW TABLES LIKE 'anexos'");
            if (!$stmtCheck->fetch()) {
                $this->success('Anexos carregados', ['anexos' => []]);
                return;
            }

            $stmt = $this->db->prepare("
                SELECT a.*, u.name as usuario_nome
                FROM anexos a
                LEFT JOIN users u ON a.created_by = u.id
                WHERE a.company_id = :company_id
                AND a.tipo = 'entrada'
                AND a.conta_id = :conta_id
                ORDER BY a.created_at DESC
            ");

            $stmt->execute(['company_id' => $companyId, 'conta_id' => $contaId]);
            $anexos = $stmt->fetchAll();

            $this->success('Anexos carregados', ['anexos' => $anexos]);

        } catch (\Exception $e) {
            error_log("Erro ao listar anexos: " . $e->getMessage());
            $this->error('Erro ao listar anexos');
        }
    }

    /**
     * Deletar anexo
     */
    public function deletarAnexo(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $anexoId = (int) $this->request->post('anexo_id');

            if (empty($anexoId)) {
                $this->error('ID do anexo não informado');
                return;
            }

            // Buscar anexo
            $stmt = $this->db->prepare("
                SELECT * FROM anexos
                WHERE id = :id AND company_id = :company_id AND tipo = 'entrada'
            ");
            $stmt->execute(['id' => $anexoId, 'company_id' => $companyId]);
            $anexo = $stmt->fetch();

            if (!$anexo) {
                $this->error('Anexo não encontrado');
                return;
            }

            // Deletar arquivo físico
            $caminhoCompleto = \ROOT_PATH . '/' . $anexo['caminho'];
            if (file_exists($caminhoCompleto)) {
                unlink($caminhoCompleto);
            }

            // Deletar do banco
            $stmt = $this->db->prepare("DELETE FROM anexos WHERE id = :id AND company_id = :company_id");
            $stmt->execute(['id' => $anexoId, 'company_id' => $companyId]);

            $this->success('Anexo excluído com sucesso');

        } catch (\Exception $e) {
            error_log("Erro ao deletar anexo: " . $e->getMessage());
            $this->error('Erro ao deletar anexo');
        }
    }

    /**
     * Download de anexo
     */
    public function downloadAnexo(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $anexoId = (int) $this->request->get('id');

            $stmt = $this->db->prepare("
                SELECT * FROM anexos
                WHERE id = :id AND company_id = :company_id AND tipo = 'entrada'
            ");
            $stmt->execute(['id' => $anexoId, 'company_id' => $companyId]);
            $anexo = $stmt->fetch();

            if (!$anexo) {
                $this->response->notFound('Anexo não encontrado');
                return;
            }

            $caminhoCompleto = \ROOT_PATH . '/' . $anexo['caminho'];
            if (!file_exists($caminhoCompleto)) {
                $this->response->notFound('Arquivo não encontrado');
                return;
            }

            header('Content-Type: ' . $anexo['tipo_mime']);
            header('Content-Disposition: attachment; filename="' . $anexo['nome_original'] . '"');
            header('Content-Length: ' . filesize($caminhoCompleto));
            readfile($caminhoCompleto);
            exit;

        } catch (\Exception $e) {
            error_log("Erro ao fazer download de anexo: " . $e->getMessage());
            $this->error('Erro ao fazer download');
        }
    }

    /**
     * Gerar boleto híbrido (Pix + Boleto) via Shipay
     */
    public function gerarBoletoShipay(): void
    {
        // Inicializar variáveis no início para evitar erros de variável não definida
        $chargeId = null;
        $linhaDigitavel = null;
        $codigoBarras = null;
        $qrCode = null;
        $qrCodeText = null;
        $pdfUrl = null;
        $status = 'pending';
        $tipo = 'pix';
        $response = null;
        $erroAoSalvar = false;
        $mensagemErroSalvar = null;

        try {
            // Logs iniciais - usar error_log e também file_put_contents para garantir que apareçam
            $logMsg = "[EntradasController] ===== INÍCIO gerarBoletoShipay =====";
            error_log($logMsg);
            file_put_contents('php://stderr', $logMsg . PHP_EOL);

            error_log("[EntradasController] POST data: " . json_encode($_POST));
            error_log("[EntradasController] Request method: " . $_SERVER['REQUEST_METHOD']);

            // Garantir que é uma requisição POST
            if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
                error_log("[EntradasController] ERRO: Método não permitido");
                $this->error('Método não permitido', [], 405);
                return;
            }

            $id = (int) $this->request->post('id');
            $tipo = $this->request->post('tipo', 'pix'); // 'pix' ou 'boleto'
            $companyId = $this->getCompanyId();

            error_log("[EntradasController] Dados recebidos - ID: {$id}, Tipo: {$tipo}, Company ID: {$companyId}");

            if (empty($id) || $id <= 0) {
                error_log("[EntradasController] ERRO: ID inválido ou não fornecido. ID recebido: " . var_export($this->request->post('id'), true));
                $this->error('ID da conta a receber é obrigatório');
                return;
            }

            if (empty($companyId)) {
                error_log("[EntradasController] ERRO: Company ID não encontrado");
                $this->error('Sessão expirada. Faça login novamente.', [], 401);
                return;
            }

            // Buscar conta a receber com dados do cliente
            error_log("[EntradasController] Buscando conta #{$id} para company_id {$companyId}");
            $stmt = $this->db->prepare("
                SELECT cr.*, p.*,
                       cr.id as conta_id,
                       cr.description as conta_description,
                       cr.notes as conta_notes,
                       cr.amount as conta_amount
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                WHERE cr.id = :id AND cr.company_id = :company_id
            ");
            $paramsConta = ['id' => $id, 'company_id' => $companyId];
            error_log("[EntradasController] Parâmetros da query conta: " . json_encode($paramsConta));
            $stmt->execute($paramsConta);
            $conta = $stmt->fetch();

            if (!$conta) {
                error_log("[EntradasController] ERRO: Conta #{$id} não encontrada para company_id {$companyId}");
                $this->error('Conta a receber não encontrada');
                return;
            }

            error_log("[EntradasController] Conta encontrada - ID: {$conta['conta_id']}, Descrição: " . ($conta['conta_description'] ?? 'N/A'));

            // Verificar se já tem boleto Shipay emitido
            if (!empty($conta['shipay_charge_id']) && !empty($conta['shipay_linha_digitavel'])) {
                // Extrair código de barras do payload salvo se disponível
                $codigoBarras = $conta['shipay_codigo_barras'] ?? null;
                if (!$codigoBarras && !empty($conta['shipay_payload'])) {
                    $payloadSalvo = json_decode($conta['shipay_payload'], true);
                    $codigoBarras = $payloadSalvo['codigo_barras'] ?? $payloadSalvo['barcode'] ?? null;
                }

                // Retornar dados existentes
                $this->success('Cobrança Shipay já foi emitida', [
                    'boleto' => [
                        'charge_id' => $conta['shipay_charge_id'],
                        'status' => $conta['shipay_status'] ?? 'pending',
                        'linha_digitavel' => $conta['shipay_linha_digitavel'],
                        'codigo_barras' => $codigoBarras,
                        'qrcode' => $conta['shipay_qr_code'],
                        'pdf_url' => $conta['shipay_pdf_url'],
                    ],
                    'existente' => true
                ]);
                return;
            }

            // Buscar empresa com configuração Shipay
            // Usar id = company_id (empresa atual) ou company_id (se houver campo company_id na tabela)
            error_log("[EntradasController] Buscando empresa com company_id {$companyId}");
            $stmtEmpresa = $this->db->prepare("
                SELECT
                    id, razao_social, nome_fantasia, cnpj, email, telefone,
                    endereco, numero, complemento, bairro, cidade, uf, cep,
                    shipay_enabled, shipay_environment, shipay_access_key, shipay_secret_key,
                    shipay_client_id, shipay_store_id, shipay_cashier_id
                FROM empresas
                WHERE (id = :company_id OR company_id = :company_id2) AND shipay_enabled = 1
                LIMIT 1
            ");
            $paramsEmpresa = ['company_id' => $companyId, 'company_id2' => $companyId];
            error_log("[EntradasController] Parâmetros da query empresa: " . json_encode($paramsEmpresa));
            $stmtEmpresa->execute($paramsEmpresa);
            $empresa = $stmtEmpresa->fetch();

            if (empty($empresa)) {
                error_log("[EntradasController] Nenhuma empresa encontrada com company_id = {$companyId} e shipay_enabled = 1");
                $this->error('Nenhuma empresa com integração Shipay ativada. Configure em Empresas > Integrações.');
                return;
            }

            error_log("[EntradasController] Empresa encontrada - ID: {$empresa['id']}, Razão Social: {$empresa['razao_social']}, Ambiente: " . ($empresa['shipay_environment'] ?? 'N/A'));

            if (empty($empresa['shipay_access_key']) || empty($empresa['shipay_secret_key']) || empty($empresa['shipay_client_id'])) {
                error_log("[EntradasController] Credenciais Shipay incompletas - Access Key: " . (!empty($empresa['shipay_access_key']) ? 'preenchido' : 'vazio') . ", Secret Key: " . (!empty($empresa['shipay_secret_key']) ? 'preenchido' : 'vazio') . ", Client ID: " . (!empty($empresa['shipay_client_id']) ? 'preenchido' : 'vazio'));
                $this->error('Credenciais da Shipay não configuradas. Verifique Access Key, Secret Key e Client ID.');
                return;
            }

            // Validar dados do cliente
            $documento = preg_replace('/\D/', '', $conta['document'] ?? '');
            if (empty($documento)) {
                error_log("[EntradasController] ERRO: Cliente não possui CPF/CNPJ. Conta ID: {$id}, Customer ID: " . ($conta['customer_id'] ?? 'N/A'));
                $this->error('Cliente não possui CPF/CNPJ cadastrado. Atualize o cadastro do cliente.');
                return;
            }

            // Validar valor da conta
            $valor = (float) ($conta['conta_amount'] ?? $conta['amount'] ?? 0);
            if ($valor <= 0) {
                error_log("[EntradasController] ERRO: Valor da conta inválido. Conta ID: {$id}, Valor: {$valor}");
                $this->error('Valor da conta deve ser maior que zero.');
                return;
            }

            // Validar data de vencimento
            $vencimento = $conta['due_date'] ?? null;
            if (empty($vencimento)) {
                error_log("[EntradasController] ERRO: Data de vencimento não informada. Conta ID: {$id}");
                $this->error('Data de vencimento é obrigatória.');
                return;
            }

            // Preparar configuração Shipay
            $paymentConfig = require \ROOT_PATH . '/config/payment.php';
            $ambiente = $empresa['shipay_environment'] ?? 'sandbox';
            $shipayConfig = [
                'access_key' => $empresa['shipay_access_key'],
                'secret_key' => $empresa['shipay_secret_key'],
                'client_id' => $empresa['shipay_client_id'],
                'environment' => $ambiente,
                'base_url' => $paymentConfig['shipay']['base_url'] ?? [],
            ];

            // Log para debug (sem expor secret_key completo)
            $secretKeyMasked = !empty($empresa['shipay_secret_key']) ? substr($empresa['shipay_secret_key'], 0, 10) . '...' : 'vazio';
            error_log("[EntradasController] Gerando cobrança Shipay - Ambiente: {$ambiente}, Access Key: {$empresa['shipay_access_key']}, Secret Key: {$secretKeyMasked}, Client ID: {$empresa['shipay_client_id']}");

            // Criar cliente Shipay
            $shipay = new ShipayClient($shipayConfig);

            // Preparar payload conforme documentação Shipay
            $telefone = preg_replace('/\D/', '', $conta['phone'] ?? $conta['mobile'] ?? $conta['telefone'] ?? '');

            $payload = [
                'valor' => (float) $conta['conta_amount'],
                'vencimento' => $conta['due_date'],
                'descricao' => $conta['conta_description'] ?? 'Conta a receber #' . $id,
                'pagador' => [
                    'nome' => $conta['name'] ?? $conta['nome'] ?? '',
                    'documento' => $documento,
                    'email' => $conta['email'] ?? '',
                    'telefone' => $telefone,
                    'endereco' => [
                        'logradouro' => $conta['address'] ?? $conta['endereco'] ?? '',
                        'numero' => $conta['numero'] ?? $conta['address_number'] ?? '',
                        'complemento' => $conta['complemento'] ?? $conta['address_complement'] ?? '',
                        'bairro' => $conta['bairro'] ?? $conta['neighborhood'] ?? '',
                        'cidade' => $conta['city'] ?? $conta['cidade'] ?? '',
                        'uf' => $conta['state'] ?? $conta['uf'] ?? '',
                        'cep' => preg_replace('/\D/', '', $conta['zip_code'] ?? $conta['cep'] ?? ''),
                    ],
                ],
            ];

            // Adicionar store_id e cashier_id se configurados
            if (!empty($empresa['shipay_store_id'])) {
                $payload['store_id'] = $empresa['shipay_store_id'];
            }
            if (!empty($empresa['shipay_cashier_id'])) {
                $payload['cashier_id'] = $empresa['shipay_cashier_id'];
            }

            // Definir wallet baseado no tipo de cobrança
            $ambiente = $empresa['shipay_environment'] ?? 'sandbox';

            // Para BOLETO: usar endpoint /v2/order-due-date (sem fallback automático)
            // Para PIX: usar endpoint /order com wallet apropriada
            if ($tipo === 'boleto') {
                // Boleto híbrido usa endpoint próprio, não precisa de wallet aqui
                error_log("[EntradasController] Gerando BOLETO HÍBRIDO Shipay - Ambiente: {$ambiente}");
            } else {
                // PIX usa endpoint /order
                if ($ambiente === 'sandbox') {
                    $payload['wallet'] = 'shipay-pagador';
                } else {
                    $payload['wallet'] = 'pix';
                }
                error_log("[EntradasController] Gerando PIX Shipay - Wallet: {$payload['wallet']}, Ambiente: {$ambiente}");
            }

            // Inicializar variáveis antes do try/catch para garantir que estejam disponíveis no catch
            $chargeId = null;
            $linhaDigitavel = null;
            $codigoBarras = null;
            $qrCode = null;
            $qrCodeText = null;
            $pdfUrl = null;
            $status = 'pending';
            $response = null;

            // Gerar cobrança na Shipay (passa o tipo para usar endpoint correto)
            try {
                $response = $shipay->createHybridBoleto($payload, $tipo);
                error_log("[EntradasController] Resposta Shipay recebida: " . json_encode($response, JSON_UNESCAPED_UNICODE));
            } catch (\Exception $e) {
                error_log("[EntradasController] ERRO ao chamar Shipay: " . $e->getMessage());
                error_log("[EntradasController] Stack trace: " . $e->getTraceAsString());
                $this->error('Erro ao gerar cobrança na Shipay: ' . $e->getMessage());
                return;
            }

            // Verificar se a resposta contém erro
            if (isset($response['error']) || isset($response['erro'])) {
                $errorMsg = $response['error'] ?? $response['erro'] ?? 'Erro desconhecido da Shipay';
                error_log("[EntradasController] Shipay retornou erro: " . $errorMsg);
                $this->error('Erro na Shipay: ' . $errorMsg);
                return;
            }

            // Extrair dados da resposta (order_id para /order, id/charge_id para outros endpoints)
            $chargeId = $response['order_id'] ?? $response['id'] ?? $response['charge_id'] ?? null;

            // Log da resposta para debug
            $ambienteLog = $ambiente ?? $environment ?? 'N/A';
            error_log("[EntradasController] Resposta Shipay - Tipo: {$tipo}, Ambiente: {$ambienteLog}, Charge ID: {$chargeId}, Status: " . ($response['status'] ?? 'N/A'));
            $linhaDigitavel = $response['linha_digitavel'] ?? $response['digitable_line'] ?? $response['barcode_digitable_line'] ?? null;
            $codigoBarras = $response['codigo_barras'] ?? $response['barcode'] ?? $response['bar_code'] ?? null;
            // QR Code pode ser imagem base64 ou texto
            $qrCode = $response['qr_code'] ?? $response['pix_copia_cola'] ?? $response['pix_qr_code'] ?? null;
            $qrCodeText = $response['qr_code_text'] ?? $response['deep_link'] ?? $response['pix_copy_paste'] ?? null;
            $pdfUrl = $response['pdf_url'] ?? $response['pdf'] ?? $response['boleto_url'] ?? $response['slip_url'] ?? null;
            $status = $response['status'] ?? 'pending';

            if (empty($chargeId)) {
                error_log("❌ Resposta Shipay sem order_id/charge_id: " . json_encode($response));
                $this->error('Shipay não retornou ID da cobrança. Verifique os logs.');
                return;
            }

            // ✅ IMPORTANTE: Se chegou aqui, a Shipay gerou o boleto com sucesso!
            // Mesmo que haja erro ao salvar no banco, devemos retornar os dados do boleto
            error_log("[EntradasController] ✅ Boleto Shipay gerado com sucesso! Charge ID: {$chargeId}");

            // Registrar em variáveis globais para proteção em caso de erro inesperado
            $GLOBALS['__shipay_charge_id'] = $chargeId;
            $GLOBALS['__shipay_status'] = $status;
            $GLOBALS['__shipay_linha_digitavel'] = $linhaDigitavel;
            $GLOBALS['__shipay_codigo_barras'] = $codigoBarras;
            $GLOBALS['__shipay_qr_code'] = $qrCode;
            $GLOBALS['__shipay_qr_code_text'] = $qrCodeText;
            $GLOBALS['__shipay_pdf_url'] = $pdfUrl;
            $GLOBALS['__shipay_tipo'] = $tipo;

            // Salvar dados do boleto no banco (com fallback se falhar)
            // Se houver qualquer erro ao salvar, retornar sucesso com os dados do boleto
            error_log("[EntradasController] ===== INICIANDO SALVAMENTO NO BANCO =====");
            error_log("[EntradasController] Charge ID: " . ($chargeId ?? 'NULL'));
            $erroAoSalvar = false;
            $mensagemErroSalvar = null;

            try {
                // Atualizar conta com dados do boleto Shipay
                // Envolver toda a seção de salvamento em try/catch para garantir que o boleto seja retornado mesmo se houver erro
                try {
                    $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber LIKE 'shipay_%'");
                    $columns = $stmtCheck->fetchAll();
                    $columnNames = array_column($columns, 'Field');
                    error_log("[EntradasController] Campos Shipay encontrados na tabela: " . json_encode($columnNames));
                } catch (\Exception $e) {
                    error_log("[EntradasController] ERRO ao verificar colunas Shipay: " . $e->getMessage());
                    // Se o boleto foi gerado, retornar sucesso com aviso
                    if (!empty($chargeId)) {
                        error_log("[EntradasController] Boleto gerado mas erro ao verificar colunas. Retornando sucesso com aviso.");
                        $this->success("Cobrança Shipay gerada com sucesso!", [
                            'boleto' => [
                                'charge_id' => $chargeId,
                                'status' => $status ?? 'pending',
                                'linha_digitavel' => $linhaDigitavel ?? null,
                                'codigo_barras' => $codigoBarras ?? null,
                                'qrcode' => $qrCode ?? null,
                                'qrcode_text' => $qrCodeText ?? null,
                                'pdf_url' => $pdfUrl ?? null,
                            ],
                            'tipo' => $tipo,
                            'existente' => false,
                            'aviso' => 'Boleto gerado, mas não foi possível verificar campos da tabela para salvar.'
                        ]);
                        return;
                    }
                    // Continuar mesmo se não conseguir verificar colunas, tentar salvar campos básicos
                    $columnNames = [];
                }

                // Construir UPDATE de forma simples e direta
                $sets = ['updated_at = NOW()'];
                $params = ['id' => $id, 'company_id' => $companyId];

                // Adicionar apenas campos que existem na tabela
                if (in_array('shipay_charge_id', $columnNames) && !empty($chargeId)) {
                    $sets[] = 'shipay_charge_id = :charge_id';
                    $params['charge_id'] = $chargeId;
                }
                if (in_array('shipay_status', $columnNames) && !empty($status)) {
                    $sets[] = 'shipay_status = :status';
                    $params['status'] = $status;
                }
                if (in_array('shipay_tipo', $columnNames)) {
                    $sets[] = 'shipay_tipo = :tipo_shipay';
                    $params['tipo_shipay'] = $tipo === 'boleto' ? 'boleto' : 'pix';
                }
                if (in_array('shipay_linha_digitavel', $columnNames) && !empty($linhaDigitavel)) {
                    $sets[] = 'shipay_linha_digitavel = :linha_digitavel';
                    $params['linha_digitavel'] = $linhaDigitavel;
                }
                if (in_array('shipay_qr_code', $columnNames) && !empty($qrCode)) {
                    $qrCodeTruncado = strlen($qrCode) > 10000 ? substr($qrCode, 0, 10000) : $qrCode;
                    $sets[] = 'shipay_qr_code = :qr_code';
                    $params['qr_code'] = $qrCodeTruncado;
                }
                // Adicionar shipay_qr_code_text se existir
                if (in_array('shipay_qr_code_text', $columnNames) && !empty($qrCodeText)) {
                    $qrCodeTextTruncado = strlen($qrCodeText) > 10000 ? substr($qrCodeText, 0, 10000) : $qrCodeText;
                    $sets[] = 'shipay_qr_code_text = :qr_code_text';
                    $params['qr_code_text'] = $qrCodeTextTruncado;
                }
                if (in_array('shipay_pdf_url', $columnNames) && !empty($pdfUrl)) {
                    $sets[] = 'shipay_pdf_url = :pdf_url';
                    $params['pdf_url'] = $pdfUrl;
                }
                if (in_array('shipay_codigo_barras', $columnNames) && !empty($codigoBarras)) {
                    $sets[] = 'shipay_codigo_barras = :codigo_barras';
                    $params['codigo_barras'] = $codigoBarras;
                }
                if (in_array('shipay_payload', $columnNames)) {
                    $payloadJson = json_encode($response, JSON_UNESCAPED_UNICODE);
                    if (strlen($payloadJson) > 50000) {
                        $payloadJson = json_encode([
                            'order_id' => $response['order_id'] ?? $response['id'] ?? $response['charge_id'] ?? null,
                            'status' => $response['status'] ?? 'pending',
                            'linha_digitavel' => $linhaDigitavel,
                            'codigo_barras' => $codigoBarras,
                            'pdf_url' => $pdfUrl
                        ], JSON_UNESCAPED_UNICODE);
                    }
                    $sets[] = 'shipay_payload = :payload';
                    $params['payload'] = $payloadJson;
                }

                // Se não há campos Shipay, apenas retornar sucesso
                if (count($sets) <= 1) {
                    error_log("[EntradasController] Nenhum campo Shipay disponível. Retornando sucesso sem salvar.");
                    $this->success("Cobrança Shipay gerada com sucesso!", [
                        'boleto' => [
                            'charge_id' => $chargeId,
                            'status' => $status,
                            'linha_digitavel' => $linhaDigitavel,
                            'codigo_barras' => $codigoBarras,
                            'qrcode' => $qrCode,
                            'qrcode_text' => $qrCodeText,
                            'pdf_url' => $pdfUrl,
                        ],
                        'tipo' => $tipo,
                        'existente' => false,
                        'aviso' => 'Campos Shipay não disponíveis na tabela. Boleto gerado mas dados não foram salvos.'
                    ]);
                    return;
                }

                // Executar UPDATE de forma simples
                $sql = "UPDATE contas_receber SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";

                // Validar que todos os parâmetros do SQL estão no array
                preg_match_all('/:(\w+)/', $sql, $matches);
                $parametrosNoSQL = array_unique($matches[1] ?? []);
                $parametrosNoArray = array_keys($params);

                $parametrosFaltando = array_diff($parametrosNoSQL, $parametrosNoArray);
                if (!empty($parametrosFaltando)) {
                    error_log("[EntradasController] ❌ ERRO: Parâmetros no SQL mas não no array: " . json_encode($parametrosFaltando));
                    error_log("[EntradasController] SQL: {$sql}");
                    error_log("[EntradasController] Parâmetros no SQL: " . json_encode($parametrosNoSQL));
                    error_log("[EntradasController] Parâmetros no array: " . json_encode($parametrosNoArray));
                    throw new \PDOException("Parâmetros SQL inconsistentes: " . implode(', ', $parametrosFaltando));
                }

                // Filtrar array para conter apenas os parâmetros que estão no SQL
                $paramsFiltrado = [];
                foreach ($parametrosNoSQL as $param) {
                    if (isset($params[$param])) {
                        $paramsFiltrado[$param] = $params[$param];
                    } else {
                        error_log("[EntradasController] ⚠️ AVISO: Parâmetro '{$param}' está no SQL mas não está definido no array!");
                    }
                }

                // Verificar novamente se todos os parâmetros estão presentes
                $parametrosFaltandoFinal = array_diff($parametrosNoSQL, array_keys($paramsFiltrado));
                if (!empty($parametrosFaltandoFinal)) {
                    error_log("[EntradasController] ❌ ERRO CRÍTICO: Parâmetros ainda faltando após filtro: " . json_encode($parametrosFaltandoFinal));
                    error_log("[EntradasController] SQL completo: {$sql}");
                    error_log("[EntradasController] Parâmetros no SQL: " . json_encode($parametrosNoSQL));
                    error_log("[EntradasController] Parâmetros filtrados: " . json_encode(array_keys($paramsFiltrado)));
                    error_log("[EntradasController] Parâmetros originais: " . json_encode(array_keys($params)));
                    throw new \PDOException("Parâmetros SQL faltando após filtro: " . implode(', ', $parametrosFaltandoFinal));
                }

                error_log("[EntradasController] Executando UPDATE: {$sql}");
                error_log("[EntradasController] Parâmetros validados (" . count($paramsFiltrado) . "): " . json_encode(array_keys($paramsFiltrado)));
                error_log("[EntradasController] Valores dos parâmetros: " . json_encode($paramsFiltrado, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));

                try {
                    $stmtUpdate = $this->db->prepare($sql);
                    $resultado = $stmtUpdate->execute($paramsFiltrado);
                } catch (\PDOException $e) {
                    error_log("[EntradasController] ❌ ERRO PDO ao executar: " . $e->getMessage());
                    error_log("[EntradasController] SQL: {$sql}");
                    error_log("[EntradasController] Parâmetros: " . json_encode($paramsFiltrado, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR));
                    error_log("[EntradasController] Error Info: " . json_encode($stmtUpdate->errorInfo() ?? []));
                    throw $e;
                }

                if (!$resultado) {
                    $errorInfo = $stmtUpdate->errorInfo();
                    error_log("[EntradasController] ❌ ERRO ao executar UPDATE: " . json_encode($errorInfo));
                    throw new \PDOException("Erro ao executar UPDATE: " . ($errorInfo[2] ?? 'Erro desconhecido'));
                }

                error_log("[EntradasController] ✅ UPDATE executado com sucesso. Linhas afetadas: " . $stmtUpdate->rowCount());
            } catch (\PDOException $e) {
                $erroAoSalvar = true;
                $mensagemErroSalvar = $e->getMessage();
                error_log("[EntradasController] ❌ ERRO PDO ao salvar: " . $e->getMessage());
                error_log("[EntradasController] Error Info: " . json_encode($e->errorInfo ?? []));
            } catch (\Exception $e) {
                $erroAoSalvar = true;
                $mensagemErroSalvar = $e->getMessage();
                error_log("[EntradasController] ❌ Erro geral ao salvar: " . $e->getMessage());
            }

            // Sempre retornar sucesso com os dados do boleto, mesmo se houve erro ao salvar
            $tipoLabel = $tipo === 'boleto' ? 'Boleto Híbrido' : 'PIX';
            $mensagemSucesso = "{$tipoLabel} Shipay gerado com sucesso!";

            if ($erroAoSalvar) {
                $mensagemSucesso .= " (Houve um erro ao salvar no banco, mas o boleto foi gerado)";
                error_log("[EntradasController] Retornando boleto mesmo com erro ao salvar: {$mensagemErroSalvar}");
            }

            // Limpar variáveis globais antes de retornar sucesso
            unset(
                $GLOBALS['__shipay_charge_id'],
                $GLOBALS['__shipay_status'],
                $GLOBALS['__shipay_linha_digitavel'],
                $GLOBALS['__shipay_codigo_barras'],
                $GLOBALS['__shipay_qr_code'],
                $GLOBALS['__shipay_qr_code_text'],
                $GLOBALS['__shipay_pdf_url'],
                $GLOBALS['__shipay_tipo']
            );

            $this->success($mensagemSucesso, [
                'boleto' => [
                    'charge_id' => $chargeId,
                    'status' => $status ?? 'pending',
                    'linha_digitavel' => $linhaDigitavel ?? null,
                    'codigo_barras' => $codigoBarras ?? null,
                    'qrcode' => $qrCode ?? null,
                    'qrcode_text' => $qrCodeText ?? null,
                    'pdf_url' => $pdfUrl ?? null,
                ],
                'tipo' => $tipo,
                'existente' => false,
                'aviso' => $erroAoSalvar ? ('Erro ao salvar no banco: ' . $mensagemErroSalvar) : null
            ]);

        } catch (\PDOException $e) {
            // Se chegou aqui, o erro ocorreu ANTES de gerar o boleto ou durante a geração
            // Verificar se o boleto foi gerado mesmo assim
            $chargeIdCheck = $chargeId ?? $GLOBALS['__shipay_charge_id'] ?? null;

            if (!empty($chargeIdCheck)) {
                // Boleto foi gerado, retornar sucesso
                $chargeId = $chargeIdCheck;
                $status = $status ?? $GLOBALS['__shipay_status'] ?? 'pending';
                $linhaDigitavel = $linhaDigitavel ?? $GLOBALS['__shipay_linha_digitavel'] ?? null;
                $codigoBarras = $codigoBarras ?? $GLOBALS['__shipay_codigo_barras'] ?? null;
                $qrCode = $qrCode ?? $GLOBALS['__shipay_qr_code'] ?? null;
                $qrCodeText = $qrCodeText ?? $GLOBALS['__shipay_qr_code_text'] ?? null;
                $pdfUrl = $pdfUrl ?? $GLOBALS['__shipay_pdf_url'] ?? null;
                $tipo = $tipo ?? $GLOBALS['__shipay_tipo'] ?? 'pix';

                $this->success("Cobrança Shipay gerada com sucesso!", [
                    'boleto' => [
                        'charge_id' => $chargeId,
                        'status' => $status,
                        'linha_digitavel' => $linhaDigitavel,
                        'codigo_barras' => $codigoBarras,
                        'qrcode' => $qrCode,
                        'qrcode_text' => $qrCodeText,
                        'pdf_url' => $pdfUrl,
                    ],
                    'tipo' => $tipo,
                    'existente' => false,
                    'aviso' => 'Boleto gerado, mas houve erro: ' . $e->getMessage()
                ]);
                return;
            }

            // Se não tem boleto, é erro real
            error_log("[EntradasController] ❌ ERRO PDO (sem boleto gerado): " . $e->getMessage());
            $this->error('Erro ao gerar boleto Shipay: ' . $e->getMessage());
        } catch (\Exception $e) {
            // Verificar se o boleto foi gerado antes do erro
            $chargeIdCheck = $chargeId ?? $GLOBALS['__shipay_charge_id'] ?? null;

            if (!empty($chargeIdCheck)) {
                $chargeId = $chargeIdCheck;
                $status = $status ?? $GLOBALS['__shipay_status'] ?? 'pending';
                $linhaDigitavel = $linhaDigitavel ?? $GLOBALS['__shipay_linha_digitavel'] ?? null;
                $codigoBarras = $codigoBarras ?? $GLOBALS['__shipay_codigo_barras'] ?? null;
                $qrCode = $qrCode ?? $GLOBALS['__shipay_qr_code'] ?? null;
                $qrCodeText = $qrCodeText ?? $GLOBALS['__shipay_qr_code_text'] ?? null;
                $pdfUrl = $pdfUrl ?? $GLOBALS['__shipay_pdf_url'] ?? null;
                $tipo = $tipo ?? $GLOBALS['__shipay_tipo'] ?? 'pix';

                $this->success("Cobrança Shipay gerada com sucesso!", [
                    'boleto' => [
                        'charge_id' => $chargeId,
                        'status' => $status,
                        'linha_digitavel' => $linhaDigitavel,
                        'codigo_barras' => $codigoBarras,
                        'qrcode' => $qrCode,
                        'qrcode_text' => $qrCodeText,
                        'pdf_url' => $pdfUrl,
                    ],
                    'tipo' => $tipo,
                    'existente' => false,
                    'aviso' => 'Boleto gerado, mas houve erro: ' . $e->getMessage()
                ]);
                return;
            }

            error_log("[EntradasController] ❌ ERRO GERAL (sem boleto): " . $e->getMessage());
            $mensagemErro = (($_ENV['APP_ENV'] ?? 'development') === 'production')
                ? 'Erro ao gerar boleto Shipay. Tente novamente mais tarde.'
                : 'Erro ao gerar boleto Shipay: ' . $e->getMessage();
            $this->error($mensagemErro);
        }
    }

    /**
     * Listar todas as cobranças Shipay emitidas
     */
    public function listarCobrancasShipay(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar quais colunas Shipay existem na tabela
            $stmtColumns = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $columns = $stmtColumns->fetchAll(\PDO::FETCH_COLUMN);

            // Verificar se as colunas Shipay existem
            $hasShipayChargeId = in_array('shipay_charge_id', $columns);
            $hasShipayOrderId = in_array('shipay_order_id', $columns);

            if (!$hasShipayChargeId && !$hasShipayOrderId) {
                // Nenhuma coluna Shipay existe - retornar lista vazia
                $this->success('Cobranças listadas', [
                    'cobrancas' => [],
                    'total' => 0,
                    'message' => 'Colunas Shipay não encontradas na tabela'
                ]);
                return;
            }

            // Construir query dinamicamente baseado nas colunas existentes
            $shipayColumn = $hasShipayChargeId ? 'shipay_charge_id' : 'shipay_order_id';
            $selectFields = [
                'cr.id',
                'cr.description',
                'cr.amount',
                'cr.due_date',
                'cr.created_at',
                'p.name as customer_name',
                'p.document as customer_document'
            ];

            if ($hasShipayChargeId)
                $selectFields[] = 'cr.shipay_charge_id';
            if ($hasShipayOrderId)
                $selectFields[] = 'cr.shipay_order_id';
            if (in_array('shipay_status', $columns))
                $selectFields[] = 'cr.shipay_status';
            if (in_array('shipay_linha_digitavel', $columns))
                $selectFields[] = 'cr.shipay_linha_digitavel';
            if (in_array('shipay_qr_code', $columns))
                $selectFields[] = 'cr.shipay_qr_code';
            if (in_array('shipay_pdf_url', $columns))
                $selectFields[] = 'cr.shipay_pdf_url';

            $sql = "
                SELECT " . implode(', ', $selectFields) . "
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                WHERE cr.company_id = :company_id
                AND cr.{$shipayColumn} IS NOT NULL
                AND cr.{$shipayColumn} != ''
                ORDER BY cr.created_at DESC
                LIMIT 100
            ";

            $stmt = $this->db->prepare($sql);
            $stmt->execute(['company_id' => $companyId]);
            $cobrancas = $stmt->fetchAll();

            $this->success('Cobranças listadas', [
                'cobrancas' => $cobrancas,
                'total' => count($cobrancas)
            ]);

        } catch (Exception $e) {
            error_log("Erro ao listar cobranças Shipay: " . $e->getMessage());
            $this->error('Erro ao listar cobranças: ' . $e->getMessage());
        }
    }

    /**
     * Listar wallets (carteiras) disponíveis na Shipay
     * Útil para verificar quais métodos de pagamento estão habilitados
     */
    public function listarWalletsShipay(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Buscar empresa com configuração Shipay
            $stmtEmpresa = $this->db->prepare("
                SELECT shipay_access_key, shipay_secret_key, shipay_client_id, shipay_environment
                FROM empresas
                WHERE company_id = :company_id AND shipay_enabled = 1
                LIMIT 1
            ");
            $stmtEmpresa->execute(['company_id' => $companyId]);
            $empresa = $stmtEmpresa->fetch();

            if (!$empresa) {
                $this->error('Integração Shipay não configurada');
                return;
            }

            // Configurar cliente Shipay
            $paymentConfig = require \ROOT_PATH . '/config/payment.php';
            $shipayConfig = [
                'access_key' => $empresa['shipay_access_key'],
                'secret_key' => $empresa['shipay_secret_key'],
                'client_id' => $empresa['shipay_client_id'],
                'environment' => $empresa['shipay_environment'] ?? 'sandbox',
                'base_url' => $paymentConfig['shipay']['base_url'] ?? [],
            ];

            $shipay = new ShipayClient($shipayConfig);

            // Consultar wallets disponíveis
            $wallets = $shipay->listWallets();

            $this->success('Wallets disponíveis', [
                'wallets' => $wallets,
                'environment' => $shipay->getEnvironment()
            ]);

        } catch (Exception $e) {
            error_log("Erro ao listar wallets Shipay: " . $e->getMessage());
            $this->error('Erro ao listar wallets: ' . $e->getMessage());
        }
    }

    /**
     * Consultar status de boleto Shipay
     */
    public function consultarBoletoShipay(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $companyId = $this->getCompanyId();

            // Buscar conta
            $stmt = $this->db->prepare("
                SELECT shipay_charge_id, shipay_status, shipay_linha_digitavel,
                       shipay_qr_code, shipay_pdf_url, shipay_payload, shipay_tipo
                FROM contas_receber
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute(['id' => $id, 'company_id' => $companyId]);
            $conta = $stmt->fetch();

            if (!$conta) {
                $this->error('Conta não encontrada');
                return;
            }

            if (empty($conta['shipay_charge_id'])) {
                $this->error('Esta conta não possui boleto Shipay gerado');
                return;
            }

            // Determinar tipo: se tem linha digitável ou shipay_tipo = 'boleto', é boleto
            $tipo = 'pix';
            if (!empty($conta['shipay_linha_digitavel']) || ($conta['shipay_tipo'] ?? '') === 'boleto') {
                $tipo = 'boleto';
            }

            // Buscar empresa com configuração Shipay
            $stmtEmpresa = $this->db->prepare("
                SELECT shipay_access_key, shipay_secret_key, shipay_client_id, shipay_environment
                FROM empresas
                WHERE company_id = :company_id AND shipay_enabled = 1
                LIMIT 1
            ");
            $stmtEmpresa->execute(['company_id' => $companyId]);
            $empresa = $stmtEmpresa->fetch();

            if (empty($empresa)) {
                // Retornar dados locais se não conseguir consultar
                $this->success('Dados do boleto (cache local)', [
                    'boleto' => [
                        'charge_id' => $conta['shipay_charge_id'],
                        'status' => $conta['shipay_status'],
                        'linha_digitavel' => $conta['shipay_linha_digitavel'],
                        'qrcode' => $conta['shipay_qr_code'],
                        'pdf_url' => $conta['shipay_pdf_url'],
                    ],
                    'fonte' => 'cache'
                ]);
                return;
            }

            // Consultar na API Shipay
            $paymentConfig = require \ROOT_PATH . '/config/payment.php';
            $shipayConfig = [
                'access_key' => $empresa['shipay_access_key'],
                'secret_key' => $empresa['shipay_secret_key'],
                'client_id' => $empresa['shipay_client_id'],
                'environment' => $empresa['shipay_environment'] ?? 'sandbox',
                'base_url' => $paymentConfig['shipay']['base_url'] ?? [],
            ];

            $shipay = new ShipayClient($shipayConfig);
            // Passar o tipo para usar o endpoint correto (/orderv para boletos)
            error_log("[EntradasController] Consultando boleto Shipay - Charge ID: {$conta['shipay_charge_id']}, Tipo: {$tipo}");
            $response = $shipay->getHybridBoleto($conta['shipay_charge_id'], $tipo);
            error_log("[EntradasController] Resposta Shipay: " . json_encode($response, JSON_UNESCAPED_UNICODE));

            // Atualizar dados locais
            $newStatus = $response['status'] ?? $conta['shipay_status'];
            error_log("[EntradasController] Status atual: {$conta['shipay_status']}, Novo status da API: {$newStatus}");
            $newLinhaDigitavel = $response['linha_digitavel'] ?? $response['digitable_line'] ?? $conta['shipay_linha_digitavel'];
            $newQrCode = $response['qr_code'] ?? $response['pix_copia_cola'] ?? $conta['shipay_qr_code'];
            $newPdfUrl = $response['pdf_url'] ?? $response['pdf'] ?? $conta['shipay_pdf_url'];

            // Verificar se o status mudou para pago
            $statusLower = strtolower($newStatus ?? '');
            $statusPago = in_array($statusLower, ['paid', 'pago', 'paid_out', 'approved']);

            // Buscar conta completa para verificar status atual
            $stmtConta = $this->db->prepare("SELECT status, status_id FROM contas_receber WHERE id = :id AND company_id = :company_id");
            $stmtConta->execute(['id' => $id, 'company_id' => $companyId]);
            $contaCompleta = $stmtConta->fetch();

            // Construir UPDATE dinamicamente
            $sets = [
                'shipay_status = :status',
                'shipay_linha_digitavel = :linha_digitavel',
                'shipay_qr_code = :qr_code',
                'shipay_pdf_url = :pdf_url',
                'shipay_payload = :payload',
                'updated_at = NOW()'
            ];

            $params = [
                'status' => $newStatus,
                'linha_digitavel' => $newLinhaDigitavel,
                'qr_code' => $newQrCode,
                'pdf_url' => $newPdfUrl,
                'payload' => json_encode($response, JSON_UNESCAPED_UNICODE),
                'id' => $id,
                'company_id' => $companyId
            ];

            // Se status mudou para pago, atualizar também o status principal
            if ($statusPago && ($contaCompleta['status'] ?? '') !== 'pago') {
                error_log("[EntradasController] Consulta detectou pagamento - Atualizando status para 'pago' na conta #{$id}");
                $sets[] = "status = 'pago'";

                // Verificar se existe status_id e buscar o ID do status "pago"
                if (!empty($contaCompleta['status_id'])) {
                    $stmtStatus = $this->db->prepare("
                        SELECT id FROM modulo_status
                        WHERE company_id = :company_id
                        AND modulo IN ('entradas', 'contas_receber')
                        AND codigo = 'pago'
                        LIMIT 1
                    ");
                    $stmtStatus->execute(['company_id' => $companyId]);
                    $statusPagoInfo = $stmtStatus->fetch();
                    if ($statusPagoInfo) {
                        $sets[] = 'status_id = :status_id';
                        $params['status_id'] = $statusPagoInfo['id'];
                    }
                }
            }

            $sql = "UPDATE contas_receber SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmtUpdate = $this->db->prepare($sql);
            $stmtUpdate->execute($params);

            $this->success('Boleto consultado com sucesso', [
                'boleto' => [
                    'charge_id' => $conta['shipay_charge_id'],
                    'status' => $newStatus,
                    'linha_digitavel' => $newLinhaDigitavel,
                    'qrcode' => $newQrCode,
                    'pdf_url' => $newPdfUrl,
                ],
                'fonte' => 'api'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao consultar boleto Shipay: " . $e->getMessage());
            $this->error('Erro ao consultar boleto: ' . $e->getMessage());
        }
    }

    /**
     * Cancelar boleto Shipay e gerar novo (segunda via)
     */
    public function reemitirBoletoShipay(): void
    {
        try {
            $id = (int) $this->request->post('id');
            $companyId = $this->getCompanyId();

            // Buscar conta com dados do cliente
            $stmt = $this->db->prepare("
                SELECT cr.*, p.*,
                       cr.id as conta_id,
                       cr.description as conta_description,
                       cr.amount as conta_amount
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                WHERE cr.id = :id AND cr.company_id = :company_id
            ");
            $stmt->execute(['id' => $id, 'company_id' => $companyId]);
            $conta = $stmt->fetch();

            if (!$conta) {
                $this->error('Conta não encontrada');
                return;
            }

            // Buscar empresa com configuração Shipay
            $stmtEmpresa = $this->db->prepare("
                SELECT *
                FROM empresas
                WHERE company_id = :company_id AND shipay_enabled = 1
                LIMIT 1
            ");
            $stmtEmpresa->execute(['company_id' => $companyId]);
            $empresa = $stmtEmpresa->fetch();

            if (empty($empresa) || empty($empresa['shipay_access_key'])) {
                $this->error('Integração Shipay não configurada');
                return;
            }

            $paymentConfig = require \ROOT_PATH . '/config/payment.php';
            $shipayConfig = [
                'access_key' => $empresa['shipay_access_key'],
                'secret_key' => $empresa['shipay_secret_key'],
                'client_id' => $empresa['shipay_client_id'],
                'environment' => $empresa['shipay_environment'] ?? 'sandbox',
                'base_url' => $paymentConfig['shipay']['base_url'] ?? [],
            ];

            $shipay = new ShipayClient($shipayConfig);

            // Se já tem boleto, cancelar primeiro
            if (!empty($conta['shipay_charge_id'])) {
                try {
                    $shipay->updateHybridBoleto($conta['shipay_charge_id'], ['status' => 'cancelled']);
                    error_log("Boleto Shipay {$conta['shipay_charge_id']} cancelado para reemissão");
                } catch (Exception $e) {
                    error_log("Erro ao cancelar boleto antigo: " . $e->getMessage());
                    // Continua mesmo se não conseguir cancelar
                }
            }

            // Validar dados do cliente
            $documento = preg_replace('/\D/', '', $conta['document'] ?? '');
            if (empty($documento)) {
                $this->error('Cliente não possui CPF/CNPJ cadastrado');
                return;
            }

            // Preparar payload para novo boleto
            $telefone = preg_replace('/\D/', '', $conta['phone'] ?? $conta['mobile'] ?? '');

            $payload = [
                'valor' => (float) $conta['conta_amount'],
                'vencimento' => $conta['due_date'],
                'descricao' => $conta['conta_description'] ?? 'Conta a receber #' . $id,
                'pagador' => [
                    'nome' => $conta['name'] ?? '',
                    'documento' => $documento,
                    'email' => $conta['email'] ?? '',
                    'telefone' => $telefone,
                    'endereco' => [
                        'logradouro' => $conta['address'] ?? '',
                        'numero' => $conta['numero'] ?? $conta['address_number'] ?? '',
                        'complemento' => $conta['complemento'] ?? '',
                        'bairro' => $conta['bairro'] ?? $conta['neighborhood'] ?? '',
                        'cidade' => $conta['city'] ?? '',
                        'uf' => $conta['state'] ?? '',
                        'cep' => preg_replace('/\D/', '', $conta['zip_code'] ?? ''),
                    ],
                ],
            ];

            if (!empty($empresa['shipay_store_id'])) {
                $payload['store_id'] = $empresa['shipay_store_id'];
            }
            if (!empty($empresa['shipay_cashier_id'])) {
                $payload['cashier_id'] = $empresa['shipay_cashier_id'];
            }

            // Gerar novo boleto
            $response = $shipay->createHybridBoleto($payload);

            // Extrair dados (order_id para /order, id/charge_id para outros endpoints)
            $chargeId = $response['order_id'] ?? $response['id'] ?? $response['charge_id'] ?? null;
            $linhaDigitavel = $response['linha_digitavel'] ?? $response['digitable_line'] ?? null;
            $qrCode = $response['qr_code'] ?? $response['pix_copia_cola'] ?? $response['qr_code_text'] ?? null;
            $pdfUrl = $response['pdf_url'] ?? $response['pdf'] ?? null;
            $status = $response['status'] ?? 'pending';

            if (empty($chargeId)) {
                $this->error('Shipay não retornou ID da cobrança');
                return;
            }

            // Atualizar conta com novos dados
            $stmtUpdate = $this->db->prepare("
                UPDATE contas_receber SET
                    shipay_charge_id = :charge_id,
                    shipay_status = :status,
                    shipay_linha_digitavel = :linha_digitavel,
                    shipay_qr_code = :qr_code,
                    shipay_pdf_url = :pdf_url,
                    shipay_payload = :payload,
                    updated_at = NOW()
                WHERE id = :id AND company_id = :company_id
            ");
            $stmtUpdate->execute([
                'charge_id' => $chargeId,
                'status' => $status,
                'linha_digitavel' => $linhaDigitavel,
                'qr_code' => $qrCode,
                'pdf_url' => $pdfUrl,
                'payload' => json_encode($response, JSON_UNESCAPED_UNICODE),
                'id' => $id,
                'company_id' => $companyId
            ]);

            $this->success('Segunda via do boleto gerada com sucesso!', [
                'boleto' => [
                    'charge_id' => $chargeId,
                    'status' => $status,
                    'linha_digitavel' => $linhaDigitavel,
                    'qrcode' => $qrCode,
                    'pdf_url' => $pdfUrl,
                ]
            ]);

        } catch (Exception $e) {
            error_log("Erro ao reemitir boleto Shipay: " . $e->getMessage());
            $this->error('Erro ao gerar segunda via: ' . $e->getMessage());
        }
    }

    /**
     * Enviar boleto Shipay por email
     */
    public function enviarBoletoShipayEmail(): void
    {
        try {
            $contaId = (int) $this->request->post('conta_id');
            $email = trim($this->request->post('email'));

            if (!$contaId || !$email) {
                $this->error('Dados inválidos');
                return;
            }

            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $this->error('Email inválido');
                return;
            }

            $companyId = $this->getCompanyId();

            // Buscar dados da conta
            $stmt = $this->db->prepare("
                SELECT cr.*, p.name as pessoa_nome
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                WHERE cr.id = :id AND cr.company_id = :company_id
            ");
            $stmt->execute(['id' => $contaId, 'company_id' => $companyId]);
            $conta = $stmt->fetch();

            if (!$conta) {
                $this->error('Conta não encontrada');
                return;
            }

            if (empty($conta['shipay_charge_id'])) {
                $this->error('Esta conta não possui boleto Shipay gerado');
                return;
            }

            // Preparar dados do email
            $valorFormatado = 'R$ ' . number_format((float) $conta['amount'], 2, ',', '.');
            $vencimento = date('d/m/Y', strtotime($conta['due_date']));

            $body = "
                <html>
                <head>
                    <style>
                        body { font-family: Arial, sans-serif; color: #333; }
                        .header { background-color: #6f42c1; color: white; padding: 20px; text-align: center; }
                        .content { padding: 20px; }
                        .info { background-color: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0; }
                        .pix-box { background-color: #e8f5e9; padding: 15px; border-radius: 5px; margin: 20px 0; border: 2px solid #4caf50; }
                        .footer { text-align: center; color: #6c757d; font-size: 12px; margin-top: 30px; }
                        code { background-color: #f5f5f5; padding: 2px 6px; border-radius: 3px; font-size: 12px; }
                    </style>
                </head>
                <body>
                    <div class='header'>
                        <h2>🎫 Boleto Híbrido - Pix + Boleto</h2>
                    </div>
                    <div class='content'>
                        <p>Olá <strong>" . htmlspecialchars($conta['pessoa_nome'] ?? 'Cliente') . "</strong>,</p>
                        <p>Segue abaixo os dados para pagamento:</p>

                        <div class='info'>
                            <p><strong>📋 Descrição:</strong> " . htmlspecialchars($conta['description'] ?? '') . "</p>
                            <p><strong>💰 Valor:</strong> {$valorFormatado}</p>
                            <p><strong>📅 Vencimento:</strong> {$vencimento}</p>
                        </div>";

            // Adicionar linha digitável se disponível
            if (!empty($conta['shipay_linha_digitavel'])) {
                $body .= "
                        <div class='info'>
                            <p><strong>📊 Linha Digitável do Boleto:</strong></p>
                            <code>" . htmlspecialchars($conta['shipay_linha_digitavel']) . "</code>
                        </div>";
            }

            // Adicionar QR Code Pix se disponível
            if (!empty($conta['shipay_qr_code'])) {
                $body .= "
                        <div class='pix-box'>
                            <p><strong>⚡ Pague com Pix (Copia e Cola):</strong></p>
                            <p><small>Copie o código abaixo e cole no app do seu banco:</small></p>
                            <textarea readonly style='width:100%; height:80px; font-size:11px; resize:none;'>" . htmlspecialchars($conta['shipay_qr_code']) . "</textarea>
                        </div>";
            }

            // Adicionar link do PDF se disponível
            if (!empty($conta['shipay_pdf_url'])) {
                $body .= "
                        <p style='text-align:center; margin-top:20px;'>
                            <a href='" . htmlspecialchars($conta['shipay_pdf_url']) . "'
                               style='background-color:#6f42c1; color:white; padding:12px 24px; text-decoration:none; border-radius:5px; display:inline-block;'>
                                📄 Baixar Boleto em PDF
                            </a>
                        </p>";
            }

            $body .= "
                        <div class='footer'>
                            <p>Este é um email automático. Por favor, não responda.</p>
                            <p>Em caso de dúvidas, entre em contato conosco.</p>
                        </div>
                    </div>
                </body>
                </html>
            ";

            // Enviar email
            $mail = new \PHPMailer\PHPMailer\PHPMailer(true);

            $mail->isSMTP();
            $mail->Host = $_ENV['MAIL_HOST'] ?? 'localhost';
            $mail->SMTPAuth = true;
            $mail->Username = $_ENV['MAIL_USERNAME'] ?? '';
            $mail->Password = $_ENV['MAIL_PASSWORD'] ?? '';
            $mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'] ?? 'tls';
            $mail->Port = (int) ($_ENV['MAIL_PORT'] ?? 587);
            $mail->CharSet = 'UTF-8';

            $mail->setFrom($_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@Systhema.com', $_ENV['MAIL_FROM_NAME'] ?? 'Systhema');
            $mail->addAddress($email);
            $mail->isHTML(true);
            $mail->Subject = "Boleto - {$conta['description']} - Vencimento: {$vencimento}";
            $mail->Body = $body;

            $mail->send();

            $this->success('Email enviado com sucesso para ' . $email);

        } catch (Exception $e) {
            error_log("Erro ao enviar email boleto Shipay: " . $e->getMessage());
            $this->error('Erro ao enviar email: ' . $e->getMessage());
        }
    }

    /**
     * Buscar títulos que vencem hoje para recebimento diário
     */
    public function recebimentoDiario(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $hoje = date('Y-m-d');

            // Buscar todos os títulos que vencem hoje
            $query = "
                SELECT cr.*,
                       p.name as customer_name,
                       p.document as customer_document,
                       ms.nome as status_nome,
                       ms.cor as status_cor,
                       ms.icone as status_icone,
                       CASE
                           WHEN cr.amount_received >= cr.amount THEN 'pago'
                           WHEN cr.amount_received > 0 THEN 'parcial'
                           ELSE 'pendente'
                       END as situacao_pagamento
                FROM contas_receber cr
                LEFT JOIN pessoas p ON cr.customer_id = p.id
                LEFT JOIN modulo_status ms ON cr.status_id = ms.id
                WHERE cr.company_id = :company_id
                  AND DATE(cr.due_date) = :hoje
                ORDER BY cr.due_date ASC, p.name ASC
            ";

            $stmt = $this->db->prepare($query);
            $stmt->execute([
                'company_id' => $companyId,
                'hoje' => $hoje
            ]);
            $titulos = $stmt->fetchAll();

            // Separar em pagos e não pagos
            $pagos = [];
            $naoPagos = [];
            $totalPagos = 0;
            $totalNaoPagos = 0;
            $totalGeral = 0;

            foreach ($titulos as $titulo) {
                $valor = floatval($titulo['amount'] ?? 0);
                $recebido = floatval($titulo['amount_received'] ?? 0);
                $restante = $valor - $recebido;

                $totalGeral += $valor;

                if ($recebido >= $valor) {
                    $pagos[] = $titulo;
                    $totalPagos += $valor;
                } else {
                    $naoPagos[] = $titulo;
                    $totalNaoPagos += $restante;
                }
            }

            $this->success('Dados carregados com sucesso', [
                'titulos' => $titulos,
                'pagos' => $pagos,
                'nao_pagos' => $naoPagos,
                'totalizadores' => [
                    'total_geral' => $totalGeral,
                    'total_pagos' => $totalPagos,
                    'total_nao_pagos' => $totalNaoPagos,
                    'quantidade_pagos' => count($pagos),
                    'quantidade_nao_pagos' => count($naoPagos),
                    'quantidade_total' => count($titulos)
                ],
                'data' => $hoje
            ]);

        } catch (Exception $e) {
            error_log("Erro ao buscar recebimento diário: " . $e->getMessage());
            $this->error('Erro ao buscar recebimento diário: ' . $e->getMessage());
        }
    }

    /**
     * Consultar datas sugeridas para envio ao Sicacred
     */
    public function sicacredConsultarDatas(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar se as colunas existem antes de consultar
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'sicacred_%'");
            $colunasExistentes = $stmtCheck->fetchAll(\PDO::FETCH_COLUMN);

            $empresa = null;

            // Se as colunas existem, buscar configurações
            if (!empty($colunasExistentes)) {
                $campos = [];
                if (in_array('sicacred_cod_fonte', $colunasExistentes))
                    $campos[] = 'sicacred_cod_fonte';
                if (in_array('sicacred_cod_grp_emp', $colunasExistentes))
                    $campos[] = 'sicacred_cod_grp_emp';
                if (in_array('sicacred_codigo_erp', $colunasExistentes))
                    $campos[] = 'sicacred_codigo_erp';
                if (in_array('sicacred_chave', $colunasExistentes))
                    $campos[] = 'sicacred_chave';
                if (in_array('sicacred_producao', $colunasExistentes))
                    $campos[] = 'sicacred_producao';

                if (!empty($campos)) {
                    $stmt = $this->db->prepare("
                        SELECT " . implode(', ', $campos) . "
                        FROM empresas
                        WHERE id = :company_id
                    ");
                    $stmt->execute(['company_id' => $companyId]);
                    $empresa = $stmt->fetch();
                }
            }

            // Se não configurado, usar dados de homologação como padrão
            if (!$empresa || empty($empresa['sicacred_cod_fonte'] ?? null)) {
                // Dados de homologação padrão
                $empresa = [
                    'sicacred_cod_fonte' => 'CSL1704',
                    'sicacred_cod_grp_emp' => '2018004',
                    'sicacred_codigo_erp' => '', // Deve ser configurado
                    'sicacred_chave' => '2504aa84-d511-4154-b877-f403c1d7',
                    'sicacred_producao' => 0
                ];
            }

            $config = [
                'cod_grp_emp' => $empresa['sicacred_cod_grp_emp'] ?? '2018004',
                'codigo_erp' => $empresa['sicacred_codigo_erp'] ?? '',
                'chave' => $empresa['sicacred_chave'] ?? '2504aa84-d511-4154-b877-f403c1d7',
                'producao' => !empty($empresa['sicacred_producao'] ?? 0)
            ];

            $codFonte = $empresa['sicacred_cod_fonte'] ?? 'CSL1704';

            $service = new \App\Services\SicacredService(
                $this->db,
                $companyId,
                $codFonte,
                $config
            );

            $resultado = $service->consultarDatas();

            $this->success('Datas consultadas com sucesso', [
                'data_sugerida' => $resultado['DataEnvioArquivo'] ?? null,
                'data_ultimo_envio' => $resultado['DatUltArquivo'] ?? null,
                'dias_atraso' => $resultado['AtrasoLib'] ?? 0,
                'mensagem' => $resultado['MensagemRetorno'] ?? '',
                'codigo' => $resultado['CodigoRetorno'] ?? 0
            ]);

        } catch (\Exception $e) {
            // Log será feito pelo SicacredService
            error_log("Erro em sicacredConsultarDatas: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao consultar datas: ' . $e->getMessage());
        }
    }

    /**
     * Enviar dados para o Sicacred
     */
    public function sicacredEnviarDados(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $dataInicial = $this->request->post('data_inicial');
            $dataFinal = $this->request->post('data_final');
            $emailResponsavel = $this->request->post('email_responsavel', '');

            if (empty($dataInicial) || empty($dataFinal)) {
                $this->error('Data inicial e data final são obrigatórias');
                return;
            }

            // Verificar se as colunas existem antes de consultar
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'sicacred_%'");
            $colunasExistentes = $stmtCheck->fetchAll(\PDO::FETCH_COLUMN);

            $empresa = null;

            // Se as colunas existem, buscar configurações
            if (!empty($colunasExistentes)) {
                $campos = [];
                if (in_array('sicacred_cod_fonte', $colunasExistentes))
                    $campos[] = 'sicacred_cod_fonte';
                if (in_array('sicacred_cod_grp_emp', $colunasExistentes))
                    $campos[] = 'sicacred_cod_grp_emp';
                if (in_array('sicacred_codigo_erp', $colunasExistentes))
                    $campos[] = 'sicacred_codigo_erp';
                if (in_array('sicacred_chave', $colunasExistentes))
                    $campos[] = 'sicacred_chave';
                if (in_array('sicacred_producao', $colunasExistentes))
                    $campos[] = 'sicacred_producao';

                if (!empty($campos)) {
                    $stmt = $this->db->prepare("
                        SELECT " . implode(', ', $campos) . "
                        FROM empresas
                        WHERE id = :company_id
                    ");
                    $stmt->execute(['company_id' => $companyId]);
                    $empresa = $stmt->fetch();
                }
            }

            // Se não configurado, usar dados de homologação como padrão
            if (!$empresa || empty($empresa['sicacred_cod_fonte'] ?? null)) {
                // Dados de homologação padrão
                $empresa = [
                    'sicacred_cod_fonte' => 'CSL1704',
                    'sicacred_cod_grp_emp' => '2018004',
                    'sicacred_codigo_erp' => '', // Deve ser configurado
                    'sicacred_chave' => '2504aa84-d511-4154-b877-f403c1d7',
                    'sicacred_producao' => 0
                ];
            }

            $config = [
                'cod_grp_emp' => $empresa['sicacred_cod_grp_emp'] ?? '2018004',
                'codigo_erp' => $empresa['sicacred_codigo_erp'] ?? '',
                'chave' => $empresa['sicacred_chave'] ?? '2504aa84-d511-4154-b877-f403c1d7',
                'producao' => !empty($empresa['sicacred_producao'] ?? 0)
            ];

            $codFonte = $empresa['sicacred_cod_fonte'] ?? 'CSL1704';

            $service = new \App\Services\SicacredService(
                $this->db,
                $companyId,
                $codFonte,
                $config
            );

            $resultado = $service->enviarDados($dataInicial, $dataFinal, $emailResponsavel);

            // Gravar histórico do envio no banco de dados
            $codigoRetorno = $resultado['CodigoRetorno'] ?? 0;
            $mensagemRetorno = $resultado['MensagemRetorno'] ?? '';
            $status = ($codigoRetorno === 100) ? 'sucesso' : 'erro';

            // Buscar totais enviados (se disponível no resultado)
            $totalClientes = $resultado['total_clientes'] ?? 0;
            $totalCompras = $resultado['total_compras'] ?? 0;
            $totalDocumentos = $resultado['total_documentos'] ?? 0;

            try {
                $stmt = $this->db->prepare("
                    INSERT INTO sicacred_envios (
                        company_id, cod_fonte, data_inicial, data_final, email_responsavel,
                        codigo_retorno, mensagem_retorno, status,
                        total_clientes, total_compras, total_documentos, producao, created_by
                    ) VALUES (
                        :company_id, :cod_fonte, :data_inicial, :data_final, :email_responsavel,
                        :codigo_retorno, :mensagem_retorno, :status,
                        :total_clientes, :total_compras, :total_documentos, :producao, :created_by
                    )
                ");

                $stmt->execute([
                    'company_id' => $companyId,
                    'cod_fonte' => $codFonte,
                    'data_inicial' => $dataInicial,
                    'data_final' => $dataFinal,
                    'email_responsavel' => $emailResponsavel ?: null,
                    'codigo_retorno' => $codigoRetorno,
                    'mensagem_retorno' => $mensagemRetorno,
                    'status' => $status,
                    'total_clientes' => $totalClientes,
                    'total_compras' => $totalCompras,
                    'total_documentos' => $totalDocumentos,
                    'producao' => $config['producao'] ? 1 : 0,
                    'created_by' => $this->getUserId()
                ]);
            } catch (\Exception $e) {
                // Log do erro, mas não interrompe o fluxo
                error_log("Erro ao gravar histórico Sicacred: " . $e->getMessage());
            }

            $this->success('Dados enviados com sucesso para o Sicacred', [
                'mensagem' => $mensagemRetorno,
                'codigo' => $codigoRetorno,
                'status' => $status
            ]);

        } catch (\Exception $e) {
            // Log será feito pelo SicacredService

            // Tentar gravar erro no histórico
            try {
                if (isset($companyId) && isset($codFonte) && isset($dataInicial) && isset($dataFinal)) {
                    $stmt = $this->db->prepare("
                        INSERT INTO sicacred_envios (
                            company_id, cod_fonte, data_inicial, data_final, email_responsavel,
                            status, erro, producao, created_by
                        ) VALUES (
                            :company_id, :cod_fonte, :data_inicial, :data_final, :email_responsavel,
                            'erro', :erro, :producao, :created_by
                        )
                    ");

                    $stmt->execute([
                        'company_id' => $companyId,
                        'cod_fonte' => $codFonte,
                        'data_inicial' => $dataInicial,
                        'data_final' => $dataFinal,
                        'email_responsavel' => $emailResponsavel ?: null,
                        'erro' => $e->getMessage(),
                        'producao' => $config['producao'] ?? 0 ? 1 : 0,
                        'created_by' => $this->getUserId()
                    ]);
                }
            } catch (\Exception $e2) {
                error_log("Erro ao gravar histórico de erro Sicacred: " . $e2->getMessage());
            }

            error_log("Erro em sicacredEnviarDados: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao enviar dados: ' . $e->getMessage());
        }
    }
}
