<?php

namespace App\Controllers;

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

class ContasReceberController extends BaseController
{
    /**
     * Lista todas as contas a receber
     */
    public function index(): void
    {
        // Verificar permissão de visualização
        if (!$this->canView('contas-receber')) {
            $this->response->forbidden('Você não tem permissão para visualizar contas a receber.');
            return;
        }

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

            // Verificar estrutura da tabela
            $stmtCols = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $colunas = $stmtCols->fetchAll(\PDO::FETCH_COLUMN, 0);
            $temPessoaId = in_array('pessoa_id', $colunas ?? [], true);
            $temCustomerId = in_array('customer_id', $colunas ?? [], true);
            $temAmountPaid = in_array('amount_paid', $colunas ?? [], true);
            $temAmountReceived = in_array('amount_received', $colunas ?? [], true);

            // Verificar se colunas Shipay existem
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber LIKE 'shipay_%'");
            $shipayColumns = $stmtCheck->fetchAll();
            $hasShipayColumns = !empty($shipayColumns);
            $shipayFields = $hasShipayColumns ? ', cr.shipay_charge_id, cr.shipay_status' : '';

            // Preparar JOIN com pessoas
            $selectCliente = '';
            $joinCliente = '';
            if ($temPessoaId || $temCustomerId) {
                $selectCliente = ', p.name as customer_name, p.document as customer_document';
                $campoJoin = $temPessoaId ? 'pessoa_id' : 'customer_id';
                $joinCliente = "LEFT JOIN pessoas p ON cr.{$campoJoin} = p.id";
            }

            // Filtros
            $filtroStatus = $this->request->get('status') ?? '';
            $filtroCliente = $this->request->get('cliente') ?? '';
            $filtroDataInicio = $this->request->get('data_inicio') ?? '';
            $filtroDataFim = $this->request->get('data_fim') ?? '';

            // Construir WHERE
            $where = ['cr.company_id = :company_id'];
            $params = ['company_id' => $companyId];

            if (!empty($filtroStatus)) {
                $where[] = 'cr.status = :status';
                $params['status'] = $filtroStatus;
            }

            if (!empty($filtroCliente)) {
                $where[] = '(p.name LIKE :cliente OR p.nome LIKE :cliente OR p.document LIKE :cliente)';
                $params['cliente'] = "%{$filtroCliente}%";
            }

            if (!empty($filtroDataInicio)) {
                $where[] = 'cr.due_date >= :data_inicio';
                $params['data_inicio'] = $filtroDataInicio;
            }

            if (!empty($filtroDataFim)) {
                $where[] = 'cr.due_date <= :data_fim';
                $params['data_fim'] = $filtroDataFim;
            }

            $whereClause = implode(' AND ', $where);

            // Buscar contas
            $stmt = $this->db->prepare("
                SELECT
                    cr.*
                    {$selectCliente}
                    {$shipayFields}
                FROM contas_receber cr
                {$joinCliente}
                WHERE {$whereClause}
                ORDER BY cr.due_date ASC, cr.id DESC
            ");
            $stmt->execute($params);
            $contas = $stmt->fetchAll();

            // Calcular resumos
            $hoje = date('Y-m-d');
            $campoAmountPaid = $temAmountPaid ? 'amount_paid' : ($temAmountReceived ? 'amount_received' : '0');

            $resumo = [
                'total_receber' => 0,
                'total_recebido' => 0,
                'total_vencidas' => 0,
                'vencendo_hoje' => 0
            ];

            foreach ($contas as $conta) {
                $valor = (float)($conta['amount'] ?? 0);
                $valorPago = (float)($conta[$campoAmountPaid] ?? 0);
                $valorRestante = (float)($conta['amount_remaining'] ?? $valor);
                $dataVencimento = $conta['due_date'] ?? '';
                $status = $conta['status'] ?? 'pendente';

                // Total a receber (soma de todas as contas)
                $resumo['total_receber'] += $valorRestante;

                // Total recebido
                if ($status === 'pago' || $valorPago > 0) {
                    $resumo['total_recebido'] += $valorPago;
                }

                // Vencidas (vencimento < hoje e status != pago)
                if ($dataVencimento < $hoje && $status !== 'pago') {
                    $resumo['total_vencidas'] += $valorRestante;
                }

                // Vencendo hoje
                if ($dataVencimento === $hoje && $status !== 'pago') {
                    $resumo['vencendo_hoje'] += $valorRestante;
                }
            }

            $this->view('contas-receber/index', [
                'contas' => $contas,
                'resumo' => $resumo,
                'filtros' => [
                    'status' => $filtroStatus,
                    'cliente' => $filtroCliente,
                    'data_inicio' => $filtroDataInicio,
                    'data_fim' => $filtroDataFim
                ],
                'pageTitle' => 'Contas a Receber'
            ]);

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

    /**
     * Exibe formulário de criação
     */
    public function create(): void
    {
        // Verificar permissão de criação
        if (!$this->canCreate('contas-receber')) {
            $this->response->forbidden('Você não tem permissão para criar contas a receber.');
            return;
        }

        try {
            $pessoas = $this->getPessoas();
            $metodosPagamento = $this->getMetodosPagamento();
            $contasBancarias = $this->getContasBancarias();
            $planoContas = $this->getPlanoContas();
            $centroCustos = $this->getCentroCustos();

            $this->view('contas-receber/create', [
                'pessoas' => $pessoas,
                'metodosPagamento' => $metodosPagamento,
                'contasBancarias' => $contasBancarias,
                'planoContas' => $planoContas,
                'centroCustos' => $centroCustos,
            'pageTitle' => 'Nova Conta a Receber'
        ]);
        } catch (Exception $e) {
            error_log("Erro ao carregar formulário: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

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

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

            $amount = (float)($this->request->post('amount') ?? 0);
            $amountPaid = (float)($this->request->post('amount_paid') ?? 0);
            $amountRemaining = $amount - $amountPaid;

            $data = [
                'company_id' => $companyId,
                'pessoa_id' => $this->request->post('pessoa_id') ?: null,
                'venda_id' => $this->request->post('venda_id') ?: null,
                'numero' => $this->request->post('numero') ?: null,
                'description' => $this->request->post('description') ?? '',
                'amount' => $amount,
                'amount_paid' => $amountPaid,
                'amount_remaining' => $amountRemaining,
                'due_date' => $this->request->post('due_date') ?? '',
                'payment_date' => $this->request->post('payment_date') ?: null,
                'status' => $this->request->post('status') ?? 'pendente',
                'metodo_pagamento_id' => $this->request->post('metodo_pagamento_id') ?: null,
                'conta_bancaria_id' => $this->request->post('conta_bancaria_id') ?: null,
                'plano_conta_id' => $this->request->post('plano_conta_id') ?: null,
                'centro_custo_id' => $this->request->post('centro_custo_id') ?: null,
                'notes' => $this->request->post('notes') ?: null,
                'created_by' => $this->getUserId(),
            ];

            // Validações
            if (empty($data['description'])) {
                $this->error('A descrição é obrigatória');
                return;
            }

            if ($data['amount'] <= 0) {
                $this->error('O valor deve ser maior que zero');
                return;
            }

            if (empty($data['due_date'])) {
                $this->error('A data de vencimento é obrigatória');
                return;
            }

            $this->db->beginTransaction();

            // Detectar estrutura da tabela dinamicamente
            $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', 'status', 'notes'];
            $valores = [':company_id', ':description', ':amount', ':amount_remaining', ':due_date', ':status', ':notes'];

            if (in_array('pessoa_id', $columnNames)) {
                $campos[] = 'pessoa_id';
                $valores[] = ':pessoa_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('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('created_by', $columnNames)) {
                $campos[] = 'created_by';
                $valores[] = ':created_by';
            }

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

            $sql = "INSERT INTO contas_receber (" . implode(', ', $campos) . ") VALUES (" . implode(', ', $valores) . ")";

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

            // Preparar dados para bind
            $dadosBind = [
                'company_id' => $companyId,
                'description' => $data['description'],
                'amount' => $data['amount'],
                'amount_remaining' => $data['amount_remaining'],
                'due_date' => $data['due_date'],
                'status' => $data['status'],
                'notes' => $data['notes'],
            ];

            if (in_array('pessoa_id', $columnNames) && $data['pessoa_id']) {
                $dadosBind['pessoa_id'] = $data['pessoa_id'];
            }
            if (in_array('venda_id', $columnNames) && $data['venda_id']) {
                $dadosBind['venda_id'] = $data['venda_id'];
            }
            if (in_array('numero', $columnNames) && $data['numero']) {
                $dadosBind['numero'] = $data['numero'];
            }
            if (in_array('amount_paid', $columnNames) || in_array('amount_received', $columnNames)) {
                $dadosBind['amount_paid'] = $data['amount_paid'];
            }
            if (in_array('payment_date', $columnNames) && $data['payment_date']) {
                $dadosBind['payment_date'] = $data['payment_date'];
            }
            if ((in_array('metodo_pagamento_id', $columnNames) || in_array('payment_method_id', $columnNames)) && $data['metodo_pagamento_id']) {
                $dadosBind['metodo_pagamento_id'] = $data['metodo_pagamento_id'];
            }
            if (in_array('conta_bancaria_id', $columnNames) && $data['conta_bancaria_id']) {
                $dadosBind['conta_bancaria_id'] = $data['conta_bancaria_id'];
            }
            if (in_array('plano_conta_id', $columnNames) && $data['plano_conta_id']) {
                $dadosBind['plano_conta_id'] = $data['plano_conta_id'];
            }
            if (in_array('centro_custo_id', $columnNames) && $data['centro_custo_id']) {
                $dadosBind['centro_custo_id'] = $data['centro_custo_id'];
            }
            if (in_array('created_by', $columnNames) && $data['created_by']) {
                $dadosBind['created_by'] = $data['created_by'];
            }

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

            // Gerar boleto automaticamente se configurado
            if (!empty($data['conta_bancaria_id'])) {
                try {
                    // Verificar se a conta bancária é do Itaú e tem integração configurada
                    $this->gerarBoletoItau($contaId, $data);
                } catch (Exception $e) {
                    error_log("Erro ao gerar boleto Itaú: " . $e->getMessage());
                    // Não interrompe o fluxo, apenas loga o erro
                }
            }

            // Se método de pagamento for Shipay, gerar boleto automaticamente
            if (!empty($data['metodo_pagamento_id'])) {
                try {
                    $this->gerarBoletoShipay($contaId, $data);
                } catch (Exception $e) {
                    error_log("Erro ao gerar boleto Shipay: " . $e->getMessage());
                    // Não interrompe o fluxo, apenas loga o erro
                }
            }

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

            $this->db->commit();

            $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 cadastrar conta a receber: ' . $e->getMessage());
        }
    }

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

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

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

            $pessoas = $this->getPessoas();
            $metodosPagamento = $this->getMetodosPagamento();
            $contasBancarias = $this->getContasBancarias();
            $planoContas = $this->getPlanoContas();
            $centroCustos = $this->getCentroCustos();

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

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

    /**
     * Atualiza uma conta a receber
     */
    public function update(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('contas-receber')) {
            $this->response->forbidden('Você não tem permissão para editar contas a receber.');
            return;
        }

        try {
            $id = (int) $this->request->post('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);
            $amountRemaining = $amount - $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', 'status = :status', 'notes = :notes'];

            if (in_array('pessoa_id', $columnNames)) {
                $sets[] = 'pessoa_id = :pessoa_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('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';
            }

            $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') ?? '',
                'status' => $this->request->post('status') ?? 'pendente',
                'notes' => $this->request->post('notes') ?: null,
            ];

            if (in_array('pessoa_id', $columnNames)) {
                $dadosBind['pessoa_id'] = $this->request->post('pessoa_id') ?: 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)) {
                $dadosBind['payment_date'] = $this->request->post('payment_date') ?: null;
            }
            if (in_array('metodo_pagamento_id', $columnNames) || in_array('payment_method_id', $columnNames)) {
                $dadosBind['metodo_pagamento_id'] = $this->request->post('metodo_pagamento_id') ?: null;
            }
            if (in_array('conta_bancaria_id', $columnNames)) {
                $dadosBind['conta_bancaria_id'] = $this->request->post('conta_bancaria_id') ?: 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;
            }

            $this->db->beginTransaction();

            $stmt->execute($dadosBind);

            // Se status mudou para 'pago', verificar se deve gerar lançamento no fluxo de caixa
            $statusNovo = $dadosBind['status'];
            $statusAntigo = $conta['status'];

            if ($statusNovo === 'pago' && $statusAntigo !== 'pago') {
                $this->criarLancamentoFluxoCaixa($id, $amount, $this->request->post('payment_date') ?: date('Y-m-d'), $dadosBind['description']);
            }

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

            $this->db->commit();

            $this->success('Conta a receber atualizada com sucesso', [
                'redirect' => UrlHelper::url('/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());
            $this->error('Erro ao atualizar conta a receber: ' . $e->getMessage());
        }
    }

    /**
     * Marca conta como recebida
     */
    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 campos da tabela
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');

            $sets = ["status = 'pago'", "updated_at = NOW()"];

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

            $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()]);

            // Criar lançamento no fluxo de caixa
            $this->criarLancamentoFluxoCaixa($id, $conta['amount'], date('Y-m-d'), $conta['description']);

            $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');
        }
    }

    /**
     * Visualiza uma conta a receber
     */
    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;
            }

            $this->view('contas-receber/show', [
                'conta' => $conta,
                'pageTitle' => 'Conta a Receber'
            ]);

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

    /**
     * Busca uma conta a receber por ID
     */
    private function getConta(int $id): ?array
    {
        $stmt = $this->db->prepare("
            SELECT * FROM contas_receber
            WHERE id = :id AND company_id = :company_id
        ");
        $stmt->execute([
            'id' => $id,
            'company_id' => $this->getCompanyId()
        ]);

        return $stmt->fetch() ?: null;
    }

    /**
     * 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, nome, name
                FROM metodos_pagamento
                WHERE company_id = :company_id AND ativo = 1
                ORDER BY COALESCE(nome, 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, banco, agencia, conta, tipo_conta
                FROM contas_bancarias
                WHERE company_id = :company_id AND ativo = 1
                ORDER BY banco ASC, agencia 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 {
            $stmt = $this->db->prepare("
                SELECT id, codigo, nome, name
                FROM plano_contas
                WHERE company_id = :company_id AND ativo = 1
                ORDER BY codigo ASC
            ");
            $stmt->execute(['company_id' => $this->getCompanyId()]);
            return $stmt->fetchAll();
        } 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 [];
        }
    }

    /**
     * Cria lançamento de entrada no fluxo de caixa
     */
    private function criarLancamentoFluxoCaixa(int $contaId, float $valor, string $data, string $descricao): void
    {
        try {
            // 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' => $contaId,
                'company_id' => $this->getCompanyId()
            ]);

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

            // Calcular saldo atual
            $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' => $this->getCompanyId()]);
            $ultimoSaldo = $stmtSaldo->fetchColumn() ?: 0;

            $novoSaldo = $ultimoSaldo + $valor;

            // Inserir lançamento no fluxo de caixa
            $stmtInsert = $this->db->prepare("
                INSERT INTO fluxo_caixa (
                    company_id,
                    date,
                    type,
                    category,
                    description,
                    amount,
                    balance,
                    reference_type,
                    reference_id,
                    created_at
                ) VALUES (
                    :company_id,
                    :date,
                    'entrada',
                    'Contas a Receber',
                    :description,
                    :amount,
                    :balance,
                    'contas_receber',
                    :reference_id,
                    NOW()
                )
            ");

            $stmtInsert->execute([
                'company_id' => $this->getCompanyId(),
                'date' => $data,
                'description' => $descricao,
                'amount' => $valor,
                'balance' => $novoSaldo,
                'reference_id' => $contaId
            ]);

        } catch (Exception $e) {
            error_log("Erro ao criar lançamento no fluxo de caixa: " . $e->getMessage());
            // Não propaga o erro para não interromper o fluxo principal
        }
    }

    /**
     * Gera boleto híbrido na Shipay para uma conta a receber
     */
    private function gerarBoletoShipay(int $contaId, array $data): void
    {
        try {
            // Buscar método de pagamento
            $metodoId = $data['metodo_pagamento_id'] ?? null;
            if (!$metodoId) {
                return;
            }

            $stmt = $this->db->prepare("SELECT gateway, type FROM metodos_pagamento WHERE id = :id AND company_id = :company_id");
            $stmt->execute(['id' => $metodoId, 'company_id' => $this->getCompanyId()]);
            $metodo = $stmt->fetch();

            // Verificar se é Shipay e se é boleto
            if (empty($metodo) || ($metodo['gateway'] ?? '') !== 'shipay' || ($metodo['type'] ?? '') !== 'boleto') {
                return;
            }

            // Buscar empresa com configuração Shipay
            $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 company_id = :company_id AND shipay_enabled = 1
                LIMIT 1
            ");
            $stmtEmpresa->execute(['company_id' => $this->getCompanyId()]);
            $empresa = $stmtEmpresa->fetch();

            if (empty($empresa) || empty($empresa['shipay_access_key']) || empty($empresa['shipay_secret_key']) || empty($empresa['shipay_client_id'])) {
                error_log("Shipay não configurado para esta empresa");
                return;
            }

            // Buscar dados da pessoa (pagador)
            $pessoa = null;
            if (!empty($data['pessoa_id'])) {
                $stmtPessoa = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id AND company_id = :company_id");
                $stmtPessoa->execute(['id' => $data['pessoa_id'], 'company_id' => $this->getCompanyId()]);
                $pessoa = $stmtPessoa->fetch();
            }

            if (empty($pessoa)) {
                error_log("Pessoa não encontrada para gerar boleto Shipay");
                return;
            }

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

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

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

            $payload = [
                'valor' => (float) $data['amount'],
                'vencimento' => $data['due_date'], // Formato: YYYY-MM-DD
                'descricao' => $data['description'] ?? 'Conta a receber #' . $contaId,
                'pagador' => [
                    'nome' => $pessoa['name'] ?? $pessoa['nome'] ?? '',
                    'documento' => $documento,
                    'email' => $pessoa['email'] ?? '',
                    'telefone' => $telefone,
                    'endereco' => [
                        'logradouro' => $pessoa['address'] ?? $pessoa['endereco'] ?? '',
                        'numero' => $pessoa['numero'] ?? '',
                        'complemento' => $pessoa['complemento'] ?? '',
                        'bairro' => $pessoa['bairro'] ?? '',
                        'cidade' => $pessoa['city'] ?? $pessoa['cidade'] ?? '',
                        'uf' => $pessoa['state'] ?? $pessoa['uf'] ?? '',
                        'cep' => preg_replace('/\D/', '', $pessoa['zip_code'] ?? $pessoa['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'];
            }

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

            // Salvar dados do boleto na conta a receber (order_id para /order, id/charge_id para outros)
            $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 ($chargeId) {
                // Verificar se as colunas Shipay existem
                $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber LIKE 'shipay_%'");
                $columns = $stmtCheck->fetchAll();
                $hasShipayColumns = !empty($columns);

                if ($hasShipayColumns) {
                    $updateFields = [];
                    $updateValues = ['id' => $contaId, 'company_id' => $this->getCompanyId()];

                    if (in_array('shipay_charge_id', array_column($columns, 'Field'))) {
                        $updateFields[] = 'shipay_charge_id = :charge_id';
                        $updateValues['charge_id'] = $chargeId;
                    }
                    if (in_array('shipay_status', array_column($columns, 'Field'))) {
                        $updateFields[] = 'shipay_status = :status';
                        $updateValues['status'] = $status;
                    }
                    if (in_array('shipay_linha_digitavel', array_column($columns, 'Field')) && $linhaDigitavel) {
                        $updateFields[] = 'shipay_linha_digitavel = :linha_digitavel';
                        $updateValues['linha_digitavel'] = $linhaDigitavel;
                    }
                    if (in_array('shipay_qr_code', array_column($columns, 'Field')) && $qrCode) {
                        $updateFields[] = 'shipay_qr_code = :qr_code';
                        $updateValues['qr_code'] = $qrCode;
                    }
                    if (in_array('shipay_pdf_url', array_column($columns, 'Field')) && $pdfUrl) {
                        $updateFields[] = 'shipay_pdf_url = :pdf_url';
                        $updateValues['pdf_url'] = $pdfUrl;
                    }
                    if (in_array('shipay_payload', array_column($columns, 'Field'))) {
                        $updateFields[] = 'shipay_payload = :payload';
                        $updateValues['payload'] = json_encode($response, JSON_UNESCAPED_UNICODE);
                    }

                    if (!empty($updateFields)) {
                        $updateFields[] = 'updated_at = NOW()';
                        $sql = "UPDATE contas_receber SET " . implode(', ', $updateFields) . " WHERE id = :id AND company_id = :company_id";
                        $stmtUpdate = $this->db->prepare($sql);
                        $stmtUpdate->execute($updateValues);
                    }
                }
            }

        } catch (Exception $e) {
            error_log("Erro ao gerar boleto Shipay para conta #{$contaId}: " . $e->getMessage());
            throw $e; // Re-lança para o caller decidir o que fazer
        }
    }

    /**
     * Gera boleto via API do Itaú
     */
    private function gerarBoletoItau(int $contaId, array $data): void
    {
        try {
            $contaBancariaId = $data['conta_bancaria_id'] ?? null;
            if (!$contaBancariaId) {
                return;
            }

            // Buscar conta bancária
            $stmt = $this->db->prepare("
                SELECT
                    id, bank_code, bank_name, agency, account_number,
                    chave_api, client_secret, certificado_path, chave_privada_path, certificado_senha,
                    digito_conta_itau, is_producao_itau
                FROM contas_bancarias
                WHERE id = :id AND company_id = :company_id AND is_active = 1
            ");
            $stmt->execute([
                'id' => $contaBancariaId,
                'company_id' => $this->getCompanyId()
            ]);
            $contaBancaria = $stmt->fetch();

            if (empty($contaBancaria)) {
                return;
            }

            // Verificar se é Itaú (código 341)
            $bankCode = $contaBancaria['bank_code'] ?? '';
            if ($bankCode !== '341' && strtoupper($contaBancaria['bank_name'] ?? '') !== 'ITAU') {
                return;
            }

            // Verificar se tem credenciais configuradas
            $clientId = $contaBancaria['chave_api'] ?? '';
            $clientSecret = $contaBancaria['client_secret'] ?? '';
            $numeroAgencia = $contaBancaria['agency'] ?? '';
            $numeroConta = $contaBancaria['account_number'] ?? '';
            $digitoConta = $contaBancaria['digito_conta_itau'] ?? '';

            if (empty($clientId) || empty($clientSecret) || empty($numeroAgencia) || empty($numeroConta)) {
                error_log("Itaú: Credenciais incompletas para conta bancária #{$contaBancariaId}");
                return;
            }

            // Buscar dados da pessoa (pagador)
            $pessoa = null;
            if (!empty($data['pessoa_id'])) {
                $stmtPessoa = $this->db->prepare("
                    SELECT * FROM pessoas
                    WHERE id = :id AND company_id = :company_id
                ");
                $stmtPessoa->execute([
                    'id' => $data['pessoa_id'],
                    'company_id' => $this->getCompanyId()
                ]);
                $pessoa = $stmtPessoa->fetch();
            }

            if (empty($pessoa)) {
                error_log("Itaú: Pessoa não encontrada para gerar boleto");
                return;
            }

            // Criar instância do cliente Itaú
            $isProducao = !empty($contaBancaria['is_producao_itau']) && $contaBancaria['is_producao_itau'] == 1;
            $itau = new BancoItau(
                $clientId,
                $clientSecret,
                $numeroAgencia,
                $numeroConta,
                $digitoConta,
                $isProducao,
                $contaBancaria['certificado_path'] ?? null,
                $contaBancaria['chave_privada_path'] ?? null,
                $contaBancaria['certificado_senha'] ?? null
            );

            // Preparar dados do pagador
            $documento = preg_replace('/\D/', '', $pessoa['document'] ?? '');
            $telefone = preg_replace('/\D/', '', $pessoa['phone'] ?? $pessoa['telefone'] ?? '');

            // Preparar payload
            $dadosCobranca = [
                'numero_documento' => (string) $contaId,
                'valor' => (float) $data['amount'],
                'data_vencimento' => $data['due_date'], // YYYY-MM-DD
                'pagador' => [
                    'nome' => $pessoa['name'] ?? $pessoa['nome'] ?? '',
                    'documento' => $documento,
                    'email' => $pessoa['email'] ?? '',
                    'telefone' => $telefone,
                    'endereco' => $pessoa['address'] ?? $pessoa['endereco'] ?? '',
                    'numero' => $pessoa['numero'] ?? '',
                    'complemento' => $pessoa['complemento'] ?? '',
                    'bairro' => $pessoa['bairro'] ?? '',
                    'cidade' => $pessoa['city'] ?? $pessoa['cidade'] ?? '',
                    'uf' => $pessoa['state'] ?? $pessoa['uf'] ?? '',
                    'cep' => preg_replace('/\D/', '', $pessoa['zip_code'] ?? $pessoa['cep'] ?? '')
                ]
            ];

            // Gerar boleto no Itaú
            $boleto = $itau->criarCobranca($dadosCobranca);

            // Atualizar conta a receber com dados do boleto
            $stmtCols = $this->db->query("SHOW COLUMNS FROM contas_receber");
            $colunas = $stmtCols->fetchAll(\PDO::FETCH_COLUMN, 0);

            $updateFields = [];
            $updateValues = ['id' => $contaId, 'company_id' => $this->getCompanyId()];

            if (in_array('nosso_numero_boleto', $colunas) && !empty($boleto['nosso_numero'])) {
                $updateFields[] = 'nosso_numero_boleto = :nosso_numero';
                $updateValues['nosso_numero'] = $boleto['nosso_numero'];
            }
            if (in_array('codigo_barras', $colunas) && !empty($boleto['codigo_barras'])) {
                $updateFields[] = 'codigo_barras = :codigo_barras';
                $updateValues['codigo_barras'] = $boleto['codigo_barras'];
            }
            if (in_array('linha_digitavel', $colunas) && !empty($boleto['linha_digitavel'])) {
                $updateFields[] = 'linha_digitavel = :linha_digitavel';
                $updateValues['linha_digitavel'] = $boleto['linha_digitavel'];
            }
            if (in_array('boleto_pdf_url', $colunas) && !empty($boleto['pdf_url'])) {
                $updateFields[] = 'boleto_pdf_url = :pdf_url';
                $updateValues['pdf_url'] = $boleto['pdf_url'];
            }
            if (in_array('boleto_status', $colunas)) {
                $updateFields[] = 'boleto_status = :status';
                $updateValues['status'] = $boleto['status'] ?? 'REGISTRADO';
            }
            if (in_array('qrcode', $colunas) && !empty($boleto['qrcode'])) {
                $updateFields[] = 'qrcode = :qrcode';
                $updateValues['qrcode'] = $boleto['qrcode'];
            }

            if (!empty($updateFields)) {
                $updateFields[] = 'updated_at = NOW()';
                $sql = "UPDATE contas_receber SET " . implode(', ', $updateFields) . " WHERE id = :id AND company_id = :company_id";
                $stmtUpdate = $this->db->prepare($sql);
                $stmtUpdate->execute($updateValues);

                error_log("Itaú: Boleto gerado com sucesso para conta #{$contaId} - Nosso Número: " . ($boleto['nosso_numero'] ?? 'N/A'));
            }

        } catch (Exception $e) {
            error_log("Erro ao gerar boleto Itaú para conta #{$contaId}: " . $e->getMessage());
            throw $e;
        }
    }
}