<?php
namespace App\Controllers;

use Exception;
use App\Integrations\ShipayClient;

class PedidosController extends BaseController
{
    /**
     * Cache simples para verificação de colunas em tabelas.
     *
     * @var array<string, bool>
     */
    private $colunasTabelaCache = [];
    /**
     * Lista pedidos agrupados por status em cards
     */
    public function index(): void
    {
        // Verificar permissão de visualização
        if (!$this->canView('pedidos')) {
            $this->response->forbidden('Você não tem permissão para visualizar pedidos.');
            return;
        }

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

            // Mapeamento de cards para status
            $cardsConfig = [
                'entrada' => [
                    'title' => 'Entrada',
                    'icon' => 'bi bi-inbox',
                    'color' => 'primary',
                    'status' => ['orcamento', 'pendente'],
                    'timeline' => ['entrada']
                ],
                'triagem' => [
                    'title' => 'Triagem',
                    'icon' => 'bi bi-search',
                    'color' => 'info',
                    'status' => ['triagem'],
                    'timeline' => ['triagem']
                ],
                'pedido' => [
                    'title' => 'Faturamento',
                    'icon' => 'bi bi-cart-check',
                    'color' => 'success',
                    'status' => ['realizado', 'pedido'],
                    'timeline' => ['pedido']
                ],
                'envaze' => [
                    'title' => 'Envaze',
                    'icon' => 'bi bi-box',
                    'color' => 'secondary',
                    'status' => ['envaze', 'envase'],
                    'timeline' => ['envaze', 'envase']
                ],
                'expedicao' => [
                    'title' => 'Expedição',
                    'icon' => 'bi bi-truck',
                    'color' => 'dark',
                    'status' => ['expedicao', 'em_entrega'],
                    'timeline' => ['expedicao', 'expedição', 'em_entrega']
                ],
                'finalizado' => [
                    'title' => 'Finalizados',
                    'icon' => 'bi bi-check-circle',
                    'color' => 'success',
                    'status' => ['finalizado', 'concluido', 'finalizado_total'],
                    'timeline' => ['finalizado']
                ]
            ];

            // Buscar vendas agrupadas por status
            $pedidosPorStatus = [];
            $totalPedidos = 0;

            // Detectar colunas importantes
            $stmtColunas = $this->db->query("SHOW COLUMNS FROM vendas");
            $colunasVendas = $stmtColunas->fetchAll();
            $colunasDisponiveis = [];
            foreach ($colunasVendas as $coluna) {
                $colunasDisponiveis[$coluna['Field']] = $coluna;
            }

            $temLinhaTemporal = isset($colunasDisponiveis['linha_temporal']);

            // Mapear valores disponíveis de status (fallback) e linha temporal
            $statusDisponiveis = [];
            if (isset($colunasDisponiveis['status'])) {
                if (preg_match("/ENUM\((.+)\)/", $colunasDisponiveis['status']['Type'], $matches)) {
                    $enumValues = str_replace("'", '', $matches[1]);
                    $statusDisponiveis = array_map('trim', explode(',', $enumValues));
                } else {
                    $stmtStatus = $this->db->prepare("SELECT DISTINCT status FROM vendas WHERE company_id = ?");
                    $stmtStatus->execute([$companyId]);
                    $statusDisponiveis = $stmtStatus->fetchAll(\PDO::FETCH_COLUMN);
                }
            }

            $linhaTemporalDisponiveis = [];
            if ($temLinhaTemporal) {
                $stmtTimeline = $this->db->prepare("SELECT DISTINCT linha_temporal FROM vendas WHERE company_id = ?");
                $stmtTimeline->execute([$companyId]);
                $linhaTemporalDisponiveis = array_filter($stmtTimeline->fetchAll(\PDO::FETCH_COLUMN), static function ($value) {
                    return $value !== null && $value !== '';
                });
            }

            foreach ($cardsConfig as $cardKey => $cardConfig) {
                if ($temLinhaTemporal) {
                    $timelineValores = $cardConfig['timeline'] ?? [$cardKey];
                    $timelineValidos = !empty($linhaTemporalDisponiveis)
                        ? array_intersect($timelineValores, $linhaTemporalDisponiveis)
                        : $timelineValores;

                    if (empty($timelineValidos)) {
                        $pedidosPorStatus[$cardKey] = [
                            'config' => $cardConfig,
                            'pedidos' => [],
                            'total' => 0
                        ];
                        continue;
                    }

                    $placeholders = str_repeat('?,', count($timelineValidos) - 1) . '?';
                    $filtroSql = "v.linha_temporal IN ({$placeholders})";
                    $params = array_merge([$companyId], $timelineValidos);
                } else {
                    $statusList = $cardConfig['status'];
                    $statusListValidos = !empty($statusDisponiveis)
                        ? array_intersect($statusList, $statusDisponiveis)
                        : $statusList;

                    if (empty($statusListValidos)) {
                        $pedidosPorStatus[$cardKey] = [
                            'config' => $cardConfig,
                            'pedidos' => [],
                            'total' => 0
                        ];
                        continue;
                    }

                    $placeholders = str_repeat('?,', count($statusListValidos) - 1) . '?';
                    $filtroSql = "v.status IN ({$placeholders})";
                    $params = array_merge([$companyId], $statusListValidos);
                }

                $stmt = $this->db->prepare("
                    SELECT
                        v.*,
                        COALESCE(p.name, v.customer_name) as customer_name,
                        COALESCE(p.document, v.customer_document) as customer_document,
                        mp.name as payment_method_name
                    FROM vendas v
                    LEFT JOIN pessoas p ON v.customer_id = p.id AND v.customer_type = 'pessoa'
                    LEFT JOIN metodos_pagamento mp ON v.payment_method_id = mp.id
                    WHERE v.company_id = ?
                      AND v.modulo_origem = 'pedido'
                      AND {$filtroSql}
                    ORDER BY v.created_at DESC
                    LIMIT 100
                ");
                $stmt->execute($params);
                $pedidos = $stmt->fetchAll();

                $pedidosPorStatus[$cardKey] = [
                    'config' => $cardConfig,
                    'pedidos' => $pedidos,
                    'total' => count($pedidos)
                ];

                $totalPedidos += count($pedidos);
            }

            // Buscar status customizados para saber todos os possíveis status
            $stmtStatus = $this->db->prepare("
                SELECT codigo, nome, cor, icone
                FROM modulo_status
                WHERE company_id = ? AND modulo = 'vendas' AND ativo = 1
                ORDER BY ordem ASC
            ");
            $stmtStatus->execute([$companyId]);
            $statusCustomizados = $stmtStatus->fetchAll();

            $this->view('pedidos/index', [
                'pedidosPorStatus' => $pedidosPorStatus,
                'totalPedidos' => $totalPedidos,
                'statusCustomizados' => $statusCustomizados,
                'pageTitle' => 'Pedidos',
                'activeMenu' => 'pedidos'
            ]);

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

    /**
     * Exibe formulário para criar novo pedido (Entrada)
     */
    public function create(): void
    {
        try {
            $companyId = $this->getCompanyId();

            $clientes = $this->buscarClientesAtivos($companyId);

            // Gerar próximo número de pedido
            $stmt = $this->db->prepare("
                SELECT MAX(CAST(SUBSTRING(sale_number, 5) AS UNSIGNED)) as ultimo_numero
                FROM vendas
                WHERE company_id = ? AND sale_number LIKE 'PED-%'
            ");
            $stmt->execute([$companyId]);
            $result = $stmt->fetch();
            $ultimoNumero = $result['ultimo_numero'] ?? 0;
            $proximoNumero = 'PED-' . str_pad((int)$ultimoNumero + 1, 6, '0', STR_PAD_LEFT);

            $triagemProdutos = $this->obterConfiguracaoTriagemProdutos($companyId);

            $this->view('pedidos/form', [
                'clientes' => $clientes,
                'proximoNumero' => $proximoNumero,
                'pageTitle' => 'Novo Pedido - Entrada',
                'activeMenu' => 'pedidos',
                'triagemProdutos' => $triagemProdutos
            ]);

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

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

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

            $customerId = $this->request->post('customer_id');
            $quantity = (float) $this->request->post('quantity');
            $saleNumber = $this->request->post('sale_number');
            $notes = $this->request->post('notes', '');
            $motorista = $this->request->post('motorista', '');
            $veiculo = $this->request->post('veiculo', '');

            if (empty($customerId) || empty($quantity) || $quantity <= 0) {
                $this->error('Cliente e quantidade são obrigatórios');
                return;
            }

            $notesFormatadas = $this->formatarNotasPedido($notes, $quantity);

            // Buscar dados do cliente
            $stmtCliente = $this->db->prepare("
                SELECT id, name, document, trade_name
                FROM pessoas
                WHERE id = ? AND company_id = ?
            ");
            $stmtCliente->execute([$customerId, $companyId]);
            $cliente = $stmtCliente->fetch();

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

            // Verificar se a coluna linha_temporal existe para popular com triagem
            $temLinhaTemporal = false;
            $temQtdInformada = false;
            $temMotorista = false;
            $temVeiculo = false;
            try {
                $stmtColuna = $this->db->query("SHOW COLUMNS FROM vendas LIKE 'linha_temporal'");
                $temLinhaTemporal = (bool) $stmtColuna->fetch();
            } catch (Exception $e) {
                $temLinhaTemporal = false;
            }

            try {
                $stmtQtdInformada = $this->db->query("SHOW COLUMNS FROM vendas LIKE 'qtd_informada'");
                $temQtdInformada = (bool) $stmtQtdInformada->fetch();
            } catch (Exception $e) {
                $temQtdInformada = false;
            }

            try {
                $stmtMotorista = $this->db->query("SHOW COLUMNS FROM vendas LIKE 'motorista'");
                $temMotorista = (bool) $stmtMotorista->fetch();
            } catch (Exception $e) {
                $temMotorista = false;
            }

            try {
                $stmtVeiculo = $this->db->query("SHOW COLUMNS FROM vendas LIKE 'veiculo'");
                $temVeiculo = (bool) $stmtVeiculo->fetch();
            } catch (Exception $e) {
                $temVeiculo = false;
            }

            $colunaLinhaTemporal = $temLinhaTemporal ? ", linha_temporal" : "";
            $valorLinhaTemporal = $temLinhaTemporal ? ", :linha_temporal" : "";
            $colunaQtdInformada = $temQtdInformada ? ", qtd_informada" : "";
            $valorQtdInformada = $temQtdInformada ? ", :qtd_informada" : "";
            $colunaMotorista = $temMotorista ? ", motorista" : "";
            $valorMotorista = $temMotorista ? ", :motorista" : "";
            $colunaVeiculo = $temVeiculo ? ", veiculo" : "";
            $valorVeiculo = $temVeiculo ? ", :veiculo" : "";

            // Inserir pedido na tabela vendas já direcionando para triagem
            $stmt = $this->db->prepare("
                INSERT INTO vendas (
                    company_id,
                    modulo_origem,
                    customer_id,
                    customer_type,
                    customer_name,
                    customer_document,
                    sale_number,
                    sale_date,
                    status,
                    notes,
                    subtotal,
                    total,
                    created_at,
                    updated_at
                    {$colunaLinhaTemporal}
                    {$colunaQtdInformada}
                    {$colunaMotorista}
                    {$colunaVeiculo}
                ) VALUES (
                    :company_id,
                    :modulo_origem,
                    :customer_id,
                    'pessoa',
                    :customer_name,
                    :customer_document,
                    :sale_number,
                    CURDATE(),
                    'triagem',
                    :notes,
                    0.00,
                    0.00,
                    NOW(),
                    NOW()
                    {$valorLinhaTemporal}
                    {$valorQtdInformada}
                    {$valorMotorista}
                    {$valorVeiculo}
                )
            ");

            $paramsInsert = [
                'company_id' => $companyId,
                'modulo_origem' => 'pedido',
                'customer_id' => $customerId,
                'customer_name' => $cliente['name'],
                'customer_document' => $cliente['document'],
                'sale_number' => $saleNumber,
                'notes' => $notesFormatadas
            ];

            if ($temLinhaTemporal) {
                $paramsInsert['linha_temporal'] = 'triagem';
            }

            if ($temQtdInformada) {
                $paramsInsert['qtd_informada'] = $quantity;
            }

            // Adicionar motorista e veiculo apenas se as colunas existirem
            // Se existirem mas estiverem vazios, passar NULL ou string vazia
            if ($temMotorista) {
                $paramsInsert['motorista'] = !empty($motorista) ? $motorista : null;
            }

            if ($temVeiculo) {
                $paramsInsert['veiculo'] = !empty($veiculo) ? $veiculo : null;
            }

            $stmt->execute($paramsInsert);

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

            $this->success('Pedido criado com sucesso!', [
                'id' => $pedidoId,
                'redirect' => url('/pedidos')
            ]);

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

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

        try {
            $companyId = $this->getCompanyId();
            $id = (int) $this->request->get('id');

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

            $pedido = $this->buscarPedido($companyId, $id);
            if (!$pedido) {
                $this->response->notFound('Pedido não encontrado');
                return;
            }

            $clientes = $this->buscarClientesAtivos($companyId);
            $triagemProdutos = $this->obterConfiguracaoTriagemProdutos($companyId);

            $quantidadeInformadaDb = isset($pedido['qtd_informada'])
                ? (float) $pedido['qtd_informada']
                : null;
            $quantidadeInformada = $quantidadeInformadaDb ?? $this->extrairQuantidadeInformada($pedido['notes'] ?? '');

            $pedido['quantidade_informada'] = $quantidadeInformada !== null
                ? number_format($quantidadeInformada, 2, '.', '')
                : '';
            $pedido['quantidade_contada'] = isset($pedido['qtd_conferida'])
                ? (string) (int) $pedido['qtd_conferida']
                : '';
            $pedido['quebra'] = isset($pedido['quebra'])
                ? (string) (int) $pedido['quebra']
                : '';
            $pedido['apto_envaze'] = isset($pedido['apto_envaze'])
                ? (string) (int) $pedido['apto_envaze']
                : '';
            $pedido['notes_limpos'] = $this->removerLinhaQtdInformada($pedido['notes'] ?? '');

            $this->view('pedidos/form', [
                'clientes' => $clientes,
                'pedido' => $pedido,
                'proximoNumero' => $pedido['sale_number'],
                'pageTitle' => 'Editar Pedido - ' . $pedido['sale_number'],
                'activeMenu' => 'pedidos',
                'triagemProdutos' => $triagemProdutos
            ]);

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

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

        try {
            $companyId = $this->getCompanyId();
            $id = (int) $this->request->post('pedido_id');

            if (!$id) {
                $this->error('Pedido inválido');
                return;
            }

            $pedido = $this->buscarPedido($companyId, $id);
            if (!$pedido) {
                $this->error('Pedido não encontrado');
                return;
            }

            $customerId = $this->request->post('customer_id');
            $quantity = (float) $this->request->post('quantity');
            $quantidadeContadaInput = $this->request->post('quantidade_contada');
            $quantidadeContada = $quantidadeContadaInput !== null ? (float) $quantidadeContadaInput : null;
            $quebraInput = $this->request->post('quebra');
            $quebra = $quebraInput !== null && $quebraInput !== '' ? (float) $quebraInput : null;
            $aptoEnvazeInput = $this->request->post('apto_envaze');
            $aptoEnvaze = $aptoEnvazeInput !== null && $aptoEnvazeInput !== '' ? (float) $aptoEnvazeInput : null;
            $notes = $this->request->post('notes', '');
            $motorista = $this->request->post('motorista', '');
            $veiculo = $this->request->post('veiculo', '');
            $triagemWorkflowPayload = $this->request->post('triagem_workflow');
            $triagemWorkflow = $triagemWorkflowPayload ? json_decode($triagemWorkflowPayload, true) : null;

            $temColunaAptoEnvaze = false;
            try {
                $stmtColunaApto = $this->db->query("SHOW COLUMNS FROM vendas LIKE 'apto_envaze'");
                $temColunaAptoEnvaze = (bool) $stmtColunaApto->fetch();
            } catch (Exception $e) {
                $temColunaAptoEnvaze = false;
            }

            $linhaTemporal = $pedido['linha_temporal'] ?? '';
            $isTriagem = $linhaTemporal === 'triagem';
            $isEntrada = $linhaTemporal === 'entrada';

            if (empty($customerId)) {
                $this->error('Cliente é obrigatório');
                return;
            }

            if ($isTriagem) {
                if (empty($quantidadeContada) || $quantidadeContada <= 0) {
                    $this->error('Quantidade contada é obrigatória');
                    return;
                }
            } else {
                if (empty($quantity) || $quantity <= 0) {
                    $this->error('Quantidade informada é obrigatória');
                    return;
                }
            }

            $stmtCliente = $this->db->prepare("
                SELECT id, name, document
                FROM pessoas
                WHERE id = ? AND company_id = ?
            ");
            $stmtCliente->execute([$customerId, $companyId]);
            $cliente = $stmtCliente->fetch();

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

            $quantidadeInformadaAtual = isset($pedido['qtd_informada'])
                ? (float) $pedido['qtd_informada']
                : $this->extrairQuantidadeInformada($pedido['notes'] ?? '');
            $quantidadeParaNotas = $isTriagem
                ? ($quantidadeInformadaAtual ?? null)
                : $quantity;

            if ($quantidadeParaNotas !== null && $quantidadeParaNotas > 0) {
                $notesFormatadas = $this->formatarNotasPedido($notes, $quantidadeParaNotas);
            } else {
                $notesFormatadas = trim($notes);
            }

            // Verificar se colunas motorista e veiculo existem
            $temMotorista = $this->tabelaTemColuna('vendas', 'motorista');
            $temVeiculo = $this->tabelaTemColuna('vendas', 'veiculo');

            $setColumns = [
                "customer_id = :customer_id",
                "customer_name = :customer_name",
                "customer_document = :customer_document",
                "notes = :notes",
                "updated_at = NOW()"
            ];

            $paramsUpdate = [
                'customer_id' => $customerId,
                'customer_name' => $cliente['name'],
                'customer_document' => $cliente['document'],
                'notes' => $notesFormatadas,
                'id' => $id,
                'company_id' => $companyId
            ];

            if ($temMotorista && !empty($motorista)) {
                $setColumns[] = "motorista = :motorista";
                $paramsUpdate['motorista'] = $motorista;
            }

            if ($temVeiculo && !empty($veiculo)) {
                $setColumns[] = "veiculo = :veiculo";
                $paramsUpdate['veiculo'] = $veiculo;
            }

            if ($isEntrada) {
                $setColumns[] = "qtd_informada = :qtd_informada";
                $paramsUpdate['qtd_informada'] = $quantity;
            }

            $diferenca = null;
            if ($isTriagem) {
                $setColumns[] = "qtd_conferida = :qtd_conferida";
                $paramsUpdate['qtd_conferida'] = $quantidadeContada;

                $baseInformada = $quantidadeInformadaAtual ?? null;
                $diferenca = ($baseInformada !== null) ? $quantidadeContada - (float) $baseInformada : null;
                $setColumns[] = "diferenca = :diferenca";
                $paramsUpdate['diferenca'] = $diferenca;

                $setColumns[] = "quebra = :quebra";
                $paramsUpdate['quebra'] = $quebra !== null && $quebra >= 0 ? $quebra : 0;

                if ($temColunaAptoEnvaze) {
                    $setColumns[] = "apto_envaze = :apto_envaze";
                    $paramsUpdate['apto_envaze'] = $aptoEnvaze !== null && $aptoEnvaze >= 0 ? $aptoEnvaze : 0;
                }

                if ($this->tabelaTemColuna('vendas', 'linha_temporal')) {
                    $setColumns[] = "linha_temporal = 'pedido'";
                }
            }

            $sql = "
                UPDATE vendas
                SET " . implode(",\n                    ", $setColumns) . "
                WHERE id = :id
                  AND company_id = :company_id
                  AND modulo_origem = 'pedido'
            ";

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

            if ($isTriagem && $triagemWorkflow) {
                $this->processarWorkflowTriagem($companyId, $pedido, $triagemWorkflow, $quantidadeContada, $aptoEnvaze, $quebra);
            }

            $this->success('Pedido atualizado com sucesso!', [
                'id' => $id,
                'redirect' => url('/pedidos')
            ]);

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

    /**
     * Atualiza o status de um pedido
     */
    public function atualizarStatus(): void
    {
        try {
            $id = (int) $this->request->post('id');
            $novoStatus = $this->request->post('status');
            $companyId = $this->getCompanyId();

            if (!$id || !$novoStatus) {
                $this->error('ID do pedido e novo status são obrigatórios');
                return;
            }

            // Verificar se o pedido existe e pertence à empresa
            $stmt = $this->db->prepare("
                SELECT id FROM vendas
                WHERE id = ? AND company_id = ?
            ");
            $stmt->execute([$id, $companyId]);
            $pedido = $stmt->fetch();

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

            // Atualizar status
            $stmtUpdate = $this->db->prepare("
                UPDATE vendas
                SET status = ?, updated_at = NOW()
                WHERE id = ? AND company_id = ?
            ");
            $stmtUpdate->execute([$novoStatus, $id, $companyId]);

            $this->success('Status atualizado com sucesso', [
                'id' => $id,
                'status' => $novoStatus
            ]);

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

    /**
     * Retorna resumo somente leitura de um pedido para o card de faturamento
     */
    public function resumo(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $pedidoId = (int) $this->request->get('id');

            if (!$companyId || !$pedidoId) {
                $this->error('Pedido não informado');
                return;
            }

            $pedido = $this->buscarPedido($companyId, $pedidoId);
            if (!$pedido) {
                $this->error('Pedido não encontrado', [], 404);
                return;
            }

            $itens = $this->buscarItensPedido($companyId, $pedidoId);
            $metodosPagamento = $this->listarMetodosPagamentoAtivos($companyId);

            $this->success('Resumo carregado com sucesso', [
                'pedido' => [
                    'id' => (int) $pedido['id'],
                    'sale_number' => $pedido['sale_number'],
                    'sale_date' => $pedido['sale_date'],
                    'status' => $pedido['status'],
                    'total' => isset($pedido['total']) ? (float) $pedido['total'] : 0.0,
                    'subtotal' => isset($pedido['subtotal']) ? (float) $pedido['subtotal'] : 0.0,
                    'notes' => $pedido['notes'] ?? null,
                ],
                'cliente' => [
                    'nome' => $pedido['customer_name'] ?? 'Cliente não informado',
                    'documento' => $pedido['customer_document'] ?? null,
                    'email' => $pedido['cliente_email'] ?? null,
                    'telefone' => $pedido['cliente_phone'] ?? $pedido['cliente_mobile'] ?? null,
                ],
                'itens' => $itens,
                'pagamento' => [
                    'metodo_atual' => $pedido['payment_method_id'] ?? null,
                    'parcelas' => isset($pedido['installments']) ? (int) $pedido['installments'] : 1,
                    'payment_term_id' => $pedido['payment_term_id'] ?? null,
                ],
                'metodos_pagamento' => $metodosPagamento
            ]);
        } catch (Exception $e) {
            error_log("Erro ao carregar resumo do pedido: " . $e->getMessage());
            $this->error('Erro ao carregar resumo do pedido');
        }
    }

    /**
     * Atualiza informações de pagamento de um pedido
     */
    public function processarPagamento(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $pedidoId = (int) $this->request->post('pedido_id');
            $paymentMethodId = (int) $this->request->post('payment_method_id');
            $installments = (int) $this->request->post('installments', 1);
            $paymentTermId = $this->request->post('payment_term_id');

            if (!$companyId || !$pedidoId || !$paymentMethodId) {
                $this->error('Pedido e método de pagamento são obrigatórios');
                return;
            }

            $pedido = $this->buscarPedido($companyId, $pedidoId);
            if (!$pedido) {
                $this->error('Pedido não encontrado', [], 404);
                return;
            }

            $totalPedido = $this->calcularTotalPedido($pedidoId, $pedido);
            if ($totalPedido <= 0) {
                $this->error('Pedido sem valor total para gerar pagamento');
                return;
            }
            $pedido['total'] = $totalPedido;

            // Validar método de pagamento informado
            $stmtMetodo = $this->db->prepare("
                SELECT id FROM metodos_pagamento
                WHERE id = :id AND company_id = :company_id AND is_active = 1
                LIMIT 1
            ");
            $stmtMetodo->execute([
                'id' => $paymentMethodId,
                'company_id' => $companyId
            ]);
            if (!$stmtMetodo->fetchColumn()) {
                $this->error('Método de pagamento inválido');
                return;
            }

            $this->db->beginTransaction();

            $temCampoPaymentTerm = $this->tabelaTemColuna('vendas', 'payment_term_id');

            $sql = "
                UPDATE vendas
                SET payment_method_id = :payment_method_id,
                    installments = :installments,
                    total = :total_pagamento,
                    updated_at = NOW()
            ";

            $params = [
                'payment_method_id' => $paymentMethodId,
                'installments' => max(1, $installments),
                'total_pagamento' => $totalPedido,
                'id' => $pedidoId,
                'company_id' => $companyId
            ];

            if ($temCampoPaymentTerm) {
                $sql .= ", payment_term_id = :payment_term_id";
                $params['payment_term_id'] = $paymentTermId ? (int) $paymentTermId : null;
            }

            $sql .= "
                WHERE id = :id
                  AND company_id = :company_id
                  AND modulo_origem = 'pedido'
                LIMIT 1
            ";

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

            $dadosPagamento = [
                'company_id' => $companyId,
                'payment_method_id' => $paymentMethodId,
                'installments' => max(1, $installments),
                'payment_term_id' => $params['payment_term_id'] ?? null,
                'total' => $totalPedido,
                'sale_date' => $pedido['sale_date'] ?? date('Y-m-d')
            ];

            $parcelas = $this->gerarParcelasPagamento($pedidoId, $dadosPagamento);

            if (isset($pedido['sale_number']) && str_contains((string) $pedido['sale_number'], '-GAR')) {
                $this->definirLinhaTemporalVenda($pedidoId, 'finalizado');
            } else {
                $this->definirLinhaTemporalVenda($pedidoId, 'envaze');
            }

            // Gerar contas a receber após pagamento aprovado
            try {
                $this->gerarContasReceber($pedidoId, array_merge($pedido, $dadosPagamento));
            } catch (Exception $e) {
                error_log("Erro ao gerar contas a receber para pedido #{$pedidoId}: " . $e->getMessage());
                // Não interromper o fluxo se falhar a geração de contas a receber
            }

            $this->db->commit();

            $this->success('Pagamento atualizado com sucesso', [
                'parcelas_geradas' => count($parcelas),
                'parcelas' => $parcelas
            ]);
        } catch (Exception $e) {
            if ($this->db && $this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao processar pagamento do pedido: " . $e->getMessage());
            $this->error('Erro ao processar pagamento do pedido');
        }
    }

    public function processarEnvaze(): void
    {
        try {
            if (!$this->request->isPost()) {
                $this->error('Método não permitido', [], 405);
                return;
            }

            $companyId = $this->getCompanyId();
            $pedidoId = (int) $this->request->post('pedido_id');
            $teveQuebra = (bool) (int) $this->request->post('teve_quebra', 0);
            $quantidadeQuebra = $this->request->post('quantidade_quebra');
            $validadeQuebra = $this->request->post('validade_quebra');

            if (!$pedidoId) {
                $this->error('Pedido não informado');
                return;
            }

            $pedido = $this->buscarPedido($companyId, $pedidoId);
            if (!$pedido) {
                $this->error('Pedido não encontrado', [], 404);
                return;
            }

            if ($teveQuebra) {
                $quantidade = $quantidadeQuebra !== null
                    ? (float) str_replace(',', '.', (string) $quantidadeQuebra)
                    : 0.0;
                $validade = $validadeQuebra ? sprintf('%s-01-01', $validadeQuebra) : null;

                if ($quantidade <= 0) {
                    $this->error('Informe a quantidade de quebra');
                    return;
                }

                $this->registrarQuebraEnvaze(
                    $companyId ?? ($pedido['company_id'] ?? null),
                    $pedidoId,
                    $quantidade,
                    $validade
                );
            }

            $this->definirLinhaTemporalVenda($pedidoId, 'expedicao');

            $this->success('Envaze atualizado com sucesso', [
                'linha_temporal' => 'expedicao',
                'teve_quebra' => $teveQuebra
            ]);
        } catch (Exception $e) {
            error_log('Erro ao processar envaze: ' . $e->getMessage());
            $this->error('Erro ao processar envaze: ' . $e->getMessage());
        }
    }

    public function atualizarLinhaTemporalPedido(): void
    {
        try {
            if (!$this->request->isPost()) {
                $this->error('Método não permitido', [], 405);
                return;
            }

            $pedidoId = (int) $this->request->post('pedido_id');
            $linhaTemporal = $this->request->post('linha_temporal');

            if (!$pedidoId || !$linhaTemporal) {
                $this->error('Pedido e linha temporal são obrigatórios');
                return;
            }

            $this->definirLinhaTemporalVenda($pedidoId, $linhaTemporal);

            $this->success('Linha temporal atualizada com sucesso', [
                'linha_temporal' => $linhaTemporal
            ]);
        } catch (Exception $e) {
            error_log('Erro ao atualizar linha temporal: ' . $e->getMessage());
            $this->error('Erro ao atualizar linha temporal: ' . $e->getMessage());
        }
    }

    /**
     * Busca veículos e motoristas do cliente
     */
    public function buscarVeiculosMotoristas(): void
    {
        try {
            $companyId = $this->getCompanyId();
            $clienteId = (int) $this->request->get('cliente_id');

            if (!$clienteId) {
                $this->error('ID do cliente não informado');
                return;
            }

            // Verificar se a tabela existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'pessoa_veiculos'");
            if ($stmt->rowCount() === 0) {
                $this->success('Nenhum veículo encontrado', [
                    'veiculos' => [],
                    'motoristas' => []
                ]);
                return;
            }

            // Buscar veículos
            $stmt = $this->db->prepare("
                SELECT *
                FROM pessoa_veiculos
                WHERE pessoa_id = :pessoa_id AND company_id = :company_id
                ORDER BY id ASC
            ");
            $stmt->execute([
                'pessoa_id' => $clienteId,
                'company_id' => $companyId
            ]);
            $veiculos = $stmt->fetchAll();

            if (empty($veiculos)) {
                $this->success('Nenhum veículo encontrado', [
                    'veiculos' => [],
                    'motoristas' => []
                ]);
                return;
            }

            // Buscar motoristas
            $ids = array_column($veiculos, 'id');
            $placeholders = implode(',', array_fill(0, count($ids), '?'));
            $stmtMotoristas = $this->db->prepare("
                SELECT *
                FROM pessoa_veiculo_motoristas
                WHERE pessoa_veiculo_id IN ($placeholders)
                ORDER BY id ASC
            ");
            $stmtMotoristas->execute($ids);
            $motoristas = $stmtMotoristas->fetchAll();

            // Agrupar motoristas por veículo
            $motoristasPorVeiculo = [];
            foreach ($motoristas as $motorista) {
                $motoristasPorVeiculo[$motorista['pessoa_veiculo_id']][] = $motorista;
            }

            // Adicionar motoristas aos veículos
            foreach ($veiculos as &$veiculo) {
                $veiculo['motoristas'] = $motoristasPorVeiculo[$veiculo['id']] ?? [];
            }

            $this->success('Veículos e motoristas encontrados', [
                'veiculos' => $veiculos,
                'motoristas' => $motoristas
            ]);

        } catch (Exception $e) {
            error_log("Erro ao buscar veículos e motoristas: " . $e->getMessage());
            $this->error('Erro ao buscar veículos e motoristas');
        }
    }

    /**
     * Busca lista de clientes ativos para o formulário
     */
    private function buscarClientesAtivos(int $companyId): array
    {
        try {
            $colunas = [];
            $stmtColunas = $this->db->query("SHOW COLUMNS FROM pessoas");
            $resultadoColunas = $stmtColunas->fetchAll();
            foreach ($resultadoColunas as $coluna) {
                $colunas[] = $coluna['Field'];
            }

            $colunaAtivo = in_array('ativo', $colunas) ? 'ativo' : (in_array('is_active', $colunas) ? 'is_active' : null);
            $colunaTipo = in_array('tipo', $colunas) ? 'tipo' : (in_array('type', $colunas) ? 'type' : null);

            $whereClientes = "WHERE company_id = ?";
            $paramsClientes = [$companyId];

            if ($colunaAtivo) {
                $whereClientes .= " AND {$colunaAtivo} = 1";
            }

            if ($colunaTipo) {
                $whereClientes .= " AND {$colunaTipo} IN ('cliente', 'ambos')";
            }

            $stmtClientes = $this->db->prepare("
                SELECT id, name, document, trade_name, email, phone, mobile
                FROM pessoas
                {$whereClientes}
                ORDER BY name ASC
            ");
            $stmtClientes->execute($paramsClientes);
            return $stmtClientes->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar clientes: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca pedido específico do módulo
     */
    private function buscarPedido(int $companyId, int $id): ?array
    {
        $stmt = $this->db->prepare("
            SELECT v.*, p.email as cliente_email, p.phone as cliente_phone, p.mobile as cliente_mobile
            FROM vendas v
            LEFT JOIN pessoas p ON v.customer_id = p.id
            WHERE v.id = :id
              AND v.company_id = :company_id
              AND v.modulo_origem = 'pedido'
            LIMIT 1
        ");
        $stmt->execute([
            'id' => $id,
            'company_id' => $companyId
        ]);
        $pedido = $stmt->fetch();
        return $pedido ?: null;
    }

    private function buscarItensPedido(int $companyId, int $pedidoId): array
    {
        try {
            $temCampoCompanyId = $this->tabelaTemColuna('vendas_itens', 'company_id');

            $sql = "
                SELECT id, product_id, product_name, quantity, unit_price, total_price
                FROM vendas_itens
                WHERE venda_id = :venda_id
            ";

            if ($temCampoCompanyId) {
                $sql .= " AND company_id = :company_id";
            }

            $sql .= " ORDER BY id ASC";

            $stmt = $this->db->prepare($sql);
            $params = ['venda_id' => $pedidoId];

            if ($temCampoCompanyId) {
                $params['company_id'] = $companyId;
            }

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

            return $itens ?: [];
        } catch (Exception $e) {
            error_log('Erro ao buscar itens do pedido: ' . $e->getMessage());
            return [];
        }
    }

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

    private function calcularTotalPedido(int $pedidoId, array $pedido): float
    {
        $total = isset($pedido['total']) ? (float) $pedido['total'] : 0.0;
        if ($total > 0) {
            return $total;
        }

        try {
            $temCompany = $this->tabelaTemColuna('vendas_itens', 'company_id');
            $sql = "
                SELECT COALESCE(SUM(total_price), 0) as total
                FROM vendas_itens
                WHERE venda_id = :venda_id
            ";

            if ($temCompany) {
                $sql .= " AND company_id = :company_id";
            }

            $stmt = $this->db->prepare($sql);
            $params = ['venda_id' => $pedidoId];
            if ($temCompany) {
                $params['company_id'] = $this->getCompanyId();
            }

            $stmt->execute($params);
            $soma = (float) $stmt->fetchColumn();
            if ($soma > 0) {
                return $soma;
            }
        } catch (Exception $e) {
            error_log('Erro ao calcular total do pedido: ' . $e->getMessage());
        }

        $subtotal = isset($pedido['subtotal']) ? (float) $pedido['subtotal'] : 0.0;
        return $subtotal > 0 ? $subtotal : 0.0;
    }

    private function definirLinhaTemporalVenda(int $vendaId, string $linhaTemporal): void
    {
        try {
            $sql = "
                UPDATE vendas
                SET linha_temporal = :linha_temporal,
                    updated_at = NOW()
                WHERE id = :id
                LIMIT 1
            ";

            $stmt = $this->db->prepare($sql);
            $stmt->execute([
                'linha_temporal' => $linhaTemporal,
                'id' => $vendaId
            ]);
        } catch (Exception $e) {
            error_log('Erro ao definir linha temporal da venda: ' . $e->getMessage());
        }
    }

    private function registrarQuebraEnvaze($companyId, int $pedidoId, float $quantidade, ?string $validade): void
    {
        if (!$companyId) {
            $stmtEmpresa = $this->db->prepare("
                SELECT company_id FROM vendas
                WHERE id = :id
                LIMIT 1
            ");
            $stmtEmpresa->execute(['id' => $pedidoId]);
            $companyId = $stmtEmpresa->fetchColumn();
        }

        if (!$companyId) {
            throw new Exception('Não foi possível identificar a empresa para registrar a quebra.');
        }

        $stmt = $this->db->prepare("
            INSERT INTO pedidos_quebras_envaze (
                company_id,
                venda_id,
                quantidade_quebra,
                validade,
                created_at
            ) VALUES (
                :company_id,
                :venda_id,
                :quantidade_quebra,
                :validade,
                NOW()
            )
        ");

        $stmt->execute([
            'company_id' => $companyId,
            'venda_id' => $pedidoId,
            'quantidade_quebra' => $quantidade,
            'validade' => $validade
        ]);
    }

    private function gerarParcelasPagamento(int $pedidoId, array $dadosPagamento): array
    {
        $companyId = $dadosPagamento['company_id'] ?? $this->getCompanyId();
        if (!$companyId) {
            throw new Exception('Empresa não identificada para gerar parcelas.');
        }

        $stmtDelete = $this->db->prepare("
            DELETE FROM vendas_pagamentos
            WHERE venda_id = :venda_id AND company_id = :company_id
        ");
        $stmtDelete->execute([
            'venda_id' => $pedidoId,
            'company_id' => $companyId
        ]);

        $total = isset($dadosPagamento['total']) ? (float) $dadosPagamento['total'] : 0.0;
        $paymentMethodId = $dadosPagamento['payment_method_id'] ?? null;
        if (!$paymentMethodId || $total <= 0) {
            throw new Exception('Dados insuficientes para gerar parcelas.');
        }

        $numParcelas = max(1, (int) ($dadosPagamento['installments'] ?? 1));
        $saleDate = $dadosPagamento['sale_date'] ?? date('Y-m-d');

        try {
            $dataBase = new \DateTime($saleDate);
        } catch (\Exception $e) {
            $dataBase = new \DateTime();
        }

        $diasPrazoTotal = 0;
        $paymentTermId = $dadosPagamento['payment_term_id'] ?? null;
        if ($paymentTermId) {
            $stmtPrazo = $this->db->prepare("
                SELECT dias FROM metodos_pagamento_prazos
                WHERE id = :id AND company_id = :company_id AND ativo = 1
                LIMIT 1
            ");
            $stmtPrazo->execute([
                'id' => $paymentTermId,
                'company_id' => $companyId
            ]);
            $prazo = $stmtPrazo->fetch();
            if ($prazo && !empty($prazo['dias'])) {
                $diasPrazoTotal = (int) $prazo['dias'];
            } else {
                $paymentTermId = null;
            }
        }

        if ($diasPrazoTotal <= 0) {
            $diasPrazoTotal = 30 * $numParcelas;
        }

        $diasPorParcela = (int) ceil($diasPrazoTotal / $numParcelas);

        $valorParcela = $total / $numParcelas;
        $valorParcelaArredondado = floor($valorParcela * 100) / 100;
        $resto = $total - ($valorParcelaArredondado * $numParcelas);

        $stmtInsert = $this->db->prepare("
            INSERT INTO vendas_pagamentos (
                company_id, venda_id, numero_parcela, total_parcelas, valor_parcela,
                data_vencimento, metodo_pagamento_id, payment_term_id, dias_prazo,
                status, created_at, updated_at
            ) VALUES (
                :company_id, :venda_id, :numero_parcela, :total_parcelas, :valor_parcela,
                :data_vencimento, :metodo_pagamento_id, :payment_term_id, :dias_prazo,
                'pendente', NOW(), NOW()
            )
        ");

        $parcelasGeradas = [];

        for ($i = 1; $i <= $numParcelas; $i++) {
            $valorAtual = $valorParcelaArredondado;
            if ($i === $numParcelas) {
                $valorAtual += $resto;
            }

            $dataVencimento = clone $dataBase;
            $diasAdicionar = ($i - 1) * $diasPorParcela;
            $dataVencimento->modify("+{$diasAdicionar} days");

            $stmtInsert->execute([
                'company_id' => $companyId,
                'venda_id' => $pedidoId,
                'numero_parcela' => $i,
                'total_parcelas' => $numParcelas,
                'valor_parcela' => round($valorAtual, 2),
                'data_vencimento' => $dataVencimento->format('Y-m-d'),
                'metodo_pagamento_id' => $paymentMethodId,
                'payment_term_id' => $paymentTermId,
                'dias_prazo' => $diasAdicionar + $diasPorParcela
            ]);

            $parcelasGeradas[] = [
                'numero_parcela' => $i,
                'valor_parcela' => round($valorAtual, 2),
                'data_vencimento' => $dataVencimento->format('Y-m-d'),
                'metodo_pagamento_id' => $paymentMethodId,
                'payment_term_id' => $paymentTermId,
                'dias_prazo' => $diasAdicionar + $diasPorParcela
            ];
        }

        if (count($parcelasGeradas) === 0) {
            throw new Exception('Falha ao gerar parcelas do pedido.');
        }

        return $parcelasGeradas;
    }

    /**
     * Remove linha de quantidade e adiciona valor atualizado
     */
    private function formatarNotasPedido(string $notes, float $quantity): string
    {
        $notesLimpos = $this->removerLinhaQtdInformada($notes);
        $linhaQuantidade = 'Qtd informada: ' . number_format($quantity, 2, ',', '.');

        $notesLimpos = trim($notesLimpos);
        if ($notesLimpos !== '') {
            $notesLimpos .= "\n";
        }

        return trim($notesLimpos . $linhaQuantidade);
    }

    /**
     * Remove linhas contendo "Qtd informada"
     */
    private function removerLinhaQtdInformada(?string $notes): string
    {
        if (empty($notes)) {
            return '';
        }

        $limpo = preg_replace('/^\s*Qtd\s+informada:.*$/im', '', $notes);
        return trim($limpo ?? '');
    }

    /**
     * Extrai quantidade informada das notas, se existir
     */
    private function extrairQuantidadeInformada(?string $notes): ?float
    {
        if (empty($notes)) {
            return null;
        }

        if (preg_match('/Qtd\s+informada:\s*([\d\.,]+)/i', $notes, $matches)) {
            $valor = str_replace('.', '', $matches[1]);
            $valor = str_replace(',', '.', $valor);
            if (is_numeric($valor)) {
                return (float) $valor;
            }
        }

        return null;
    }

    private function buscarProdutoBasico(int $companyId, int $produtoId): ?array
    {
        try {
            $stmt = $this->db->prepare("
                SELECT id, name, price, fator_cashback
                FROM produtos
                WHERE company_id = :company_id
                  AND id = :id
                LIMIT 1
            ");
            $stmt->execute([
                'company_id' => $companyId,
                'id' => $produtoId
            ]);
            $produto = $stmt->fetch();
            if (!$produto) {
                return null;
            }

            return [
                'id' => (int) $produto['id'],
                'name' => $produto['name'],
                'price' => isset($produto['price']) ? (float) $produto['price'] : 0.0,
                'fator_cashback' => isset($produto['fator_cashback']) ? (float) $produto['fator_cashback'] : 0.0,
            ];
        } catch (Exception $e) {
            error_log('Erro ao buscar produto básico para triagem: ' . $e->getMessage());
            return null;
        }
    }

    private function obterConfiguracaoTriagemProdutos(int $companyId): array
    {
        $produtoGarrafao = $this->buscarProdutoBasico($companyId, 2);

        return [
            'garrafao' => $produtoGarrafao,
            'itensAutomaticos' => [
                'envaze' => 1,
                'garrafao' => 2,
                'lacre' => 3,
                'selo' => 4,
                'tampa' => 5
            ]
        ];
    }

    private function tabelaTemColuna(string $tabela, string $coluna): bool
    {
        $cacheKey = "{$tabela}.{$coluna}";
        if (array_key_exists($cacheKey, $this->colunasTabelaCache)) {
            return $this->colunasTabelaCache[$cacheKey];
        }

        try {
            $stmt = $this->db->prepare("SHOW COLUMNS FROM {$tabela} LIKE :coluna");
            $stmt->execute(['coluna' => $coluna]);
            $existe = (bool) $stmt->fetch();
        } catch (Exception $e) {
            $existe = false;
        }

        $this->colunasTabelaCache[$cacheKey] = $existe;
        return $existe;
    }

    private function criarVendaGarrafao(int $companyId, array $pedido): int
    {
        $saleNumber = $this->gerarSaleNumberDerivado($companyId, (string) ($pedido['sale_number'] ?? 'PED-' . $pedido['id']), '-GAR');
        $temLinhaTemporal = $this->tabelaTemColuna('vendas', 'linha_temporal');
        $colunaLinhaTemporal = $temLinhaTemporal ? ', linha_temporal' : '';
        $valorLinhaTemporal = $temLinhaTemporal ? ", 'pedido'" : '';

        $stmtInsert = $this->db->prepare("
            INSERT INTO vendas (
                company_id,
                modulo_origem,
                customer_id,
                customer_type,
                customer_name,
                customer_document,
                sale_number,
                sale_date,
                status,
                notes,
                subtotal,
                discount,
                total,
                generate_receivables,
                update_stock,
                created_at,
                updated_at
                {$colunaLinhaTemporal}
            ) VALUES (
                :company_id,
                'pedido',
                :customer_id,
                'pessoa',
                :customer_name,
                :customer_document,
                :sale_number,
                CURDATE(),
                'pedido',
                :notes,
                0,
                0,
                0,
                1,
                1,
                NOW(),
                NOW()
                {$valorLinhaTemporal}
            )
        ");

        $stmtInsert->execute([
            'company_id' => $companyId,
            'customer_id' => $pedido['customer_id'],
            'customer_name' => $pedido['customer_name'],
            'customer_document' => $pedido['customer_document'],
            'sale_number' => $saleNumber,
            'notes' => 'Venda (garrafões) gerada automaticamente a partir do pedido #' . ($pedido['sale_number'] ?? $pedido['id'])
        ]);

        $garrafaoId = (int) $this->db->lastInsertId();

        if ($temLinhaTemporal) {
            $this->definirLinhaTemporalVenda($garrafaoId, 'pedido');
        }

        return $garrafaoId;
    }

    private function gerarSaleNumberDerivado(int $companyId, string $baseNumber, string $sufixo): string
    {
        $tentativa = $baseNumber . $sufixo;
        $contador = 1;
        while ($this->saleNumberExiste($companyId, $tentativa)) {
            $tentativa = $baseNumber . $sufixo . '-' . $contador;
            $contador++;
        }
        return $tentativa;
    }

    private function saleNumberExiste(int $companyId, string $saleNumber): bool
    {
        $stmt = $this->db->prepare("
            SELECT 1 FROM vendas
            WHERE company_id = :company_id AND sale_number = :sale_number
            LIMIT 1
        ");
        $stmt->execute([
            'company_id' => $companyId,
            'sale_number' => $saleNumber
        ]);
        return (bool) $stmt->fetchColumn();
    }

    private function atualizarTotaisVenda(int $vendaId): void
    {
        $stmt = $this->db->prepare("
            UPDATE vendas v
            SET subtotal = (
                    SELECT COALESCE(SUM(total_price), 0)
                    FROM vendas_itens
                    WHERE venda_id = v.id
                ),
                total = (
                    SELECT COALESCE(SUM(total_price), 0)
                    FROM vendas_itens
                    WHERE venda_id = v.id
                ),
                updated_at = NOW()
            WHERE v.id = :id
            LIMIT 1
        ");
        $stmt->execute(['id' => $vendaId]);
    }

    private function processarWorkflowTriagem(int $companyId, array $pedido, array $workflow, ?float $quantidadeContada, ?float $aptoEnvaze, ?float $inaptoTriagem): void
    {
        try {
            $resumo = $workflow['resumo'] ?? [];
            $acoes = $workflow['acoes'] ?? [];

            $completarQuantidade = !empty($acoes['completarQuantidade']);
            $converterCashback = !empty($acoes['converterCashback']);
            $completarSobra = !empty($acoes['completarSobra']);

            $quantInformada = isset($resumo['informada']) ? (int) $resumo['informada'] : (int) ($pedido['qtd_informada'] ?? 0);
            $quantContada = isset($resumo['contada']) ? (int) $resumo['contada'] : (int) ($quantidadeContada ?? 0);
            $quantApto = isset($resumo['apto']) ? (int) $resumo['apto'] : (int) ($aptoEnvaze ?? 0);
            $quantInapto = isset($resumo['inapto']) ? (int) $resumo['inapto'] : (int) ($inaptoTriagem ?? 0);
            $cashbackTotal = isset($resumo['cashbackTotal']) ? (int) $resumo['cashbackTotal'] : 0;
            $cashbackSobra = isset($resumo['cashbackSobra']) ? (int) $resumo['cashbackSobra'] : 0;
            $descontoCalculado = isset($resumo['descontoCalculado']) ? (float) $resumo['descontoCalculado'] : 0.0;

            $triagemProdutos = $this->obterConfiguracaoTriagemProdutos($companyId);
            $produtoGarrafao = $triagemProdutos['garrafao'] ?? null;
            if (!$produtoGarrafao) {
                throw new Exception('Produto garrafão não configurado para triagem.');
            }

            $itensAutomaticos = $triagemProdutos['itensAutomaticos'] ?? [];
            if (empty($itensAutomaticos)) {
                throw new Exception('Itens automáticos da triagem não configurados.');
            }

            $quantidadeGarrafaoCashback = 0;
            if ($converterCashback && $cashbackTotal > 0) {
                $quantidadeGarrafaoCashback += $cashbackTotal;
            }
            if ($completarQuantidade) {
                $diferencaPortaria = max(0, $quantInformada - $quantContada);
                $quantidadeGarrafaoCashback += $diferencaPortaria;
            }

            if ($quantidadeGarrafaoCashback <= 0 && !$converterCashback && !$completarQuantidade) {
                return;
            }

            $this->db->beginTransaction();

            $garrafaoVendaId = null;
            $envazeAtualizado = false;

            if ($converterCashback) {
                if ($quantidadeGarrafaoCashback > 0) {
                    $garrafaoVendaId = $this->criarVendaGarrafao($companyId, $pedido);
                    $this->definirLinhaTemporalVenda((int) $pedido['id'], 'pedido');
                    $this->adicionarItemVenda(
                        $garrafaoVendaId,
                        $itensAutomaticos['garrafao'] ?? 2,
                        $quantidadeGarrafaoCashback,
                        $produtoGarrafao['price'] ?? 0.0
                    );
                }

                $quantidadeEnvaze = $quantContada > 0 ? $quantContada : $quantApto;
                if ($quantidadeEnvaze > 0) {
                    foreach (['envaze', 'lacre', 'selo', 'tampa'] as $chaveItem) {
                        if (!isset($itensAutomaticos[$chaveItem])) {
                            continue;
                        }
                        $this->adicionarItemVenda(
                            $pedido['id'],
                            $itensAutomaticos[$chaveItem],
                            $quantidadeEnvaze
                        );
                        $envazeAtualizado = true;
                    }
                }

                if ($garrafaoVendaId && $cashbackSobra > 0 && $completarSobra && $produtoGarrafao['price'] > 0 && $produtoGarrafao['fator_cashback'] > 0) {
                    $valorUnitario = ($produtoGarrafao['price'] / $produtoGarrafao['fator_cashback']) * $cashbackSobra;
                    if ($valorUnitario > 0) {
                        $this->atualizarDescontoVenda((int) $garrafaoVendaId, $valorUnitario);
                    }
                }
            } elseif ($quantidadeGarrafaoCashback > 0) {
                $garrafaoVendaId = $this->criarVendaGarrafao($companyId, $pedido);
                $this->definirLinhaTemporalVenda((int) $pedido['id'], 'pedido');
                $this->adicionarItemVenda(
                    $garrafaoVendaId,
                    $itensAutomaticos['garrafao'] ?? 2,
                    $quantidadeGarrafaoCashback,
                    $produtoGarrafao['price'] ?? 0.0
                );
            }

            if ($envazeAtualizado) {
                $this->atualizarTotaisVenda($pedido['id']);
            }

            if ($garrafaoVendaId) {
                $this->atualizarTotaisVenda($garrafaoVendaId);
            }

            $this->db->commit();
        } catch (Exception $e) {
            $this->db->rollBack();
            error_log('Erro ao processar workflow de triagem: ' . $e->getMessage());
            throw $e;
        }
    }

    private function adicionarItemVenda(int $vendaId, int $produtoId, int $quantidade, float $precoUnitario = 0.0): void
    {
        if ($quantidade <= 0) {
            return;
        }

        $stmtProduto = $this->db->prepare("
            SELECT id, name, price
            FROM produtos
            WHERE id = :id
              AND company_id = :company_id
            LIMIT 1
        ");
        $stmtProduto->execute([
            'id' => $produtoId,
            'company_id' => $this->getCompanyId()
        ]);
        $produto = $stmtProduto->fetch();

        if (!$produto) {
            throw new Exception('Produto não encontrado para adicionar na venda.');
        }

        $price = $precoUnitario > 0 ? $precoUnitario : (float) ($produto['price'] ?? 0);
        $total = $price * $quantidade;

        $stmt = $this->db->prepare("
            INSERT INTO vendas_itens (
                company_id,
                venda_id,
                product_id,
                product_name,
                quantity,
                unit_price,
                total_price,
                created_at
            ) VALUES (
                :company_id,
                :venda_id,
                :product_id,
                :product_name,
                :quantity,
                :unit_price,
                :total_price,
                NOW()
            )
        ");

        $stmt->execute([
            'company_id' => $this->getCompanyId(),
            'venda_id' => $vendaId,
            'product_id' => $produtoId,
            'product_name' => $produto['name'],
            'quantity' => $quantidade,
            'unit_price' => $price,
            'total_price' => $total
        ]);
    }

    private function atualizarDescontoVenda(int $vendaId, float $valorDesconto): void
    {
        $stmt = $this->db->prepare("
            UPDATE vendas
            SET discount = COALESCE(discount, 0) + :valor_desconto,
                updated_at = NOW()
            WHERE id = :id
            LIMIT 1
        ");

        $stmt->execute([
            'valor_desconto' => $valorDesconto,
            'id' => $vendaId
        ]);
    }

    /**
     * Gera contas a receber para um pedido após pagamento aprovado
     */
    private function gerarContasReceber(int $pedidoId, array $pedidoData): void
    {
        try {
            $companyId = $this->getCompanyId();

            if (!$companyId) {
                throw new Exception("Company ID não pode ser nulo");
            }

            if (empty($pedidoData['payment_method_id'])) {
                throw new Exception("Método de pagamento é obrigatório para gerar contas a receber");
            }

            if (empty($pedidoData['total']) || (float)$pedidoData['total'] <= 0) {
                throw new Exception("Total do pedido deve ser maior que zero");
            }

            // Verificar estrutura da tabela
            $stmtCheck = $this->db->prepare("SHOW COLUMNS FROM contas_receber");
            $stmtCheck->execute();
            $colunas = $stmtCheck->fetchAll(\PDO::FETCH_COLUMN);
            $colunasArray = array_flip($colunas);

            $temCustomerId = isset($colunasArray['customer_id']);
            $temPessoaId = isset($colunasArray['pessoa_id']);
            $temVendaId = isset($colunasArray['venda_id']);
            $temAmountPaid = isset($colunasArray['amount_paid']);
            $temAmountReceived = isset($colunasArray['amount_received']);
            $temMetodoPagamentoId = isset($colunasArray['metodo_pagamento_id']);
            $temPaymentMethod = isset($colunasArray['payment_method']);
            $temNumero = isset($colunasArray['numero']);

            // Verificar se já existem contas a receber para este pedido
            if ($temVendaId) {
                $whereVenda = "venda_id = :venda_id AND company_id = :company_id";
                $paramsVenda = ['venda_id' => $pedidoId, 'company_id' => $companyId];
            } else {
                $whereVenda = "company_id = :company_id AND description LIKE :desc_pattern";
                $descPattern = "Pedido #{$pedidoData['sale_number']}%";
                $paramsVenda = ['company_id' => $companyId, 'desc_pattern' => $descPattern];
            }

            $camposSelect = ['id', 'description', 'amount', 'amount_remaining', 'due_date'];
            if ($temAmountPaid) {
                $camposSelect[] = 'amount_paid';
            } elseif ($temAmountReceived) {
                $camposSelect[] = 'amount_received';
            }

            $stmtExistentes = $this->db->prepare("
                SELECT " . implode(', ', $camposSelect) . "
                FROM contas_receber
                WHERE {$whereVenda}
                ORDER BY due_date ASC
            ");
            $stmtExistentes->execute($paramsVenda);
            $contasExistentes = $stmtExistentes->fetchAll();

            $totalPedido = (float) ($pedidoData['total'] ?? 0);
            $numParcelas = (int) ($pedidoData['installments'] ?? 1);
            $numParcelas = max(1, $numParcelas);

            $dataPedido = $pedidoData['sale_date'] ?? date('Y-m-d');
            $dataBase = new \DateTime($dataPedido);

            // Buscar informações do prazo de pagamento se houver
            $diasPrazoTotal = 0;
            if (!empty($pedidoData['payment_term_id'])) {
                $stmtPrazo = $this->db->prepare("
                    SELECT dias FROM metodos_pagamento_prazos
                    WHERE id = :term_id AND company_id = :company_id AND ativo = 1
                    LIMIT 1
                ");
                $stmtPrazo->execute([
                    'term_id' => $pedidoData['payment_term_id'],
                    'company_id' => $companyId
                ]);
                $prazo = $stmtPrazo->fetch();
                if ($prazo && !empty($prazo['dias'])) {
                    $diasPrazoTotal = (int) $prazo['dias'];
                }
            }

            // Se não há prazo configurado, usar 30 dias por parcela como padrão
            if ($diasPrazoTotal <= 0) {
                $diasPrazoTotal = 30 * $numParcelas;
            }

            $diasPorParcela = (int) ceil($diasPrazoTotal / $numParcelas);

            // Calcular valor das parcelas
            $valorParcela = $totalPedido / $numParcelas;
            $valorParcelaArredondado = floor($valorParcela * 100) / 100;
            $resto = $totalPedido - ($valorParcelaArredondado * $numParcelas);

            // Buscar próximo número se o campo existir
            $proximoNumero = 1;
            if ($temNumero) {
                try {
                    $stmtNum = $this->db->prepare("
                        SELECT numero FROM contas_receber
                        WHERE company_id = :company_id AND numero IS NOT NULL AND numero != ''
                        ORDER BY CAST(numero AS UNSIGNED) DESC LIMIT 1
                    ");
                    $stmtNum->execute(['company_id' => $companyId]);
                    $ultimaConta = $stmtNum->fetch();
                    if ($ultimaConta && !empty($ultimaConta['numero'])) {
                        $ultimoNumero = (int) filter_var($ultimaConta['numero'], FILTER_SANITIZE_NUMBER_INT);
                        if ($ultimoNumero > 0) {
                            $proximoNumero = $ultimoNumero + 1;
                        }
                    }
                } catch (\Exception $e) {
                    $proximoNumero = 1;
                    $temNumero = false;
                }
            }

            // Preparar query de inserção
            $camposInsert = ['company_id', 'description', 'amount', 'amount_remaining', 'due_date', 'status', 'notes'];
            $valoresInsert = [':company_id', ':description', ':amount', ':amount_remaining', ':due_date', ':status', ':notes'];

            if ($temAmountPaid) {
                $camposInsert[] = 'amount_paid';
                $valoresInsert[] = ':amount_paid';
            } elseif ($temAmountReceived) {
                $camposInsert[] = 'amount_received';
                $valoresInsert[] = ':amount_received';
            }

            if ($temNumero) {
                $camposInsert[] = 'numero';
                $valoresInsert[] = ':numero';
            }

            if ($temPessoaId) {
                $camposInsert[] = 'pessoa_id';
                $valoresInsert[] = ':pessoa_id';
            } elseif ($temCustomerId) {
                $camposInsert[] = 'customer_id';
                $valoresInsert[] = ':customer_id';
            }

            if ($temVendaId) {
                $camposInsert[] = 'venda_id';
                $valoresInsert[] = ':venda_id';
            }

            if ($temMetodoPagamentoId && !empty($pedidoData['payment_method_id'])) {
                $camposInsert[] = 'metodo_pagamento_id';
                $valoresInsert[] = ':metodo_pagamento_id';
            } elseif ($temPaymentMethod && !empty($pedidoData['payment_method_id'])) {
                $camposInsert[] = 'payment_method';
                $valoresInsert[] = ':payment_method';
            }

            $sqlInsert = "INSERT INTO contas_receber (" . implode(', ', $camposInsert) . ", created_at, updated_at) VALUES (" . implode(', ', $valoresInsert) . ", NOW(), NOW())";
            $stmtInsert = $this->db->prepare($sqlInsert);

            // Se o número de parcelas mudou e há contas existentes, deletar as antigas
            if (count($contasExistentes) > 0 && count($contasExistentes) != $numParcelas) {
                if ($temVendaId) {
                    $stmtDelete = $this->db->prepare("
                        DELETE FROM contas_receber
                        WHERE venda_id = :venda_id AND company_id = :company_id
                    ");
                    $stmtDelete->execute(['venda_id' => $pedidoId, 'company_id' => $companyId]);
                } else {
                    $descPattern = "Pedido #{$pedidoData['sale_number']}%";
                    $stmtDelete = $this->db->prepare("
                        DELETE FROM contas_receber
                        WHERE company_id = :company_id AND description LIKE :desc_pattern
                    ");
                    $stmtDelete->execute(['company_id' => $companyId, 'desc_pattern' => $descPattern]);
                }
                $contasExistentes = [];
            }

            // Preparar dados do cliente
            $clienteId = $pedidoData['customer_id'] ?? null;
            $clienteNome = $pedidoData['customer_name'] ?? 'Cliente não informado';

            // Criar uma conta para cada parcela
            for ($i = 1; $i <= $numParcelas; $i++) {
                $valorParcelaAtual = $valorParcelaArredondado;
                if ($i == $numParcelas) {
                    $valorParcelaAtual += $resto;
                }

                if ($valorParcelaAtual <= 0) {
                    $valorParcelaAtual = $totalPedido / $numParcelas;
                }

                $valorFinal = round($valorParcelaAtual, 2);

                // Calcular data de vencimento
                $dataVencimento = clone $dataBase;
                $diasAdicionar = ($i - 1) * $diasPorParcela;
                $dataVencimento->modify("+{$diasAdicionar} days");

                // Descrição
                $descricaoParcela = "Pedido #{$pedidoData['sale_number']}";
                if ($numParcelas > 1) {
                    $descricaoParcela .= " - Parcela {$i} de {$numParcelas}";
                }

                // Verificar se já existe conta para esta parcela
                $contaExistente = null;
                foreach ($contasExistentes as $conta) {
                    preg_match('/Parcela\s+(\d+)/i', $conta['description'] ?? '', $matches);
                    $parcela = !empty($matches[1]) ? (int)$matches[1] : 1;
                    if ($parcela == $i) {
                        $contaExistente = $conta;
                        break;
                    }
                }

                if (!$contaExistente) {
                    // Criar nova conta
                    $dadosConta = [
                        'company_id' => (int)$companyId,
                        'description' => $descricaoParcela,
                        'amount' => (float)$valorFinal,
                        'amount_remaining' => (float)$valorFinal,
                        'due_date' => $dataVencimento->format('Y-m-d'),
                        'status' => 'pendente',
                        'notes' => !empty($pedidoData['notes']) ? "Pedido #{$pedidoData['sale_number']}: {$pedidoData['notes']}" : "Gerada automaticamente do pedido #{$pedidoData['sale_number']}"
                    ];

                    if ($temAmountPaid) {
                        $dadosConta['amount_paid'] = 0.00;
                    } elseif ($temAmountReceived) {
                        $dadosConta['amount_received'] = 0.00;
                    }

                    if ($temNumero) {
                        $dadosConta['numero'] = (string)$proximoNumero;
                        $proximoNumero++;
                    }

                    if ($temPessoaId && $clienteId) {
                        $dadosConta['pessoa_id'] = (int)$clienteId;
                    } elseif ($temCustomerId && $clienteId) {
                        $dadosConta['customer_id'] = (int)$clienteId;
                    }

                    if ($temVendaId) {
                        $dadosConta['venda_id'] = (int)$pedidoId;
                    }

                    if ($temMetodoPagamentoId && !empty($pedidoData['payment_method_id'])) {
                        $dadosConta['metodo_pagamento_id'] = (int)$pedidoData['payment_method_id'];
                    } elseif ($temPaymentMethod && !empty($pedidoData['payment_method_id'])) {
                        $dadosConta['payment_method'] = (int)$pedidoData['payment_method_id'];
                    }

                    $stmtInsert->execute($dadosConta);
                    $contaId = (int) $this->db->lastInsertId();
                    error_log("Pedido #{$pedidoId}: Conta a receber criada - Parcela {$i} - Valor: R$ " . number_format($valorFinal, 2, ',', '.'));

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

            error_log("Pedido #{$pedidoId}: Contas a receber geradas com sucesso - {$numParcelas} parcela(s)");

        } catch (Exception $e) {
            error_log("Erro ao gerar contas a receber para pedido #{$pedidoId}: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * 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);
                        error_log("Pedido: Boleto Shipay gerado para conta #{$contaId} - Charge ID: {$chargeId}");
                    }
                }
            }

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