<?php

/**
 * BTC Catch Miner — Telegram Bot Webhook Handler (MySQL Edition)
 * ================================================================
 * Handles all bot commands: /start, /help, /balance, /top, /stats
 *
 * Set your webhook:
 *   https://api.telegram.org/bot{BOT_TOKEN}/setWebhook?url=https://yourdomain.com/btcgame/bot.php
 *
 * Or run via CLI:
 *   php bot.php setwebhook
 */

declare(strict_types=1);

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';

// ─── CLI: register webhook ───────────────────────────────────────────────────
if (php_sapi_name() === 'cli' && ($argv[1] ?? '') === 'setwebhook') {
    $url = 'https://api.telegram.org/bot' . BOT_TOKEN . '/setWebhook';
    $ch  = curl_init($url . '?url=' . urlencode(WEBAPP_URL . '/../bot.php'));
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 10,
    ]);
    $res = curl_exec($ch);
    curl_close($ch);
    echo $res . "\n";
    exit;
}

// ─── INCOMING UPDATE ─────────────────────────────────────────────────────────
$update = json_decode(file_get_contents('php://input'), true);
if (!$update) {
    exit;
}

// ─── ROUTER ──────────────────────────────────────────────────────────────────
if (!empty($update['message'])) {
    handleMessage($update['message']);
} elseif (!empty($update['callback_query'])) {
    handleCallback($update['callback_query']);
}

// ═══════════════════════════════════════════════════════════════════════════
// MESSAGE HANDLER
// ═══════════════════════════════════════════════════════════════════════════

function handleMessage(array $message): void {
    $chatId    = (string)($message['chat']['id'] ?? '');
    $text      = trim($message['text'] ?? '');
    $userId    = (string)($message['from']['id'] ?? '');
    $username  = sanitize($message['from']['username'] ?? $message['from']['first_name'] ?? 'Player');
    $firstName = sanitize($message['from']['first_name'] ?? '');

    if (!$chatId || !$userId) {
        return;
    }

    if (str_starts_with($text, '/start')) {
        handleStart($chatId, $userId, $username, $firstName, $text);
    } elseif (str_starts_with($text, '/help')) {
        handleHelp($chatId);
    } elseif (str_starts_with($text, '/balance')) {
        handleBalance($chatId, $userId);
    } elseif (str_starts_with($text, '/top')) {
        handleTop($chatId);
    } elseif (str_starts_with($text, '/stats')) {
        handleStats($chatId, $userId);
    } elseif (str_starts_with($text, '/withdraw')) {
        handleWithdrawInfo($chatId, $userId);
    } elseif (str_starts_with($text, '/referral')) {
        handleReferralInfo($chatId, $userId);
    }
    // Unknown text: do nothing
}

// ═══════════════════════════════════════════════════════════════════════════
// CALLBACK QUERY HANDLER
// ═══════════════════════════════════════════════════════════════════════════

function handleCallback(array $callback): void {
    $chatId = (string)($callback['message']['chat']['id'] ?? '');
    $userId = (string)($callback['from']['id'] ?? '');
    $data   = $callback['data'] ?? '';

    if (!$chatId) {
        return;
    }

    answerCallback($callback['id']);

    switch ($data) {
        case 'leaderboard':
            sendLeaderboardMessage($chatId);
            break;
        case 'balance':
            handleBalance($chatId, $userId);
            break;
        case 'withdraw':
            handleWithdrawInfo($chatId, $userId);
            break;
        case 'stats':
            handleStats($chatId, $userId);
            break;
        case 'top':
            handleTop($chatId);
            break;
        case 'referral':
            handleReferralInfo($chatId, $userId);
            break;
        case 'help':
            handleHelp($chatId);
            break;
    }
}

// ═══════════════════════════════════════════════════════════════════════════
// /start — Registers user, processes referral, sends photo + game button
// ═══════════════════════════════════════════════════════════════════════════

function handleStart(string $chatId, string $userId, string $username, string $firstName, string $text): void {
    // Parse referral: /start ref123456789
    $referrer = '';
    if (preg_match('/\/start\s+ref(\d+)/', $text, $m)) {
        $referrer = $m[1];
    }

    // Check if player already exists
    $player = DB::row('SELECT * FROM players WHERE telegram_id = ?', [$userId]);
    $isNew  = !$player;

    if ($isNew) {
        $photoUrl = fetchTelegramPhoto($userId);

        DB::exec(
            'INSERT INTO players (telegram_id, username, first_name, photo_url, coins, btc_balance,
             total_withdraw, referrer_id, referrals, referral_coins, faucet_email,
             join_date, level, xp, games_played, best_score, game_points, last_gamepoints_reset)
             VALUES (?,?,?,?,0,0,0,NULL,0,0,?,NOW(),1,0,0,0,?,CURDATE())',
            [$userId, $username, $firstName, $photoUrl, '', DAILY_GAME_POINTS]
        );

        // Process referral bonus
        if ($referrer && $referrer !== $userId) {
            $referrerPlayer = DB::row('SELECT * FROM players WHERE telegram_id = ?', [$referrer]);
            if ($referrerPlayer) {
                DB::exec(
                    'UPDATE players SET coins = coins + ?, referrals = referrals + 1,
                     referral_coins = referral_coins + ?, game_points = game_points + ? WHERE telegram_id = ?',
                    [REFERRAL_BONUS_COINS, REFERRAL_BONUS_COINS, REFERRAL_GAME_POINTS, $referrer]
                );
                DB::exec(
                    'UPDATE players SET referrer_id = ? WHERE telegram_id = ?',
                    [$referrer, $userId]
                );
                DB::exec(
                    'INSERT IGNORE INTO referrals (referrer_id, referred_id, coins_awarded, game_points_awarded)
                     VALUES (?,?,?,?)',
                    [$referrer, $userId, REFERRAL_BONUS_COINS, REFERRAL_GAME_POINTS]
                );

                $safeFirstName = escapeMarkdownV2($firstName);

                $refMsg = "🎉 *New Referral Joined\!*\n\n"
                        . "👤 *{$safeFirstName}* just joined via your link\!\n"
                        . "💰 You earned *\+" . REFERRAL_BONUS_COINS . " coins\!*\n"
                        . "🎮 You earned *\+" . REFERRAL_GAME_POINTS . " game points\!*\n\n"
                        . "🔗 Keep sharing to earn more\! 🚀";

                $refKeyboard = [
                    'inline_keyboard' => [
                        [['text' => '♻️ Play & Earn', 'web_app' => ['url' => WEBAPP_URL]]],
                    ],
                ];

                $inviteImages = [
                    __DIR__ . '/image/invite.png',
                    __DIR__ . '/image/invite1.png',
                    __DIR__ . '/image/invite2.png',
                    __DIR__ . '/image/invite3.png',
                ];

                $inviteImage = $inviteImages[array_rand($inviteImages)];
                if (file_exists($inviteImage)) {
                    sendPhoto($referrer, $inviteImage, $refMsg, $refKeyboard);
                } else {
                    $plainMsg = "🎉 New Referral Joined\!\n\n"
                              . "👤 {$safeFirstName} just joined via your link\!\n\n"
                              . "💰 You earned \+" . REFERRAL_BONUS_COINS . " coins\!\n"
                              . "🎮 You earned \+" . REFERRAL_GAME_POINTS . " game points\!\n\n"
                              . "🔗 Keep sharing to earn more\! 🚀";
                    sendMessage($referrer, $plainMsg, $refKeyboard);
                }
            }
        }

        $player = DB::row('SELECT * FROM players WHERE telegram_id = ?', [$userId]);
    }

    $webAppUrl = WEBAPP_URL . (str_contains(WEBAPP_URL, '?') ? '&' : '?') . 'ref=' . $userId;

    $greeting = $isNew ? "Welcome" : "Welcome back";
    $emojis   = ['🚀', '🔥', '🎯', '💰', '👋', '😊', '🎉', '🌟', '✨', '💫', '😄', '🙌', '💎', '👍'];
    $emoji    = $emojis[array_rand($emojis)];

    $caption  = "{$emoji} *{$greeting}, {$firstName}\!*\n\n";
    $caption .= "Catch falling crypto coins and earn real Bitcoin\!\n\n";
    $caption .= "🔻 *How To Earn:*\n";
    $caption .= ">🟡 Tap Coin → \+" . COIN_VALUE . " coins\n";
    $caption .= ">💎 Tap Diamond → \+" . DIAMOND_VALUE . " coins\n";
    $caption .= ">⚡ Tap Boost → 2× for 5 seconds\n";
    $caption .= "> 💣 Avoid Bomb → \-30 coins & \-5 seconds\n\n";
    $caption .= "💸 *Withdraw Bitcoin Instantly*\n";
    $caption .= "👫 *Earn " . REFERRAL_BONUS_COINS . " coins* per friend you invite\!\n\n";
    $caption .= "👇 Tap the button to start playing\!";

    $keyboard = [
        'inline_keyboard' => [
            [
                ['text' => randomText(['⛏️ Start Playing', '🚀 Play & Earn', '⚡ Play Now', '🔋 Start Earning']),
                 'web_app' => ['url' => $webAppUrl]],
            ],
            [
                ['text' => randomText(['💰 Balance', '💳 Wallet', '🏦 My Funds', '💸 Account']),
                 'callback_data' => 'balance'],
                 ['text' => randomText(['👫 Referrals', '🔗 Invite Friends', '🎁 Earn Bonus', '🤝 Partners']),
                 'callback_data' => 'referral'],
                
            ],
            [
                
                ['text' => randomText(['💹 Statistics', '📊 Insights', '📈 Analytics', '📉 Reports']),
                 'callback_data' => 'stats'],
                 ['text' => randomText(['👑 Leaderboard', '📊 Top 20', '📊 Top Ranked', '🏆 Top Players', '🌟 Best Players']),
                 'callback_data' => 'top'],
            ],
            [
                
                 ['text' => randomText(['📥 Withdraw', '💵 Cash Out', '🏧 Payout', '💲 Get Money']),
                 'callback_data' => 'withdraw'],
                
            ],
        ],
    ];

    $images = [
        'https://btcgame.vexusbingo.xyz/btcgame2/btcgame/image/start.png',
        'https://btcgame.vexusbingo.xyz/btcgame2/btcgame/image/start1.png',
        'https://btcgame.vexusbingo.xyz/btcgame2/btcgame/image/start2.png',
        'https://btcgame.vexusbingo.xyz/btcgame2/btcgame/image/start3.png',
    ];

    $imageUrl = $images[array_rand($images)];
    sendPhoto($chatId, $imageUrl, $caption, $keyboard);
}

// ═══════════════════════════════════════════════════════════════════════════
// HELPER — escape special characters for MarkdownV2
// ═══════════════════════════════════════════════════════════════════════════

function escapeMarkdownV2(string $text): string {
    return preg_replace('/([_\\*\\[\\]\\(\\)~`>#+\\-=|{}.!\\\\])/', '\\\\$1', $text);
}

// ═══════════════════════════════════════════════════════════════════════════
// HELPER — random button label
// ═══════════════════════════════════════════════════════════════════════════

function randomText(array $options): string {
    return $options[array_rand($options)];
}

// ═══════════════════════════════════════════════════════════════════════════
// /help
// ═══════════════════════════════════════════════════════════════════════════

function handleHelp(string $chatId): void {
    $msg  = "ℹ️ *BTC Catch Game — Help*\n\n";
    $msg .= "🎮 *Game Items:*\n";
    $msg .= ">🟡 Coin \= \+" . COIN_VALUE . " coins\n";
    $msg .= ">💎 Diamond \= \+" . DIAMOND_VALUE . " coins\n";
    $msg .= ">⚡ Boost \= 5s double coins\n";
    $msg .= ">💣 Bomb \= \-" . BOMB_PENALTY . " coins\n\n";
    $msg .= "💸 *Withdrawal:*\n";
    $msg .= "• " . COINS_PER_SAT . " coins \= 1 SAT\n";
    $msg .= "• Min: " . MIN_WITHDRAW_SAT . " SAT\n";
    $msg .= "• Paid via FaucetPay\.io instantly\n\n";
    $msg .= "👫 *Referrals:*\n";
    $msg .= "• Earn " . REFERRAL_BONUS_COINS . " coins per friend\n";
    $msg .= "• Unlimited referrals\!\n\n";
    $msg .= "📋 *Commands:*\n";
    $msg .= "/start — Open game\n";
    $msg .= "/balance — Your coin balance\n";
    $msg .= "/top — Top 10 players\n";
    $msg .= "/stats — Your full stats\n";
    $msg .= "/referral — Your referral info\n";
    $msg .= "/withdraw — Withdrawal info\n";
    $msg .= "/help — This message";

    $keyboard = [
        'inline_keyboard' => [
            [['text' => '⛏️ Play Now', 'web_app' => ['url' => WEBAPP_URL]]],
        ],
    ];

    sendMessage($chatId, $msg, $keyboard);
}

// ═══════════════════════════════════════════════════════════════════════════
// /balance
// ═══════════════════════════════════════════════════════════════════════════

function handleBalance(string $chatId, string $userId): void {
    $player = DB::row('SELECT * FROM players WHERE telegram_id = ?', [$userId]);

    if (!$player) {
        sendMessage($chatId, "❌ Account not found\.\n\nUse /start to create one\.");
        return;
    }

    $coins     = (int)$player['coins'];
    $sat       = (int)$player['btc_balance'];
    $level     = (int)$player['level'];
    $refs      = (int)$player['referrals'];
    $withdrawn = (int)$player['total_withdraw'];
    $games     = (int)$player['games_played'];

    $safeUsername = escapeMarkdownV2($player['username']);

    $canWithdraw = $sat >= MIN_WITHDRAW_SAT
        ? "✅ Ready to withdraw\!"
        : "⏳ Need " . escapeMarkdownV2((string)(MIN_WITHDRAW_SAT * COINS_PER_SAT - $coins)) . " more coins";

    $msg  = "💼 *Your Balance*\n\n";
    $msg .= "👤 *{$safeUsername}* — Level {$level}\n";
    $msg .= "━━━━━━━━━━━━━━━━━━\n";
    $msg .= "🪙 Coins:       *" . number_format($coins) . "*\n";
    $msg .= "₿ BTC Balance: *{$sat} SAT*\n";
    $msg .= "💸 Withdrawn:   *{$withdrawn} SAT*\n";
    $msg .= "🎮 Games:       *{$games}*\n";
    $msg .= "👫 Referrals:   *{$refs}*\n";
    $msg .= "━━━━━━━━━━━━━━━━━━\n";
    $msg .= $canWithdraw;

    $keyboard = [
        'inline_keyboard' => [
            [['text' => '⛏️ Play Now', 'web_app' => ['url' => WEBAPP_URL]]],
        ],
    ];

    sendMessage($chatId, $msg, $keyboard);
}

// ═══════════════════════════════════════════════════════════════════════════
// /stats — detailed player stats
// ═══════════════════════════════════════════════════════════════════════════

function handleStats(string $chatId, string $userId): void {
    $player = DB::row('SELECT * FROM players WHERE telegram_id = ?', [$userId]);

    if (!$player) {
        sendMessage($chatId, "❌ Account not found\. Use /start first\.");
        return;
    }

    $recentGames = DB::all(
        'SELECT score, coins_earned, played_at FROM game_sessions
         WHERE telegram_id = ? ORDER BY played_at DESC LIMIT 5',
        [$userId]
    );

    $recentWds = DB::all(
        'SELECT amount_sat, status, created_at FROM withdrawals
         WHERE telegram_id = ? AND status = \'success\'
         ORDER BY created_at DESC LIMIT 3',
        [$userId]
    );

    $safeUsername = escapeMarkdownV2($player['username']);
    $joinDate     = escapeMarkdownV2(date('d M Y', strtotime($player['join_date'])));

    $msg  = "📊 *Your Full Stats*\n\n";
    $msg .= "👤 *{$safeUsername}*\n";
    $msg .= "🆔 ID: `{$player['telegram_id']}`\n";
    $msg .= "📅 Joined: {$joinDate}\n\n";
    $msg .= "⭐ *Progress*\n";
    $msg .= "🏅 Level: *{$player['level']}* \| XP: *" . number_format((int)$player['xp']) . "*\n";
    $msg .= "🎮 Games Played: *{$player['games_played']}*\n";
    $msg .= "🏆 Best Score: *" . number_format((int)$player['best_score']) . "*\n\n";
    $msg .= "💰 *Earnings*\n";
    $msg .= "🪙 Coins: *" . number_format((int)$player['coins']) . "*\n";
    $msg .= "₿ SAT Balance: *{$player['btc_balance']} SAT*\n";
    $msg .= "💸 Total Withdrawn: *{$player['total_withdraw']} SAT*\n";
    $msg .= "👫 Referral Earnings: *" . number_format((int)$player['referral_coins']) . " coins*\n\n";

    if ($recentGames) {
        $msg .= "🎮 *Recent Games*\n";
        foreach ($recentGames as $g) {
            $d    = escapeMarkdownV2(date('d/m', strtotime($g['played_at'])));
            $msg .= ">• {$d}: Score *{$g['score']}* → \+{$g['coins_earned']} coins\n";
        }
        $msg .= "\n";
    }

    if ($recentWds) {
        $msg .= "💸 *Recent Withdrawals*\n";
        foreach ($recentWds as $w) {
            $d = escapeMarkdownV2(date('d/m', strtotime($w['created_at'])));
            $msg .= ">• Withdraw {$d}: *{$w['amount_sat']} SAT* ✅\n";
        }
    }

    sendMessage($chatId, $msg);
}

// ═══════════════════════════════════════════════════════════════════════════
// /top — Leaderboard
// ═══════════════════════════════════════════════════════════════════════════

function handleTop(string $chatId): void {
    sendLeaderboardMessage($chatId);
}

function sendLeaderboardMessage(string $chatId): void {
    $top = DB::all(
        'SELECT username, coins, level, total_withdraw
         FROM players ORDER BY coins DESC LIMIT 20'
    );

    if (!$top) {
        sendMessage($chatId, "🏆 No players yet\! Be the first to play some BTC\!");
        return;
    }

    $medals = ['🥇', '🥈', '🥉'];
    $msg    = "🏆 *Top Players*\n\n";

    foreach ($top as $i => $p) {
        $medal        = $medals[$i] ?? "\#" . ($i + 1);
        $coins        = number_format((int)$p['coins']);
        $safeUsername = escapeMarkdownV2($p['username']);
        $msg         .= ">{$medal} *{$safeUsername}* — {$coins} 🪙 \(Lv\.{$p['level']}\)\n";
    }

    $msg .= "\n_Updated just now_";

    $keyboard = [
        'inline_keyboard' => [
            [['text' => '⛏️ Join the Competition', 'web_app' => ['url' => WEBAPP_URL]]],
        ],
    ];

    sendMessage($chatId, $msg, $keyboard);
}

// ═══════════════════════════════════════════════════════════════════════════
// /withdraw — Withdrawal info
// ═══════════════════════════════════════════════════════════════════════════

function handleWithdrawInfo(string $chatId, string $userId): void {
    $player = DB::row('SELECT * FROM players WHERE telegram_id = ?', [$userId]);

    if (!$player) {
        sendMessage($chatId, "❌ Account not found\. Use /start first\.");
        return;
    }

    $sat    = (int)$player['btc_balance'];
    $coins  = (int)$player['coins'];
    $needed = max(0, MIN_WITHDRAW_SAT * COINS_PER_SAT - $coins);

    $msg  = "💸 *Withdrawal Info*\n\n";
    $msg .= "💼 Your balance: *{$sat} SAT* \({$coins} coins\)\n\n";
    $msg .= "📋 *Requirements:*\n";
    $msg .= "• Minimum: *" . MIN_WITHDRAW_SAT . " SAT*\n";
    $msg .= "• Rate: *" . COINS_PER_SAT . " coins \= 1 SAT*\n\n";

    if ($sat >= MIN_WITHDRAW_SAT) {
        $msg .= "✅ *You can withdraw now\!*\n";
        $msg .= "Open the game to process your withdrawal\.";
    } else {
        $msg .= "⏳ *Need " . number_format($needed) . " more coins*\n";
        $msg .= "Keep playing to earn more\!";
    }

    $recent = DB::all(
        'SELECT amount_sat, status, created_at FROM withdrawals
         WHERE telegram_id = ? ORDER BY created_at DESC LIMIT 3',
        [$userId]
    );

    if ($recent) {
        $msg .= "\n\n📋 *Recent Withdrawals:*\n";
        foreach ($recent as $w) {
            $icon = $w['status'] === 'success' ? '✅' : ($w['status'] === 'failed' ? '❌' : '⏳');
            $d    = escapeMarkdownV2(date('d/m/Y', strtotime($w['created_at'])));
            $safeStatus = escapeMarkdownV2($w['status']);
            $msg .= ">{$icon} {$d}: *{$w['amount_sat']} SAT* \({$safeStatus}\)\n";
        }
    }

    $keyboard = [
        'inline_keyboard' => [
            [['text' => '💸 Withdraw Now', 'web_app' => ['url' => WEBAPP_URL]]],
        ],
    ];

    sendMessage($chatId, $msg, $keyboard);
}

// ═══════════════════════════════════════════════════════════════════════════
// /referral — Referral info
// ═══════════════════════════════════════════════════════════════════════════

function handleReferralInfo(string $chatId, string $userId): void {
    $player = DB::row('SELECT * FROM players WHERE telegram_id = ?', [$userId]);

    if (!$player) {
        sendMessage($chatId, "❌ Account not found\. Use /start first\.");
        return;
    }

    $refLink  = "https://t.me/" . BOT_USERNAME . "?start=ref{$userId}";
    $refs     = (int)$player['referrals'];
    $refCoins = (int)$player['referral_coins'];

    $refList = DB::all(
        'SELECT p.username, r.created_at
         FROM referrals r
         JOIN players p ON p.telegram_id = r.referred_id
         WHERE r.referrer_id = ?
         ORDER BY r.created_at DESC LIMIT 5',
        [$userId]
    );

    $msg  = "👫 *Your Referral Program*\n\n";
    $msg .= "👥 Total Referrals: *{$refs}*\n";
    $msg .= "🪙 Earned from Referrals: *" . number_format($refCoins) . " coins*\n\n";
    $msg .= "👇 *Your Referral Link:*\n";
    $msg .= "`https://t.me/" . BOT_USERNAME . "?start=ref{$userId}`\n\n";
    $msg .= "💡 *Earn " . REFERRAL_BONUS_COINS . " coins per friend who joins\!*\n";
    $msg .= "No limit — invite as many as you want\!\n\n";

    if ($refList) {
        $msg .= "👥 *Recent Referrals:*\n";
        foreach ($refList as $r) {
            $d            = escapeMarkdownV2(date('d/m/Y', strtotime($r['created_at'])));
            $safeUsername = escapeMarkdownV2($r['username']);
            $msg .= ">• *{$safeUsername}* joined {$d}\n";
        }
    } else {
        $msg .= "_No referrals yet\. Share your link to start earning\!_";
    }

    $rawRefLink = "https://t.me/" . BOT_USERNAME . "?start=ref{$userId}";
    $shareText  = urlencode("🚀 Join BTC Catch Game and earn real Bitcoin! Play mini-games and withdraw to FaucetPay! Use my link:");
    $keyboard   = [
        'inline_keyboard' => [
            [
                ['text' => '📤 Share Link', 'url' => "https://t.me/share/url?url=" . urlencode($rawRefLink) . "&text={$shareText}"],
            ],
            [
                ['text' => '⛏️ Play Now', 'web_app' => ['url' => WEBAPP_URL]],
            ],
        ],
    ];

    sendMessage($chatId, $msg, $keyboard);
}

// ═══════════════════════════════════════════════════════════════════════════
// TELEGRAM PROFILE PHOTO HELPER
// ═══════════════════════════════════════════════════════════════════════════

function fetchTelegramPhoto(string $userId): ?string {
    $url = 'https://api.telegram.org/bot' . BOT_TOKEN . '/getUserProfilePhotos';
    $ch  = curl_init($url . '?' . http_build_query(['user_id' => $userId, 'limit' => 1]));
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 8,
    ]);
    $res = curl_exec($ch);
    curl_close($ch);
    if (!$res) {
        return null;
    }

    $data   = json_decode($res, true);
    $fileId = $data['result']['photos'][0][0]['file_id'] ?? null;
    if (!$fileId) {
        return null;
    }

    $url2 = 'https://api.telegram.org/bot' . BOT_TOKEN . '/getFile?' . http_build_query(['file_id' => $fileId]);
    $ch   = curl_init($url2);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 8,
    ]);
    $res2 = curl_exec($ch);
    curl_close($ch);
    if (!$res2) {
        return null;
    }

    $data2   = json_decode($res2, true);
    $filePath = $data2['result']['file_path'] ?? null;
    if (!$filePath) {
        return null;
    }

    return 'https://api.telegram.org/file/bot' . BOT_TOKEN . '/' . $filePath;
}

// ═══════════════════════════════════════════════════════════════════════════
// TELEGRAM API HELPERS
// ═══════════════════════════════════════════════════════════════════════════

/**
 * sendChatAction — Show a status indicator in the chat.
 *
 * Common actions:
 *   typing          — "typing..."      (text responses)
 *   upload_photo    — "sending photo"   (before sendPhoto)
 *   upload_document — "sending file"    (before file uploads)
 *
 * Kept here for optional use, but not called in this version for faster replies.
 */
function sendChatAction(string $chatId, string $action = 'typing'): void {
    $ch = curl_init('https://api.telegram.org/bot' . BOT_TOKEN . '/sendChatAction');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(['chat_id' => $chatId, 'action' => $action]),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_TIMEOUT        => 5,
    ]);
    curl_exec($ch);
    curl_close($ch);
}

/**
 * sendPhoto — Send either a local image file or a direct image URL with caption + keyboard.
 */
function sendPhoto(string $chatId, string $imageSource, string $caption = '', array $keyboard = []): void {
    $payload = [
        'chat_id'    => $chatId,
        'parse_mode' => 'MarkdownV2',
    ];

    if (preg_match('~^https?://~i', $imageSource)) {
        $payload['photo'] = $imageSource;
    } elseif (is_file($imageSource)) {
        $payload['photo'] = new CURLFile($imageSource, 'image/png', basename($imageSource));
    } else {
        return;
    }

    if ($caption !== '') {
        $payload['caption'] = $caption;
    }

    if ($keyboard) {
        $payload['reply_markup'] = json_encode($keyboard);
    }

    $ch = curl_init('https://api.telegram.org/bot' . BOT_TOKEN . '/sendPhoto');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_TIMEOUT        => 8,
        CURLOPT_CONNECTTIMEOUT  => 4,
    ]);
    curl_exec($ch);
    curl_close($ch);
}

/**
 * sendMessage — Send a MarkdownV2 text message with optional inline keyboard.
 */
function sendMessage(string $chatId, string $text, array $keyboard = []): void {
    $payload = [
        'chat_id'                  => $chatId,
        'text'                     => $text,
        'parse_mode'               => 'MarkdownV2',
        'disable_web_page_preview' => true,
    ];

    if ($keyboard) {
        $payload['reply_markup'] = json_encode($keyboard);
    }

    $ch = curl_init('https://api.telegram.org/bot' . BOT_TOKEN . '/sendMessage');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode($payload),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_TIMEOUT        => 8,
        CURLOPT_CONNECTTIMEOUT  => 4,
    ]);
    curl_exec($ch);
    curl_close($ch);
}

/**
 * answerCallback — Acknowledge a callback query to remove the loading spinner.
 */
function answerCallback(string $callbackId, string $text = ''): void {
    $ch = curl_init('https://api.telegram.org/bot' . BOT_TOKEN . '/answerCallbackQuery');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(['callback_query_id' => $callbackId, 'text' => $text]),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER  => true,
        CURLOPT_TIMEOUT        => 5,
    ]);
    curl_exec($ch);
    curl_close($ch);
}

/**
 * sanitize — Strip tags and escape HTML entities.
 */
function sanitize(string $str): string {
    return htmlspecialchars(strip_tags(trim($str)), ENT_QUOTES, 'UTF-8');
}