<?php
declare(strict_types=1);
require_once dirname(__DIR__) . '/includes/payment_revenda_helper.php';
require_once dirname(__DIR__) . '/_app_guard.php';
app_guard_validate();





header("Content-Type: application/json; charset=UTF-8");

$dbPathToken = dirname(__DIR__) . "/db.db";
$pagamentosPath = dirname(__DIR__) . "/thefulltv_pagamentos.json";

function logPushin($msg) {
    file_put_contents(
        dirname(__DIR__) . "/thefulltv_pushin.log",
        "[" . date("Y-m-d H:i:s") . "] $msg\n",
        FILE_APPEND
    );
}

function logPixIn($msg) {
    file_put_contents(
        dirname(__DIR__) . "/thefulltv_pix_in.txt",
        "[" . date("Y-m-d H:i:s") . "] $msg\n",
        FILE_APPEND
    );
}
function gerarEmailFallback(string $prefixo = "thefull"): string
{
    try {
        $sufixo = str_pad((string)random_int(10, 99), 2, "0", STR_PAD_LEFT);
    } catch (Throwable $e) {
        $sufixo = str_pad((string)mt_rand(10, 99), 2, "0", STR_PAD_LEFT);
    }

    return strtolower($prefixo . $sufixo . "@gmail.com");
}

function cpfEhValido(string $cpf): bool
{
    $cpf = preg_replace('/\D+/', '', $cpf);

    if (strlen($cpf) !== 11) {
        return false;
    }

    if (preg_match('/^(\d)\1{10}$/', $cpf)) {
        return false;
    }

    for ($t = 9; $t < 11; $t++) {
        $d = 0;
        for ($c = 0; $c < $t; $c++) {
            $d += intval($cpf[$c]) * (($t + 1) - $c);
        }

        $d = ((10 * $d) % 11) % 10;

        if (intval($cpf[$c]) !== $d) {
            return false;
        }
    }

    return true;
}

function gerarCpfFallback(): string
{
    $nove = [];
    for ($i = 0; $i < 9; $i++) {
        $nove[] = random_int(0, 9);
    }

    $soma1 = 0;
    for ($i = 0; $i < 9; $i++) {
        $soma1 += $nove[$i] * (10 - $i);
    }
    $d1 = ($soma1 * 10) % 11;
    if ($d1 === 10) $d1 = 0;

    $soma2 = 0;
    for ($i = 0; $i < 9; $i++) {
        $soma2 += $nove[$i] * (11 - $i);
    }
    $soma2 += $d1 * 2;
    $d2 = ($soma2 * 10) % 11;
    if ($d2 === 10) $d2 = 0;

    return implode('', $nove) . $d1 . $d2;
}
function jsonResponse(array $data) {
    echo json_encode($data, JSON_UNESCAPED_UNICODE);
    exit;
}

function httpPostJson($url, array $headers, array $payload) {
    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload, JSON_UNESCAPED_UNICODE));
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);

    curl_close($ch);

    return [
        "http_code" => $httpCode,
        "response"  => $response,
        "error"     => $curlError
    ];
}

function httpPostRaw(string $url, array $headers, string $body, ?string $basicAuth = null): array {
    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    curl_setopt($ch, CURLOPT_TIMEOUT, 60);

    if ($basicAuth !== null) {
        curl_setopt($ch, CURLOPT_USERPWD, $basicAuth);
    }

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);

    curl_close($ch);

    return [
        "http_code" => $httpCode,
        "response"  => $response,
        "error"     => $curlError
    ];
}

function httpGetBinaryBase64(string $url): ?string {
    $ch = curl_init($url);

    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $curlError = curl_error($ch);

    curl_close($ch);

    if ($curlError || $httpCode < 200 || $httpCode >= 300 || !$response) {
        return null;
    }

    return base64_encode($response);
}

function columnExists(PDO $db, $table, $column) {
    $stmt = $db->query("PRAGMA table_info($table)");
    $columns = $stmt->fetchAll(PDO::FETCH_ASSOC);

    foreach ($columns as $col) {
        if (isset($col["name"]) && $col["name"] === $column) {
            return true;
        }
    }

    return false;
}

function tableExists(PDO $db, string $table): bool {
    $stmt = $db->prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = :table LIMIT 1");
    $stmt->execute([":table" => $table]);
    return (bool)$stmt->fetchColumn();
}

function getTableColumns(PDO $db, string $table): array {
    $stmt = $db->query("PRAGMA table_info($table)");
    $rows = $stmt ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
    $cols = [];

    foreach ($rows as $row) {
        if (!empty($row["name"])) {
            $cols[] = $row["name"];
        }
    }

    return $cols;
}

function garantirArquivoPagamentos(string $path): void {
    if (!file_exists($path)) {
        file_put_contents(
            $path,
            json_encode(["pagamentos" => []], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
        );
    }
}

function lerPagamentos(string $path): array {
    garantirArquivoPagamentos($path);

    $raw = @file_get_contents($path);
    $json = json_decode((string)$raw, true);

    if (!is_array($json) || !isset($json["pagamentos"]) || !is_array($json["pagamentos"])) {
        return ["pagamentos" => []];
    }

    return $json;
}

function salvarPagamentoJson(string $path, array $novoPagamento): bool {
    garantirArquivoPagamentos($path);

    $fp = fopen($path, "c+");
    if (!$fp) {
        return false;
    }

    try {
        if (!flock($fp, LOCK_EX)) {
            fclose($fp);
            return false;
        }

        $conteudo = stream_get_contents($fp);
        $arquivo = json_decode((string)$conteudo, true);

        if (!is_array($arquivo) || !isset($arquivo["pagamentos"]) || !is_array($arquivo["pagamentos"])) {
            $arquivo = ["pagamentos" => []];
        }

        $arquivo["pagamentos"][] = $novoPagamento;

        rewind($fp);
        ftruncate($fp, 0);
        fwrite($fp, json_encode($arquivo, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
        fflush($fp);
        flock($fp, LOCK_UN);
        fclose($fp);

        return true;
    } catch (Throwable $e) {
        @flock($fp, LOCK_UN);
        @fclose($fp);
        return false;
    }
}

function normalizarProdutos($produtos) {
    if (is_array($produtos)) {
        return $produtos;
    }

    if (is_object($produtos)) {
        return json_decode(json_encode($produtos, JSON_UNESCAPED_UNICODE), true);
    }

    return [];
}

function normalizarMac(?string $mac): string {
    $mac = strtoupper(trim((string)$mac));

    if ($mac === "") {
        return "";
    }

    $mac = preg_replace('/[^A-F0-9]/', '', $mac);

    if (strlen($mac) !== 12) {
        return "";
    }

    $normalizado = implode(":", str_split($mac, 2));

    if ($normalizado === "00:00:00:00:00:00" || $normalizado === "02:00:00:00:00:00") {
        return "";
    }

    return $normalizado;
}


function normalizarTelefoneBusca(?string $telefone): string {
    $digits = preg_replace('/\D+/', '', (string)$telefone);
    if ($digits === '') {
        return '';
    }

    if (strpos($digits, '55') === 0 && strlen($digits) > 11) {
        return substr($digits, 2);
    }

    return $digits;
}

function buscarClientePorWhatsapp(PDO $db, string $whatsapp): ?array {
    $telefone = normalizarTelefoneBusca($whatsapp);

    if ($telefone === '') {
        return null;
    }

    $tables = [
        [
            "table" => "usuarios",
            "id_column" => "rowid",
            "nome_columns" => ["nome_cliente", "username", "nome"],
            "email_columns" => ["email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular"],
        ],
        [
            "table" => "clientes",
            "id_column" => "id",
            "nome_columns" => ["nome", "nome_cliente", "username"],
            "email_columns" => ["email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular"],
        ],
        [
            "table" => "payments",
            "id_column" => "id",
            "nome_columns" => ["nome", "customer_name", "nome_cliente"],
            "email_columns" => ["email", "customer_email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular", "customer_phone"],
        ],
        [
            "table" => "pagamentos",
            "id_column" => "id",
            "nome_columns" => ["nome", "customer_name", "nome_cliente"],
            "email_columns" => ["email", "customer_email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular", "customer_phone"],
        ],
    ];

    foreach ($tables as $cfg) {
        if (!tableExists($db, $cfg["table"])) {
            continue;
        }

        $columns = getTableColumns($db, $cfg["table"]);

        $whatsappColumn = null;
        foreach ($cfg["whatsapp_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $whatsappColumn = $candidate;
                break;
            }
        }

        if (!$whatsappColumn) {
            continue;
        }

        $idColumn = in_array($cfg["id_column"], $columns, true) ? $cfg["id_column"] : null;

        $nomeColumn = null;
        foreach ($cfg["nome_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $nomeColumn = $candidate;
                break;
            }
        }

        $emailColumn = null;
        foreach ($cfg["email_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $emailColumn = $candidate;
                break;
            }
        }

        $select = [];
        $select[] = $idColumn ? "$idColumn AS cliente_id" : "NULL AS cliente_id";
        $select[] = $nomeColumn ? "$nomeColumn AS cliente_nome" : "NULL AS cliente_nome";
        $select[] = $emailColumn ? "$emailColumn AS cliente_email" : "NULL AS cliente_email";
        $select[] = "$whatsappColumn AS cliente_whatsapp";

        $sql = "
            SELECT " . implode(", ", $select) . "
            FROM {$cfg["table"]}
            WHERE REPLACE(REPLACE(REPLACE(REPLACE(REPLACE($whatsappColumn, ' ', ''), '(', ''), ')', ''), '-', ''), '+', '') LIKE :fone
            LIMIT 1
        ";

        $stmt = $db->prepare($sql);
        $stmt->execute([":fone" => "%" . $telefone]);

        $found = $stmt->fetch(PDO::FETCH_ASSOC);
        if ($found) {
            $found["origem_tabela"] = $cfg["table"];
            $found["telefone_busca"] = $telefone;
            return $found;
        }
    }

    return null;
}

function buscarClientePorMac(PDO $db, string $mac): ?array {
    $mac = normalizarMac($mac);

    if ($mac === "") {
        return null;
    }

    $macSemSeparador = str_replace(":", "", $mac);

    $candidatos = [
        [
            "table" => "usuarios",
            "mac_columns" => ["mac"],
            "id_columns" => ["id"],
            "nome_columns" => ["nome", "name", "username"],
            "email_columns" => ["email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular"],
        ],
        [
            "table" => "clientes",
            "mac_columns" => ["mac", "mac_address", "macaddress"],
            "id_columns" => ["id"],
            "nome_columns" => ["nome", "name"],
            "email_columns" => ["email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular"],
        ],
        [
            "table" => "servidores",
            "mac_columns" => ["mac", "mac_address", "macaddress"],
            "id_columns" => ["id"],
            "nome_columns" => ["nome", "name"],
            "email_columns" => ["email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular"],
        ],
        [
            "table" => "users",
            "mac_columns" => ["mac", "mac_address", "macaddress"],
            "id_columns" => ["id"],
            "nome_columns" => ["name", "nome"],
            "email_columns" => ["email"],
            "whatsapp_columns" => ["whatsapp", "telefone", "celular"],
        ],
    ];

    foreach ($candidatos as $cfg) {
        $table = $cfg["table"];

        if (!tableExists($db, $table)) {
            continue;
        }

        $columns = getTableColumns($db, $table);
        if (!$columns) {
            continue;
        }

        $macColumn = null;
        foreach ($cfg["mac_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $macColumn = $candidate;
                break;
            }
        }

        if (!$macColumn) {
            continue;
        }

        $idColumn = null;
        foreach ($cfg["id_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $idColumn = $candidate;
                break;
            }
        }

        $nomeColumn = null;
        foreach ($cfg["nome_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $nomeColumn = $candidate;
                break;
            }
        }

        $emailColumn = null;
        foreach ($cfg["email_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $emailColumn = $candidate;
                break;
            }
        }

        $whatsappColumn = null;
        foreach ($cfg["whatsapp_columns"] as $candidate) {
            if (in_array($candidate, $columns, true)) {
                $whatsappColumn = $candidate;
                break;
            }
        }

        $select = [];
        $select[] = $idColumn ? "$idColumn AS cliente_id" : "NULL AS cliente_id";
        $select[] = $nomeColumn ? "$nomeColumn AS cliente_nome" : "NULL AS cliente_nome";
        $select[] = $emailColumn ? "$emailColumn AS cliente_email" : "NULL AS cliente_email";
        $select[] = $whatsappColumn ? "$whatsappColumn AS cliente_whatsapp" : "NULL AS cliente_whatsapp";
        $select[] = "$macColumn AS mac_encontrado";

        $sql = "
            SELECT " . implode(", ", $select) . "
            FROM $table
            WHERE REPLACE(REPLACE(REPLACE(UPPER($macColumn), ':', ''), '-', ''), '.', '') = :mac
            LIMIT 1
        ";

        $stmt = $db->prepare($sql);
        $stmt->execute([
            ":mac" => strtoupper($macSemSeparador)
        ]);

        $found = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($found) {
            $found["origem_tabela"] = $table;
            $found["mac_normalizado"] = $mac;
            return $found;
        }
    }

    return null;
}

/* =========================================================
   PIX MANUAL - HELPERS
========================================================= */

function limparPixText(string $text, int $maxLen): string {
    $text = trim($text);
    $text = iconv("UTF-8", "ASCII//TRANSLIT//IGNORE", $text);
    $text = preg_replace('/[^A-Za-z0-9 \-]/', '', (string)$text);
    $text = preg_replace('/\s+/', ' ', (string)$text);
    $text = trim((string)$text);

    if ($text === "") {
        return "";
    }

    return mb_substr($text, 0, $maxLen, "UTF-8");
}

function normalizarChavePix(string $chave): string {
    $chave = trim($chave);

    if ($chave === "") {
        return "";
    }

    if (preg_match('/^\d{10,13}$/', $chave)) {
        if (strpos($chave, "55") !== 0) {
            return "+55" . $chave;
        }

        if (strpos($chave, "+") !== 0) {
            return "+" . $chave;
        }

        return $chave;
    }

    $num = preg_replace('/\D+/', '', $chave);

    if (strlen($num) === 11 || strlen($num) === 14) {
        return $num;
    }

    if (strpos($chave, "@") !== false) {
        return mb_strtolower($chave, "UTF-8");
    }

    if (preg_match('/^[a-f0-9-]{32,36}$/i', $chave)) {
        return $chave;
    }

    return $chave;
}

function montarCampoPix(string $id, string $valor): string {
    return $id . str_pad((string)strlen($valor), 2, "0", STR_PAD_LEFT) . $valor;
}

function montarMerchantAccount(string $chave): string {
    $gui = "BR.GOV.BCB.PIX";
    $guiField = montarCampoPix("00", $gui);
    $chaveField = montarCampoPix("01", $chave);
    $value = $guiField . $chaveField;
    return montarCampoPix("26", $value);
}

function crc16(string $payload): string {
    $polynom = 0x1021;
    $result = 0xFFFF;

    $len = strlen($payload);
    for ($i = 0; $i < $len; $i++) {
        $result ^= (ord($payload[$i]) << 8);

        for ($j = 0; $j < 8; $j++) {
            $result <<= 1;
            if ($result & 0x10000) {
                $result ^= $polynom;
            }
            $result &= 0xFFFF;
        }
    }

    return strtoupper(str_pad(dechex($result), 4, "0", STR_PAD_LEFT));
}

function gerarTxIdManual(): string {
    return "TX" . strtoupper(substr(md5(uniqid((string)mt_rand(), true)), 0, 8));
}

function gerarPixCode(string $nome, string $cidade, string $chave, float $valor): string {
    $nome = limparPixText($nome, 25);
    $cidade = limparPixText($cidade, 15);
    $chave = normalizarChavePix($chave);

    if ($nome === "") {
        $nome = "THEFULLTV";
    }

    if ($cidade === "") {
        $cidade = "BRASIL";
    }

    $pf = "000201";
    $account = montarMerchantAccount($chave);
    $cat = "52040000";
    $moeda = "5303986";
    $valorFmt = number_format($valor, 2, ".", "");
    $valorField = montarCampoPix("54", $valorFmt);
    $pais = "5802BR";
    $merchant = montarCampoPix("59", $nome);
    $city = montarCampoPix("60", $cidade);

    $tx = gerarTxIdManual();
    $txid = montarCampoPix("05", $tx);
    $add = montarCampoPix("62", $txid);

    $payload = $pf . $account . $cat . $moeda . $valorField . $pais . $merchant . $city . $add . "6304";
    return $payload . crc16($payload);
}

function gerarQrCodeBase64Manual(string $pixCode): ?string {
    $url = "https://api.qrserver.com/v1/create-qr-code/?size=400x400&format=png&data=" . urlencode($pixCode);
    $base64 = httpGetBinaryBase64($url);

    if (!$base64) {
        return null;
    }

    return "data:image/png;base64," . $base64;
}

/* =========================================================
   PAYPAL - HELPERS
========================================================= */

function getPaypalBaseUrl(string $mode): string {
    return strtolower($mode) === "live"
        ? "https://api-m.paypal.com"
        : "https://api-m.sandbox.paypal.com";
}

function getPaypalAccessToken(string $clientId, string $clientSecret, string $mode): array {
    $baseUrl = getPaypalBaseUrl($mode);

    $result = httpPostRaw(
        $baseUrl . "/v1/oauth2/token",
        [
            "Accept: application/json",
            "Accept-Language: pt-BR",
            "Content-Type: application/x-www-form-urlencoded"
        ],
        "grant_type=client_credentials",
        $clientId . ":" . $clientSecret
    );

    if (!empty($result["error"])) {
        return [
            "success" => false,
            "error" => "Erro CURL ao gerar access token PayPal",
            "details" => $result["error"]
        ];
    }

    $json = json_decode((string)$result["response"], true);

    if ((int)$result["http_code"] !== 200 || empty($json["access_token"])) {
        return [
            "success" => false,
            "error" => "Não foi possível obter access token do PayPal",
            "details" => $json
        ];
    }

    return [
        "success" => true,
        "access_token" => (string)$json["access_token"]
    ];
}

function paypalFindLink(array $links, string $rel): ?string {
    foreach ($links as $link) {
        if (($link["rel"] ?? "") === $rel && !empty($link["href"])) {
            return (string)$link["href"];
        }
    }
    return null;
}

function createPaypalOrder(
    string $clientId,
    string $clientSecret,
    string $mode,
    float $total,
    string $description,
    string $returnUrl,
    string $cancelUrl
): array {
    $token = getPaypalAccessToken($clientId, $clientSecret, $mode);
    if (!$token["success"]) {
        return $token;
    }

    $baseUrl = getPaypalBaseUrl($mode);

    $payload = [
        "intent" => "CAPTURE",
        "purchase_units" => [
            [
                "description" => $description,
                "amount" => [
                    "currency_code" => "BRL",
                    "value" => number_format($total, 2, ".", "")
                ]
            ]
        ],
        "application_context" => [
            "brand_name" => "TheFullTV",
            "landing_page" => "LOGIN",
            "user_action" => "PAY_NOW",
            "return_url" => $returnUrl,
            "cancel_url" => $cancelUrl
        ]
    ];

    $result = httpPostJson(
        $baseUrl . "/v2/checkout/orders",
        [
            "Authorization: Bearer " . $token["access_token"],
            "Accept: application/json",
            "Content-Type: application/json",
            "PayPal-Request-Id: PAYPAL_" . time() . "_" . mt_rand(1000, 9999)
        ],
        $payload
    );

    if (!empty($result["error"])) {
        return [
            "success" => false,
            "error" => "Erro CURL ao criar order PayPal",
            "details" => $result["error"]
        ];
    }

    $json = json_decode((string)$result["response"], true);

    if (!in_array((int)$result["http_code"], [200, 201], true) || empty($json["id"])) {
        return [
            "success" => false,
            "error" => "Erro ao criar order PayPal",
            "details" => $json
        ];
    }

    $approveUrl = paypalFindLink($json["links"] ?? [], "approve");

    return [
        "success" => true,
        "order" => $json,
        "order_id" => (string)$json["id"],
        "status" => (string)($json["status"] ?? ""),
        "approve_url" => $approveUrl
    ];
}

/* ========================================================= */

try {
    $dbToken = new PDO("sqlite:" . $dbPathToken, null, null, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]);

    if (!columnExists($dbToken, "pushin_config", "mercado_pago_token")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN mercado_pago_token TEXT");
        logPixIn("Coluna mercado_pago_token criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "gateway_ativo")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN gateway_ativo TEXT");
        logPixIn("Coluna gateway_ativo criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "pix_manual_tipo")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN pix_manual_tipo TEXT");
        logPixIn("Coluna pix_manual_tipo criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "pix_manual_chave")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN pix_manual_chave TEXT");
        logPixIn("Coluna pix_manual_chave criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "pix_manual_nome")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN pix_manual_nome TEXT");
        logPixIn("Coluna pix_manual_nome criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "pix_manual_cidade")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN pix_manual_cidade TEXT");
        logPixIn("Coluna pix_manual_cidade criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "pix_manual_email")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN pix_manual_email TEXT");
        logPixIn("Coluna pix_manual_email criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "pix_manual_cpf")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN pix_manual_cpf TEXT");
        logPixIn("Coluna pix_manual_cpf criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "pix_manual_celular")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN pix_manual_celular TEXT");
        logPixIn("Coluna pix_manual_celular criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "paypal_client_id")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN paypal_client_id TEXT");
        logPixIn("Coluna paypal_client_id criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "paypal_client_secret")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN paypal_client_secret TEXT");
        logPixIn("Coluna paypal_client_secret criada com sucesso");
    }

    if (!columnExists($dbToken, "pushin_config", "paypal_mode")) {
        $dbToken->exec("ALTER TABLE pushin_config ADD COLUMN paypal_mode TEXT");
        logPixIn("Coluna paypal_mode criada com sucesso");
    }

    $dbToken->exec("
        UPDATE pushin_config
        SET gateway_ativo = COALESCE(NULLIF(gateway_ativo, ''), 'pushinpay')
        WHERE id = 1
    ");

    $cfg = $dbToken->query("
        SELECT 
            pushin_token,
            mercado_pago_token,
            gateway_ativo,
            pix_manual_tipo,
            pix_manual_chave,
            pix_manual_nome,
            pix_manual_cidade,
            pix_manual_email,
            pix_manual_cpf,
            pix_manual_celular,
            paypal_client_id,
            paypal_client_secret,
            paypal_mode
        FROM pushin_config
        WHERE id = 1
        LIMIT 1
    ")->fetch();

    if (!$cfg) {
        jsonResponse([
            "success" => false,
            "error" => "Configuração pushin_config id=1 não encontrada"
        ]);
    }

    $TOKEN_PUSHIN      = trim((string)($cfg["pushin_token"] ?? ""));
    $TOKEN_MP          = trim((string)($cfg["mercado_pago_token"] ?? ""));
    $GATEWAY_ATIVO     = trim((string)($cfg["gateway_ativo"] ?? "pushinpay"));
    $PIX_MANUAL_TIPO   = trim((string)($cfg["pix_manual_tipo"] ?? ""));
    $PIX_MANUAL_CHAVE  = trim((string)($cfg["pix_manual_chave"] ?? ""));
    $PIX_MANUAL_NOME   = trim((string)($cfg["pix_manual_nome"] ?? ""));
    $PIX_MANUAL_CIDADE = trim((string)($cfg["pix_manual_cidade"] ?? ""));
    $PIX_MANUAL_EMAIL  = trim((string)($cfg["pix_manual_email"] ?? ""));
    $PIX_MANUAL_CPF    = preg_replace('/\D+/', '', (string)($cfg["pix_manual_cpf"] ?? ""));
    $PIX_MANUAL_CEL    = trim((string)($cfg["pix_manual_celular"] ?? ""));
    $PAYPAL_CLIENT_ID     = trim((string)($cfg["paypal_client_id"] ?? ""));
    $PAYPAL_CLIENT_SECRET = trim((string)($cfg["paypal_client_secret"] ?? ""));
    $PAYPAL_MODE          = trim((string)($cfg["paypal_mode"] ?? "sandbox"));

    if ($GATEWAY_ATIVO === "") {
        $GATEWAY_ATIVO = "pushinpay";
    }
} catch (Throwable $e) {
    jsonResponse([
        "success" => false,
        "error" => "Erro ao buscar tokens/configurações",
        "detalhes" => $e->getMessage()
    ]);
}

$raw = file_get_contents("php://input");
$data = json_decode($raw, true);

revenda_credit_ensure_schema($dbToken);
logPixIn("RAW: " . $raw);

if (!$data) {
    logPixIn("❌ JSON inválido");
    jsonResponse(["success" => false, "error" => "JSON inválido"]);
}

$gatewayMap = [
    "pushinpay"   => 0,
    "mercadopago" => 1,
    "pixmanual"   => 2,
    "paypal"      => 3
];

if (isset($data["gateway"]) && $data["gateway"] !== "" && $data["gateway"] !== null) {
    $gateway = intval($data["gateway"]);
} else {
    $gateway = $gatewayMap[$GATEWAY_ATIVO] ?? 0;
}

// 0 = PushinPay | 1 = Mercado Pago | 2 = Pix Manual | 3 = PayPal
$nome     = trim((string)($data["nome"] ?? ""));
$whatsapp = trim((string)($data["whatsapp"] ?? ""));
$email    = trim((string)($data["email"] ?? ""));
$cpf      = preg_replace('/\D+/', '', (string)($data["cpf"] ?? ""));
$macRaw   = trim((string)($data["mac"] ?? ""));
$mac      = normalizarMac($macRaw);
$deviceId = trim((string)($data["device_id"] ?? ""));
$produtos = normalizarProdutos($data["produtos"] ?? []);
$total    = floatval($data["total"] ?? 0);
$paymentContext = is_array($data["payment_context"] ?? null) ? $data["payment_context"] : [];
$paymentContextType = trim((string)($paymentContext["type"] ?? ''));

logPixIn("NOME=$nome | WHATSAPP=$whatsapp | EMAIL=$email | CPF=$cpf | MAC_RAW=$macRaw | MAC=$mac | DEVICE_ID=$deviceId | TOTAL=$total | GATEWAY=$gateway | GATEWAY_ATIVO=$GATEWAY_ATIVO");

if ($nome === "") {
    $nome = "TheFullTV";
}

if ($email === "" || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $email = gerarEmailFallback("thefull");
}

if (!cpfEhValido($cpf)) {
    $cpf = gerarCpfFallback();
}

if ($total <= 0) {
    logPixIn("❌ Total inválido");
    jsonResponse(["success" => false, "error" => "Valor inválido"]);
}

$cliente = null;

try {
    if ($mac !== '') {
        $cliente = buscarClientePorMac($dbToken, $mac);

        if ($cliente) {
            logPixIn("CLIENTE LOCALIZADO POR MAC → ID=" . ($cliente["cliente_id"] ?? "null") . " | NOME=" . ($cliente["cliente_nome"] ?? "") . " | TABELA=" . ($cliente["origem_tabela"] ?? ""));
        }
    }

    if (!$cliente && $whatsapp !== '') {
        $cliente = buscarClientePorWhatsapp($dbToken, $whatsapp);

        if ($cliente) {
            logPixIn("CLIENTE LOCALIZADO POR WHATSAPP → ID=" . ($cliente["cliente_id"] ?? "null") . " | NOME=" . ($cliente["cliente_nome"] ?? "") . " | TABELA=" . ($cliente["origem_tabela"] ?? ""));
        }
    }

    if ($cliente) {
        if ((empty($nome) || $nome === "TheFullTV") && !empty($cliente["cliente_nome"])) {
            $nome = trim((string)$cliente["cliente_nome"]);
        }

        if ((empty($email) || $email === "cliente@thefulltv.local") && !empty($cliente["cliente_email"])) {
            $email = trim((string)$cliente["cliente_email"]);
        }

        if ((empty($whatsapp) || $whatsapp === "11999999999") && !empty($cliente["cliente_whatsapp"])) {
            $whatsapp = trim((string)$cliente["cliente_whatsapp"]);
        }
    } else {
        logPixIn("CLIENTE NÃO ENCONTRADO PARA MAC/WHATSAPP | MAC=$mac | WHATSAPP=$whatsapp");
    }
} catch (Throwable $e) {
    logPixIn("ERRO AO BUSCAR CLIENTE POR MAC/WHATSAPP: " . $e->getMessage());
}

$protocol = (!empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off") ? "https://" : "http://";
$domain   = $protocol . $_SERVER["HTTP_HOST"];
$basePath = rtrim(dirname($_SERVER["SCRIPT_NAME"]), "/");
$webhook  = $domain . $basePath . "/thefulltv_webhook.php";
$paypalReturn = $domain . $basePath . "/thefulltv_paypal_return.php";
$paypalCancel = $domain . $basePath . "/thefulltv_paypal_cancel.php";

garantirArquivoPagamentos($pagamentosPath);

try {
    if ($gateway === 0) {
        if (empty($TOKEN_PUSHIN)) {
            jsonResponse([
                "success" => false,
                "error" => "Token PushinPay não encontrado no banco"
            ]);
        }

        $value = intval(round($total * 100));

        $payload = [
            "value" => $value,
            "webhook_url" => $webhook
        ];

        logPushin("📤 PUSHIN ENVIADO → " . json_encode($payload, JSON_UNESCAPED_UNICODE));

        $result = httpPostJson(
            "https://api.pushinpay.com.br/api/pix/cashIn",
            [
                "Authorization: Bearer $TOKEN_PUSHIN",
                "Accept: application/json",
                "Content-Type: application/json"
            ],
            $payload
        );

        logPushin("📥 PUSHIN RECEBIDO ({$result["http_code"]}) → " . $result["response"]);

        if (!empty($result["error"])) {
            jsonResponse([
                "success" => false,
                "error" => "Erro CURL PushinPay",
                "detalhes" => $result["error"]
            ]);
        }

        $dataPushin = json_decode($result["response"], true);

        if ($result["http_code"] !== 200 || !isset($dataPushin["id"])) {
            logPushin("❌ ERRO PUSHINPAY");
            jsonResponse([
                "success" => false,
                "error" => "Erro PushinPay",
                "detalhes" => $dataPushin
            ]);
        }

        $novo = [
            "gateway"           => 0,
            "gateway_nome"      => "pushinpay",
            "payment_id"        => (string)$dataPushin["id"],
            "nome"              => $nome,
            "whatsapp"          => $whatsapp,
            "email"             => $email,
            "cpf"               => $cpf,
            "mac_raw"           => $macRaw,
            "mac"               => $mac,
            "device_id"         => $deviceId,
            "cliente_id"        => $cliente["cliente_id"] ?? null,
            "cliente_nome"      => $cliente["cliente_nome"] ?? null,
            "cliente_email"     => $cliente["cliente_email"] ?? null,
            "cliente_whatsapp"  => $cliente["cliente_whatsapp"] ?? null,
            "cliente_tabela"    => $cliente["origem_tabela"] ?? null,
            "produtos"          => $produtos,
            "payment_context"   => $paymentContext,
            "total"             => $total,
            "pix_code"          => $dataPushin["qr_code"] ?? null,
            "qr_code_base64"    => $dataPushin["qr_code_base64"] ?? null,
            "pix_chave"         => $dataPushin["qr_code"] ?? null,
            "status"            => "pendente",
            "criado_em"         => time()
        ];

        if (!salvarPagamentoJson($pagamentosPath, $novo)) {
            jsonResponse([
                "success" => false,
                "error" => "Não foi possível salvar o pagamento criado"
            ]);
        }

        logPixIn("SALVO PUSHIN → payment_id=" . $dataPushin["id"] . " | MAC=" . $mac . " | CLIENTE_ID=" . ($cliente["cliente_id"] ?? "null"));

        if ($paymentContextType === 'revenda_credito') {
            revenda_credit_upsert_order($dbToken, [
                'payment_id' => (string)($novo['payment_id'] ?? ''),
                'external_reference' => (string)($novo['external_reference'] ?? ''),
                'revendedor_id' => (int)($paymentContext['revendedor_id'] ?? 0),
                'opcao_id' => isset($paymentContext['opcao_id']) ? (int)$paymentContext['opcao_id'] : null,
                'creditos' => (int)($paymentContext['creditos'] ?? 0),
                'valor' => (float)$total,
                'gateway_nome' => (string)($novo['gateway_nome'] ?? ''),
                'status' => (string)($novo['status'] ?? 'pendente'),
                'payload_json' => json_encode($novo, JSON_UNESCAPED_UNICODE),
            ]);
        }

        jsonResponse([
            "success" => true,
            "gateway" => 0,
            "gateway_nome" => "pushinpay",
            "payment_id" => (string)$dataPushin["id"],
            "pix_code" => $dataPushin["qr_code"] ?? null,
            "qr_code_base64" => $dataPushin["qr_code_base64"] ?? null,
            "pix_chave" => $dataPushin["qr_code"] ?? null,
            "total" => $total,
            "valor_gerado" => $total,
            "cliente_encontrado" => !empty($cliente)
        ]);
    }

  if ($gateway === 1) {
    if (empty($TOKEN_MP)) {
        jsonResponse([
            "success" => false,
            "error" => "Token Mercado Pago não encontrado no banco"
        ]);
    }

    if ($email === "" || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        jsonResponse([
            "success" => false,
            "error" => "E-mail do cliente inválido para Mercado Pago",
            "detalhes" => [
                "email_recebido" => $email,
                "mac" => $mac,
                "cliente_encontrado" => !empty($cliente)
            ]
        ]);
    }

    if (strlen($cpf) !== 11) {
        jsonResponse([
            "success" => false,
            "error" => "CPF do cliente inválido para Mercado Pago",
            "detalhes" => [
                "cpf_recebido" => $cpf,
                "mac" => $mac,
                "cliente_encontrado" => !empty($cliente)
            ]
        ]);
    }

    $externalReference = "THEFULLTV_" . time() . "_" . mt_rand(1000, 9999);

    $nomeParts = preg_split('/\s+/', trim($nome));
    $firstName = $nomeParts[0] ?? "Cliente";
    $lastName = count($nomeParts) > 1 ? implode(" ", array_slice($nomeParts, 1)) : "TheFullTV";

    $payloadMP = [
        "transaction_amount" => round($total, 2),
        "description" => "Pagamento TheFullTV",
        "payment_method_id" => "pix",
        "external_reference" => $externalReference,
        "notification_url" => $webhook,
        "payer" => [
            "email" => $email,
            "first_name" => $firstName,
            "last_name" => $lastName,
            "identification" => [
                "type" => "CPF",
                "number" => $cpf
            ]
        ]
    ];

    logPushin("📤 MP ENVIADO → " . json_encode($payloadMP, JSON_UNESCAPED_UNICODE));

    $result = httpPostJson(
        "https://api.mercadopago.com/v1/payments",
        [
            "Authorization: Bearer $TOKEN_MP",
            "Accept: application/json",
            "Content-Type: application/json",
            "X-Idempotency-Key: " . $externalReference
        ],
        $payloadMP
    );

    logPushin("📥 MP RECEBIDO ({$result["http_code"]}) → " . $result["response"]);

    if (!empty($result["error"])) {
        jsonResponse([
            "success" => false,
            "error" => "Erro CURL Mercado Pago",
            "detalhes" => $result["error"]
        ]);
    }

    $dataMP = json_decode($result["response"], true);

    if (!in_array($result["http_code"], [200, 201], true) || !isset($dataMP["id"])) {
        jsonResponse([
            "success" => false,
            "error" => "Erro Mercado Pago",
            "detalhes" => [
                "http_code" => $result["http_code"],
                "resposta" => $dataMP,
                "payload_enviado" => $payloadMP
            ]
        ]);
    }

    $pixCode = $dataMP["point_of_interaction"]["transaction_data"]["qr_code"] ?? null;
    $qrCodeBase64 = $dataMP["point_of_interaction"]["transaction_data"]["qr_code_base64"] ?? null;

    $novo = [
        "gateway"            => 1,
        "gateway_nome"       => "mercadopago",
        "payment_id"         => (string)$dataMP["id"],
        "external_reference" => $externalReference,
        "nome"               => $nome,
        "whatsapp"           => $whatsapp,
        "email"              => $email,
        "cpf"                => $cpf,
        "mac_raw"            => $macRaw,
        "mac"                => $mac,
        "device_id"          => $deviceId,
        "cliente_id"         => $cliente["cliente_id"] ?? null,
        "cliente_nome"       => $cliente["cliente_nome"] ?? null,
        "cliente_email"      => $cliente["cliente_email"] ?? null,
        "cliente_whatsapp"   => $cliente["cliente_whatsapp"] ?? null,
        "cliente_tabela"     => $cliente["origem_tabela"] ?? null,
        "produtos"           => $produtos,
        "payment_context"    => $paymentContext,
        "total"              => $total,
        "pix_code"           => $pixCode,
        "qr_code_base64"     => $qrCodeBase64,
        "pix_chave"          => $pixCode,
        "status"             => $dataMP["status"] ?? "pending",
        "criado_em"          => time()
    ];

    if (!salvarPagamentoJson($pagamentosPath, $novo)) {
        jsonResponse([
            "success" => false,
            "error" => "Não foi possível salvar o pagamento criado"
        ]);
    }

    logPixIn("SALVO MP → payment_id=" . $dataMP["id"] . " | MAC=" . $mac . " | CLIENTE_ID=" . ($cliente["cliente_id"] ?? "null"));

        if ($paymentContextType === 'revenda_credito') {
            revenda_credit_upsert_order($dbToken, [
                'payment_id' => (string)($novo['payment_id'] ?? ''),
                'external_reference' => (string)($novo['external_reference'] ?? ''),
                'revendedor_id' => (int)($paymentContext['revendedor_id'] ?? 0),
                'opcao_id' => isset($paymentContext['opcao_id']) ? (int)$paymentContext['opcao_id'] : null,
                'creditos' => (int)($paymentContext['creditos'] ?? 0),
                'valor' => (float)$total,
                'gateway_nome' => (string)($novo['gateway_nome'] ?? ''),
                'status' => (string)($novo['status'] ?? 'pendente'),
                'payload_json' => json_encode($novo, JSON_UNESCAPED_UNICODE),
            ]);
        }

    jsonResponse([
        "success" => true,
        "gateway" => 1,
        "gateway_nome" => "mercadopago",
        "payment_id" => (string)$dataMP["id"],
        "pix_code" => $pixCode,
        "qr_code_base64" => $qrCodeBase64,
        "pix_chave" => $pixCode,
        "status" => $dataMP["status"] ?? "pending",
        "total" => $total,
            "valor_gerado" => $total,
        "cliente_encontrado" => !empty($cliente)
    ]);
}

    if ($gateway === 2) {
        if ($PIX_MANUAL_CHAVE === "") {
            jsonResponse([
                "success" => false,
                "error" => "Chave PIX manual não configurada no banco"
            ]);
        }

        $manualNome = $PIX_MANUAL_NOME !== "" ? $PIX_MANUAL_NOME : "THEFULLTV";
        $manualCidade = $PIX_MANUAL_CIDADE !== "" ? $PIX_MANUAL_CIDADE : "BRASIL";
        $manualChave = normalizarChavePix($PIX_MANUAL_CHAVE);

        $pixCode = gerarPixCode($manualNome, $manualCidade, $manualChave, $total);
        $qrCodeBase64 = gerarQrCodeBase64Manual($pixCode);

        $paymentId = "PIXMANUAL_" . time() . "_" . mt_rand(1000, 9999);

        $novo = [
            "gateway"            => 2,
            "gateway_nome"       => "pixmanual",
            "payment_id"         => $paymentId,
            "nome"               => $nome,
            "whatsapp"           => $whatsapp,
            "email"              => $email,
            "cpf"                => $cpf,
            "mac_raw"            => $macRaw,
            "mac"                => $mac,
            "device_id"          => $deviceId,
            "cliente_id"         => $cliente["cliente_id"] ?? null,
            "cliente_nome"       => $cliente["cliente_nome"] ?? null,
            "cliente_email"      => $cliente["cliente_email"] ?? null,
            "cliente_whatsapp"   => $cliente["cliente_whatsapp"] ?? null,
            "cliente_tabela"     => $cliente["origem_tabela"] ?? null,
            "produtos"           => $produtos,
            "total"              => $total,
            "pix_code"           => $pixCode,
            "qr_code_base64"     => $qrCodeBase64,
        "pix_chave"          => $pixCode,
            "status"             => "pendente",
            "criado_em"          => time(),
            "pix_manual" => [
                "tipo"     => $PIX_MANUAL_TIPO,
                "chave"    => $manualChave,
                "nome"     => $manualNome,
                "cidade"   => $manualCidade,
                "email"    => $PIX_MANUAL_EMAIL,
                "cpf"      => $PIX_MANUAL_CPF,
                "celular"  => $PIX_MANUAL_CEL
            ]
        ];

        if (!salvarPagamentoJson($pagamentosPath, $novo)) {
            jsonResponse([
                "success" => false,
                "error" => "Não foi possível salvar o pagamento criado"
            ]);
        }

        logPixIn("SALVO PIX MANUAL → payment_id=" . $paymentId . " | MAC=" . $mac . " | CLIENTE_ID=" . ($cliente["cliente_id"] ?? "null"));

        if ($paymentContextType === 'revenda_credito') {
            revenda_credit_upsert_order($dbToken, [
                'payment_id' => (string)($novo['payment_id'] ?? ''),
                'external_reference' => (string)($novo['external_reference'] ?? ''),
                'revendedor_id' => (int)($paymentContext['revendedor_id'] ?? 0),
                'opcao_id' => isset($paymentContext['opcao_id']) ? (int)$paymentContext['opcao_id'] : null,
                'creditos' => (int)($paymentContext['creditos'] ?? 0),
                'valor' => (float)$total,
                'gateway_nome' => (string)($novo['gateway_nome'] ?? ''),
                'status' => (string)($novo['status'] ?? 'pendente'),
                'payload_json' => json_encode($novo, JSON_UNESCAPED_UNICODE),
            ]);
        }

        jsonResponse([
            "success" => true,
            "gateway" => 2,
            "gateway_nome" => "pixmanual",
            "payment_id" => $paymentId,
            "pix_code" => $pixCode,
            "qr_code_base64" => $qrCodeBase64,
        "pix_chave" => $pixCode,
            "status" => "pending",
            "total" => $total,
            "valor_gerado" => $total,
            "cliente_encontrado" => !empty($cliente)
        ]);
    }

    if ($gateway === 3) {
        if ($PAYPAL_CLIENT_ID === "" || $PAYPAL_CLIENT_SECRET === "") {
            jsonResponse([
                "success" => false,
                "error" => "Client ID ou Client Secret do PayPal não configurados no banco"
            ]);
        }

        $descricao = "Pagamento TheFullTV";

        if (!empty($produtos["nome"])) {
            $descricao = "Plano " . trim((string)$produtos["nome"]);
        }

        $paypal = createPaypalOrder(
            $PAYPAL_CLIENT_ID,
            $PAYPAL_CLIENT_SECRET,
            $PAYPAL_MODE !== "" ? $PAYPAL_MODE : "sandbox",
            $total,
            $descricao,
            $paypalReturn,
            $paypalCancel
        );

        if (!$paypal["success"]) {
            jsonResponse($paypal);
        }

        $order = $paypal["order"];
        $paymentId = $paypal["order_id"];
        $approveUrl = $paypal["approve_url"];
        $externalReference = "PAYPAL_" . time() . "_" . mt_rand(1000, 9999);

        if (!$approveUrl) {
            jsonResponse([
                "success" => false,
                "error" => "PayPal não retornou approve_url",
                "detalhes" => $order
            ]);
        }

        $novo = [
            "gateway"            => 3,
            "gateway_nome"       => "paypal",
            "payment_id"         => $paymentId,
            "external_reference" => $externalReference,
            "nome"               => $nome,
            "whatsapp"           => $whatsapp,
            "email"              => $email,
            "cpf"                => $cpf,
            "mac_raw"            => $macRaw,
            "mac"                => $mac,
            "device_id"          => $deviceId,
            "cliente_id"         => $cliente["cliente_id"] ?? null,
            "cliente_nome"       => $cliente["cliente_nome"] ?? null,
            "cliente_email"      => $cliente["cliente_email"] ?? null,
            "cliente_whatsapp"   => $cliente["cliente_whatsapp"] ?? null,
            "cliente_tabela"     => $cliente["origem_tabela"] ?? null,
            "produtos"           => $produtos,
            "total"              => $total,
            "paypal_mode"        => $PAYPAL_MODE !== "" ? $PAYPAL_MODE : "sandbox",
            "paypal_status"      => $order["status"] ?? null,
            "paypal_approve_url" => $approveUrl,
            "status"             => "pendente",
            "criado_em"          => time()
        ];

        if (!salvarPagamentoJson($pagamentosPath, $novo)) {
            jsonResponse([
                "success" => false,
                "error" => "Não foi possível salvar o pagamento PayPal criado"
            ]);
        }

        logPixIn("SALVO PAYPAL → payment_id=" . $paymentId . " | MAC=" . $mac . " | CLIENTE_ID=" . ($cliente["cliente_id"] ?? "null"));

        if ($paymentContextType === 'revenda_credito') {
            revenda_credit_upsert_order($dbToken, [
                'payment_id' => (string)($novo['payment_id'] ?? ''),
                'external_reference' => (string)($novo['external_reference'] ?? ''),
                'revendedor_id' => (int)($paymentContext['revendedor_id'] ?? 0),
                'opcao_id' => isset($paymentContext['opcao_id']) ? (int)$paymentContext['opcao_id'] : null,
                'creditos' => (int)($paymentContext['creditos'] ?? 0),
                'valor' => (float)$total,
                'gateway_nome' => (string)($novo['gateway_nome'] ?? ''),
                'status' => (string)($novo['status'] ?? 'pendente'),
                'payload_json' => json_encode($novo, JSON_UNESCAPED_UNICODE),
            ]);
        }

        jsonResponse([
            "success" => true,
            "gateway" => 3,
            "gateway_nome" => "paypal",
            "payment_id" => $paymentId,
            "approve_url" => $approveUrl,
            "status" => $order["status"] ?? "CREATED",
            "total" => $total,
            "valor_gerado" => $total,
            "cliente_encontrado" => !empty($cliente)
        ]);
    }

    jsonResponse([
        "success" => false,
        "error" => "Gateway inválido. Use 0 para Pushin Pay, 1 para Mercado Pago, 2 para Pix Manual ou 3 para PayPal."
    ]);

} catch (Throwable $e) {
    logPixIn("❌ EXCEPTION: " . $e->getMessage());

    jsonResponse([
        "success" => false,
        "error" => "Erro interno",
        "detalhes" => $e->getMessage()
    ]);
}