<?php

declare(strict_types=1);

namespace App\Controllers;

use Exception;

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

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

            $query = "
                SELECT fc.*,
                       p.name as pessoa_nome,
                       p.document as pessoa_documento,
                       pc.code as plano_codigo,
                       pc.name as plano_nome
                FROM fluxo_caixa fc
                LEFT JOIN pessoas p ON fc.people_id = p.id
                LEFT JOIN plano_contas pc ON fc.plano_contas_id = pc.id
                WHERE fc.company_id = :company_id
            ";

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

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

            if (!empty($type)) {
                $query .= " AND fc.type = :type";
                $params['type'] = $type;
            }

            if (!empty($date_from)) {
                $query .= " AND fc.date >= :date_from";
                $params['date_from'] = $date_from;
            }

            if (!empty($date_to)) {
                $query .= " AND fc.date <= :date_to";
                $params['date_to'] = $date_to;
            }

            $query .= " ORDER BY fc.date DESC, fc.created_at DESC";

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

            // Calcula totais
            $stmt = $this->db->prepare("
                SELECT
                    COALESCE(SUM(CASE WHEN type = 'entrada' THEN amount ELSE 0 END), 0) as total_entradas,
                    COALESCE(SUM(CASE WHEN type = 'saida' THEN amount ELSE 0 END), 0) as total_saidas
                FROM fluxo_caixa
                WHERE company_id = :company_id
            ");
            $stmt->execute(['company_id' => $companyId]);
            $totais = $stmt->fetch();
            $totalEntradas = $totais['total_entradas'] ?? 0;
            $totalSaidas = $totais['total_saidas'] ?? 0;
            $saldoTotal = $totalEntradas - $totalSaidas;

            $this->view('fluxo-caixa/index', [
                'movimentos' => $movimentos,
                'totalEntradas' => $totalEntradas,
                'totalSaidas' => $totalSaidas,
                'saldoTotal' => $saldoTotal,
                'search' => $search,
                'type' => $type,
                'date_from' => $date_from,
                'date_to' => $date_to,
                'pageTitle' => 'Fluxo de Caixa',
                'activeMenu' => 'fluxo-caixa'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao carregar fluxo de caixa: " . $e->getMessage());
            $this->error('Erro ao carregar fluxo de caixa');
        }
    }

    public function create(): void
    {
        $this->view('fluxo-caixa/create', [
            'pageTitle' => 'Nova Movimentação',
            'activeMenu' => 'fluxo-caixa',
            'planosContas' => $this->getPlanosContas(),
            'centrosCustos' => $this->getCentrosCustos(),
            'pessoas' => $this->getPessoas(),
            'usuarios' => $this->getUsuarios()
        ]);
    }

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

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

            $amount = (float) $this->request->post('amount');
            $type = $this->request->post('type');

            // Calcula saldo atual
            $stmt = $this->db->prepare("
                SELECT
                    COALESCE(SUM(CASE WHEN type = 'entrada' THEN amount ELSE -amount END), 0) as saldo_atual
                FROM fluxo_caixa
                WHERE company_id = :company_id
            ");
            $stmt->execute(['company_id' => $companyId]);
            $saldoAtual = $stmt->fetch()['saldo_atual'] ?? 0;

            $novoSaldo = ($type === 'entrada') ? $saldoAtual + $amount : $saldoAtual - $amount;

            $data = [
                'company_id' => $companyId,
                'date' => $this->request->post('date'),
                'type' => $type,
                'category' => $this->request->post('category') ?: 'Geral',
                'description' => $this->request->post('description'),
                'amount' => $amount,
                'balance' => $novoSaldo,
                'reference_type' => $this->request->post('reference_type') ?: null,
                'reference_id' => $this->request->post('reference_id') ?: null,
                'plano_contas_id' => $this->request->post('plano_contas_id') ?: null,
                'centro_custo_id' => $this->request->post('centro_custo_id') ?: null,
                'people_id' => $this->request->post('people_id') ?: null,
                'responsible_id' => $this->request->post('responsible_id') ?: null,
            ];

            $this->db->beginTransaction();

            // Verificar se as colunas existem
            $columns = $this->getTableColumns('fluxo_caixa');
            $hasPlanoContas = in_array('plano_contas_id', $columns);
            $hasCentroCusto = in_array('centro_custo_id', $columns);
            $hasPeopleId = in_array('people_id', $columns);
            $hasResponsibleId = in_array('responsible_id', $columns);

            $campos = 'company_id, date, type, category, description, amount, balance, reference_type, reference_id, created_at';
            $valores = ':company_id, :date, :type, :category, :description, :amount, :balance, :reference_type, :reference_id, NOW()';

            if ($hasPlanoContas) {
                $campos .= ', plano_contas_id';
                $valores .= ', :plano_contas_id';
            } else {
                unset($data['plano_contas_id']);
            }

            if ($hasCentroCusto) {
                $campos .= ', centro_custo_id';
                $valores .= ', :centro_custo_id';
            } else {
                unset($data['centro_custo_id']);
            }

            if ($hasPeopleId) {
                $campos .= ', people_id';
                $valores .= ', :people_id';
            } else {
                unset($data['people_id']);
            }

            if ($hasResponsibleId) {
                $campos .= ', responsible_id';
                $valores .= ', :responsible_id';
            } else {
                unset($data['responsible_id']);
            }

            $stmt = $this->db->prepare("
                INSERT INTO fluxo_caixa ({$campos})
                VALUES ({$valores})
            ");
            $stmt->execute($data);
            $movimentoId = (int) $this->db->lastInsertId();

            $this->logActivity('create', 'fluxo_caixa', $movimentoId, $data);
            $this->db->commit();

            $this->success('Movimentação criada com sucesso', [
                'id' => $movimentoId,
                'redirect' => '/fluxo-caixa'
            ]);

        } catch (Exception $e) {
            $this->db->rollBack();
            error_log("Erro ao criar movimentação: " . $e->getMessage());
            $this->error('Erro ao criar movimentação');
        }
    }

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

        try {
            $id = (int) $this->request->get('id');
            $movimento = $this->getMovimento($id);

            if (!$movimento) {
                $this->response->notFound('Movimentação não encontrada');
                return;
            }

            $this->view('fluxo-caixa/edit', [
                'movimento' => $movimento,
                'pageTitle' => 'Editar Movimentação',
                'activeMenu' => 'fluxo-caixa',
                'planosContas' => $this->getPlanosContas(),
                'centrosCustos' => $this->getCentrosCustos(),
                'pessoas' => $this->getPessoas(),
                'usuarios' => $this->getUsuarios()
            ]);

        } catch (Exception $e) {
            error_log("Erro ao editar movimentação: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

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

        try {
            $id = (int) $this->request->post('id');
            $movimento = $this->getMovimento($id);

            if (!$movimento) {
                $this->error('Movimentação não encontrada');
                return;
            }

            $data = [
                'date' => $this->request->post('date'),
                'type' => $this->request->post('type'),
                'category' => $this->request->post('category') ?: 'Geral',
                'description' => $this->request->post('description'),
                'amount' => (float) $this->request->post('amount'),
                'reference_type' => $this->request->post('reference_type') ?: null,
                'reference_id' => $this->request->post('reference_id') ?: null,
                'plano_contas_id' => $this->request->post('plano_contas_id') ?: null,
                'centro_custo_id' => $this->request->post('centro_custo_id') ?: null,
                'people_id' => $this->request->post('people_id') ?: null,
                'responsible_id' => $this->request->post('responsible_id') ?: null,
                'id' => $id,
                'company_id' => $this->getCompanyId()
            ];

            $this->db->beginTransaction();

            // Verificar se as colunas existem
            $columns = $this->getTableColumns('fluxo_caixa');
            $hasPlanoContas = in_array('plano_contas_id', $columns);
            $hasCentroCusto = in_array('centro_custo_id', $columns);
            $hasPeopleId = in_array('people_id', $columns);
            $hasResponsibleId = in_array('responsible_id', $columns);

            $sets = "date = :date, type = :type, category = :category, description = :description, amount = :amount, reference_type = :reference_type, reference_id = :reference_id";

            if ($hasPlanoContas) {
                $sets .= ', plano_contas_id = :plano_contas_id';
            } else {
                unset($data['plano_contas_id']);
            }

            if ($hasCentroCusto) {
                $sets .= ', centro_custo_id = :centro_custo_id';
            } else {
                unset($data['centro_custo_id']);
            }

            if ($hasPeopleId) {
                $sets .= ', people_id = :people_id';
            } else {
                unset($data['people_id']);
            }

            if ($hasResponsibleId) {
                $sets .= ', responsible_id = :responsible_id';
            } else {
                unset($data['responsible_id']);
            }

            $stmt = $this->db->prepare("
                UPDATE fluxo_caixa SET {$sets}
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute($data);

            // Recalcula todos os saldos após esta data
            $this->recalculateBalances($data['date']);

            $this->logActivity('update', 'fluxo_caixa', $id, $data);
            $this->db->commit();

            $this->success('Movimentação atualizada com sucesso', [
                'redirect' => '/fluxo-caixa'
            ]);

        } catch (Exception $e) {
            $this->db->rollBack();
            error_log("Erro ao atualizar movimentação: " . $e->getMessage());
            $this->error('Erro ao atualizar movimentação');
        }
    }

    public function updatePlanoContas(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('fluxo-caixa')) {
            $this->response->json([
                'success' => false,
                'message' => 'Você não tem permissão para editar movimentações de fluxo de caixa.'
            ]);
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            $planoContasId = $this->request->post('plano_contas_id');

            // Converter string vazia para null
            if ($planoContasId === '' || $planoContasId === null) {
                $planoContasId = null;
            } else {
                $planoContasId = (int) $planoContasId;
            }

            $movimento = $this->getMovimento($id);
            if (!$movimento) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Movimentação não encontrada'
                ]);
                return;
            }

            $this->db->beginTransaction();

            // Verificar se a coluna existe
            $columns = $this->getTableColumns('fluxo_caixa');
            if (!in_array('plano_contas_id', $columns)) {
                $this->db->rollBack();
                $this->response->json([
                    'success' => false,
                    'message' => 'Campo plano_contas_id não existe na tabela'
                ]);
                return;
            }

            $stmt = $this->db->prepare("
                UPDATE fluxo_caixa
                SET plano_contas_id = :plano_contas_id
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute([
                'plano_contas_id' => $planoContasId,
                'id' => $id,
                'company_id' => $this->getCompanyId()
            ]);

            // Se o lançamento foi gerado de contas_receber ou contas_pagar, atualizar também na tabela de origem
            $referenceType = $movimento['reference_type'] ?? null;
            $referenceId = $movimento['reference_id'] ?? null;

            if ($referenceType && $referenceId) {
                // Verificar se a tabela de origem tem o campo plano_conta_id ou plano_contas_id
                if ($referenceType === 'contas_receber') {
                    $columnsOrigem = $this->getTableColumns('contas_receber');
                    $campoPlano = null;
                    if (in_array('plano_contas_id', $columnsOrigem)) {
                        $campoPlano = 'plano_contas_id';
                    } elseif (in_array('plano_conta_id', $columnsOrigem)) {
                        $campoPlano = 'plano_conta_id';
                    }

                    if ($campoPlano) {
                        $stmt = $this->db->prepare("
                            UPDATE contas_receber
                            SET {$campoPlano} = :plano_contas_id
                            WHERE id = :reference_id AND company_id = :company_id
                        ");
                        $stmt->execute([
                            'plano_contas_id' => $planoContasId,
                            'reference_id' => $referenceId,
                            'company_id' => $this->getCompanyId()
                        ]);
                    }
                } elseif ($referenceType === 'contas_pagar') {
                    $columnsOrigem = $this->getTableColumns('contas_pagar');
                    $campoPlano = null;
                    if (in_array('plano_contas_id', $columnsOrigem)) {
                        $campoPlano = 'plano_contas_id';
                    } elseif (in_array('plano_conta_id', $columnsOrigem)) {
                        $campoPlano = 'plano_conta_id';
                    }

                    if ($campoPlano) {
                        $stmt = $this->db->prepare("
                            UPDATE contas_pagar
                            SET {$campoPlano} = :plano_contas_id
                            WHERE id = :reference_id AND company_id = :company_id
                        ");
                        $stmt->execute([
                            'plano_contas_id' => $planoContasId,
                            'reference_id' => $referenceId,
                            'company_id' => $this->getCompanyId()
                        ]);
                    }
                }
            }

            $this->logActivity('update', 'fluxo_caixa', $id, ['plano_contas_id' => $planoContasId]);
            $this->db->commit();

            $this->response->json([
                'success' => true,
                'message' => 'Plano de Contas atualizado com sucesso'
            ]);

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao atualizar plano de contas: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao atualizar plano de contas: ' . $e->getMessage()
            ]);
        }
    }

    public function updateCentroCusto(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('fluxo-caixa')) {
            $this->response->json([
                'success' => false,
                'message' => 'Você não tem permissão para editar movimentações de fluxo de caixa.'
            ]);
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            $centroCustoId = $this->request->post('centro_custo_id');

            // Converter string vazia para null
            if ($centroCustoId === '' || $centroCustoId === null) {
                $centroCustoId = null;
            } else {
                $centroCustoId = (int) $centroCustoId;
            }

            $movimento = $this->getMovimento($id);
            if (!$movimento) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Movimentação não encontrada'
                ]);
                return;
            }

            $this->db->beginTransaction();

            // Verificar se a coluna existe
            $columns = $this->getTableColumns('fluxo_caixa');
            if (!in_array('centro_custo_id', $columns)) {
                $this->db->rollBack();
                $this->response->json([
                    'success' => false,
                    'message' => 'Campo centro_custo_id não existe na tabela'
                ]);
                return;
            }

            $stmt = $this->db->prepare("
                UPDATE fluxo_caixa
                SET centro_custo_id = :centro_custo_id
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute([
                'centro_custo_id' => $centroCustoId,
                'id' => $id,
                'company_id' => $this->getCompanyId()
            ]);

            // Se o lançamento foi gerado de contas_receber ou contas_pagar, atualizar também na tabela de origem
            $referenceType = $movimento['reference_type'] ?? null;
            $referenceId = $movimento['reference_id'] ?? null;

            if ($referenceType && $referenceId) {
                // Verificar se a tabela de origem tem o campo centro_custo_id
                if ($referenceType === 'contas_receber') {
                    $columnsOrigem = $this->getTableColumns('contas_receber');
                    if (in_array('centro_custo_id', $columnsOrigem)) {
                        $stmt = $this->db->prepare("
                            UPDATE contas_receber
                            SET centro_custo_id = :centro_custo_id
                            WHERE id = :reference_id AND company_id = :company_id
                        ");
                        $stmt->execute([
                            'centro_custo_id' => $centroCustoId,
                            'reference_id' => $referenceId,
                            'company_id' => $this->getCompanyId()
                        ]);
                    }
                } elseif ($referenceType === 'contas_pagar') {
                    $columnsOrigem = $this->getTableColumns('contas_pagar');
                    if (in_array('centro_custo_id', $columnsOrigem)) {
                        $stmt = $this->db->prepare("
                            UPDATE contas_pagar
                            SET centro_custo_id = :centro_custo_id
                            WHERE id = :reference_id AND company_id = :company_id
                        ");
                        $stmt->execute([
                            'centro_custo_id' => $centroCustoId,
                            'reference_id' => $referenceId,
                            'company_id' => $this->getCompanyId()
                        ]);
                    }
                }
            }

            $this->logActivity('update', 'fluxo_caixa', $id, ['centro_custo_id' => $centroCustoId]);
            $this->db->commit();

            $this->response->json([
                'success' => true,
                'message' => 'Centro de Custos atualizado com sucesso'
            ]);

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao atualizar centro de custos: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao atualizar centro de custos: ' . $e->getMessage()
            ]);
        }
    }

    public function getPlanosContasAjax(): void
    {
        try {
            $planosContas = $this->getPlanosContas();
            $this->response->json([
                'success' => true,
                'data' => $planosContas
            ]);
        } catch (Exception $e) {
            error_log("Erro ao buscar planos de contas: " . $e->getMessage());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao buscar planos de contas'
            ]);
        }
    }

    public function getCentrosCustosAjax(): void
    {
        try {
            $centrosCustos = $this->getCentrosCustos();
            $this->response->json([
                'success' => true,
                'data' => $centrosCustos
            ]);
        } catch (Exception $e) {
            error_log("Erro ao buscar centros de custos: " . $e->getMessage());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao buscar centros de custos'
            ]);
        }
    }

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

        try {
            $id = (int) $this->request->post('id');
            $movimento = $this->getMovimento($id);

            if (!$movimento) {
                $this->error('Movimentação não encontrada');
                return;
            }

            $this->db->beginTransaction();

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

            // Recalcula saldos
            $this->recalculateBalances($movimento['date']);

            $this->logActivity('delete', 'fluxo_caixa', $id, $movimento);
            $this->db->commit();

            $this->success('Movimentação excluída com sucesso');

        } catch (Exception $e) {
            $this->db->rollBack();
            error_log("Erro ao excluir movimentação: " . $e->getMessage());
            $this->error('Erro ao excluir movimentação');
        }
    }

    private function getMovimento(int $id): ?array
    {
        $stmt = $this->db->prepare("SELECT * FROM fluxo_caixa WHERE id = :id AND company_id = :company_id");
        $stmt->execute(['id' => $id, 'company_id' => $this->getCompanyId()]);
        return $stmt->fetch() ?: null;
    }

    private function recalculateBalances(string $fromDate): void
    {
        $companyId = $this->getCompanyId();

        // Busca todos os movimentos a partir da data informada
        $stmt = $this->db->prepare("
            SELECT * FROM fluxo_caixa
            WHERE company_id = :company_id AND date >= :from_date
            ORDER BY date ASC, created_at ASC
        ");
        $stmt->execute(['company_id' => $companyId, 'from_date' => $fromDate]);
        $movimentos = $stmt->fetchAll();

        $saldoAtual = 0;

        // Calcula saldo até a data anterior
        $stmt = $this->db->prepare("
            SELECT
                COALESCE(SUM(CASE WHEN type = 'entrada' THEN amount ELSE -amount END), 0) as saldo
            FROM fluxo_caixa
            WHERE company_id = :company_id AND date < :from_date
        ");
        $stmt->execute(['company_id' => $companyId, 'from_date' => $fromDate]);
        $saldoAtual = $stmt->fetch()['saldo'] ?? 0;

        // Recalcula saldos dos movimentos
        foreach ($movimentos as $movimento) {
            $saldoAtual += ($movimento['type'] === 'entrada') ? $movimento['amount'] : -$movimento['amount'];

            $stmt = $this->db->prepare("
                UPDATE fluxo_caixa SET balance = :balance
                WHERE id = :id
            ");
            $stmt->execute(['balance' => $saldoAtual, 'id' => $movimento['id']]);
        }
    }

    private function getPlanosContas(): array
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar se a tabela existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'plano_contas'");
            if (!$stmt->fetch()) {
                return [];
            }

            // Verificar estrutura da tabela
            $stmtColumns = $this->db->query("SHOW COLUMNS FROM plano_contas");
            $columns = array_column($stmtColumns->fetchAll(), 'Field');

            $colCodigo = in_array('code', $columns) ? 'code' : (in_array('codigo', $columns) ? 'codigo' : 'id');
            $colNome = in_array('name', $columns) ? 'name' : (in_array('nome', $columns) ? 'nome' : 'name');

            $sql = "SELECT id, {$colCodigo} as codigo, {$colNome} as nome
                    FROM plano_contas
                    WHERE company_id = :company_id AND is_active = 1
                    ORDER BY {$colCodigo} ASC";

            $stmt = $this->db->prepare($sql);
            $stmt->execute(['company_id' => $companyId]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao carregar planos de contas: " . $e->getMessage());
            return [];
        }
    }

    private function getCentrosCustos(): array
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar se a tabela existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'centro_custos'");
            if (!$stmt->fetch()) {
                return [];
            }

            $sql = "SELECT id, code as codigo, name as nome
                    FROM centro_custos
                    WHERE company_id = :company_id AND is_active = 1
                    ORDER BY code ASC";

            $stmt = $this->db->prepare($sql);
            $stmt->execute(['company_id' => $companyId]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao carregar centros de custos: " . $e->getMessage());
            return [];
        }
    }

    public function conciliacao(): void
    {
        if (!$this->canView('fluxo-caixa')) {
            $this->response->forbidden('Você não tem permissão para visualizar conciliação.');
            return;
        }

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

            // Buscar contas bancárias
            $stmt = $this->db->prepare("
                SELECT id, bank_name, bank_code, agency, account_number, account_type
                FROM contas_bancarias
                WHERE company_id = :company_id AND is_active = 1
                ORDER BY bank_name ASC, account_number ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $contasBancarias = $stmt->fetchAll();

            $this->view('fluxo-caixa/conciliacao', [
                'contasBancarias' => $contasBancarias,
                'pageTitle' => 'Conciliação Bancária',
                'activeMenu' => 'fluxo-caixa'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao carregar conciliação: " . $e->getMessage());
            $this->error('Erro ao carregar conciliação');
        }
    }

    public function saldoBancario(): void
    {
        if (!$this->canView('fluxo-caixa')) {
            $this->response->forbidden('Você não tem permissão para visualizar saldo bancário.');
            return;
        }

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

            // Buscar contas bancárias com saldo inicial
            $stmt = $this->db->prepare("
                SELECT
                    cb.id,
                    cb.bank_name,
                    cb.bank_code,
                    cb.agency,
                    cb.account_number,
                    cb.account_type,
                    cb.balance as saldo_inicial,
                    cb.credit_limit
                FROM contas_bancarias cb
                WHERE cb.company_id = :company_id AND cb.is_active = 1
                ORDER BY cb.bank_name ASC, cb.account_number ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $contas = $stmt->fetchAll();

            $hoje = date('Y-m-d');
            $ontem = date('Y-m-d', strtotime('-1 day'));

            // Verificar se existe campo conta_bancaria_id
            $columns = $this->getTableColumns('fluxo_caixa');
            $hasContaBancaria = in_array('conta_bancaria_id', $columns);

            // Verificar se as tabelas de origem têm conta_bancaria_id
            $hasContaBancariaReceber = false;
            $hasContaBancariaPagar = false;

            try {
                $stmt = $this->db->query("SHOW TABLES LIKE 'contas_receber'");
                if ($stmt->fetch()) {
                    $columnsContasReceber = $this->getTableColumns('contas_receber');
                    $hasContaBancariaReceber = in_array('conta_bancaria_id', $columnsContasReceber);
                }
            } catch (Exception $e) {
                error_log("Erro ao verificar tabela contas_receber: " . $e->getMessage());
            }

            try {
                $stmt = $this->db->query("SHOW TABLES LIKE 'contas_pagar'");
                if ($stmt->fetch()) {
                    $columnsContasPagar = $this->getTableColumns('contas_pagar');
                    $hasContaBancariaPagar = in_array('conta_bancaria_id', $columnsContasPagar);
                }
            } catch (Exception $e) {
                error_log("Erro ao verificar tabela contas_pagar: " . $e->getMessage());
            }

            // Calcular saldos para cada conta
            foreach ($contas as &$conta) {
                $contaId = $conta['id'];
                $saldoInicial = (float) ($conta['saldo_inicial'] ?? 0);

                // Construir query considerando múltiplas fontes de vínculo
                $whereConditions = [];
                $params = [
                    'company_id' => $companyId,
                    'conta_id' => $contaId,
                    'hoje' => $hoje
                ];

                // Se fluxo_caixa tem conta_bancaria_id diretamente
                if ($hasContaBancaria) {
                    $whereConditions[] = "fc.conta_bancaria_id = :conta_id";
                }

                // Se contas_receber tem conta_bancaria_id, incluir movimentações vinculadas
                if ($hasContaBancariaReceber) {
                    $whereConditions[] = "(fc.reference_type = 'contas_receber' AND cr.conta_bancaria_id = :conta_id)";
                }

                // Se contas_pagar tem conta_bancaria_id, incluir movimentações vinculadas
                if ($hasContaBancariaPagar) {
                    $whereConditions[] = "(fc.reference_type = 'contas_pagar' AND cp.conta_bancaria_id = :conta_id)";
                }

                if (empty($whereConditions)) {
                    // Se não há nenhum vínculo possível, usar apenas saldo inicial
                    $conta['saldo_ontem'] = $saldoInicial;
                    $conta['saldo_atual'] = $saldoInicial;
                    continue;
                }

                $whereClause = '(' . implode(' OR ', $whereConditions) . ')';

                // Calcular movimentações até ontem (saldo do dia anterior)
                $queryOntem = "
                    SELECT
                        COALESCE(SUM(CASE WHEN fc.type = 'entrada' THEN fc.amount ELSE -fc.amount END), 0) as movimentacoes
                    FROM fluxo_caixa fc
                ";

                // Adicionar JOINs necessários
                $joins = [];
                if ($hasContaBancariaReceber) {
                    $joins[] = "LEFT JOIN contas_receber cr ON fc.reference_type = 'contas_receber' AND fc.reference_id = cr.id AND cr.company_id = :company_id";
                }
                if ($hasContaBancariaPagar) {
                    $joins[] = "LEFT JOIN contas_pagar cp ON fc.reference_type = 'contas_pagar' AND fc.reference_id = cp.id AND cp.company_id = :company_id";
                }

                $joinClause = !empty($joins) ? implode(' ', $joins) : '';

                // Calcular movimentações até ontem (saldo do dia anterior)
                $queryOntem = "
                    SELECT
                        COALESCE(SUM(CASE WHEN fc.type = 'entrada' THEN fc.amount ELSE -fc.amount END), 0) as movimentacoes
                    FROM fluxo_caixa fc
                    {$joinClause}
                    WHERE fc.company_id = :company_id
                    AND {$whereClause}
                    AND fc.date < :hoje
                ";

                try {
                    $stmt = $this->db->prepare($queryOntem);
                    $stmt->execute($params);
                    $movOntem = $stmt->fetchColumn() ?: 0;
                } catch (Exception $e) {
                    error_log("Erro ao calcular movimentações até ontem para conta {$contaId}: " . $e->getMessage());
                    error_log("Query: " . $queryOntem);
                    error_log("Params: " . json_encode($params));
                    $movOntem = 0;
                }
                $conta['saldo_ontem'] = $saldoInicial + $movOntem;

                // Calcular movimentações até hoje (saldo atual)
                $queryHoje = "
                    SELECT
                        COALESCE(SUM(CASE WHEN fc.type = 'entrada' THEN fc.amount ELSE -fc.amount END), 0) as movimentacoes
                    FROM fluxo_caixa fc
                    {$joinClause}
                    WHERE fc.company_id = :company_id
                    AND {$whereClause}
                    AND fc.date <= :hoje
                ";

                try {
                    $stmt = $this->db->prepare($queryHoje);
                    $stmt->execute($params);
                    $movHoje = $stmt->fetchColumn() ?: 0;
                } catch (Exception $e) {
                    error_log("Erro ao calcular movimentações até hoje para conta {$contaId}: " . $e->getMessage());
                    error_log("Query: " . $queryHoje);
                    error_log("Params: " . json_encode($params));
                    $movHoje = 0;
                }
                $conta['saldo_atual'] = $saldoInicial + $movHoje;
            }

            $this->view('fluxo-caixa/saldo-bancario', [
                'contas' => $contas,
                'dataOntem' => $ontem,
                'dataHoje' => $hoje,
                'pageTitle' => 'Saldo Bancário',
                'activeMenu' => 'fluxo-caixa'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao carregar saldo bancário: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao carregar saldo bancário: ' . $e->getMessage());
        }
    }

    public function movimentacaoDia(): void
    {
        if (!$this->canView('fluxo-caixa')) {
            $this->response->forbidden('Você não tem permissão para visualizar movimentações.');
            return;
        }

        try {
            $companyId = $this->getCompanyId();
            $hoje = date('Y-m-d');

            // Verificar se existe campo conta_bancaria_id
            $columns = $this->getTableColumns('fluxo_caixa');
            $hasContaBancaria = in_array('conta_bancaria_id', $columns);

            $query = "
                SELECT fc.*,
                       p.name as pessoa_nome,
                       p.document as pessoa_documento,
                       pc.code as plano_codigo,
                       pc.name as plano_nome";

            if ($hasContaBancaria) {
                $query .= ",
                       cb.bank_name,
                       cb.account_number";
            }

            $query .= "
                FROM fluxo_caixa fc
                LEFT JOIN pessoas p ON fc.people_id = p.id
                LEFT JOIN plano_contas pc ON fc.plano_contas_id = pc.id";

            if ($hasContaBancaria) {
                $query .= " LEFT JOIN contas_bancarias cb ON fc.conta_bancaria_id = cb.id";
            }

            $query .= "
                WHERE fc.company_id = :company_id
                AND fc.date = :hoje
                ORDER BY fc.created_at DESC
            ";

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

            // Calcular totais do dia
            $stmt = $this->db->prepare("
                SELECT
                    COALESCE(SUM(CASE WHEN type = 'entrada' THEN amount ELSE 0 END), 0) as total_entradas,
                    COALESCE(SUM(CASE WHEN type = 'saida' THEN amount ELSE 0 END), 0) as total_saidas
                FROM fluxo_caixa
                WHERE company_id = :company_id AND date = :hoje
            ");
            $stmt->execute(['company_id' => $companyId, 'hoje' => $hoje]);
            $totais = $stmt->fetch();
            $totalEntradas = $totais['total_entradas'] ?? 0;
            $totalSaidas = $totais['total_saidas'] ?? 0;
            $saldoDia = $totalEntradas - $totalSaidas;

            $this->view('fluxo-caixa/movimentacao-dia', [
                'movimentos' => $movimentos,
                'totalEntradas' => $totalEntradas,
                'totalSaidas' => $totalSaidas,
                'saldoDia' => $saldoDia,
                'dataHoje' => $hoje,
                'hasContaBancaria' => $hasContaBancaria,
                'pageTitle' => 'Movimentação do Dia',
                'activeMenu' => 'fluxo-caixa'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao carregar movimentação do dia: " . $e->getMessage());
            $this->error('Erro ao carregar movimentação do dia');
        }
    }

    public function processarConciliacao(): void
    {
        // SOLUÇÃO DEFINITIVA: Interceptar TODA saída e garantir que apenas JSON seja enviado

        // Função helper para logar erros em storage/logs
        $logError = function ($message, $context = []) {
            $logDir = ROOT_PATH . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'logs';
            if (!is_dir($logDir)) {
                @mkdir($logDir, 0755, true);
            }
            $logFile = $logDir . DIRECTORY_SEPARATOR . 'conciliacao-errors-' . date('Y-m-d') . '.log';
            $timestamp = date('Y-m-d H:i:s');
            $contextStr = !empty($context) ? ' | Context: ' . json_encode($context) : '';
            $logMessage = "[{$timestamp}] {$message}{$contextStr}\n";
            @file_put_contents($logFile, $logMessage, FILE_APPEND | LOCK_EX);
        };

        // DESABILITAR COMPLETAMENTE exibição de erros
        $oldErrorReporting = error_reporting(0); // ZERO = desabilitar TODOS os erros
        $oldDisplayErrors = ini_get('display_errors');
        $oldLogErrors = ini_get('log_errors');
        ini_set('display_errors', '0');
        ini_set('log_errors', '1');
        ini_set('error_log', ROOT_PATH . '/storage/logs/php-errors.log');

        // Capturar erros PHP e logar (SEM exibir)
        set_error_handler(function ($severity, $message, $file, $line) use ($logError) {
            $logError("PHP Error: {$message}", [
                'severity' => $severity,
                'file' => $file,
                'line' => $line
            ]);
            return true; // SUPRIME o erro completamente
        }, E_ALL | E_STRICT);

        // Capturar exceções não tratadas
        set_exception_handler(function ($e) use ($logError) {
            $logError("Uncaught Exception: " . $e->getMessage(), [
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString()
            ]);
            // Enviar JSON de erro
            http_response_code(500);
            header('Content-Type: application/json; charset=utf-8');
            echo json_encode(['success' => false, 'message' => 'Erro interno do servidor']);
            exit;
        });

        // Limpar TODOS os níveis de output buffer
        while (ob_get_level() > 0) {
            $output = ob_get_clean();
            if (!empty($output)) {
                $logError("Output buffer capturado no início", ['output' => substr($output, 0, 1000)]);
            }
        }

        // Iniciar novo output buffer para capturar qualquer coisa
        ob_start(function ($buffer) use ($logError) {
            // Se houver qualquer output, logar e retornar vazio
            if (!empty($buffer)) {
                $logError("Output inesperado capturado", ['output' => substr($buffer, 0, 1000)]);
            }
            return ''; // Retornar vazio para não enviar nada
        });

        if (!$this->canEdit('fluxo-caixa')) {
            $this->response->json([
                'success' => false,
                'message' => 'Você não tem permissão para processar conciliação.'
            ]);
            return;
        }

        try {
            $contaBancariaId = (int) $this->request->post('conta_bancaria_id');
            $arquivo = $_FILES['arquivo_ofx'] ?? null;

            if (!$contaBancariaId || !$arquivo || $arquivo['error'] !== UPLOAD_ERR_OK) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Arquivo inválido ou não enviado'
                ]);
                return;
            }

            // Validar extensão
            $extensao = strtolower(pathinfo($arquivo['name'], PATHINFO_EXTENSION));
            if ($extensao !== 'ofx') {
                $this->response->json([
                    'success' => false,
                    'message' => 'Arquivo deve ser do tipo OFX'
                ]);
                return;
            }

            // Ler conteúdo do arquivo
            $conteudo = file_get_contents($arquivo['tmp_name']);

            // Parse básico do OFX (simplificado - pode precisar de biblioteca mais robusta)
            $transacoes = $this->parsearOFX($conteudo);

            if (empty($transacoes)) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Nenhuma transação encontrada no arquivo OFX'
                ]);
                return;
            }

            // Buscar movimentações do sistema para comparar
            $companyId = $this->getCompanyId();
            $columns = $this->getTableColumns('fluxo_caixa');
            $hasContaBancaria = in_array('conta_bancaria_id', $columns);

            $whereConta = '';
            if ($hasContaBancaria) {
                $whereConta = 'AND conta_bancaria_id = :conta_id';
            }

            $stmt = $this->db->prepare("
                SELECT id, date, description, amount, type, balance
                FROM fluxo_caixa
                WHERE company_id = :company_id
                {$whereConta}
                ORDER BY date DESC, id DESC
            ");

            $params = ['company_id' => $companyId];
            if ($hasContaBancaria) {
                $params['conta_id'] = $contaBancariaId;
            }

            $stmt->execute($params);
            $movimentacoesSistema = $stmt->fetchAll();

            // Comparar transações
            $resultado = $this->compararTransacoes($transacoes, $movimentacoesSistema);

            // Gerar HTML do resultado (capturar qualquer output)
            try {
                $html = $this->gerarHtmlResultadoConciliacao($resultado);
            } catch (Exception $e) {
                $logError("Erro ao gerar HTML da conciliação: " . $e->getMessage(), [
                    'trace' => $e->getTraceAsString()
                ]);
                $html = '<div class="alert alert-danger">Erro ao gerar resultado da conciliação.</div>';
            }

            // LIMPAR TUDO antes de enviar JSON
            while (ob_get_level() > 0) {
                $output = ob_get_clean();
                if (!empty($output)) {
                    $logError("Output capturado antes de enviar JSON", ['output' => substr($output, 0, 1000)]);
                }
            }

            // Enviar JSON DIRETAMENTE sem usar Response::json() para ter controle total
            http_response_code(200);
            header('Content-Type: application/json; charset=utf-8');

            $jsonData = [
                'success' => true,
                'message' => 'Conciliação processada com sucesso',
                'html' => $html,
                'data' => $resultado
            ];

            $jsonOutput = json_encode($jsonData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

            if ($jsonOutput === false) {
                $logError("Erro ao codificar JSON", ['error' => json_last_error_msg()]);
                $jsonOutput = json_encode(['success' => false, 'message' => 'Erro ao processar resposta']);
            }

            echo $jsonOutput;
            exit; // SAIR IMEDIATAMENTE para evitar qualquer output adicional

        } catch (Exception $e) {
            $logError("Erro ao processar conciliação: " . $e->getMessage(), [
                'trace' => $e->getTraceAsString(),
                'file' => $e->getFile(),
                'line' => $e->getLine()
            ]);

            // Limpar QUALQUER output
            while (ob_get_level() > 0) {
                $output = ob_get_clean();
                if (!empty($output)) {
                    $logError("Output capturado durante tratamento de erro", ['output' => substr($output, 0, 1000)]);
                }
            }

            // Enviar JSON DIRETAMENTE
            http_response_code(500);
            header('Content-Type: application/json; charset=utf-8');
            echo json_encode([
                'success' => false,
                'message' => 'Erro ao processar arquivo. Verifique os logs para mais detalhes.'
            ]);
            exit; // SAIR IMEDIATAMENTE
        } finally {
            // Limpar output buffer final
            while (ob_get_level() > 0) {
                ob_end_clean();
            }

            // Restaurar error handlers
            restore_error_handler();
            restore_exception_handler();

            // Restaurar configurações de erro
            error_reporting($oldErrorReporting);
            ini_set('display_errors', $oldDisplayErrors);
            ini_set('log_errors', $oldLogErrors);
        }
    }

    private function parsearOFX(string $conteudo): array
    {
        $transacoes = [];

        // Função helper para logar
        $logError = function ($message, $context = []) {
            $logDir = ROOT_PATH . DIRECTORY_SEPARATOR . 'storage' . DIRECTORY_SEPARATOR . 'logs';
            if (!is_dir($logDir)) {
                @mkdir($logDir, 0755, true);
            }
            $logFile = $logDir . DIRECTORY_SEPARATOR . 'ofx-parse-' . date('Y-m-d') . '.log';
            $timestamp = date('Y-m-d H:i:s');
            $contextStr = !empty($context) ? ' | Context: ' . json_encode($context) : '';
            $logMessage = "[{$timestamp}] {$message}{$contextStr}\n";
            @file_put_contents($logFile, $logMessage, FILE_APPEND | LOCK_EX);
        };

        // Parse do OFX - suporta múltiplos formatos
        // O formato do arquivo pode ter tags sem fechamento (OFX 2.x)
        // Exemplo: <STMTTRN>\n<TRNTYPE>CREDIT\n<DTPOSTED>20251031100000[-03:EST]\n...

        // Buscar todas as transações - formato sem fechamento de tag
        // Captura desde <STMTTRN> até o próximo <STMTTRN> ou </BANKTRANLIST> ou </CCTRANLIST>
        preg_match_all('/<STMTTRN>(.*?)(?=<STMTTRN>|<\/BANKTRANLIST>|<\/CCTRANLIST>|$)/s', $conteudo, $matches);

        // Se não encontrou, tentar formato com fechamento
        if (empty($matches[0]) || (count($matches[0]) === 1 && empty(trim($matches[0][0])))) {
            preg_match_all('/<STMTTRN>(.*?)<\/STMTTRN>/s', $conteudo, $matches);
        }

        $logError("Total de transações encontradas no OFX: " . count($matches[0]));

        foreach ($matches[0] as $index => $transacao) {
            // Tentar múltiplos formatos de data
            $data = null;
            $dataFormatada = null;

            // Formato 1: <DTPOSTED>YYYYMMDDHHMMSS[-03:EST] ou <DTPOSTED>YYYYMMDDHHMMSS
            if (preg_match('/<DTPOSTED>(\d{8,14})/', $transacao, $dataMatch)) {
                $data = substr($dataMatch[1], 0, 8); // Pegar apenas YYYYMMDD
            }
            // Formato 2: <DTUSER>YYYYMMDD
            elseif (preg_match('/<DTUSER>(\d{8})/', $transacao, $dataMatch)) {
                $data = $dataMatch[1];
            }

            // Tentar múltiplos formatos de valor
            $valor = null;

            // Formato 1: <TRNAMT>123.45 (sem fechamento, pode ter quebra de linha depois)
            if (preg_match('/<TRNAMT>([-\d.]+)/', $transacao, $valorMatch)) {
                $valor = (float) trim($valorMatch[1]);
            }
            // Formato 2: <TRNAMT>-123.45</TRNAMT>
            elseif (preg_match('/<TRNAMT>([-\d.]+)<\/TRNAMT>/', $transacao, $valorMatch)) {
                $valor = (float) trim($valorMatch[1]);
            }

            // Descrição - múltiplos campos possíveis
            $descricao = '';
            // Descrição - múltiplos campos possíveis
            // Formato 1: <MEMO>texto</MEMO> (com fechamento)
            if (preg_match('/<MEMO>(.*?)<\/MEMO>/s', $transacao, $descricaoMatch)) {
                $descricao = trim($descricaoMatch[1]);
            }
            // Formato 2: <MEMO>texto (sem fechamento, termina na quebra de linha antes de próxima tag ou </STMTTRN>)
            elseif (preg_match('/<MEMO>(.*?)(?=\n<[A-Z]|<\/STMTTRN>|$)/s', $transacao, $descricaoMatch)) {
                $descricao = trim($descricaoMatch[1]);
            }
            // Formato 3: <NAME>texto</NAME>
            elseif (preg_match('/<NAME>(.*?)<\/NAME>/s', $transacao, $descricaoMatch)) {
                $descricao = trim($descricaoMatch[1]);
            }
            // Formato 4: <NAME>texto (sem fechamento)
            elseif (preg_match('/<NAME>(.*?)(?=\n<[A-Z]|<\/STMTTRN>|$)/s', $transacao, $descricaoMatch)) {
                $descricao = trim($descricaoMatch[1]);
            }
            // Formato 5: <DESC>texto</DESC>
            elseif (preg_match('/<DESC>(.*?)<\/DESC>/s', $transacao, $descricaoMatch)) {
                $descricao = trim($descricaoMatch[1]);
            }
            // Formato 6: <DESC>texto (sem fechamento)
            elseif (preg_match('/<DESC>(.*?)(?=\n<[A-Z]|<\/STMTTRN>|$)/s', $transacao, $descricaoMatch)) {
                $descricao = trim($descricaoMatch[1]);
            }

            // FITID
            $fitid = '';
            if (preg_match('/<FITID>(.*?)<\/FITID>/s', $transacao, $fitidMatch)) {
                $fitid = trim($fitidMatch[1]);
            } elseif (preg_match('/<FITID>(.*?)(?=\n<[A-Z]|<\/STMTTRN>|$)/s', $transacao, $fitidMatch)) {
                $fitid = trim($fitidMatch[1]);
            }

            // Se tem data, adicionar transação (valor pode ser zero)
            if ($data) {
                $ano = substr($data, 0, 4);
                $mes = substr($data, 4, 2);
                $dia = substr($data, 6, 2);
                $dataFormatada = "{$ano}-{$mes}-{$dia}";

                $transacoes[] = [
                    'data' => $dataFormatada,
                    'valor' => $valor ?? 0.0, // Se não encontrou valor, usar 0.0
                    'descricao' => $descricao,
                    'fitid' => $fitid
                ];

                $logError("Transação parseada", [
                    'index' => $index,
                    'data' => $dataFormatada,
                    'valor' => $valor ?? 0.0,
                    'descricao' => substr($descricao, 0, 50)
                ]);
            } else {
                $logError("Transação ignorada (falta data)", [
                    'index' => $index,
                    'transacao_preview' => substr($transacao, 0, 300)
                ]);
            }
        }

        $logError("Total de transações parseadas: " . count($transacoes));

        return $transacoes;
    }

    private function compararTransacoes(array $transacoesOfx, array $movimentacoesSistema): array
    {
        $conciliadas = [];
        $naoConciliadas = [];
        $sistemaSemOfx = [];

        foreach ($transacoesOfx as $transacao) {
            $encontrada = false;
            foreach ($movimentacoesSistema as $mov) {
                $dataMov = date('Y-m-d', strtotime($mov['date']));
                $valorMov = abs((float) $mov['amount']);
                $valorTrans = abs($transacao['valor']);

                // Considerar conciliada se data e valor forem próximos (tolerância de 0.01)
                if ($dataMov === $transacao['data'] && abs($valorMov - $valorTrans) < 0.01) {
                    $conciliadas[] = [
                        'ofx' => $transacao,
                        'sistema' => $mov
                    ];
                    $encontrada = true;
                    break;
                }
            }

            if (!$encontrada) {
                $naoConciliadas[] = $transacao;
            }
        }

        // Verificar movimentações do sistema que não estão no OFX
        foreach ($movimentacoesSistema as $mov) {
            $encontrada = false;
            foreach ($transacoesOfx as $transacao) {
                $dataMov = date('Y-m-d', strtotime($mov['date']));
                $valorMov = abs((float) $mov['amount']);
                $valorTrans = abs($transacao['valor']);

                if ($dataMov === $transacao['data'] && abs($valorMov - $valorTrans) < 0.01) {
                    $encontrada = true;
                    break;
                }
            }

            if (!$encontrada) {
                $sistemaSemOfx[] = $mov;
            }
        }

        return [
            'conciliadas' => $conciliadas,
            'nao_conciliadas' => $naoConciliadas,
            'sistema_sem_ofx' => $sistemaSemOfx
        ];
    }

    private function gerarHtmlResultadoConciliacao(array $resultado): string
    {
        $html = '<style>
            .comparacao-grid {
                display: grid;
                grid-template-columns: 1fr 1fr;
                gap: 1.5rem;
                margin-top: 1rem;
            }
            .comparacao-coluna {
                background: #f8f9fa;
                border: 1px solid #dee2e6;
                border-radius: 6px;
                padding: 1rem;
            }
            .comparacao-coluna h6 {
                margin-bottom: 1rem;
                font-weight: 600;
                color: var(--text-primary);
                font-size: 0.9rem;
            }
            .comparacao-tabela {
                font-size: 0.85rem;
            }
            .comparacao-tabela thead th {
                background: #e9ecef;
                font-weight: 500;
                font-size: 0.8rem;
                padding: 0.5rem;
            }
            .comparacao-tabela tbody td {
                padding: 0.5rem;
                border-bottom: 1px solid #dee2e6;
            }
            .comparacao-tabela tbody tr:last-child td {
                border-bottom: none;
            }
            .linha-conciliada {
                background-color: #d1e7dd !important;
            }
            .linha-nao-conciliada {
                background-color: #f8d7da !important;
            }
            .resumo-conciliacao {
                display: flex;
                gap: 1rem;
                margin-bottom: 1.5rem;
                flex-wrap: wrap;
            }
            .resumo-item {
                padding: 0.75rem 1rem;
                border-radius: 6px;
                font-size: 0.875rem;
                font-weight: 500;
            }
            .resumo-conciliadas {
                background: #d1e7dd;
                color: #0f5132;
            }
            .resumo-ofx {
                background: #fff3cd;
                color: #856404;
            }
            .resumo-sistema {
                background: #cfe2ff;
                color: #084298;
            }
            /* Checkbox moderno */
            .checkbox-wrapper {
                position: relative;
                display: inline-block;
                width: 24px;
                height: 24px;
            }
            .checkbox-conciliacao {
                width: 24px;
                height: 24px;
                cursor: pointer;
                appearance: none;
                -webkit-appearance: none;
                -moz-appearance: none;
                border: 2px solid #6c757d;
                border-radius: 4px;
                background: white;
                position: relative;
                transition: all 0.2s ease;
                margin: 0;
            }
            .checkbox-conciliacao:hover {
                border-color: var(--primary-color);
                background: #f8f9fa;
            }
            .checkbox-conciliacao:checked {
                background: var(--primary-color);
                border-color: var(--primary-color);
            }
            .checkbox-conciliacao:checked::after {
                content: "✓";
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                color: white;
                font-size: 14px;
                font-weight: bold;
                line-height: 1;
            }
            .checkbox-conciliacao:focus {
                outline: none;
                box-shadow: 0 0 0 3px rgba(0, 18, 35, 0.1);
            }
            .checkbox-conciliacao:indeterminate {
                background: var(--primary-color);
                border-color: var(--primary-color);
            }
            .checkbox-conciliacao:indeterminate::after {
                content: "−";
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                color: white;
                font-size: 16px;
                font-weight: bold;
                line-height: 1;
            }
            .totalizador {
                background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
                padding: 1rem;
                border-radius: 8px;
                margin-top: 1rem;
                font-weight: 600;
                font-size: 0.95rem;
                border: 1px solid #dee2e6;
                display: flex;
                justify-content: space-between;
                align-items: center;
            }
            .totalizador .label {
                color: #6c757d;
                font-weight: 500;
            }
            .totalizador .valor {
                color: var(--primary-color);
                font-size: 1.1rem;
                font-weight: 700;
                transition: transform 0.2s ease, color 0.2s ease;
            }
            .totalizador .valor.animando {
                transform: scale(1.15);
                color: var(--primary-color);
            }
            .btn-lancar-ofx {
                padding: 0.35rem 0.6rem;
                font-size: 0.8rem;
                border: none;
                background: #6c757d;
                color: white;
                border-radius: 5px;
                cursor: pointer;
                opacity: 0.75;
                transition: all 0.2s ease;
                display: inline-flex;
                align-items: center;
                gap: 0.25rem;
            }
            .btn-lancar-ofx:hover {
                opacity: 1;
                background: #5a6268;
                transform: translateY(-1px);
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
            .btn-lancar-ofx:active {
                transform: translateY(0);
            }
            .btn-lancar-ofx:disabled {
                opacity: 0.4;
                cursor: not-allowed;
                transform: none;
            }
        </style>';

        // Resumo
        $html .= '<div class="resumo-conciliacao">';
        $html .= '<div class="resumo-item resumo-conciliadas">';
        $html .= '<strong>Conciliadas:</strong> ' . count($resultado['conciliadas']);
        $html .= '</div>';
        $html .= '<div class="resumo-item resumo-ofx">';
        $html .= '<strong>Não Conciliadas (OFX):</strong> ' . count($resultado['nao_conciliadas']);
        $html .= '</div>';
        $html .= '<div class="resumo-item resumo-sistema">';
        $html .= '<strong>Não Conciliadas (Sistema):</strong> ' . count($resultado['sistema_sem_ofx']);
        $html .= '</div>';
        $html .= '</div>';

        // Preparar todas as transações para comparação lado a lado
        // Criar um array unificado com todas as transações, garantindo que linhas correspondentes fiquem alinhadas
        $todasTransacoes = [];

        // Primeiro, adicionar transações conciliadas (já têm correspondência)
        foreach ($resultado['conciliadas'] as $item) {
            $todasTransacoes[] = [
                'tipo' => 'conciliada',
                'ofx' => $item['ofx'],
                'sistema' => $item['sistema'],
                'data_comparacao' => $item['ofx']['data'] // Usar data do OFX para ordenação
            ];
        }

        // Adicionar transações não conciliadas do OFX
        foreach ($resultado['nao_conciliadas'] as $trans) {
            $todasTransacoes[] = [
                'tipo' => 'ofx_nao_conciliada',
                'ofx' => $trans,
                'sistema' => null,
                'data_comparacao' => $trans['data']
            ];
        }

        // Adicionar movimentações do sistema não encontradas no OFX
        foreach ($resultado['sistema_sem_ofx'] as $mov) {
            $todasTransacoes[] = [
                'tipo' => 'sistema_nao_conciliada',
                'ofx' => null,
                'sistema' => $mov,
                'data_comparacao' => date('Y-m-d', strtotime($mov['date']))
            ];
        }

        // Ordenar por data (mais recente primeiro) e depois por valor para facilitar comparação
        usort($todasTransacoes, function ($a, $b) {
            // Primeiro ordena por data
            $cmpData = strcmp($b['data_comparacao'], $a['data_comparacao']);
            if ($cmpData !== 0) {
                return $cmpData;
            }
            // Se a data for igual, ordena por valor (absoluto)
            // Garantir que os valores sejam numéricos antes de usar abs()
            $valorA = 0;
            if ($a['ofx'] && isset($a['ofx']['valor'])) {
                $valorA = abs((float) $a['ofx']['valor']);
            } elseif ($a['sistema'] && isset($a['sistema']['amount'])) {
                $valorA = abs((float) $a['sistema']['amount']);
            }

            $valorB = 0;
            if ($b['ofx'] && isset($b['ofx']['valor'])) {
                $valorB = abs((float) $b['ofx']['valor']);
            } elseif ($b['sistema'] && isset($b['sistema']['amount'])) {
                $valorB = abs((float) $b['sistema']['amount']);
            }

            return $valorB <=> $valorA;
        });

        // Grid de comparação lado a lado
        $html .= '<div class="comparacao-grid">';

        // Coluna: Dados do Sistema
        $html .= '<div class="comparacao-coluna">';
        $html .= '<h6><i class="bi bi-database me-2"></i> Movimentações do Sistema</h6>';
        $html .= '<div class="table-responsive">';
        $html .= '<table class="table table-sm comparacao-tabela mb-0">';
        $html .= '<thead><tr><th style="width: 40px;"><input type="checkbox" id="check-all-sistema" class="checkbox-conciliacao" title="Marcar todas"></th><th>ID</th><th>Data</th><th>Valor</th><th>Descrição</th></tr></thead>';
        $html .= '<tbody>';

        foreach ($todasTransacoes as $index => $item) {
            if ($item['sistema']) {
                $classeLinha = $item['tipo'] === 'conciliada' ? 'linha-conciliada' : 'linha-nao-conciliada';
                $sistemaId = $item['sistema']['id'];
                $valorSistema = (float) ($item['sistema']['amount'] ?? 0);
                $tipoSistema = $item['sistema']['type'] ?? 'entrada';
                $dataSistema = $item['sistema']['date'] ?? '';

                $html .= '<tr class="' . $classeLinha . '" data-sistema-id="' . $sistemaId . '" data-valor="' . $valorSistema . '">';
                $html .= '<td style="text-align: center;"><div class="checkbox-wrapper"><input type="checkbox" class="checkbox-conciliacao checkbox-sistema" data-id="' . $sistemaId . '" data-valor="' . $valorSistema . '"></div></td>';
                $html .= '<td>' . htmlspecialchars($sistemaId) . '</td>';
                $html .= '<td>' . date('d/m/Y', strtotime($dataSistema)) . '</td>';
                $html .= '<td class="' . ($tipoSistema === 'entrada' ? 'text-success' : 'text-danger') . '">';
                $valorFormatado = number_format(abs($valorSistema), 2, ',', '.');
                $html .= ($tipoSistema === 'entrada' ? '+' : '-') . ' R$ ' . $valorFormatado;
                $html .= '</td>';
                $html .= '<td>' . htmlspecialchars($item['sistema']['description'] ?? '') . '</td>';
                $html .= '</tr>';
            } else {
                $html .= '<tr class="linha-nao-conciliada">';
                $html .= '<td></td>';
                $html .= '<td colspan="4" class="text-center text-muted" style="font-style: italic;">-</td>';
                $html .= '</tr>';
            }
        }

        $html .= '</tbody></table>';
        $html .= '</div>';
        $html .= '<div class="totalizador" id="totalizador-sistema">';
        $html .= '<span class="label">Total Selecionado:</span>';
        $html .= '<span class="valor" id="total-sistema">R$ 0,00</span>';
        $html .= '</div>';
        $html .= '</div>';

        // Coluna: Dados do OFX
        $html .= '<div class="comparacao-coluna">';
        $html .= '<h6><i class="bi bi-file-earmark-text me-2"></i> Transações do Arquivo OFX</h6>';
        $html .= '<div class="table-responsive">';
        $html .= '<table class="table table-sm comparacao-tabela mb-0">';
        $html .= '<thead><tr><th style="width: 50px; text-align: center;"><div class="checkbox-wrapper"><input type="checkbox" id="check-all-ofx" class="checkbox-conciliacao" title="Marcar todas"></div></th><th>Data</th><th>Valor</th><th>Descrição</th><th style="width: 80px;">Ação</th></tr></thead>';
        $html .= '<tbody>';

        foreach ($todasTransacoes as $index => $item) {
            if ($item['ofx']) {
                $classeLinha = $item['tipo'] === 'conciliada' ? 'linha-conciliada' : 'linha-nao-conciliada';
                $valorOfx = (float) ($item['ofx']['valor'] ?? 0);
                $dataOfx = $item['ofx']['data'] ?? '';
                $descricaoOfx = $item['ofx']['descricao'] ?? '';
                $fitidOfx = $item['ofx']['fitid'] ?? '';

                // Criar hash único para identificar a transação OFX
                $ofxHash = md5($dataOfx . '|' . $valorOfx . '|' . $fitidOfx);

                $html .= '<tr class="' . $classeLinha . '" data-ofx-hash="' . $ofxHash . '" data-valor="' . $valorOfx . '">';
                $html .= '<td style="text-align: center;"><div class="checkbox-wrapper"><input type="checkbox" class="checkbox-conciliacao checkbox-ofx" data-hash="' . $ofxHash . '" data-valor="' . $valorOfx . '"></div></td>';
                $html .= '<td>' . date('d/m/Y', strtotime($dataOfx)) . '</td>';
                $html .= '<td class="' . ($valorOfx >= 0 ? 'text-success' : 'text-danger') . '">';
                $valorFormatado = number_format(abs($valorOfx), 2, ',', '.');
                $html .= 'R$ ' . $valorFormatado;
                $html .= '</td>';
                $html .= '<td>' . htmlspecialchars($descricaoOfx) . '</td>';
                $html .= '<td>';
                // Botão discreto para criar lançamento
                $html .= '<button type="button" class="btn-lancar-ofx" data-ofx-data="' . htmlspecialchars(json_encode([
                    'data' => $dataOfx,
                    'valor' => $valorOfx,
                    'descricao' => $descricaoOfx,
                    'fitid' => $fitidOfx
                ])) . '" title="Criar lançamento no fluxo de caixa">';
                $html .= '<i class="bi bi-plus-circle"></i>';
                $html .= '</button>';
                $html .= '</td>';
                $html .= '</tr>';
            } else {
                $html .= '<tr class="linha-nao-conciliada">';
                $html .= '<td></td>';
                $html .= '<td colspan="4" class="text-center text-muted" style="font-style: italic;">-</td>';
                $html .= '</tr>';
            }
        }

        $html .= '</tbody></table>';
        $html .= '</div>';
        $html .= '<div class="totalizador" id="totalizador-ofx">';
        $html .= '<span class="label">Total Selecionado:</span>';
        $html .= '<span class="valor" id="total-ofx">R$ 0,00</span>';
        $html .= '</div>';
        $html .= '</div>';

        $html .= '</div>';

        // JavaScript para checkboxes e totalizadores
        $html .= '<script>
        (function() {
            // Função para formatar valor
            function formatarValor(valor) {
                const valorAbs = Math.abs(valor);
                return "R$ " + valorAbs.toFixed(2).replace(".", ",").replace(/\B(?=(\d{3})+(?!\d))/g, ".");
            }

            // Calcular total do sistema
            function calcularTotalSistema() {
                let total = 0;
                let count = 0;
                const checkboxes = document.querySelectorAll(".checkbox-sistema");

                checkboxes.forEach(function(cb) {
                    if (cb.checked) {
                        const valor = parseFloat(cb.getAttribute("data-valor") || cb.dataset.valor || 0);
                        total += valor;
                        count++;
                    }
                });

                const totalElement = document.getElementById("total-sistema");
                if (totalElement) {
                    totalElement.textContent = formatarValor(total);
                    // Adicionar animação
                    totalElement.classList.add("animando");
                    setTimeout(function() {
                        totalElement.classList.remove("animando");
                    }, 300);
                }

                // Atualizar checkbox "marcar todas" do sistema
                const checkAllSistema = document.getElementById("check-all-sistema");
                if (checkAllSistema) {
                    const totalCheckboxes = checkboxes.length;
                    checkAllSistema.checked = count > 0 && count === totalCheckboxes;
                    checkAllSistema.indeterminate = count > 0 && count < totalCheckboxes;
                }
            }

            // Calcular total do OFX
            function calcularTotalOfx() {
                let total = 0;
                let count = 0;
                const checkboxes = document.querySelectorAll(".checkbox-ofx");

                checkboxes.forEach(function(cb) {
                    if (cb.checked) {
                        const valor = parseFloat(cb.getAttribute("data-valor") || cb.dataset.valor || 0);
                        total += valor;
                        count++;
                    }
                });

                const totalElement = document.getElementById("total-ofx");
                if (totalElement) {
                    totalElement.textContent = formatarValor(total);
                    // Adicionar animação
                    totalElement.classList.add("animando");
                    setTimeout(function() {
                        totalElement.classList.remove("animando");
                    }, 300);
                }

                // Atualizar checkbox "marcar todas" do OFX
                const checkAllOfx = document.getElementById("check-all-ofx");
                if (checkAllOfx) {
                    const totalCheckboxes = checkboxes.length;
                    checkAllOfx.checked = count > 0 && count === totalCheckboxes;
                    checkAllOfx.indeterminate = count > 0 && count < totalCheckboxes;
                }
            }

            // Função para anexar event listeners
            function anexarEventListeners() {
                // Marcar/desmarcar todas do sistema
                const checkAllSistema = document.getElementById("check-all-sistema");
                if (checkAllSistema && !checkAllSistema.hasAttribute("data-listener-attached")) {
                    checkAllSistema.setAttribute("data-listener-attached", "true");
                    checkAllSistema.addEventListener("change", function() {
                        const checked = this.checked;
                        document.querySelectorAll(".checkbox-sistema").forEach(function(cb) {
                            cb.checked = checked;
                        });
                        calcularTotalSistema();
                    });
                }

                // Marcar/desmarcar todas do OFX
                const checkAllOfx = document.getElementById("check-all-ofx");
                if (checkAllOfx && !checkAllOfx.hasAttribute("data-listener-attached")) {
                    checkAllOfx.setAttribute("data-listener-attached", "true");
                    checkAllOfx.addEventListener("change", function() {
                        const checked = this.checked;
                        document.querySelectorAll(".checkbox-ofx").forEach(function(cb) {
                            cb.checked = checked;
                        });
                        calcularTotalOfx();
                    });
                }

                // Event listeners para checkboxes individuais do sistema
                document.querySelectorAll(".checkbox-sistema").forEach(function(cb) {
                    if (!cb.hasAttribute("data-listener-attached")) {
                        cb.setAttribute("data-listener-attached", "true");
                        cb.addEventListener("change", function() {
                            calcularTotalSistema();
                        });
                    }
                });

                // Event listeners para checkboxes individuais do OFX
                document.querySelectorAll(".checkbox-ofx").forEach(function(cb) {
                    if (!cb.hasAttribute("data-listener-attached")) {
                        cb.setAttribute("data-listener-attached", "true");
                        cb.addEventListener("change", function() {
                            calcularTotalOfx();
                        });
                    }
                });
            }

            // Função para inicializar tudo
            function inicializarConciliacao() {
                // Anexar event listeners
                anexarEventListeners();

                // Inicializar totais
                calcularTotalSistema();
                calcularTotalOfx();
            }

            // Executar quando o DOM estiver pronto
            if (document.readyState === "loading") {
                document.addEventListener("DOMContentLoaded", inicializarConciliacao);
            } else {
                // DOM já está pronto
                inicializarConciliacao();
            }

            // Também executar após um pequeno delay para garantir que o HTML foi inserido
            setTimeout(inicializarConciliacao, 300);

            // Usar MutationObserver para detectar quando novos elementos são adicionados
            const observer = new MutationObserver(function(mutations) {
                let shouldReinit = false;
                mutations.forEach(function(mutation) {
                    if (mutation.addedNodes.length > 0) {
                        mutation.addedNodes.forEach(function(node) {
                            if (node.nodeType === 1 && node.classList && (node.classList.contains("checkbox-sistema") || node.classList.contains("checkbox-ofx") || node.querySelector(".checkbox-sistema") || node.querySelector(".checkbox-ofx"))) {
                                shouldReinit = true;
                            }
                        });
                    }
                });
                if (shouldReinit) {
                    setTimeout(inicializarConciliacao, 100);
                }
            });

            // Observar mudanças no body
            if (document.body) {
                observer.observe(document.body, {
                    childList: true,
                    subtree: true
                });
            }

            // Botões para criar lançamento do OFX
            document.querySelectorAll(".btn-lancar-ofx").forEach(function(btn) {
                btn.addEventListener("click", function() {
                    const ofxData = JSON.parse(this.dataset.ofxData || "{}");

                    if (!ofxData.data || ofxData.valor === undefined) {
                        Toast.error("Dados inválidos para criar lançamento");
                        return;
                    }

                    // Obter conta bancária do formulário de conciliação
                    const contaBancariaId = document.getElementById("conta_bancaria_id")?.value || "";

                    // Confirmar criação
                    Swal.fire({
                        title: "Criar Lançamento?",
                        html: "Data: " + ofxData.data + "<br>Valor: " + formatarValor(ofxData.valor) + "<br>Descrição: " + (ofxData.descricao || "-"),
                        icon: "question",
                        showCancelButton: true,
                        confirmButtonText: "Criar",
                        cancelButtonText: "Cancelar"
                    }).then(function(result) {
                        if (result.isConfirmed) {
                            // Desabilitar botão
                            btn.disabled = true;
                            btn.innerHTML = "<span class=\"spinner-border spinner-border-sm\"></span>";

                            // Fazer requisição para criar lançamento
                            fetch(appUrl("/fluxo-caixa/conciliacao/criar-lancamento"), {
                                method: "POST",
                                headers: {
                                    "Content-Type": "application/json"
                                },
                                body: JSON.stringify({
                                    data: ofxData.data,
                                    valor: ofxData.valor,
                                    descricao: ofxData.descricao || "",
                                    fitid: ofxData.fitid || "",
                                    conta_bancaria_id: contaBancariaId
                                })
                            })
                            .then(response => response.json())
                            .then(data => {
                                if (data.success) {
                                    Toast.success("Lançamento criado com sucesso!");
                                    // Atualizar página após 1 segundo
                                    setTimeout(function() {
                                        location.reload();
                                    }, 1000);
                                } else {
                                    Toast.error(data.message || "Erro ao criar lançamento");
                                    btn.disabled = false;
                                    btn.innerHTML = "<i class=\"bi bi-plus-circle\"></i>";
                                }
                            })
                            .catch(error => {
                                console.error("Erro:", error);
                                Toast.error("Erro ao criar lançamento");
                                btn.disabled = false;
                                btn.innerHTML = "<i class=\"bi bi-plus-circle\"></i>";
                            });
                        }
                    });
                });
            });
        })();
        </script>';

        return $html;
    }

    public function criarLancamentoOfx(): void
    {
        // Verificar permissão de criação
        if (!$this->canCreate('fluxo-caixa')) {
            $this->response->json([
                'success' => false,
                'message' => 'Você não tem permissão para criar movimentações de fluxo de caixa.'
            ]);
            return;
        }

        try {
            // Limpar output buffer
            while (ob_get_level() > 0) {
                ob_end_clean();
            }

            $companyId = $this->getCompanyId();

            // Receber dados JSON
            $json = file_get_contents('php://input');
            $data = json_decode($json, true);

            if (!$data) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Dados inválidos'
                ]);
                return;
            }

            $date = $data['data'] ?? '';
            $valor = (float) ($data['valor'] ?? 0);
            $descricao = $data['descricao'] ?? '';
            $fitid = $data['fitid'] ?? '';

            if (empty($date) || $valor == 0) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Data e valor são obrigatórios'
                ]);
                return;
            }

            // Determinar tipo (entrada ou saída) baseado no valor
            $type = $valor >= 0 ? 'entrada' : 'saida';
            $amount = abs($valor);

            // Calcular saldo atual
            $stmt = $this->db->prepare("
                SELECT
                    COALESCE(SUM(CASE WHEN type = 'entrada' THEN amount ELSE -amount END), 0) as saldo_atual
                FROM fluxo_caixa
                WHERE company_id = :company_id
            ");
            $stmt->execute(['company_id' => $companyId]);
            $saldoAtual = $stmt->fetch()['saldo_atual'] ?? 0;

            $novoSaldo = ($type === 'entrada') ? $saldoAtual + $amount : $saldoAtual - $amount;

            // Preparar dados para inserção
            $insertData = [
                'company_id' => $companyId,
                'date' => $date,
                'type' => $type,
                'category' => 'Conciliação Bancária',
                'description' => $descricao ?: 'Lançamento do OFX' . ($fitid ? ' (FITID: ' . $fitid . ')' : ''),
                'amount' => $amount,
                'balance' => $novoSaldo,
                'reference_type' => 'conciliacao_ofx',
                'reference_id' => $fitid ?: null,
            ];

            $this->db->beginTransaction();

            // Verificar colunas opcionais
            $columns = $this->getTableColumns('fluxo_caixa');
            $hasContaBancaria = in_array('conta_bancaria_id', $columns);

            $campos = 'company_id, date, type, category, description, amount, balance, reference_type, reference_id, created_at';
            $valores = ':company_id, :date, :type, :category, :description, :amount, :balance, :reference_type, :reference_id, NOW()';

            if ($hasContaBancaria && !empty($data['conta_bancaria_id'])) {
                $campos .= ', conta_bancaria_id';
                $valores .= ', :conta_bancaria_id';
                $insertData['conta_bancaria_id'] = (int) $data['conta_bancaria_id'];
            }

            $stmt = $this->db->prepare("
                INSERT INTO fluxo_caixa ({$campos})
                VALUES ({$valores})
            ");
            $stmt->execute($insertData);
            $movimentoId = (int) $this->db->lastInsertId();

            $this->logActivity('create', 'fluxo_caixa', $movimentoId, $insertData);
            $this->db->commit();

            $this->response->json([
                'success' => true,
                'message' => 'Lançamento criado com sucesso',
                'id' => $movimentoId
            ]);

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao criar lançamento do OFX: " . $e->getMessage());

            // Limpar output buffer
            while (ob_get_level() > 0) {
                ob_end_clean();
            }

            $this->response->json([
                'success' => false,
                'message' => 'Erro ao criar lançamento: ' . $e->getMessage()
            ]);
        }
    }

    private function getTableColumns(string $table): array
    {
        try {
            // Verificar se a tabela existe primeiro
            $stmt = $this->db->query("SHOW TABLES LIKE '{$table}'");
            if (!$stmt->fetch()) {
                return [];
            }

            $stmt = $this->db->query("SHOW COLUMNS FROM {$table}");
            return array_column($stmt->fetchAll(), 'Field');
        } catch (Exception $e) {
            error_log("Erro ao obter colunas da tabela {$table}: " . $e->getMessage());
            return [];
        }
    }

    private function getPessoas(): array
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar se a tabela existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'pessoas'");
            if (!$stmt->fetch()) {
                return [];
            }

            $sql = "SELECT id, name, trade_name, document, email, phone, mobile
                    FROM pessoas
                    WHERE company_id = :company_id AND is_active = 1
                    ORDER BY name ASC";

            $stmt = $this->db->prepare($sql);
            $stmt->execute(['company_id' => $companyId]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao carregar pessoas: " . $e->getMessage());
            return [];
        }
    }

    private function getUsuarios(): array
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar se a tabela existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'users'");
            if (!$stmt->fetch()) {
                return [];
            }

            $sql = "SELECT id, name, email
                    FROM users
                    WHERE company_id = :company_id AND is_active = 1
                    ORDER BY name ASC";

            $stmt = $this->db->prepare($sql);
            $stmt->execute(['company_id' => $companyId]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao carregar usuários: " . $e->getMessage());
            return [];
        }
    }
}