<?php
/**
 * Backend Boleto Mercado Pago - Versão Simples Atualizada para SDK v3.5+
 * Processamento de pagamento via Boleto Bancário (Mercado Pago)
 */

// Configuração de logs brutos para diagnóstico
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/erro_php_bruto.log');
error_reporting(E_ALL);

// Forçar JSON no header
header('Content-Type: application/json; charset=utf-8');

// Autoload do Composer
require __DIR__ . '/../vendor/autoload.php'; 

// Conexão com o banco de dados
require __DIR__ . '/../config/config_db.php'; 

// Importa o arquivo com o access token
require __DIR__ . '/../config/token.php'; 

// Imports do SDK v3.5+
use MercadoPago\Client\Payment\PaymentClient;
use MercadoPago\Client\Common\RequestOptions;
use MercadoPago\MercadoPagoConfig;
use MercadoPago\Exceptions\MPApiException;

// Tratamento global de erros
set_error_handler(function($errno, $errstr, $errfile, $errline) {
    error_log("Erro em process_payment_boleto_mercadopago.php: [$errno] $errstr em $errfile:$errline");
    return false;
});

// Defina o cabeçalho da resposta como JSON
header('Content-Type: application/json; charset=utf-8');

// Garantir que sempre retorne JSON, mesmo em caso de erro fatal
register_shutdown_function(function() {
    $error = error_get_last();
    if ($error !== NULL && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR])) {
        http_response_code(500);
        echo json_encode([
            'status' => 'error',
            'message' => 'Erro interno do servidor. Por favor, tente novamente.'
        ]);
    }
});

// Configurar o token de acesso do Mercado Pago (Nova forma v3)
try {
    MercadoPagoConfig::setAccessToken(ACCESS_TOKEN);
    MercadoPagoConfig::setRuntimeEnviroment(MercadoPagoConfig::LOCAL);
} catch (Exception $e) {
    echo json_encode(['status' => 'error', 'message' => 'Erro na configuração do SDK: ' . $e->getMessage()]);
    exit;
}

// Envolver TODO o código principal em try-catch para capturar erros fatais
try {
    // Recebe os dados enviados pelo front-end (JSON)
    $raw_input = file_get_contents('php://input');
    $data = json_decode($raw_input, true);
    
    // Verificar se o JSON foi decodificado corretamente
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new Exception('Erro ao decodificar JSON: ' . json_last_error_msg());
    }
    
    // Verifica se os dados obrigatórios foram fornecidos
    if (!isset($data['transaction_amount']) || !isset($data['payer']['email']) || !isset($data['payer']['phone']['number']) || !isset($data['link_entregavel'])) {
        $missing = [];
        if (!isset($data['transaction_amount'])) $missing[] = 'transaction_amount';
        if (!isset($data['payer']['email'])) $missing[] = 'payer.email';
        if (!isset($data['payer']['phone']['number'])) $missing[] = 'payer.phone.number';
        if (!isset($data['link_entregavel'])) $missing[] = 'link_entregavel';
        throw new Exception('Dados obrigatórios não foram fornecidos: ' . implode(', ', $missing));
    }

    // ============================================================
    // BLINDAGEM: BUSCAR PREÇO REAL DO BANCO DE DADOS (Backend Authority)
    // ============================================================
    $produto_id_para_preco = isset($data['product']['id']) ? intval($data['product']['id']) : null;
    $transaction_amount_original = isset($data['transaction_amount']) ? floatval($data['transaction_amount']) : 0;
    
    // Se temos product_id, buscar preço do banco (ignorar valor do frontend)
    if ($produto_id_para_preco > 0) {
        try {
            $sql_preco = "SELECT preco_atual, preco FROM produtos WHERE id = :produto_id LIMIT 1";
            $stmt_preco = $pdo->prepare($sql_preco);
            $stmt_preco->execute([':produto_id' => $produto_id_para_preco]);
            $row_preco = $stmt_preco->fetch(PDO::FETCH_ASSOC);
            
            if ($row_preco) {
                // Priorizar preco_atual, se não tiver ou for 0, usar preco
                $preco_banco = !empty($row_preco['preco_atual']) && floatval($row_preco['preco_atual']) > 0 
                    ? floatval($row_preco['preco_atual']) 
                    : floatval($row_preco['preco']);
                
                if ($preco_banco > 0) {
                    // SOBRESCREVER: Usar preço do banco (ignorar valor do frontend)
                    $data['transaction_amount'] = round($preco_banco, 2);
                    error_log("BOLETO BACKEND AUTHORITY: Produto ID {$produto_id_para_preco} - Preço do banco: R$ " . number_format($preco_banco, 2, ',', '.') . " | Valor recebido do frontend: R$ " . number_format($transaction_amount_original, 2, ',', '.') . " (IGNORADO)");
                } else {
                    error_log("BOLETO BACKEND AUTHORITY: Produto ID {$produto_id_para_preco} encontrado, mas preço está zerado no banco. Usando valor do frontend: R$ " . number_format($transaction_amount_original, 2, ',', '.'));
                }
            } else {
                error_log("BOLETO BACKEND AUTHORITY: Produto ID {$produto_id_para_preco} não encontrado no banco. Usando valor do frontend: R$ " . number_format($transaction_amount_original, 2, ',', '.'));
            }
        } catch (PDOException $e) {
            error_log("BOLETO BACKEND AUTHORITY: Erro ao buscar preço do produto: " . $e->getMessage() . " | Usando valor do frontend: R$ " . number_format($transaction_amount_original, 2, ',', '.'));
        }
    } else {
        error_log("BOLETO BACKEND AUTHORITY: Product ID não fornecido. Usando valor do frontend: R$ " . number_format($transaction_amount_original, 2, ',', '.'));
    }
    
    // Validação final: Garantir que transaction_amount seja válido
    if (empty($data['transaction_amount']) || floatval($data['transaction_amount']) <= 0) {
        throw new Exception('Valor da transação inválido ou zerado. Não é possível gerar boleto.');
    }
    // ============================================================

    // Separar nome completo (com múltiplas fontes e fallback - igual ao PIX)
    $first_name = 'Consumidor';
    $last_name = '';
    
    // Prioridade 1: payer.full_name
    if (isset($data['payer']['full_name']) && !empty(trim($data['payer']['full_name']))) {
        $name_parts = explode(' ', trim($data['payer']['full_name']), 2);
        $first_name = $name_parts[0] ?? 'Consumidor';
        $last_name = $name_parts[1] ?? '';
    }
    // Prioridade 2: payer.first_name + last_name
    elseif (isset($data['payer']['first_name']) && !empty(trim($data['payer']['first_name']))) {
        $first_name = trim($data['payer']['first_name']);
        $last_name = isset($data['payer']['last_name']) ? trim($data['payer']['last_name']) : '';
    }
    
    // Garantir que first_name não esteja vazio
    if (empty(trim($first_name))) {
        $first_name = 'Consumidor';
    }
    if (empty(trim($last_name))) {
        $last_name = 'Consumidor';
    }

    // Criar uma referência externa única
    $external_reference = uniqid('txn_', true);

    // Concatena código do país e código de área do telefone
    $country_code = isset($data['payer']['phone']['country_code']) ? preg_replace('/[^0-9+]/', '', $data['payer']['phone']['country_code']) : '';
    $area_code = isset($data['payer']['phone']['area_code']) ? preg_replace('/[^0-9]/', '', $data['payer']['phone']['area_code']) : '11'; // Fallback: São Paulo
    $phone_number_raw = isset($data['payer']['phone']['number']) ? $data['payer']['phone']['number'] : '000000000';
    $phone_number = preg_replace('/[^0-9]/', '', $phone_number_raw);
    
    // Garantir que area_code tenha 2 dígitos e phone_number tenha 9 dígitos
    if (strlen($area_code) > 2) {
        $area_code = substr($area_code, 0, 2);
    }
    if (strlen($phone_number) > 9) {
        $phone_number = substr($phone_number, -9);
    }
    if (empty($phone_number) || strlen($phone_number) < 8) {
        $phone_number = '000000000';
    }
    
    $full_phone_number = trim($country_code . ' ' . $area_code . ' ' . $phone_number);

    // Buscar produto_id e produtor_id
    $produto_id = isset($data['product']['id']) ? intval($data['product']['id']) : null;
    $produtor_id = null;
    $afiliado_id = null;
    $tipo_produto = 'digital'; // Default
    
    if ($produto_id) {
        try {
            $sql_produto = "SELECT usuario_id, tipo_produto FROM produtos WHERE id = :produto_id LIMIT 1";
            $stmt_produto = $pdo->prepare($sql_produto);
            $stmt_produto->execute([':produto_id' => $produto_id]);
            $produto = $stmt_produto->fetch(PDO::FETCH_ASSOC);
            if ($produto) {
                $produtor_id = intval($produto['usuario_id']);
                $tipo_produto = $produto['tipo_produto'] ?? 'digital';
            }
        } catch (PDOException $e) {
            error_log("Erro ao buscar produtor: " . $e->getMessage());
        }
    }
    
    // Buscar afiliado do cookie
    if (isset($_COOKIE['affiliate_id']) && isset($_COOKIE['affiliate_produto_id'])) {
        $cookie_afiliado_id = intval($_COOKIE['affiliate_id']);
        $cookie_produto_id = intval($_COOKIE['affiliate_produto_id']);
        
        // Validar se o afiliado é válido para este produto
        if ($cookie_produto_id == $produto_id && $cookie_afiliado_id > 0) {
            try {
                $sql_afiliado = "SELECT usuario_id FROM afiliacoes WHERE id = :afiliado_id AND produto_id = :produto_id AND status = 'ativo' LIMIT 1";
                $stmt_afiliado = $pdo->prepare($sql_afiliado);
                $stmt_afiliado->execute([':afiliado_id' => $cookie_afiliado_id, ':produto_id' => $produto_id]);
                $afiliado = $stmt_afiliado->fetch(PDO::FETCH_ASSOC);
                if ($afiliado) {
                    $afiliado_id = intval($afiliado['usuario_id']);
                }
            } catch (PDOException $e) {
                error_log("Erro ao buscar afiliado: " . $e->getMessage());
            }
        }
    }
    
    // ENDEREÇO E FRETE (Produtos Físicos e Boleto - SEMPRE OBRIGATÓRIO para Boleto)
    $safeEnderecoJson = null;
    $safeFreteCobrado = 0;
    $safeStatusEntrega = null;
    
    // VALIDAÇÃO CRÍTICA: Para BOLETO, endereço é SEMPRE OBRIGATÓRIO (independente do tipo do produto)
    // Para produtos físicos (outros métodos de pagamento), endereço também é obrigatório
    // IMPORTANTE: Como este é o arquivo de processamento de BOLETO, o endereço é SEMPRE obrigatório
    if (!isset($data['endereco_json']) || empty($data['endereco_json'])) {
        throw new Exception('Por favor, preencha todos os campos de endereço obrigatórios. Boleto requer endereço de entrega.');
    }
    
    $endereco_array = json_decode($data['endereco_json'], true);
    if (json_last_error() !== JSON_ERROR_NONE || !is_array($endereco_array)) {
        throw new Exception('Erro ao processar dados de endereço. Por favor, verifique os campos e tente novamente.');
    }
    
    // Validar campos obrigatórios
    $campos_faltando = [];
    if (empty($endereco_array['cep']) || strlen(preg_replace('/[^0-9]/', '', $endereco_array['cep'])) !== 8) {
        $campos_faltando[] = 'CEP';
    }
    if (empty($endereco_array['rua'])) {
        $campos_faltando[] = 'Rua';
    }
    if (empty($endereco_array['numero']) || $endereco_array['numero'] === '0') {
        $campos_faltando[] = 'Número';
    }
    if (empty($endereco_array['bairro'])) {
        $campos_faltando[] = 'Bairro';
    }
    if (empty($endereco_array['cidade'])) {
        $campos_faltando[] = 'Cidade';
    }
    if (empty($endereco_array['estado']) || strlen($endereco_array['estado']) !== 2) {
        $campos_faltando[] = 'Estado (UF)';
    }
    
    if (!empty($campos_faltando)) {
        throw new Exception('Por favor, preencha todos os campos de endereço obrigatórios: ' . implode(', ', $campos_faltando));
    }
    
    $safeEnderecoJson = $data['endereco_json'];
    $safeStatusEntrega = 'preparando';
    
    if (isset($data['frete_cobrado']) && is_numeric($data['frete_cobrado'])) {
        $safeFreteCobrado = max(0, floatval($data['frete_cobrado']));
    }

    // Insere a transação no banco de dados
    try {
        $stmt = $pdo->prepare("INSERT INTO transacoes (produto_id, produtor_id, afiliado_id, nome, sobrenome, email, telefone, cpf, device_ip, valor, descricao, status, tipo_pagamento, gateway, device_id, external_reference, metadados, link_entregavel, endereco_json, frete_cobrado, status_entrega) 
                               VALUES (:produto_id, :produtor_id, :afiliado_id, :nome, :sobrenome, :email, :telefone, :cpf, :device_ip, :valor, :descricao, :status, :tipo_pagamento, :gateway, :device_id, :external_reference, :metadados, :link_entregavel, :endereco_json, :frete_cobrado, :status_entrega)");
        $stmt->execute([
            ':produto_id' => $produto_id,
            ':produtor_id' => $produtor_id,
            ':afiliado_id' => $afiliado_id,
            ':nome' => $first_name,
            ':sobrenome' => $last_name,
            ':email' => $data['payer']['email'],
            ':telefone' => $full_phone_number,
            ':cpf' => isset($data['payer']['identification']['number']) ? $data['payer']['identification']['number'] : null,
            ':device_ip' => isset($data['client_ip']) ? $data['client_ip'] : null,
            ':valor' => round((float)$data['transaction_amount'], 2),
            ':descricao' => $data['description'],
            ':status' => 'Pendente',
            ':tipo_pagamento' => 'Boleto',
            ':gateway' => 'mercadopago',
            ':device_id' => isset($data['device_id']) ? $data['device_id'] : null,
            ':external_reference' => $external_reference,
            ':metadados' => json_encode($data['additional_products'] ?? []),
            ':link_entregavel' => $data['link_entregavel'] ?? '',
            ':endereco_json' => $safeEnderecoJson,
            ':frete_cobrado' => $safeFreteCobrado,
            ':status_entrega' => $safeStatusEntrega
        ]);
    } catch (PDOException $e) {
        // Se falhar por colunas novas, tentar sem elas
        if (strpos($e->getMessage(), 'endereco_json') !== false || strpos($e->getMessage(), 'frete_cobrado') !== false || strpos($e->getMessage(), 'status_entrega') !== false) {
            try {
                $stmt = $pdo->prepare("INSERT INTO transacoes (produto_id, produtor_id, afiliado_id, nome, sobrenome, email, telefone, cpf, device_ip, valor, descricao, status, tipo_pagamento, gateway, device_id, external_reference, metadados, link_entregavel) 
                                       VALUES (:produto_id, :produtor_id, :afiliado_id, :nome, :sobrenome, :email, :telefone, :cpf, :device_ip, :valor, :descricao, :status, :tipo_pagamento, :gateway, :device_id, :external_reference, :metadados, :link_entregavel)");
                $stmt->execute([
                    ':produto_id' => $produto_id,
                    ':produtor_id' => $produtor_id,
                    ':afiliado_id' => $afiliado_id,
                    ':nome' => $first_name,
                    ':sobrenome' => $last_name,
                    ':email' => $data['payer']['email'],
                    ':telefone' => $full_phone_number,
                    ':cpf' => isset($data['payer']['identification']['number']) ? $data['payer']['identification']['number'] : null,
                    ':device_ip' => isset($data['client_ip']) ? $data['client_ip'] : null,
                    ':valor' => round((float)$data['transaction_amount'], 2),
                    ':descricao' => $data['description'],
                    ':status' => 'Pendente',
                    ':tipo_pagamento' => 'Boleto',
                    ':gateway' => 'mercadopago',
                    ':device_id' => isset($data['device_id']) ? $data['device_id'] : null,
                    ':external_reference' => $external_reference,
                    ':metadados' => json_encode($data['additional_products'] ?? []),
                    ':link_entregavel' => $data['link_entregavel'] ?? ''
                ]);
            } catch (PDOException $e2) {
                // Retrocompatibilidade: se as colunas principais não existirem
                if (strpos($e2->getMessage(), 'produto_id') !== false || strpos($e2->getMessage(), 'produtor_id') !== false || strpos($e2->getMessage(), 'afiliado_id') !== false) {
                    $stmt = $pdo->prepare("INSERT INTO transacoes (nome, sobrenome, email, telefone, cpf, device_ip, valor, descricao, status, tipo_pagamento, gateway, device_id, external_reference, metadados, link_entregavel) 
                                           VALUES (:nome, :sobrenome, :email, :telefone, :cpf, :device_ip, :valor, :descricao, :status, :tipo_pagamento, :gateway, :device_id, :external_reference, :metadados, :link_entregavel)");
                    $stmt->execute([
                        ':nome' => $first_name,
                        ':sobrenome' => $last_name,
                        ':email' => $data['payer']['email'],
                        ':telefone' => $full_phone_number,
                        ':cpf' => isset($data['payer']['identification']['number']) ? $data['payer']['identification']['number'] : null,
                        ':device_ip' => isset($data['client_ip']) ? $data['client_ip'] : null,
                        ':valor' => round((float)$data['transaction_amount'], 2),
                        ':descricao' => $data['description'],
                        ':status' => 'Pendente',
                        ':tipo_pagamento' => 'Boleto',
                        ':gateway' => 'mercadopago',
                        ':device_id' => isset($data['device_id']) ? $data['device_id'] : null,
                        ':external_reference' => $external_reference,
                        ':metadados' => json_encode($data['additional_products'] ?? []),
                        ':link_entregavel' => $data['link_entregavel'] ?? ''
                    ]);
                } else {
                    throw $e2;
                }
            }
        } else {
            throw $e;
        }
    }

    // Obtém o último ID inserido no banco de dados
    $transaction_id = $pdo->lastInsertId();

    // Inserir cada produto adicional na tabela `transacoes_adicionais`
    if (isset($data['additional_products']) && is_array($data['additional_products']) && !empty($data['additional_products'])) {
        foreach ($data['additional_products'] as $produto) {
            // Validar estrutura do produto antes de inserir
            if (isset($produto['id']) && isset($produto['nome']) && isset($produto['preco'])) {
                try {
                    $stmt = $pdo->prepare("INSERT INTO transacoes_adicionais (transacao_id, produto_id, nome, preco) 
                                           VALUES (:transacao_id, :produto_id, :nome, :preco)");
                    $stmt->execute([
                        ':transacao_id' => $transaction_id,
                        ':produto_id' => (int)$produto['id'],
                        ':nome' => trim($produto['nome']),
                        ':preco' => round((float)$produto['preco'], 2)
                    ]);
                } catch (PDOException $e) {
                    error_log("Erro ao inserir produto adicional (boleto): " . $e->getMessage());
                    // Continuar processamento mesmo se houver erro em produto adicional
                }
            } else {
                error_log("Produto adicional com estrutura inválida (boleto): " . json_encode($produto));
            }
        }
    }

    // ============ CRIAR PAGAMENTO BOLETO COM SDK v3 ============
    
    $client = new PaymentClient();
    
    // Criar request options com idempotency key
    $requestOptions = new RequestOptions();
    $idempotencyKey = uniqid('boleto_', true) . '_' . time();
    $requestOptions->setCustomHeaders(["X-Idempotency-Key: {$idempotencyKey}"]);
    
    // Validações finais antes de montar payload
    if (empty($data['payer']['email']) || !filter_var($data['payer']['email'], FILTER_VALIDATE_EMAIL)) {
        throw new Exception('Email do pagador é obrigatório e deve ser válido.');
    }
    
    if (empty(trim($first_name))) {
        $first_name = 'Consumidor';
    }
    
    if (empty(trim($last_name))) {
        $last_name = 'Consumidor';
    }
    
    // Validar CPF obrigatório antes de montar payload
    $cpf_limpo = isset($data['payer']['identification']['number']) ? preg_replace('/[^0-9]/', '', $data['payer']['identification']['number']) : '';
    if (empty($cpf_limpo) || strlen($cpf_limpo) !== 11) {
        throw new Exception('CPF é obrigatório para gerar boleto e deve ter 11 dígitos.');
    }
    
    // Validar transaction_amount final
    $transaction_amount_final = round((float)$data['transaction_amount'], 2);
    if ($transaction_amount_final <= 0) {
        throw new Exception('Valor da transação inválido ou zerado. Não é possível gerar boleto.');
    }
    
    // Preparar estrutura base do pagamento Boleto (Nova estrutura v3)
    $paymentData = [
        "transaction_amount" => $transaction_amount_final,
        "description" => $data['description'] ?? 'Pagamento via Boleto',
        "payment_method_id" => "bolbradesco", // Boleto Bancário
        "external_reference" => $external_reference,
        "notification_url" => "https://" . $_SERVER['HTTP_HOST'] . "/backend/webhook.php",
        "payer" => [
            "email" => trim($data['payer']['email']),
            "first_name" => trim($first_name),
            "last_name" => trim($last_name),
            "identification" => [
                "type" => "CPF",
                "number" => $cpf_limpo
            ],
            "phone" => [
                "area_code" => $area_code,
                "number" => $phone_number
            ]
        ],
        "date_of_expiration" => date('Y-m-d\TH:i:s.000-03:00', strtotime('+3 days')) // Boleto vence em 3 dias
    ];
    
    // ============================================================
    // ADICIONAR ENDEREÇO NO payer.address (OBRIGATÓRIO para BOLETO)
    // IMPORTANTE: Para BOLETO, o Mercado Pago EXIGE payer.address (diferente do PIX)
    // ============================================================
    if (!empty($safeEnderecoJson)) {
        $endereco_array = json_decode($safeEnderecoJson, true);
        if (json_last_error() === JSON_ERROR_NONE && is_array($endereco_array)) {
            // Sanitizar e validar campos do endereço
            $cep = preg_replace('/[^0-9]/', '', $endereco_array['cep'] ?? '');
            $rua = trim($endereco_array['rua'] ?? '');
            $numero = trim($endereco_array['numero'] ?? '');
            $bairro = trim($endereco_array['bairro'] ?? '');
            $cidade = trim($endereco_array['cidade'] ?? '');
            $estado = strtoupper(trim($endereco_array['estado'] ?? ''));
            
            // Garantir que CEP tenha 8 dígitos
            if (strlen($cep) === 8) {
                // Garantir que estado tenha 2 caracteres
                if (strlen($estado) === 2) {
                    // Montar endereço no formato exigido pela API
                    $paymentData['payer']['address'] = [
                        'zip_code' => $cep,
                        'street_name' => $rua,
                        'street_number' => $numero,
                        'neighborhood' => $bairro,
                        'city' => $cidade,
                        'federal_unit' => $estado
                    ];
                    
                    // Adicionar complemento se não estiver vazio
                    if (!empty(trim($endereco_array['complemento'] ?? ''))) {
                        $paymentData['payer']['address']['complement'] = trim($endereco_array['complemento']);
                    }
                    
                    error_log("BOLETO - payer.address montado: " . json_encode($paymentData['payer']['address'], JSON_UNESCAPED_UNICODE));
                } else {
                    error_log("BOLETO - Estado inválido (deve ter 2 caracteres): " . $estado);
                }
            } else {
                error_log("BOLETO - CEP inválido (deve ter 8 dígitos): " . $cep);
            }
        }
    }
    
    // ============================================================
    // ESTRUTURA PARA BOLETO: additional_info -> items (SEM shipments para BOLETO)
    // IMPORTANTE: Para BOLETO, o Mercado Pago NÃO aceita shipments.receiver_address (igual ao PIX)
    // O endereço é enviado em payer.address (acima), não em additional_info.shipments
    // ============================================================
    // Montar items: produto principal + produtos adicionais (se houver)
    $items = [];
    
    // Item principal
    $produto_nome = $data['description'] ?? 'Produto';
    $produto_preco = round((float)$data['transaction_amount'], 2);
    
    $items[] = [
        'id' => (string) ($produto_id ?? '1'),
        'title' => $produto_nome,
        'quantity' => 1,
        'unit_price' => $produto_preco
    ];
    
    // Adicionar produtos adicionais aos items se existirem
    if (isset($data['additional_products']) && is_array($data['additional_products']) && !empty($data['additional_products'])) {
        foreach ($data['additional_products'] as $produto_adicional) {
            if (isset($produto_adicional['id']) && isset($produto_adicional['nome']) && isset($produto_adicional['preco'])) {
                $items[] = [
                    'id' => (string) $produto_adicional['id'],
                    'title' => trim($produto_adicional['nome']),
                    'quantity' => 1,
                    'unit_price' => round((float)$produto_adicional['preco'], 2)
                ];
            }
        }
    }
    
    // Para BOLETO, enviar apenas items (sem shipments) - igual ao PIX
    // O endereço já foi validado e salvo no banco de dados
    if (!empty($items)) {
        $paymentData['additional_info'] = [
            'items' => $items
        ];
        error_log("BOLETO - additional_info montado (apenas items, SEM shipments): " . json_encode($paymentData['additional_info'], JSON_UNESCAPED_UNICODE));
    }
    
    // Validação final: Verificar se todos os dados obrigatórios estão presentes
    if (empty($paymentData['transaction_amount']) || $paymentData['transaction_amount'] <= 0) {
        throw new Exception('Valor da transação inválido. Não é possível gerar boleto.');
    }
    
    if (empty($paymentData['payer']['email'])) {
        throw new Exception('Email do pagador é obrigatório.');
    }
    
    if (empty($paymentData['payer']['first_name']) || empty($paymentData['payer']['last_name'])) {
        throw new Exception('Nome completo do pagador é obrigatório.');
    }
    
    if (empty($paymentData['payer']['identification']['number'])) {
        throw new Exception('CPF é obrigatório para gerar boleto.');
    }
    
    // Log do payload COMPLETO antes de enviar (debug) - SEM dados sensíveis completos
    $log_payload_before = $paymentData;
    if (isset($log_payload_before['payer']['identification']['number'])) {
        $cpf_log = $log_payload_before['payer']['identification']['number'];
        $log_payload_before['payer']['identification']['number'] = substr($cpf_log, 0, 3) . '***' . substr($cpf_log, -2);
    }
    error_log("BOLETO - Payload COMPLETO antes de enviar: " . json_encode($log_payload_before, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));

    try {
        // Criar pagamento
        $payment = $client->create($paymentData, $requestOptions);
        
        // Extrair URL do boleto e código de barras
        $ticket_url = '';
        $barcode = '';
        
        // Tentar diferentes formas de acessar a URL do boleto (SDK v3 pode retornar em formatos diferentes)
        if (isset($payment->transaction_details->external_resource_url)) {
            $ticket_url = $payment->transaction_details->external_resource_url;
        } elseif (isset($payment->point_of_interaction->transaction_data->external_resource_url)) {
            $ticket_url = $payment->point_of_interaction->transaction_data->external_resource_url;
        } elseif (method_exists($payment, 'getTransactionDetails') && $payment->getTransactionDetails()) {
            $ticket_url = $payment->getTransactionDetails()->external_resource_url ?? '';
        }
        
        // Extrair código de barras (pode ser objeto ou string)
        if (isset($payment->transaction_details->barcode)) {
            $barcode_obj = $payment->transaction_details->barcode;
            if (is_object($barcode_obj) && isset($barcode_obj->content)) {
                $barcode = $barcode_obj->content;
            } elseif (is_string($barcode_obj)) {
                $barcode = $barcode_obj;
            }
        } elseif (isset($payment->point_of_interaction->transaction_data->barcode)) {
            $barcode_obj = $payment->point_of_interaction->transaction_data->barcode;
            if (is_object($barcode_obj) && isset($barcode_obj->content)) {
                $barcode = $barcode_obj->content;
            } elseif (is_string($barcode_obj)) {
                $barcode = $barcode_obj;
            }
        }
        
        // Log para debug
        error_log("BOLETO GERADO - Payment ID: " . $payment->id);
        error_log("BOLETO URL: " . $ticket_url);
        error_log("BOLETO BARCODE: " . $barcode);
        error_log("BOLETO RAW RESPONSE: " . json_encode([
            'transaction_details' => isset($payment->transaction_details) ? json_encode($payment->transaction_details) : 'null',
            'point_of_interaction' => isset($payment->point_of_interaction) ? json_encode($payment->point_of_interaction) : 'null'
        ]));
        
        // Atualizar transação com payment_id e dados do boleto
        $stmt = $pdo->prepare("UPDATE transacoes SET payment_id = :payment_id, qr_code = :ticket_url, qr_code_base64 = :ticket_url_base64, status = 'Pendente' WHERE id = :id");
        $stmt->execute([
            ':payment_id' => $payment->id,
            ':ticket_url' => $ticket_url,
            ':ticket_url_base64' => base64_encode($ticket_url),
            ':id' => $transaction_id
        ]);
        
        // Retornar resposta de sucesso com dados do boleto
        echo json_encode([
            'status' => 'success',
            'transaction_id' => $transaction_id,
            'payment_id' => $payment->id,
            'ticket_url' => $ticket_url,
            'ticket_url_base64' => base64_encode($ticket_url),
            'barcode' => $barcode,
            'date_of_expiration' => $payment->date_of_expiration ?? '',
            'external_resource_url' => $ticket_url // Alias para compatibilidade
        ]);
        
    } catch (MPApiException $e) {
        // Log detalhado do erro
        error_log('=== ERRO DA API MERCADO PAGO BOLETO ===');
        error_log('Mensagem: ' . $e->getMessage());
        error_log('Código: ' . ($e->getStatusCode() ?? 'N/A'));
        
        // Tentar extrair informações adicionais - SDK v3 usa getContent() ou getApiResponse()
        $error_message = $e->getMessage();
        $api_response = null;
        
        // Tentar getContent() (método mais comum no SDK v3)
        if (method_exists($e, 'getContent')) {
            try {
                $api_response = $e->getContent();
                error_log('Resposta da API (getContent): ' . json_encode($api_response, JSON_UNESCAPED_UNICODE));
            } catch (Exception $ex) {
                error_log('Erro ao chamar getContent(): ' . $ex->getMessage());
            }
        }
        
        // Tentar getApiResponse() como fallback
        if (empty($api_response) && method_exists($e, 'getApiResponse')) {
            try {
                $api_response = $e->getApiResponse();
                error_log('Resposta da API (getApiResponse): ' . json_encode($api_response, JSON_UNESCAPED_UNICODE));
            } catch (Exception $ex) {
                error_log('Erro ao chamar getApiResponse(): ' . $ex->getMessage());
            }
        }
        
        // Extrair mensagem mais específica da resposta
        if (!empty($api_response)) {
            if (is_array($api_response)) {
                // Tentar extrair mensagem principal
                if (isset($api_response['message'])) {
                    $error_message = $api_response['message'];
                }
                
                // Tentar extrair causas específicas
                if (isset($api_response['cause']) && is_array($api_response['cause'])) {
                    $causes = [];
                    foreach ($api_response['cause'] as $cause) {
                        if (isset($cause['description'])) {
                            $causes[] = $cause['description'];
                        } elseif (isset($cause['code'])) {
                            $causes[] = 'Código: ' . $cause['code'];
                        }
                    }
                    if (!empty($causes)) {
                        $error_message = implode('. ', $causes);
                    }
                }
                
                // Tentar extrair erros de validação
                if (isset($api_response['errors']) && is_array($api_response['errors'])) {
                    $errors = [];
                    foreach ($api_response['errors'] as $error) {
                        if (isset($error['message'])) {
                            $errors[] = $error['message'];
                        }
                    }
                    if (!empty($errors)) {
                        $error_message = implode('. ', $errors);
                    }
                }
            }
        }
        
        // Log do payload COMPLETO enviado para debug (sem dados sensíveis como CPF completo)
        if (isset($paymentData)) {
            // Criar cópia do payload para log (sem dados sensíveis)
            $log_payload = $paymentData;
            if (isset($log_payload['payer']['identification']['number'])) {
                $cpf_log = $log_payload['payer']['identification']['number'];
                $log_payload['payer']['identification']['number'] = substr($cpf_log, 0, 3) . '***' . substr($cpf_log, -2);
            }
            error_log('Payload COMPLETO enviado à API: ' . json_encode($log_payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
        }
        
        // Atualizar transação com status de erro
        if (isset($transaction_id)) {
            try {
                $stmt = $pdo->prepare("UPDATE transacoes SET status = 'Falha', erro = :erro WHERE id = :id");
                $stmt->execute([
                    ':erro' => $error_message,
                    ':id' => $transaction_id
                ]);
            } catch (PDOException $db_error) {
                error_log("Erro ao atualizar transação após erro da API: " . $db_error->getMessage());
            }
        }
        
        echo json_encode([
            'status' => 'error',
            'message' => 'Erro ao gerar boleto: ' . $error_message
        ]);
    } catch (Exception $e) {
        error_log("Erro geral ao criar boleto: " . $e->getMessage());
        
        // Atualizar transação com status de erro
        $stmt = $pdo->prepare("UPDATE transacoes SET status = 'Falha', erro = :erro WHERE id = :id");
        $stmt->execute([
            ':erro' => $e->getMessage(),
            ':id' => $transaction_id
        ]);
        
        echo json_encode([
            'status' => 'error',
            'message' => 'Erro ao processar pagamento: ' . $e->getMessage()
        ]);
    }
    
} catch (MPApiException $e) {
    // Erro específico da API Mercado Pago
    error_log("Erro da API MercadoPago (boleto): " . $e->getMessage());
    error_log("Código: " . ($e->getStatusCode() ?? 'N/A'));
    
    if (isset($transaction_id)) {
        try {
            $stmt = $pdo->prepare("UPDATE transacoes SET status = 'Falha', erro = :erro WHERE id = :id");
            $stmt->execute([
                ':erro' => $e->getMessage(),
                ':id' => $transaction_id
            ]);
        } catch (PDOException $db_error) {
            error_log("Erro ao atualizar transação após erro da API: " . $db_error->getMessage());
        }
    }
    
    http_response_code(400);
    echo json_encode([
        'status' => 'error',
        'message' => 'Erro ao gerar boleto: ' . $e->getMessage()
    ]);
    exit;
} catch (Exception $e) {
    // Log detalhado do erro
    error_log("Erro fatal em process_payment_boleto_mercadopago.php: " . $e->getMessage());
    error_log("Stack trace: " . $e->getTraceAsString());
    
    // Atualizar transação se existir
    if (isset($transaction_id)) {
        try {
            $stmt = $pdo->prepare("UPDATE transacoes SET status = 'Erro', erro = :erro WHERE id = :id");
            $stmt->execute([
                ':erro' => $e->getMessage(),
                ':id' => $transaction_id
            ]);
        } catch (PDOException $db_error) {
            error_log("Erro ao atualizar transação após erro fatal: " . $db_error->getMessage());
        }
    }
    
    http_response_code(500);
    echo json_encode([
        'status' => 'error',
        'message' => 'Erro interno do servidor. Por favor, tente novamente. Detalhes: ' . $e->getMessage()
    ]);
    exit;
}

