<?php
/**
 * bot/bot_handler.php
 * نسخه کامل - گروه VIP = 6، نمایش گیگ + مگ، دکمه‌های کامل
 * + note برای سرویس‌ها (آیدی عددی و نام کاربری)
 * + پاکسازی سرویس‌های منقضی بعد از ۲ روز
 * + بخش حذف کد تخفیف
 */

if (ob_get_level() === 0) {
    ob_start();
}

error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/php_errors.log');

if (!function_exists('handlerLog')) {
    function handlerLog($msg, $data = null) {
        try {
            $logFile = __DIR__ . '/handler_log.txt';
            $log = "[" . date('Y-m-d H:i:s') . "] " . $msg;
            if ($data !== null) {
                if (is_array($data) || is_object($data)) {
                    $log .= " | " . json_encode($data, JSON_UNESCAPED_UNICODE);
                } else {
                    $log .= " | " . $data;
                }
            }
            @file_put_contents($logFile, $log . "\n", FILE_APPEND | LOCK_EX);
        } catch (Exception $e) {}
    }
}

if (!function_exists('handlerException')) {
    function handlerException($e) {
        handlerLog("EXCEPTION", ["message" => $e->getMessage(), "file" => $e->getFile(), "line" => $e->getLine()]);
    }
}
if (!function_exists('handlerError')) {
    function handlerError($errno, $errstr, $errfile, $errline) {
        handlerLog("PHP ERROR", ["no" => $errno, "str" => $errstr, "file" => $errfile, "line" => $errline]);
        return false;
    }
}

handlerLog("=== bot_handler.php LOADED ===");

// ============================================================
// ============ توابع پایه ====================================
// ============================================================

if (!function_exists('getBotInfo')) {
    function getBotInfo($botToken) {
        try {
            $url = "https://api.telegram.org/bot" . $botToken . "/getMe";
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_TIMEOUT, 20);
            $response = curl_exec($ch);
            curl_close($ch);
            return json_decode($response, true);
        } catch (Exception $e) { return null; }
    }
}

if (!function_exists('setWebhook')) {
    function setWebhook($botToken, $botUsername) {
        try {
            if (!defined('BOT_BASE_URL')) return null;
            $webhookUrl = BOT_BASE_URL . '/' . $botUsername . '/index.php';
            $url = "https://api.telegram.org/bot" . $botToken . "/setWebhook?url=" . urlencode($webhookUrl);
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_TIMEOUT, 20);
            $response = curl_exec($ch);
            curl_close($ch);
            handlerLog("setWebhook OK", ["url" => $webhookUrl]);
            return json_decode($response, true);
        } catch (Exception $e) {
            handlerLog("setWebhook ERROR", $e->getMessage());
            return null;
        }
    }
}

if (!function_exists('sendMessage')) {
    function sendMessage($chat_id, $text, $keyboard = null) {
        try {
            if (!defined('BOT_TOKEN')) return false;
            $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/sendMessage";
            $data = ["chat_id" => $chat_id, "text" => $text, "parse_mode" => "HTML"];
            if ($keyboard) $data["reply_markup"] = json_encode($keyboard, JSON_UNESCAPED_UNICODE);
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_TIMEOUT, 20);
            $response = curl_exec($ch);
            curl_close($ch);
            return $response;
        } catch (Exception $e) { return false; }
    }
}

if (!function_exists('callPanelAPI')) {
    function callPanelAPI($method, $endpoint, $data = null) {
        try {
            if (!defined('PANEL_URL') || !defined('PANEL_API_KEY')) return ["status" => 0, "body" => null];
            $url = PANEL_URL . $endpoint;
            $headers = ["X-Api-Key: " . PANEL_API_KEY, "Content-Type: application/json"];
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_TIMEOUT, 30);
            if ($method === "POST") {
                curl_setopt($ch, CURLOPT_POST, true);
                if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            } elseif ($method === "PUT") {
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
                if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
            } elseif ($method === "DELETE") {
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
            }
            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            return ["status" => $httpCode, "body" => json_decode($response, true), "raw" => $response];
        } catch (Exception $e) { return ["status" => 0, "body" => null]; }
    }
}

// ============================================================
// ============ Template ربات =================================
// ============================================================

if (!function_exists('getBotTemplate')) {
    function getBotTemplate() {
        $templatePath = __DIR__ . '/bot_template.txt';
        if (file_exists($templatePath)) {
            $content = file_get_contents($templatePath);
            if ($content !== false && strlen($content) > 500) {
                handlerLog("getBotTemplate: from FILE");
                return $content;
            }
        }
        $templatePath2 = dirname(__DIR__) . '/bot_template.txt';
        if (file_exists($templatePath2)) {
            $content = file_get_contents($templatePath2);
            if ($content !== false && strlen($content) > 500) {
                handlerLog("getBotTemplate: from FILE2");
                return $content;
            }
        }
        handlerLog("getBotTemplate: using BUILT-IN");
        return getBotTemplateBuiltIn();
    }
}

if (!function_exists('getBotTemplateBuiltIn')) {
    function getBotTemplateBuiltIn() {
        return <<<'BOTTEMPLATE'

function db() {
    static $pdo = null;
    if ($pdo === null) {
        try {
            $pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8mb4", DB_USER, DB_PASS);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $pdo->exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci");
        } catch (Exception $e) { dlog("DB CONNECTION ERROR", $e->getMessage()); die("DB Error"); }
    }
    return $pdo;
}

function dlog($msg, $data = null) {
    try {
        if (!defined('LOG_FILE')) return;
        $log = "[" . date('Y-m-d H:i:s') . "] " . $msg;
        if ($data !== null) $log .= " | " . (is_array($data) ? json_encode($data, JSON_UNESCAPED_UNICODE) : $data);
        @file_put_contents(LOG_FILE, $log . "\n", FILE_APPEND | LOCK_EX);
    } catch (Exception $e) {}
}

function callPanelAPI($method, $endpoint, $data = null) {
    try {
        $url = PANEL_URL . $endpoint;
        $headers = ["X-Api-Key: " . PANEL_API_KEY, "Content-Type: application/json", "Accept: application/json"];
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        if ($method === "POST") {
            curl_setopt($ch, CURLOPT_POST, true);
            if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
        } elseif ($method === "PUT") {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
            if ($data) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
        } elseif ($method === "DELETE") {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
        }
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $curlError = curl_error($ch);
        curl_close($ch);
        if ($curlError) dlog("PANEL CURL ERROR", ["endpoint" => $endpoint, "error" => $curlError]);
        return ["status" => $httpCode, "body" => json_decode($response, true), "raw" => $response, "curl_error" => $curlError];
    } catch (Exception $e) {
        dlog("callPanelAPI ERROR", $e->getMessage());
        return ["status" => 0, "body" => null, "raw" => "", "curl_error" => $e->getMessage()];
    }
}

function sendMessage($chat_id, $text, $keyboard = null) {
    try {
        $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/sendMessage";
        $data = ["chat_id" => $chat_id, "text" => $text, "parse_mode" => "HTML"];
        if ($keyboard) $data["reply_markup"] = json_encode($keyboard, JSON_UNESCAPED_UNICODE);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 20);
        $response = curl_exec($ch);
        $err = curl_error($ch);
        curl_close($ch);
        if ($err) dlog("sendMessage ERROR", ["chat_id" => $chat_id, "err" => $err]);
        return $response;
    } catch (Exception $e) { dlog("sendMessage EXCEPTION", $e->getMessage()); return false; }
}

function sendPhoto($chat_id, $photoUrl, $caption = "") {
    try {
        $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/sendPhoto";
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, ['chat_id' => $chat_id, 'photo' => $photoUrl, 'caption' => $caption]);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 20);
        curl_exec($ch);
        curl_close($ch);
    } catch (Exception $e) { dlog("sendPhoto ERROR", $e->getMessage()); }
}

function getPlans($botToken) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_plans WHERE bot_token = ? ORDER BY id DESC");
        $stmt->execute([$botToken]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return []; }
}

function getUnlimitedPlans($botToken, $onlyActive = true) {
    try {
        $pdo = db();
        if ($onlyActive) {
            $stmt = $pdo->prepare("SELECT * FROM bot_unlimited_plans WHERE bot_token = ? AND active = 1 ORDER BY id DESC");
        } else {
            $stmt = $pdo->prepare("SELECT * FROM bot_unlimited_plans WHERE bot_token = ? ORDER BY id DESC");
        }
        $stmt->execute([$botToken]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return []; }
}

function getBotSetting($botToken, $key, $default = '') {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT $key FROM bots WHERE bot_token = ?");
        $stmt->execute([$botToken]);
        $val = $stmt->fetchColumn();
        if ($val === false || $val === null) return $default;
        if ($val === '' && $default !== '') return $default;
        return $val;
    } catch (Exception $e) { return $default; }
}

function updateBotSetting($botToken, $key, $value) {
    try {
        $pdo = db();
        $allowed = [
            'card_number','prefix','trial_limit','trial_days','force_channel','channel_url',
            'support_id','ref_reward_type','ref_reward_amount','ref_new_user_share',
            'vip_active','vip_price_per_gb','vip_min_balance','vip_days'
        ];
        if (!in_array($key, $allowed)) { dlog("updateBotSetting BLOCKED", ["key" => $key]); return false; }
        $check = $pdo->query("SHOW COLUMNS FROM bots LIKE '$key'");
        if ($check->rowCount() == 0) {
            if (is_numeric($value)) $pdo->exec("ALTER TABLE bots ADD COLUMN $key INT DEFAULT 0");
            else $pdo->exec("ALTER TABLE bots ADD COLUMN $key VARCHAR(255) DEFAULT ''");
        }
        $checkRow = $pdo->prepare("SELECT COUNT(*) FROM bots WHERE bot_token = ?");
        $checkRow->execute([$botToken]);
        if ($checkRow->fetchColumn() == 0) $pdo->prepare("INSERT INTO bots (bot_token) VALUES (?)")->execute([$botToken]);
        $stmt = $pdo->prepare("UPDATE bots SET $key = ? WHERE bot_token = ?");
        $stmt->execute([$value, $botToken]);
        return true;
    } catch (Exception $e) { dlog("updateBotSetting ERROR", ["key" => $key, "error" => $e->getMessage()]); return false; }
}

function getWalletBalance($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT balance FROM bot_wallets WHERE bot_token = ? AND telegram_id = ?");
        $stmt->execute([$botToken, $telegramId]);
        return $stmt->fetchColumn() ?: 0;
    } catch (Exception $e) { return 0; }
}

function addWalletBalance($botToken, $telegramId, $amount, $username = '') {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("INSERT INTO bot_wallets (bot_token, telegram_id, balance, username) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE balance = balance + ?, username = ?");
        $stmt->execute([$botToken, $telegramId, $amount, $username, $amount, $username]);
    } catch (Exception $e) { dlog("addWalletBalance ERROR", $e->getMessage()); }
}

function deductWalletBalance($botToken, $telegramId, $amount) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("UPDATE bot_wallets SET balance = balance - ? WHERE bot_token = ? AND telegram_id = ?");
        $stmt->execute([$amount, $botToken, $telegramId]);
    } catch (Exception $e) { dlog("deductWalletBalance ERROR", $e->getMessage()); }
}

function isBotAdmin($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM bot_admins WHERE bot_token = ? AND telegram_id = ?");
        $stmt->execute([$botToken, $telegramId]);
        return $stmt->fetchColumn() > 0;
    } catch (Exception $e) { return false; }
}

function getBotAdmins($botToken) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_admins WHERE bot_token = ?");
        $stmt->execute([$botToken]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return []; }
}

function addBotAdmin($botToken, $telegramId, $username) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("INSERT IGNORE INTO bot_admins (bot_token, telegram_id, username) VALUES (?, ?, ?)");
        $stmt->execute([$botToken, $telegramId, $username]);
    } catch (Exception $e) {}
}

function removeBotAdmin($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("DELETE FROM bot_admins WHERE bot_token = ? AND telegram_id = ?");
        $stmt->execute([$botToken, $telegramId]);
    } catch (Exception $e) {}
}

function hasTakenTrial($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT taken FROM bot_trials WHERE bot_token = ? AND telegram_id = ?");
        $stmt->execute([$botToken, $telegramId]);
        return $stmt->fetchColumn() == 1;
    } catch (Exception $e) { return false; }
}

function markTrialTaken($botToken, $telegramId, $username) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("INSERT INTO bot_trials (bot_token, telegram_id, username, taken) VALUES (?, ?, ?, 1) ON DUPLICATE KEY UPDATE taken = 1, username = ?");
        $stmt->execute([$botToken, $telegramId, $username, $username]);
    } catch (Exception $e) {}
}

function resetAllTrials($botToken) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("UPDATE bot_trials SET taken = 0 WHERE bot_token = ?");
        $stmt->execute([$botToken]);
    } catch (Exception $e) {}
}

function generateQR($text) {
    return "https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=" . urlencode($text);
}

// ============ توابع ساخت Note سرویس ============
if (!function_exists('buildServiceNote')) {
    function buildServiceNote($userId, $username = '') {
        $name = !empty($username) ? $username : 'بدون‌نام';
        return "TgID: {$userId} | User: {$name}";
    }
}

// ============ کد تخفیف ============
function createDiscountCode($botToken, $code, $percent, $maxUses) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("INSERT INTO bot_discounts (bot_token, code, percent, max_uses, used) VALUES (?, ?, ?, ?, 0)");
        $stmt->execute([$botToken, $code, $percent, $maxUses]);
    } catch (Exception $e) {}
}

function getDiscountCode($botToken, $code) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_discounts WHERE bot_token = ? AND code = ?");
        $stmt->execute([$botToken, $code]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return null; }
}

function getAllDiscountCodes($botToken) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_discounts WHERE bot_token = ? ORDER BY id DESC");
        $stmt->execute([$botToken]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return []; }
}

function deleteDiscountCode($botToken, $codeId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("DELETE FROM bot_discounts WHERE id = ? AND bot_token = ?");
        $stmt->execute([$codeId, $botToken]);
        return $stmt->rowCount() > 0;
    } catch (Exception $e) { return false; }
}

function useDiscountCode($botToken, $code) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("UPDATE bot_discounts SET used = used + 1 WHERE bot_token = ? AND code = ?");
        $stmt->execute([$botToken, $code]);
    } catch (Exception $e) {}
}

function hasUsedDiscount($botToken, $telegramId, $code) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM bot_discount_uses WHERE bot_token = ? AND telegram_id = ? AND code = ?");
        $stmt->execute([$botToken, $telegramId, $code]);
        return $stmt->fetchColumn() > 0;
    } catch (Exception $e) { return false; }
}

function markDiscountUsed($botToken, $telegramId, $code) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("INSERT IGNORE INTO bot_discount_uses (bot_token, telegram_id, code) VALUES (?, ?, ?)");
        $stmt->execute([$botToken, $telegramId, $code]);
    } catch (Exception $e) {}
}

function generateRefCode($telegramId) {
    return "REF" . substr(md5($telegramId . time()), 0, 8);
}

function getUserRefCode($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT ref_code FROM bot_referrals WHERE bot_token = ? AND telegram_id = ?");
        $stmt->execute([$botToken, $telegramId]);
        $code = $stmt->fetchColumn();
        if (!$code) {
            $code = generateRefCode($telegramId);
            $stmt = $pdo->prepare("INSERT INTO bot_referrals (bot_token, telegram_id, ref_code) VALUES (?, ?, ?)");
            $stmt->execute([$botToken, $telegramId, $code]);
        }
        return $code;
    } catch (Exception $e) { return ""; }
}

function getReferrerByCode($botToken, $refCode) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT telegram_id FROM bot_referrals WHERE bot_token = ? AND ref_code = ?");
        $stmt->execute([$botToken, $refCode]);
        return $stmt->fetchColumn();
    } catch (Exception $e) { return null; }
}

function hasBeenReferred($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM bot_referral_relations WHERE bot_token = ? AND referred_id = ?");
        $stmt->execute([$botToken, $telegramId]);
        return $stmt->fetchColumn() > 0;
    } catch (Exception $e) { return false; }
}

function addReferralRelation($botToken, $referrerId, $referredId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("INSERT IGNORE INTO bot_referral_relations (bot_token, referrer_id, referred_id) VALUES (?, ?, ?)");
        $stmt->execute([$botToken, $referrerId, $referredId]);
    } catch (Exception $e) {}
}

function getReferralCount($botToken, $referrerId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM bot_referral_relations WHERE bot_token = ? AND referrer_id = ?");
        $stmt->execute([$botToken, $referrerId]);
        return $stmt->fetchColumn();
    } catch (Exception $e) { return 0; }
}

function giveReferralReward($botToken, $referrerId, $referredId) {
    try {
        $rewardType = getBotSetting($botToken, 'ref_reward_type', 'balance');
        $rewardAmount = intval(getBotSetting($botToken, 'ref_reward_amount', 10000));
        $newUserShare = intval(getBotSetting($botToken, 'ref_new_user_share', 50));
        $referrerReward = $rewardAmount;
        $newUserReward = intval($rewardAmount * $newUserShare / 100);
        if ($rewardType == 'balance') {
            addWalletBalance($botToken, $referrerId, $referrerReward);
            addWalletBalance($botToken, $referredId, $newUserReward);
            sendMessage($referrerId, "🎉 پاداش دعوت!\n\n💰 " . number_format($referrerReward) . " تومان اضافه شد.");
            sendMessage($referredId, "🎁 هدیه!\n\n💰 " . number_format($newUserReward) . " تومان اضافه شد.");
        } else {
            $prefix = getBotSetting($botToken, 'prefix', PREFIX);
            $username1 = $prefix . "_ref_" . substr(md5($referrerId . time()), 0, 6);
            $result1 = callPanelAPI("POST", "/user", [
                "username" => $username1, "status" => "active",
                "data_limit" => $referrerReward * 1024 * 1024 * 1024,
                "expire" => time() + (30 * 86400), "group_ids" => [1],
                "note" => buildServiceNote($referrerId, 'referrer')
            ]);
            $username2 = $prefix . "_ref_" . substr(md5($referredId . time()), 0, 6);
            $result2 = callPanelAPI("POST", "/user", [
                "username" => $username2, "status" => "active",
                "data_limit" => $newUserReward * 1024 * 1024 * 1024,
                "expire" => time() + (30 * 86400), "group_ids" => [1],
                "note" => buildServiceNote($referredId, 'referred')
            ]);
            if ($result1["status"] == 200 || $result1["status"] == 201) {
                $subUrl1 = $result1["body"]["subscription_url"] ?? "";
                if ($subUrl1 && strpos($subUrl1, "http") !== 0) $subUrl1 = SUB_BASE_URL . $subUrl1;
                sendMessage($referrerId, "🎉 پاداش!\n👤 <code>$username1</code>\n🔗 <code>$subUrl1</code>");
            }
            if ($result2["status"] == 200 || $result2["status"] == 201) {
                $subUrl2 = $result2["body"]["subscription_url"] ?? "";
                if ($subUrl2 && strpos($subUrl2, "http") !== 0) $subUrl2 = SUB_BASE_URL . $subUrl2;
                sendMessage($referredId, "🎁 هدیه!\n👤 <code>$username2</code>\n🔗 <code>$subUrl2</code>");
            }
        }
    } catch (Exception $e) { dlog("giveReferralReward ERROR", $e->getMessage()); }
}

function getReviews($botToken, $limit = 10) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_reviews WHERE bot_token = ? ORDER BY id DESC LIMIT ?");
        $stmt->bindValue(1, $botToken);
        $stmt->bindValue(2, $limit, PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return []; }
}

function getAverageRating($botToken) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT AVG(rating) as avg_rating, COUNT(*) as total FROM bot_reviews WHERE bot_token = ?");
        $stmt->execute([$botToken]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return ['avg_rating' => 0, 'total' => 0]; }
}

function addReview($botToken, $telegramId, $username, $serviceUsername, $rating, $comment) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("INSERT INTO bot_reviews (bot_token, telegram_id, username, service_username, rating, comment) VALUES (?, ?, ?, ?, ?, ?)");
        $stmt->execute([$botToken, $telegramId, $username, $serviceUsername, $rating, $comment]);
    } catch (Exception $e) {}
}

function checkBotChannel($botToken, $userId) {
    try {
        $channelId = getBotSetting($botToken, 'force_channel', '');
        if (empty($channelId)) return true;
        $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/getChatMember?chat_id={$channelId}&user_id={$userId}";
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        $response = curl_exec($ch);
        curl_close($ch);
        $result = json_decode($response, true);
        return in_array($result['result']['status'] ?? '', ['member', 'administrator', 'creator']);
    } catch (Exception $e) { return true; }
}

function showChannelJoinMessage($chat_id) {
    try {
        $channelId = trim(getBotSetting(BOT_TOKEN, 'force_channel', ''));
        $channelUrl = trim(getBotSetting(BOT_TOKEN, 'channel_url', ''));
        $channelName = "کانال";
        $channelLink = "";
        if (!empty($channelId)) {
            $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/getChat?chat_id={$channelId}";
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_TIMEOUT, 10);
            $response = curl_exec($ch);
            curl_close($ch);
            $result = json_decode($response, true);
            if (isset($result['result']['title'])) $channelName = $result['result']['title'];
            if (isset($result['result']['username'])) $channelLink = "https://t.me/" . $result['result']['username'];
        }
        if (empty($channelLink) && !empty($channelUrl)) $channelLink = $channelUrl;
        $msg = "⚠️ برای استفاده از ربات، ابتدا در کانال زیر عضو شوید:\n\n📢 " . $channelName . "\n\nبعد از عضویت، دکمه «عضو شدم» را بزنید.";
        $keyboard = ["inline_keyboard" => [
            [["text" => "📢 عضویت در " . $channelName, "url" => $channelLink]],
            [["text" => "✅ عضو شدم", "callback_data" => "check_membership"]]
        ]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) {}
}

// ============ VIP ============
// گروه VIP ثابت = 6
if (!defined('VIP_GROUP_ID')) {
    define('VIP_GROUP_ID', 6);
}

function isVipActive($botToken) {
    $v = getBotSetting($botToken, 'vip_active', 0);
    return intval($v) === 1;
}

function getVipPricePerGb($botToken) {
    $v = intval(getBotSetting($botToken, 'vip_price_per_gb', VIP_DEFAULT_PRICE_PER_GB));
    return $v > 0 ? $v : VIP_DEFAULT_PRICE_PER_GB;
}

function getVipMinBalance($botToken) {
    $v = intval(getBotSetting($botToken, 'vip_min_balance', VIP_DEFAULT_MIN_BALANCE));
    return $v > 0 ? $v : VIP_DEFAULT_MIN_BALANCE;
}

function getVipPricePerMb($botToken) {
    return getVipPricePerGb($botToken) / 1024;
}

function ensureVipTable() {
    try {
        $pdo = db();
        $pdo->exec("CREATE TABLE IF NOT EXISTS `bot_vip_services` (
          `id` INT AUTO_INCREMENT PRIMARY KEY,
          `bot_token` VARCHAR(255) NOT NULL,
          `telegram_id` BIGINT NOT NULL,
          `panel_username` VARCHAR(100) NOT NULL,
          `subscription_url` TEXT,
          `status` ENUM('active','inactive') DEFAULT 'active',
          `last_synced_traffic` BIGINT DEFAULT 0,
          `total_charged` BIGINT DEFAULT 0,
          `total_used_mb` DECIMAL(15,4) DEFAULT 0,
          `expire_at` DATETIME NULL,
          `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
          INDEX `idx_bot_user` (`bot_token`, `telegram_id`),
          INDEX `idx_status` (`status`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;");
    } catch (Exception $e) { dlog("ensureVipTable ERROR", $e->getMessage()); }
}

function getUserVipService($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_vip_services WHERE bot_token = ? AND telegram_id = ? AND status = 'active' ORDER BY id DESC LIMIT 1");
        $stmt->execute([$botToken, $telegramId]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return false; }
}

function getUserAnyVipService($botToken, $telegramId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_vip_services WHERE bot_token = ? AND telegram_id = ? ORDER BY id DESC LIMIT 1");
        $stmt->execute([$botToken, $telegramId]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    } catch (Exception $e) { return false; }
}

function syncVipUsage($botToken, $vipService) {
    try {
        if (!$vipService) return;
        $pdo = db();
        $serviceId = $vipService['id'];
        $telegramId = $vipService['telegram_id'];
        $username = $vipService['panel_username'];
        $result = callPanelAPI("GET", "/user/" . $username);
        if ($result["status"] != 200 || !isset($result["body"])) return;
        $panelUser = $result["body"];
        $usedTraffic = intval($panelUser["used_traffic"] ?? 0);
        $lastSynced = intval($vipService['last_synced_traffic'] ?? 0);
        if ($usedTraffic > $lastSynced) {
            $newBytes = $usedTraffic - $lastSynced;
            $newMb = $newBytes / 1048576;
            $pricePerMb = getVipPricePerMb($botToken);
            $cost = ceil($newMb * $pricePerMb);
            $balance = intval(getWalletBalance($botToken, $telegramId));
            if ($balance >= $cost && $cost > 0) {
                deductWalletBalance($botToken, $telegramId, $cost);
                $stmt = $pdo->prepare("UPDATE bot_vip_services SET last_synced_traffic = ?, total_charged = total_charged + ?, total_used_mb = total_used_mb + ? WHERE id = ?");
                $stmt->execute([$usedTraffic, $cost, $newMb, $serviceId]);
            } else {
                $stmt = $pdo->prepare("UPDATE bot_vip_services SET status = 'inactive', last_synced_traffic = ? WHERE id = ?");
                $stmt->execute([$usedTraffic, $serviceId]);
                callPanelAPI("PUT", "/user/" . $username, ["status" => "disabled"]);
                sendMessage($telegramId, "⚠️ سرویس ویژه غیرفعال شد. موجودی کافی نیست.");
            }
        }
    } catch (Exception $e) { dlog("syncVipUsage ERROR", $e->getMessage()); }
}

function createVipService($chat_id, $userId, $userUsername = '') {
    try {
        $existing = getUserAnyVipService(BOT_TOKEN, $userId);
        if ($existing && $existing['status'] == 'active') {
            sendMessage($chat_id, "❌ شما سرویس ویژه فعال دارید.");
            return;
        }
        $minBalance = getVipMinBalance(BOT_TOKEN);
        $balance = getWalletBalance(BOT_TOKEN, $userId);
        if ($balance < $minBalance) {
            sendMessage($chat_id, "❌ موجودی کافی نیست.\nحداقل: " . number_format($minBalance) . " تومان");
            return;
        }
        $prefix = getBotSetting(BOT_TOKEN, 'prefix', PREFIX);
        $username = $prefix . "_vip_" . substr(md5($userId . time()), 0, 8);
        $vipDays = intval(getBotSetting(BOT_TOKEN, 'vip_days', 30));
        $expireTime = time() + ($vipDays * 86400);
        // ⭐ گروه ثابت 6
        $result = callPanelAPI("POST", "/user", [
            "username" => $username, "status" => "active",
            "expire" => $expireTime, "data_limit" => 0,
            "group_ids" => [VIP_GROUP_ID],
            "note" => buildServiceNote($userId, $userUsername)
        ]);
        dlog("VIP CREATE RESULT", ["status" => $result["status"], "body" => $result["body"], "group" => VIP_GROUP_ID]);
        if ($result["status"] == 200 || $result["status"] == 201) {
            $subUrl = $result["body"]["subscription_url"] ?? "";
            if ($subUrl && strpos($subUrl, "http") !== 0) $subUrl = SUB_BASE_URL . $subUrl;
            $pdo = db();
            $stmt = $pdo->prepare("INSERT INTO bot_vip_services (bot_token, telegram_id, panel_username, subscription_url, status, last_synced_traffic, total_charged, total_used_mb, expire_at) VALUES (?, ?, ?, ?, 'active', 0, 0, 0, FROM_UNIXTIME(?))");
            $stmt->execute([BOT_TOKEN, $userId, $username, $subUrl, $expireTime]);
            $msg = "✅ سرویس ویژه فعال شد!\n👤 <code>$username</code>\n💰 " . number_format(getVipPricePerGb(BOT_TOKEN)) . " تومان/گیگ";
            if ($subUrl) $msg .= "\n🔗 <code>$subUrl</code>";
            sendMessage($chat_id, $msg);
        } else {
            sendMessage($chat_id, "❌ خطا در ساخت سرویس ویژه.");
        }
    } catch (Exception $e) { dlog("createVipService ERROR", $e->getMessage()); sendMessage($chat_id, "❌ خطا."); }
}

function formatVipUsage($totalMb) {
    $totalMb = floatval($totalMb);
    if ($totalMb < 1) {
        return round($totalMb * 1024, 2) . " کیلوبایت";
    } elseif ($totalMb < 1024) {
        return round($totalMb, 2) . " مگابایت";
    } else {
        $gb = $totalMb / 1024;
        return round($gb, 3) . " گیگابایت (" . round($totalMb, 1) . " مگ)";
    }
}

function showVipService($chat_id, $userId) {
    try {
        $vip = getUserAnyVipService(BOT_TOKEN, $userId);
        $balance = getWalletBalance(BOT_TOKEN, $userId);
        $pricePerGb = getVipPricePerGb(BOT_TOKEN);
        if (!$vip) {
            $msg = "💎 سرویس ویژه (مصرفی)\n\n";
            $msg .= "💰 قیمت هر گیگ: " . number_format($pricePerGb) . " تومان\n";
            $msg .= "💵 حداقل موجودی: " . number_format(getVipMinBalance(BOT_TOKEN)) . " تومان\n";
            $msg .= "👛 موجودی شما: " . number_format($balance) . " تومان";
            $keyboard = ["inline_keyboard" => [
                [["text" => "🛒 خرید سرویس ویژه", "callback_data" => "vip_buy"]],
                [["text" => "↩️ بازگشت", "callback_data" => "menu_buy"]]
            ]];
            sendMessage($chat_id, $msg, $keyboard);
        } else {
            $statusText = ($vip['status'] == 'active') ? "✅ فعال" : "❌ غیرفعال";
            $usedFormatted = formatVipUsage($vip['total_used_mb']);
            $msg = "💎 سرویس ویژه شما\n\n";
            $msg .= "📊 وضعیت: $statusText\n";
            $msg .= "👤 نام: <code>" . $vip['panel_username'] . "</code>\n";
            $msg .= "📈 مصرف کل: " . $usedFormatted . "\n";
            $msg .= "💵 کل پرداختی: " . number_format($vip['total_charged']) . " تومان\n";
            $msg .= "💰 قیمت هر گیگ: " . number_format($pricePerGb) . " تومان\n";
            $msg .= "👛 موجودی کیف پول: " . number_format($balance) . " تومان";
            if (!empty($vip['subscription_url'])) $msg .= "\n🔗 <code>" . $vip['subscription_url'] . "</code>";
            $keyboard = ["inline_keyboard" => []];
            if ($vip['status'] == 'active') {
                $keyboard["inline_keyboard"][] = [["text" => "🔄 بروزرسانی مصرف", "callback_data" => "vip_refresh"]];
            } else {
                $keyboard["inline_keyboard"][] = [["text" => "🔄 فعال‌سازی مجدد", "callback_data" => "vip_reactivate"]];
            }
            $keyboard["inline_keyboard"][] = [["text" => "🗑 حذف سرویس ویژه", "callback_data" => "vip_delete"]];
            $keyboard["inline_keyboard"][] = [["text" => "↩️ بازگشت", "callback_data" => "menu_buy"]];
            sendMessage($chat_id, $msg, $keyboard);
        }
    } catch (Exception $e) { dlog("showVipService ERROR", $e->getMessage()); }
}

function reactivateVipService($chat_id, $userId) {
    try {
        $vip = getUserAnyVipService(BOT_TOKEN, $userId);
        if (!$vip) return;
        $minBalance = getVipMinBalance(BOT_TOKEN);
        $balance = getWalletBalance(BOT_TOKEN, $userId);
        if ($balance < $minBalance) { sendMessage($chat_id, "❌ موجودی کافی نیست."); return; }
        $result = callPanelAPI("PUT", "/user/" . $vip['panel_username'], ["status" => "active"]);
        if ($result["status"] == 200 || $result["status"] == 201) {
            $userInfo = callPanelAPI("GET", "/user/" . $vip['panel_username']);
            $currentUsed = intval($userInfo["body"]["used_traffic"] ?? 0);
            $pdo = db();
            $pdo->prepare("UPDATE bot_vip_services SET status = 'active', last_synced_traffic = ? WHERE id = ?")->execute([$currentUsed, $vip['id']]);
            sendMessage($chat_id, "✅ سرویس ویژه فعال شد!");
        }
    } catch (Exception $e) { dlog("reactivateVipService ERROR", $e->getMessage()); }
}

function deleteVipService($chat_id, $userId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_vip_services WHERE bot_token = ? AND telegram_id = ? ORDER BY id DESC LIMIT 1");
        $stmt->execute([BOT_TOKEN, $userId]);
        $vip = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$vip) { sendMessage($chat_id, "❌ یافت نشد."); return; }
        callPanelAPI("DELETE", "/user/" . $vip['panel_username']);
        $pdo->prepare("DELETE FROM bot_vip_services WHERE id = ?")->execute([$vip['id']]);
        sendMessage($chat_id, "✅ سرویس ویژه حذف شد.");
    } catch (Exception $e) { dlog("deleteVipService ERROR", $e->getMessage()); }
}

function showVipAdminPanel($chat_id) {
    try {
        $active = isVipActive(BOT_TOKEN);
        $pricePerGb = getVipPricePerGb(BOT_TOKEN);
        $minBalance = getVipMinBalance(BOT_TOKEN);
        $vipDays = intval(getBotSetting(BOT_TOKEN, 'vip_days', 30));
        $msg = "💎 مدیریت پلن ویژه\n\n";
        $msg .= "📊 وضعیت: " . ($active ? "✅ روشن" : "❌ خاموش") . "\n";
        $msg .= "💰 قیمت هر گیگ: " . number_format($pricePerGb) . " تومان\n";
        $msg .= "💵 حداقل موجودی: " . number_format($minBalance) . " تومان\n";
        $msg .= "⏰ مدت اعتبار: $vipDays روز\n";
        $msg .= "👥 گروه پنل: " . VIP_GROUP_ID . " (ثابت)";
        $keyboard = ["inline_keyboard" => [
            [["text" => ($active ? "🔴 خاموش کردن" : "🟢 روشن کردن"), "callback_data" => "vip_toggle"]],
            [["text" => "💰 تنظیم قیمت هر گیگ", "callback_data" => "vip_set_price"]],
            [["text" => "💵 تنظیم حداقل موجودی", "callback_data" => "vip_set_min"]],
            [["text" => "⏰ تنظیم مدت اعتبار (روز)", "callback_data" => "vip_set_days"]],
            [["text" => "🔄 بروزرسانی مصرف همه", "callback_data" => "vip_sync_all"]],
            [["text" => "📊 لیست سرویس‌های ویژه", "callback_data" => "vip_list"]],
            [["text" => "↩️ بازگشت", "callback_data" => "menu_admin"]]
        ]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) { dlog("showVipAdminPanel ERROR", $e->getMessage()); }
}

function showVipServicesList($chat_id) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_vip_services WHERE bot_token = ? ORDER BY id DESC LIMIT 30");
        $stmt->execute([BOT_TOKEN]);
        $services = $stmt->fetchAll(PDO::FETCH_ASSOC);
        if (count($services) == 0) { sendMessage($chat_id, "📭 خالی."); return; }
        $msg = "📊 لیست سرویس‌های ویژه\n\n";
        foreach ($services as $s) {
            $icon = ($s['status'] == 'active') ? "✅" : "❌";
            $usedFormatted = formatVipUsage($s['total_used_mb']);
            $msg .= "$icon <code>" . $s['panel_username'] . "</code>\n";
            $msg .= "   📈 " . $usedFormatted . "\n";
            $msg .= "   💵 " . number_format($s['total_charged']) . " تومان\n\n";
        }
        sendMessage($chat_id, $msg);
    } catch (Exception $e) { dlog("showVipServicesList ERROR", $e->getMessage()); }
}

function syncAllVipServices($botToken) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_vip_services WHERE bot_token = ? AND status = 'active'");
        $stmt->execute([$botToken]);
        $services = $stmt->fetchAll(PDO::FETCH_ASSOC);
        foreach ($services as $svc) syncVipUsage($botToken, $svc);
        return count($services);
    } catch (Exception $e) { return 0; }
}

// ============ پاکسازی سرویس‌های منقضی (۲ روز) ============
if (!function_exists('cleanupExpiredServices')) {
    function cleanupExpiredServices($botToken, $graceDays = 2) {
        $deleted = 0;
        try {
            $pdo = db();
            // بازه مجاز: expire_at <= now - graceDays  (چه از نظر زمان چه از نظر حجم)
            $cutoffTs = time() - ($graceDays * 86400);
            $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE bot_token = ? AND status = 'active'");
            $stmt->execute([$botToken]);
            $services = $stmt->fetchAll(PDO::FETCH_ASSOC);
            foreach ($services as $s) {
                $isExpired = false;
                // بررسی زمان
                if (!empty($s['expire_at'])) {
                    $expTs = strtotime($s['expire_at']);
                    if ($expTs !== false && $expTs <= $cutoffTs) $isExpired = true;
                }
                // بررسی حجم (فقط برای حجمی‌ها)
                if (!$isExpired && empty($s['is_unlimited'])) {
                    $info = callPanelAPI("GET", "/user/" . $s['username']);
                    if ($info['status'] == 200 && isset($info['body'])) {
                        $used = intval($info['body']['used_traffic'] ?? 0);
                        $limit = intval($info['body']['data_limit'] ?? 0);
                        $status = $info['body']['status'] ?? '';
                        if ($limit > 0 && $used >= $limit) {
                            // حجم تمام شده - بررسی کنیم از کِی؟ از expire_at استفاده می‌کنیم
                            if (!empty($s['expire_at'])) {
                                $expTs = strtotime($s['expire_at']);
                                if ($expTs !== false && $expTs <= $cutoffTs) $isExpired = true;
                            } else {
                                // اگر expire_at نداریم، از created_at + days استفاده می‌کنیم
                                $createdTs = strtotime($s['created_at'] ?? 'now');
                                $expTs = $createdTs + (intval($s['days']) * 86400);
                                if ($expTs <= $cutoffTs) $isExpired = true;
                            }
                        }
                        if ($status === 'expired' || $status === 'limited') {
                            if (!empty($s['expire_at'])) {
                                $expTs = strtotime($s['expire_at']);
                                if ($expTs !== false && $expTs <= $cutoffTs) $isExpired = true;
                            } else {
                                $createdTs = strtotime($s['created_at'] ?? 'now');
                                $expTs = $createdTs + (intval($s['days']) * 86400);
                                if ($expTs <= $cutoffTs) $isExpired = true;
                            }
                        }
                    }
                }
                if ($isExpired) {
                    // حذف از پنل
                    callPanelAPI("DELETE", "/user/" . $s['username']);
                    // حذف از دیتابیس
                    $pdo->prepare("DELETE FROM bot_services WHERE id = ?")->execute([$s['id']]);
                    $pdo->prepare("DELETE FROM bot_reminders WHERE bot_token = ? AND service_id = ?")->execute([$botToken, $s['id']]);
                    $deleted++;
                }
            }
        } catch (Exception $e) {
            dlog("cleanupExpiredServices ERROR", $e->getMessage());
        }
        return $deleted;
    }
}

// ============ پنل ادمین ============
function showBotAdminPanel($chat_id) {
    try {
        $plans = getPlans(BOT_TOKEN);
        $unlimitedPlans = getUnlimitedPlans(BOT_TOKEN, false);
        $card = getBotSetting(BOT_TOKEN, 'card_number', '');
        $prefix = getBotSetting(BOT_TOKEN, 'prefix', PREFIX);
        $trialLimit = getBotSetting(BOT_TOKEN, 'trial_limit', 1073741824);
        $trialDays = getBotSetting(BOT_TOKEN, 'trial_days', 3);
        $channel = getBotSetting(BOT_TOKEN, 'force_channel', '');
        $support = getBotSetting(BOT_TOKEN, 'support_id', '');
        $admins = getBotAdmins(BOT_TOKEN);
        $avgRating = getAverageRating(BOT_TOKEN);
        $refRewardType = getBotSetting(BOT_TOKEN, 'ref_reward_type', 'balance');
        $refRewardAmount = getBotSetting(BOT_TOKEN, 'ref_reward_amount', '10000');
        $refTypeText = ($refRewardType == 'balance') ? 'موجودی' : 'کانفیگ';
        $refAmountText = ($refRewardType == 'balance') ? number_format($refRewardAmount) . ' تومان' : $refRewardAmount . ' گیگ';
        $ratingText = ($avgRating['total'] > 0) ? round($avgRating['avg_rating'], 1) . " ⭐ (" . $avgRating['total'] . ")" : "بدون نظر";
        $msg = "👤 پنل مدیریت ربات\n\n";
        $msg .= "🔤 پیشوند: " . $prefix . "\n";
        $msg .= "💳 کارت: " . ($card ?: "تنظیم نشده") . "\n";
        $msg .= "📦 حجم تست: " . round($trialLimit / 1048576) . " مگابایت\n";
        $msg .= "⏰ مدت تست: " . $trialDays . " روز\n";
        $msg .= "📢 کانال: " . ($channel ? "✅" : "❌") . "\n";
        $msg .= "🎧 پشتیبانی: " . ($support ? "@" . $support : "تنظیم نشده") . "\n";
        $msg .= "🎁 پاداش دعوت: " . $refTypeText . " - " . $refAmountText . "\n";
        $msg .= "💎 پلن ویژه: " . (isVipActive(BOT_TOKEN) ? "✅ روشن" : "❌ خاموش") . "\n";
        $msg .= "👥 ادمین‌ها: " . count($admins) . "\n";
        $msg .= "📊 امتیاز: " . $ratingText;
        $keyboard = ["inline_keyboard" => [
            [["text" => "💳 شماره کارت", "callback_data" => "ba_card"], ["text" => "🔤 پیشوند", "callback_data" => "ba_prefix"]],
            [["text" => "📦 حجم تست", "callback_data" => "ba_trial_limit"], ["text" => "⏰ مدت تست", "callback_data" => "ba_trial_days"]],
            [["text" => "🔄 ریست تست", "callback_data" => "ba_trial_reset"]],
            [["text" => "➕ ساخت پلن جدید", "callback_data" => "ba_add_plan"], ["text" => "🗑 حذف پلن", "callback_data" => "ba_delete_plan"]],
            [["text" => "♾ پلن‌های نامحدود", "callback_data" => "ba_unlimited_plans"]],
            [["text" => "💎 پلن ویژه (مصرفی)", "callback_data" => "ba_vip_panel"]],
            [["text" => "🎁 تنظیم پاداش دعوت", "callback_data" => "ba_ref_reward"]],
            [["text" => "➕ افزودن ادمین", "callback_data" => "ba_add_admin"], ["text" => "🗑 حذف ادمین", "callback_data" => "ba_remove_admin"]],
            [["text" => "📢 تنظیم کانال", "callback_data" => "ba_channel"], ["text" => "🗑 حذف کانال", "callback_data" => "ba_channel_remove"]],
            [["text" => "🎧 پشتیبانی", "callback_data" => "ba_support"]],
            [["text" => "🏷 کد تخفیف", "callback_data" => "ba_discount"], ["text" => "🗑 حذف کد تخفیف", "callback_data" => "ba_discount_delete"]],
            [["text" => "💰 مدیریت کیف پول", "callback_data" => "ba_wallet"]],
            [["text" => "📨 پیام همگانی", "callback_data" => "ba_broadcast"]],
            [["text" => "⭐ نظرات کاربران", "callback_data" => "ba_reviews"]],
            [["text" => "📊 گزارش کامل", "callback_data" => "ba_report"]],
            [["text" => "👥 مدیریت کاربران", "callback_data" => "ba_users"]],
            [["text" => "↩️ بازگشت", "callback_data" => "ba_back"]]
        ]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) { dlog("showBotAdminPanel ERROR", $e->getMessage()); }
}

function showBotUserMenu($chat_id, $userId) {
    try {
        $balance = getWalletBalance(BOT_TOKEN, $userId);
        $msg = "🌟 منوی کاربر\n\n💰 موجودی: " . number_format($balance) . " تومان";
        $keyboard = ["inline_keyboard" => [
            [["text" => "🛒 خرید سرویس", "callback_data" => "menu_buy"], ["text" => "🔄 تمدید سرویس", "callback_data" => "menu_renew"]],
            [["text" => "🎁 تست رایگان", "callback_data" => "menu_trial"], ["text" => "📦 سرویس‌های من", "callback_data" => "menu_services"]],
            [["text" => "👤 حساب کاربری", "callback_data" => "menu_account"], ["text" => "💰 افزایش موجودی", "callback_data" => "menu_balance"]],
            [["text" => "🔗 لینک دعوت من", "callback_data" => "menu_ref"]],
            [["text" => "🎧 پشتیبانی", "callback_data" => "menu_support"], ["text" => "📚 راهنمای اتصال", "callback_data" => "menu_guide"]]
        ]];
        if (isBotAdmin(BOT_TOKEN, $userId)) {
            $keyboard["inline_keyboard"][] = [["text" => "👤 پنل مدیریت", "callback_data" => "menu_admin"]];
        }
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) { dlog("showBotUserMenu ERROR", $e->getMessage()); }
}

function showReferral($chat_id, $userId) {
    try {
        $refCode = getUserRefCode(BOT_TOKEN, $userId);
        $pdo = db();
        $stmt = $pdo->prepare("SELECT bot_username FROM bots WHERE bot_token = ?");
        $stmt->execute([BOT_TOKEN]);
        $botUsername = $stmt->fetchColumn();
        $refLink = "https://t.me/" . $botUsername . "?start=" . $refCode;
        $count = getReferralCount(BOT_TOKEN, $userId);
        $refRewardType = getBotSetting(BOT_TOKEN, 'ref_reward_type', 'balance');
        $refRewardAmount = getBotSetting(BOT_TOKEN, 'ref_reward_amount', '10000');
        $refNewShare = getBotSetting(BOT_TOKEN, 'ref_new_user_share', 50);
        $rewardText = ($refRewardType == 'balance') ? number_format($refRewardAmount) . ' تومان' : $refRewardAmount . ' گیگ';
        $newUserReward = ($refRewardType == 'balance') ? number_format(intval($refRewardAmount * $refNewShare / 100)) . ' تومان' : intval($refRewardAmount * $refNewShare / 100) . ' گیگ';
        $msg = "🔗 لینک دعوت شما:\n\n<code>$refLink</code>\n\n📊 تعداد دعوت‌شده: $count\n\n🎁 پاداش شما: " . $rewardText . "\n🎁 پاداش دوست شما: " . $newUserReward;
        $keyboard = ["inline_keyboard" => [
            [["text" => "📤 اشتراک‌گذاری لینک", "url" => "https://t.me/share/url?url=" . urlencode($refLink) . "&text=" . urlencode("با لینک من عضو شو!")]]
        ]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) { dlog("showReferral ERROR", $e->getMessage()); }
}

function showConnectionGuide($chat_id) {
    $keyboard = ["inline_keyboard" => [
        [["text" => "📱 دانلود Happ اندروید", "url" => "https://play.google.com/store/apps/details?id=com.happproxy"]],
        [["text" => "🍎 دانلود V2box آیفون", "url" => "https://apps.apple.com/app/id6446814690"]],
        [["text" => "💻 دانلود Hiddify ویندوز", "url" => "https://github.com/hiddify/hiddify-app/releases/download/v4.1.1/Hiddify-Windows-Setup-x64.exe"]]
    ]];
    sendMessage($chat_id, "📚 راهنمای اتصال\n\n🔗 لینک‌های دانلود:", $keyboard);
}

function showSupport($chat_id) {
    $supportId = trim(getBotSetting(BOT_TOKEN, 'support_id', ''));
    $msg = "🎧 پشتیبانی\n\n";
    $msg .= (!empty($supportId)) ? "برای ارتباط با پشتیبانی:\n\n👤 @" . $supportId : "پشتیبانی تنظیم نشده.";
    sendMessage($chat_id, $msg);
}

function showAccount($chat_id, $userId) {
    try {
        $balance = getWalletBalance(BOT_TOKEN, $userId);
        $pdo = db();
        $stmt = $pdo->prepare("SELECT COUNT(*) FROM bot_services WHERE bot_token = ? AND telegram_id = ? AND status = 'active'");
        $stmt->execute([BOT_TOKEN, $userId]);
        $servicesCount = $stmt->fetchColumn();
        $refCount = getReferralCount(BOT_TOKEN, $userId);
        $msg = "👤 حساب کاربری\n\n🆔 آیدی: <code>$userId</code>\n💰 موجودی: " . number_format($balance) . " تومان\n📦 تعداد سرویس‌ها: $servicesCount\n🎁 تعداد دعوت‌شده: $refCount";
        sendMessage($chat_id, $msg);
    } catch (Exception $e) { dlog("showAccount ERROR", $e->getMessage()); }
}

function startTrial($chat_id, $userId, $userUsername = '') {
    try {
        if (hasTakenTrial(BOT_TOKEN, $userId)) { sendMessage($chat_id, "❌ شما قبلاً تست گرفته‌اید."); return; }
        $trialLimit = getBotSetting(BOT_TOKEN, 'trial_limit', 1073741824);
        $trialDays = getBotSetting(BOT_TOKEN, 'trial_days', 3);
        $prefix = getBotSetting(BOT_TOKEN, 'prefix', PREFIX);
        $username = $prefix . "_trial_" . substr(md5($userId . time()), 0, 6);
        $expireTime = time() + ($trialDays * 86400);
        $result = callPanelAPI("POST", "/user", [
            "username" => $username, "status" => "active",
            "data_limit" => $trialLimit, "expire" => $expireTime, "group_ids" => [1],
            "note" => buildServiceNote($userId, $userUsername)
        ]);
        if ($result["status"] == 200 || $result["status"] == 201) {
            markTrialTaken(BOT_TOKEN, $userId, $username);
            $subUrl = $result["body"]["subscription_url"] ?? "";
            if ($subUrl && strpos($subUrl, "http") !== 0) $subUrl = SUB_BASE_URL . $subUrl;
            $pdo = db();
            $stmt = $pdo->prepare("INSERT INTO bot_services (bot_token, telegram_id, username, plan_id, size_gb, days, price, subscription_url, status, expire_at) VALUES (?, ?, ?, 0, ?, ?, 0, ?, 'active', FROM_UNIXTIME(?))");
            $stmt->execute([BOT_TOKEN, $userId, $username, round($trialLimit / 1073741824), $trialDays, $subUrl, $expireTime]);
            $msg = "✅ تست رایگان فعال شد!\n\n👤 <code>$username</code>\n📦 " . round($trialLimit / 1048576) . " مگابایت\n⏰ " . $trialDays . " روز";
            if ($subUrl) { $msg .= "\n🔗 <code>$subUrl</code>"; sendPhoto($chat_id, generateQR($subUrl), "📱 QR Code"); }
            sendMessage($chat_id, $msg);
        } else { sendMessage($chat_id, "❌ خطا."); }
    } catch (Exception $e) { dlog("startTrial ERROR", $e->getMessage()); }
}

function showBuyPlans($chat_id, $userId) {
    try {
        $plans = getPlans(BOT_TOKEN);
        $unlimitedPlans = getUnlimitedPlans(BOT_TOKEN, true);
        $balance = getWalletBalance(BOT_TOKEN, $userId);
        $vipActive = isVipActive(BOT_TOKEN);
        if (count($plans) == 0 && count($unlimitedPlans) == 0 && !$vipActive) { sendMessage($chat_id, "📭 پلنی اضافه نشده است."); return; }
        $msg = "🛒 خرید سرویس\n\n💰 موجودی: " . number_format($balance) . " تومان\n\n";
        $keyboard = ["inline_keyboard" => []];
        if (count($plans) > 0) {
            $msg .= "📦 پلن‌های حجمی:\n\n";
            foreach ($plans as $plan) {
                $msg .= "📌 " . $plan["name"] . " - " . $plan["size_gb"] . " گیگابایت / " . $plan["days"] . " روز - " . number_format($plan["price"]) . " تومان\n";
                $keyboard["inline_keyboard"][] = [[
                    "text" => "🛒 " . $plan["name"] . " - " . number_format($plan["price"]) . " تومان",
                    "callback_data" => "buy_plan_" . $plan["id"]
                ]];
            }
            $msg .= "\n";
        }
        if (count($unlimitedPlans) > 0) {
            $msg .= "♾ پلن‌های نامحدود:\n\n";
            foreach ($unlimitedPlans as $plan) {
                $msg .= "📌 " . $plan["name"] . " - نامحدود / " . $plan["days"] . " روز - " . number_format($plan["price"]) . " تومان\n";
                $keyboard["inline_keyboard"][] = [[
                    "text" => "♾ " . $plan["name"] . " - " . number_format($plan["price"]) . " تومان",
                    "callback_data" => "buy_unlimited_" . $plan["id"]
                ]];
            }
            $msg .= "\n";
        }
        if ($vipActive) {
            $vip = getUserAnyVipService(BOT_TOKEN, $userId);
            $vipStatus = $vip ? " (" . ($vip['status'] == 'active' ? "✅ فعال" : "❌ غیرفعال") . ")" : "";
            $msg .= "💎 سرویس ویژه (مصرفی):\n\n";
            $msg .= "📌 قیمت هر گیگ: " . number_format(getVipPricePerGb(BOT_TOKEN)) . " تومان$vipStatus\n\n";
            $keyboard["inline_keyboard"][] = [["text" => "💎 سرویس ویژه (مصرفی)" . $vipStatus, "callback_data" => "menu_vip"]];
        }
        $keyboard["inline_keyboard"][] = [["text" => "↩️ بازگشت", "callback_data" => "menu_back"]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) { dlog("showBuyPlans ERROR", $e->getMessage()); }
}

function showInvoice($chat_id, $userId, $planId, $type = "normal") {
    try {
        $pdo = db();
        if ($type == "normal") {
            $stmt = $pdo->prepare("SELECT * FROM bot_plans WHERE id = ? AND bot_token = ?");
            $stmt->execute([$planId, BOT_TOKEN]);
            $plan = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$plan) { sendMessage($chat_id, "❌ پلن یافت نشد."); return; }
            $planName = $plan["name"];
            $planDesc = $plan["size_gb"] . " گیگابایت / " . $plan["days"] . " روز";
            $price = intval($plan["price"]);
        } else {
            $stmt = $pdo->prepare("SELECT * FROM bot_unlimited_plans WHERE id = ? AND bot_token = ? AND active = 1");
            $stmt->execute([$planId, BOT_TOKEN]);
            $plan = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$plan) { sendMessage($chat_id, "❌ پلن یافت نشد."); return; }
            $planName = $plan["name"];
            $planDesc = "نامحدود / " . $plan["days"] . " روز";
            $price = intval($plan["price"]);
        }
        $balance = intval(getWalletBalance(BOT_TOKEN, $userId));
        $card = getBotSetting(BOT_TOKEN, 'card_number', '');
        $discountPercent = 0; $discountCode = "";
        $stmtState = $pdo->prepare("SELECT state, temp_data FROM bot_user_states WHERE chat_id = ?");
        $stmtState->execute([$chat_id]);
        $userState = $stmtState->fetch(PDO::FETCH_ASSOC);
        if ($userState && $userState["state"] == "discount_applied") {
            $parts = explode("|", $userState["temp_data"]);
            if ($parts[0] == $planId && isset($parts[1]) && $parts[1] == $type) {
                $discount = getDiscountCode(BOT_TOKEN, $parts[2]);
                if ($discount) { $discountPercent = intval($discount["percent"]); $discountCode = $parts[2]; }
            }
        }
        $finalPrice = $price;
        if ($discountPercent > 0) $finalPrice = $price - ($price * $discountPercent / 100);
        $msg = "🧾 فاکتور خرید\n\n📦 پلن: " . $planName . "\n📊 مشخصات: " . $planDesc . "\n";
        if ($discountPercent > 0) {
            $msg .= "💰 قیمت اصلی: " . number_format($price) . " تومان\n🏷 تخفیف: " . $discountPercent . "%\n💵 مبلغ نهایی: " . number_format($finalPrice) . " تومان\n";
        } else { $msg .= "💰 مبلغ: " . number_format($finalPrice) . " تومان\n"; }
        $msg .= "💳 موجودی شما: " . number_format($balance) . " تومان\n\n";
        $keyboard = ["inline_keyboard" => []];
        if ($balance >= $finalPrice) {
            $msg .= "✅ موجودی شما کافی است.";
            $keyboard["inline_keyboard"][] = [["text" => "✅ پرداخت از موجودی", "callback_data" => "pay_wallet_" . $type . "_" . $planId]];
            $keyboard["inline_keyboard"][] = [["text" => "🏷 اعمال کد تخفیف", "callback_data" => "apply_discount_" . $type . "_" . $planId]];
        } else {
            $msg .= "⚠️ موجودی کافی نیست.\n\n💵 لطفاً مبلغ " . number_format($finalPrice) . " تومان را به کارت زیر واریز کنید:\n\n";
            if ($card) $msg .= "💳 <code>$card</code>\n\n";
            $msg .= "سپس عکس رسید را ارسال کنید.";
            $orderId = uniqid('order_');
            $username = ($type == "normal") ? $plan["size_gb"] . "GB" : "unlimited";
            $stmt = $pdo->prepare("INSERT INTO orders (order_id, chat_id, size, price, status, username, plan_type, plan_id, discount_code, discount_percent) VALUES (?, ?, ?, ?, 'pending', ?, ?, ?, ?, ?)");
            $sizeVal = ($type == "normal") ? intval($plan["size_gb"]) : 0;
            $stmt->execute([$orderId, $chat_id, $sizeVal, $finalPrice, $username, $type, $planId, $discountCode, $discountPercent]);
            $keyboard["inline_keyboard"][] = [["text" => "🏷 اعمال کد تخفیف", "callback_data" => "apply_discount_" . $type . "_" . $planId]];
        }
        $keyboard["inline_keyboard"][] = [["text" => "↩️ بازگشت", "callback_data" => "menu_buy"]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) { dlog("showInvoice ERROR", $e->getMessage()); }
}

function payFromWallet($chat_id, $userId, $type, $planId, $userUsername = '') {
    try {
        $pdo = db();
        if ($type == "normal") {
            $stmt = $pdo->prepare("SELECT * FROM bot_plans WHERE id = ? AND bot_token = ?");
            $stmt->execute([$planId, BOT_TOKEN]);
            $plan = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$plan) { sendMessage($chat_id, "❌ پلن یافت نشد."); return; }
            $size = intval($plan["size_gb"]); $days = intval($plan["days"]); $price = intval($plan["price"]); $groupId = 1; $isUnlimited = 0;
        } else {
            $stmt = $pdo->prepare("SELECT * FROM bot_unlimited_plans WHERE id = ? AND bot_token = ? AND active = 1");
            $stmt->execute([$planId, BOT_TOKEN]);
            $plan = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$plan) { sendMessage($chat_id, "❌ پلن یافت نشد."); return; }
            $size = 0; $days = intval($plan["days"]); $price = intval($plan["price"]); $groupId = 2; $isUnlimited = 1;
        }
        $discountPercent = 0; $discountCode = "";
        $stmtState = $pdo->prepare("SELECT state, temp_data FROM bot_user_states WHERE chat_id = ?");
        $stmtState->execute([$chat_id]);
        $userState = $stmtState->fetch(PDO::FETCH_ASSOC);
        if ($userState && $userState["state"] == "discount_applied") {
            $parts = explode("|", $userState["temp_data"]);
            if ($parts[0] == $planId && isset($parts[1]) && $parts[1] == $type) {
                $discount = getDiscountCode(BOT_TOKEN, $parts[2]);
                if ($discount) { $discountPercent = intval($discount["percent"]); $discountCode = $parts[2]; }
            }
        }
        $finalPrice = $price;
        if ($discountPercent > 0) $finalPrice = $price - ($price * $discountPercent / 100);
        $balance = intval(getWalletBalance(BOT_TOKEN, $userId));
        if ($balance < $finalPrice) { sendMessage($chat_id, "❌ موجودی کافی نیست."); return; }
        deductWalletBalance(BOT_TOKEN, $userId, $finalPrice);
        if ($discountPercent > 0 && !empty($discountCode)) { useDiscountCode(BOT_TOKEN, $discountCode); markDiscountUsed(BOT_TOKEN, $userId, $discountCode); }
        $prefix = getBotSetting(BOT_TOKEN, 'prefix', PREFIX);
        $username = $prefix . "_" . substr(md5(time() . $userId), 0, 8);
        $expireTime = time() + ($days * 86400);
        $result = callPanelAPI("POST", "/user", [
            "username" => $username, "status" => "active",
            "expire" => $expireTime, "group_ids" => [$groupId],
            "data_limit" => $isUnlimited ? 0 : ($size * 1024 * 1024 * 1024),
            "note" => buildServiceNote($userId, $userUsername)
        ]);
        if ($result["status"] == 200 || $result["status"] == 201) {
            $subUrl = $result["body"]["subscription_url"] ?? "";
            if ($subUrl && strpos($subUrl, "http") !== 0) $subUrl = SUB_BASE_URL . $subUrl;
            $stmt = $pdo->prepare("INSERT INTO bot_services (bot_token, telegram_id, username, plan_id, size_gb, days, price, subscription_url, is_unlimited, unlimited_plan_id, expire_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FROM_UNIXTIME(?))");
            $stmt->execute([BOT_TOKEN, $userId, $username, $planId, $size, $days, $finalPrice, $subUrl, $isUnlimited, $isUnlimited ? $planId : null, $expireTime]);
            $msg = "✅ سرویس با موفقیت ساخته شد!\n\n👤 <code>$username</code>\n";
            $msg .= $isUnlimited ? "♾ نامحدود / ⏰ $days روز\n" : "📦 $size گیگابایت / ⏰ $days روز\n";
            $msg .= "💰 پرداخت: " . number_format($finalPrice) . " تومان\n";
            if ($subUrl) { $msg .= "🔗 <code>$subUrl</code>\n"; sendPhoto($chat_id, generateQR($subUrl), "📱 QR Code"); }
            sendMessage($chat_id, $msg);
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            requestReview($chat_id, $username);
        } else {
            addWalletBalance(BOT_TOKEN, $userId, $finalPrice);
            sendMessage($chat_id, "❌ خطا در ساخت سرویس.");
        }
    } catch (Exception $e) { dlog("payFromWallet ERROR", $e->getMessage()); }
}

function requestReview($chat_id, $serviceUsername) {
    try {
        $pdo = db();
        $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "waiting_review", $serviceUsername]);
        $keyboard = ["inline_keyboard" => [
            [["text" => "⭐⭐⭐⭐⭐ عالی", "callback_data" => "review_5_" . $serviceUsername]],
            [["text" => "⭐⭐⭐⭐ خوب", "callback_data" => "review_4_" . $serviceUsername]],
            [["text" => "⭐⭐⭐ متوسط", "callback_data" => "review_3_" . $serviceUsername]],
            [["text" => "⭐⭐ ضعیف", "callback_data" => "review_2_" . $serviceUsername]],
            [["text" => "⭐ بد", "callback_data" => "review_1_" . $serviceUsername]],
            [["text" => "⏭ بعداً", "callback_data" => "review_skip"]]
        ]];
        sendMessage($chat_id, "⭐ نظر شما برای ما مهم است!\n\nلطفاً به سرویس خود امتیاز دهید:", $keyboard);
    } catch (Exception $e) {}
}

function showRenewServices($chat_id, $userId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE bot_token = ? AND telegram_id = ? AND status = 'active' ORDER BY id DESC");
        $stmt->execute([BOT_TOKEN, $userId]);
        $services = $stmt->fetchAll(PDO::FETCH_ASSOC);
        if (count($services) == 0) { sendMessage($chat_id, "📭 سرویسی برای تمدید ندارید."); return; }
        $msg = "🔄 تمدید سرویس\n\nسرویس‌های شما:\n\n";
        $keyboard = ["inline_keyboard" => []];
        foreach ($services as $s) {
            $type = $s["is_unlimited"] ? "♾ نامحدود" : $s["size_gb"] . " گیگابایت";
            $keyboard["inline_keyboard"][] = [["text" => "🔄 " . $s["username"] . " (" . $type . ")", "callback_data" => "renew_service_" . $s["id"]]];
        }
        $keyboard["inline_keyboard"][] = [["text" => "↩️ بازگشت", "callback_data" => "menu_back"]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) {}
}

function showRenewPlans($chat_id, $serviceId) {
    try {
        $plans = getPlans(BOT_TOKEN);
        $unlimitedPlans = getUnlimitedPlans(BOT_TOKEN, true);
        if (count($plans) == 0 && count($unlimitedPlans) == 0) { sendMessage($chat_id, "📭 پلنی نیست."); return; }
        $msg = "🔄 انتخاب پلن برای تمدید:\n\n";
        $keyboard = ["inline_keyboard" => []];
        foreach ($plans as $plan) {
            $keyboard["inline_keyboard"][] = [["text" => "🔄 " . $plan["name"] . " - " . number_format($plan["price"]) . " تومان", "callback_data" => "confirm_renew_" . $serviceId . "_normal_" . $plan["id"]]];
        }
        foreach ($unlimitedPlans as $plan) {
            $keyboard["inline_keyboard"][] = [["text" => "♾ " . $plan["name"] . " - " . number_format($plan["price"]) . " تومان", "callback_data" => "confirm_renew_" . $serviceId . "_unlimited_" . $plan["id"]]];
        }
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) {}
}

function renewService($chat_id, $userId, $serviceId, $type, $planId, $userUsername = '') {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE id = ? AND telegram_id = ? AND bot_token = ?");
        $stmt->execute([$serviceId, $userId, BOT_TOKEN]);
        $service = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$service) { sendMessage($chat_id, "❌ سرویس یافت نشد."); return; }
        if ($type == "normal") {
            $stmt = $pdo->prepare("SELECT * FROM bot_plans WHERE id = ? AND bot_token = ?");
            $stmt->execute([$planId, BOT_TOKEN]);
            $plan = $stmt->fetch(PDO::FETCH_ASSOC);
            $size = intval($plan["size_gb"]); $groupId = 1; $isUnlimited = 0;
        } else {
            $stmt = $pdo->prepare("SELECT * FROM bot_unlimited_plans WHERE id = ? AND bot_token = ?");
            $stmt->execute([$planId, BOT_TOKEN]);
            $plan = $stmt->fetch(PDO::FETCH_ASSOC);
            $size = 0; $groupId = 2; $isUnlimited = 1;
        }
        if (!$plan) { sendMessage($chat_id, "❌ پلن یافت نشد."); return; }
        $days = intval($plan["days"]); $price = intval($plan["price"]);
        $balance = intval(getWalletBalance(BOT_TOKEN, $userId));
        if ($balance < $price) { sendMessage($chat_id, "❌ موجودی کافی نیست."); return; }
        deductWalletBalance(BOT_TOKEN, $userId, $price);
        $userInfo = callPanelAPI("GET", "/user/" . $service["username"]);
        if ($userInfo["status"] == 200) {
            $currentExpire = $userInfo["body"]["expire"] ?? time();
            if ($currentExpire < time()) $currentExpire = time();
            $newExpire = $currentExpire + ($days * 86400);
            $updateData = ["expire" => $newExpire, "note" => buildServiceNote($userId, $userUsername)];
            if ($isUnlimited) { $updateData["data_limit"] = 0; $updateData["group_ids"] = [2]; }
            else { $updateData["data_limit"] = $size * 1024 * 1024 * 1024; }
            $result = callPanelAPI("PUT", "/user/" . $service["username"], $updateData);
            if ($result["status"] == 200 || $result["status"] == 201) {
                $pdo->prepare("UPDATE bot_services SET size_gb = ?, days = ?, price = ?, is_unlimited = ?, unlimited_plan_id = ?, expire_at = FROM_UNIXTIME(?) WHERE id = ?")->execute([$size, $days, $price, $isUnlimited, $isUnlimited ? $planId : null, $newExpire, $serviceId]);
                $pdo->prepare("DELETE FROM bot_reminders WHERE bot_token = ? AND service_id = ?")->execute([BOT_TOKEN, $serviceId]);
                sendMessage($chat_id, "✅ سرویس با موفقیت تمدید شد!\n\n📦 " . ($isUnlimited ? "نامحدود" : $size . " گیگابایت") . " / ⏰ $days روز");
            } else {
                addWalletBalance(BOT_TOKEN, $userId, $price);
                sendMessage($chat_id, "❌ خطا در تمدید.");
            }
        }
    } catch (Exception $e) { dlog("renewService ERROR", $e->getMessage()); }
}

function showMyServices($chat_id, $userId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE bot_token = ? AND telegram_id = ? AND status = 'active' ORDER BY id DESC");
        $stmt->execute([BOT_TOKEN, $userId]);
        $services = $stmt->fetchAll(PDO::FETCH_ASSOC);
        if (count($services) == 0) { sendMessage($chat_id, "📭 سرویسی ندارید."); return; }
        $msg = "📦 سرویس‌های من:\n\n";
        $keyboard = ["inline_keyboard" => []];
        foreach ($services as $s) {
            $type = $s["is_unlimited"] ? "♾ نامحدود" : $s["size_gb"] . " گیگابایت";
            $msg .= "👤 <code>" . $s["username"] . "</code> - $type / " . $s["days"] . " روز\n";
            $keyboard["inline_keyboard"][] = [
                ["text" => "📋 جزئیات " . $s["username"], "callback_data" => "service_detail_" . $s["id"]],
                ["text" => "🗑 حذف", "callback_data" => "del_service_" . $s["id"]]
            ];
        }
        $keyboard["inline_keyboard"][] = [["text" => "↩️ بازگشت", "callback_data" => "menu_back"]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) {}
}

function showServiceDetail($chat_id, $serviceId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE id = ? AND bot_token = ?");
        $stmt->execute([$serviceId, BOT_TOKEN]);
        $s = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$s) { sendMessage($chat_id, "❌ سرویس یافت نشد."); return; }
        $type = $s["is_unlimited"] ? "نامحدود" : $s["size_gb"] . " گیگابایت";
        $msg = "📋 جزئیات سرویس\n\n👤 <code>" . $s["username"] . "</code>\n📦 $type\n⏰ " . $s["days"] . " روز";
        if (!empty($s["subscription_url"])) $msg .= "\n🔗 <code>" . $s["subscription_url"] . "</code>";
        $keyboard = ["inline_keyboard" => [
            [["text" => "🔄 تمدید سرویس", "callback_data" => "renew_service_" . $s["id"]]],
            [["text" => "📱 نمایش QR Code", "callback_data" => "show_qr_" . $s["id"]]],
            [["text" => "🗑 حذف سرویس", "callback_data" => "del_service_" . $s["id"]]],
            [["text" => "↩️ بازگشت", "callback_data" => "menu_services"]]
        ]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) {}
}

function deleteUserService($chat_id, $userId, $serviceId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE id = ? AND telegram_id = ? AND bot_token = ?");
        $stmt->execute([$serviceId, $userId, BOT_TOKEN]);
        $service = $stmt->fetch(PDO::FETCH_ASSOC);
        if (!$service) { sendMessage($chat_id, "❌ سرویس یافت نشد."); return; }
        if (!empty($service['username'])) callPanelAPI("DELETE", "/user/" . $service['username']);
        $pdo->prepare("DELETE FROM bot_services WHERE id = ?")->execute([$serviceId]);
        $pdo->prepare("DELETE FROM bot_reminders WHERE bot_token = ? AND service_id = ?")->execute([BOT_TOKEN, $serviceId]);
        sendMessage($chat_id, "✅ سرویس با موفقیت حذف شد.");
    } catch (Exception $e) { dlog("deleteUserService ERROR", $e->getMessage()); }
}

function showAddBalance($chat_id) {
    sendMessage($chat_id, "💰 لطفاً مبلغ مورد نظر را به تومان وارد کنید:\n\nمثال: 100000");
    $pdo = db();
    $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "add_balance_amount", ""]);
}

function processAddBalance($chat_id, $userId, $amount) {
    $amount = intval($amount);
    if ($amount < 10000) { sendMessage($chat_id, "❌ حداقل مبلغ ۱۰,۰۰۰ تومان است."); return; }
    $card = getBotSetting(BOT_TOKEN, 'card_number', '');
    $msg = "💰 افزایش موجودی\n\n💳 مبلغ: " . number_format($amount) . " تومان\n\n";
    if ($card) $msg .= "لطفاً مبلغ را به کارت زیر واریز کنید:\n\n💳 <code>$card</code>\n\n";
    $msg .= "📸 سپس عکس رسید را ارسال کنید.";
    $pdo = db();
    $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "add_balance_photo", $amount]);
    sendMessage($chat_id, $msg);
}

function showWalletManagement($chat_id) {
    sendMessage($chat_id, "💰 مدیریت کیف پول\n\nافزودن موجودی:\n<code>add:TELEGRAM_ID:AMOUNT</code>\n\nکسر موجودی:\n<code>deduct:TELEGRAM_ID:AMOUNT</code>");
    $pdo = db();
    $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_wallet_manage", ""]);
}

function startBroadcast($chat_id) {
    sendMessage($chat_id, "📨 لطفاً متن پیام همگانی را وارد کنید:");
    $pdo = db();
    $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_broadcast_msg", ""]);
}

function sendBroadcast($text) {
    try {
        $pdo = db();
        $users = $pdo->prepare("SELECT DISTINCT telegram_id FROM bot_wallets WHERE bot_token = ?");
        $users->execute([BOT_TOKEN]);
        $userList = $users->fetchAll(PDO::FETCH_ASSOC);
        $count = 0;
        foreach ($userList as $user) { sendMessage($user['telegram_id'], $text); $count++; usleep(50000); }
        return $count;
    } catch (Exception $e) { dlog("sendBroadcast ERROR", $e->getMessage()); return 0; }
}

function showFullReport($chat_id) {
    try {
        $pdo = db();
        $q = function($sql, $params = []) use ($pdo) { $stmt = $pdo->prepare($sql); $stmt->execute($params); return $stmt->fetchColumn(); };
        $totalBotUsers = $q("SELECT COUNT(*) FROM bot_wallets WHERE bot_token = ?", [BOT_TOKEN]);
        $totalBuyers = $q("SELECT COUNT(DISTINCT telegram_id) FROM bot_services WHERE bot_token = ? AND price > 0", [BOT_TOKEN]);
        $totalTrial = $q("SELECT COUNT(*) FROM bot_trials WHERE bot_token = ?", [BOT_TOKEN]);
        $totalReferrals = $q("SELECT COUNT(*) FROM bot_referral_relations WHERE bot_token = ?", [BOT_TOKEN]);
        $totalServices = $q("SELECT COUNT(*) FROM bot_services WHERE bot_token = ?", [BOT_TOKEN]);
        $activeServices = $q("SELECT COUNT(*) FROM bot_services WHERE bot_token = ? AND status = 'active'", [BOT_TOKEN]);
        $totalRevenue = $q("SELECT COALESCE(SUM(price), 0) FROM bot_services WHERE bot_token = ?", [BOT_TOKEN]);
        $todayRevenue = $q("SELECT COALESCE(SUM(price), 0) FROM bot_services WHERE bot_token = ? AND DATE(created_at) = CURDATE()", [BOT_TOKEN]);
        $totalBalance = $q("SELECT COALESCE(SUM(balance), 0) FROM bot_wallets WHERE bot_token = ?", [BOT_TOKEN]);
        $avgRating = getAverageRating(BOT_TOKEN);
        $msg = "📊 گزارش کامل ربات\n\n";
        $msg .= "👥 کاربران:\n• کل کاربران: $totalBotUsers\n• خریداران: $totalBuyers\n• تست گرفته: $totalTrial\n• دعوت شده: $totalReferrals\n\n";
        $msg .= "📦 سرویس‌ها:\n• کل: $totalServices\n• فعال: $activeServices\n\n";
        $msg .= "💵 درآمد:\n• کل: " . number_format($totalRevenue) . " تومان\n• امروز: " . number_format($todayRevenue) . " تومان\n\n";
        $msg .= "💰 موجودی کل کاربران: " . number_format($totalBalance) . " تومان\n";
        if ($avgRating['total'] > 0) $msg .= "⭐ امتیاز: " . round($avgRating['avg_rating'], 1) . " (" . $avgRating['total'] . " نظر)\n";
        sendMessage($chat_id, $msg);
    } catch (Exception $e) { dlog("showFullReport ERROR", $e->getMessage()); }
}

function showUserManagement($chat_id) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT DISTINCT telegram_id FROM bot_wallets WHERE bot_token = ? LIMIT 20");
        $stmt->execute([BOT_TOKEN]);
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
        if (count($users) == 0) { sendMessage($chat_id, "📭 کاربری نیست."); return; }
        $msg = "👥 مدیریت کاربران\n\nبرای جستجو:\n<code>search:USERNAME</code>\n\n";
        $keyboard = ["inline_keyboard" => []];
        foreach ($users as $u) {
            $keyboard["inline_keyboard"][] = [["text" => "👤 " . $u["telegram_id"], "callback_data" => "user_info_" . $u["telegram_id"]]];
        }
        $keyboard["inline_keyboard"][] = [["text" => "↩️ بازگشت", "callback_data" => "ba_back"]];
        sendMessage($chat_id, $msg, $keyboard);
        $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "user_search", ""]);
    } catch (Exception $e) {}
}

function showUserInfo($chat_id, $targetUserId) {
    try {
        $pdo = db();
        $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE bot_token = ? AND telegram_id = ? ORDER BY id DESC");
        $stmt->execute([BOT_TOKEN, $targetUserId]);
        $services = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $balance = getWalletBalance(BOT_TOKEN, $targetUserId);
        $refCount = getReferralCount(BOT_TOKEN, $targetUserId);
        $vip = getUserAnyVipService(BOT_TOKEN, $targetUserId);
        $vipText = $vip ? "✅ " . $vip['panel_username'] : "❌ ندارد";
        $msg = "👤 اطلاعات کاربر\n\n🆔 <code>$targetUserId</code>\n💰 موجودی: " . number_format($balance) . " تومان\n📦 سرویس‌ها: " . count($services) . "\n💎 سرویس ویژه: $vipText\n🎁 دعوت‌شده: $refCount";
        sendMessage($chat_id, $msg);
    } catch (Exception $e) {}
}

function showReviews($chat_id) {
    try {
        $reviews = getReviews(BOT_TOKEN, 10);
        $avg = getAverageRating(BOT_TOKEN);
        if (count($reviews) == 0) { sendMessage($chat_id, "📭 نظری ثبت نشده است."); return; }
        $msg = "⭐ نظرات کاربران\n\n📊 میانگین: " . round($avg['avg_rating'], 1) . " از " . $avg['total'] . " نظر\n\n";
        foreach ($reviews as $r) {
            $msg .= str_repeat("⭐", intval($r["rating"])) . "\n";
            if (!empty($r["comment"])) $msg .= "💬 " . $r["comment"] . "\n";
            $msg .= "\n";
        }
        sendMessage($chat_id, $msg);
    } catch (Exception $e) {}
}

// ============ نمایش لیست و حذف کد تخفیف ============
function showDiscountCodesList($chat_id) {
    try {
        $codes = getAllDiscountCodes(BOT_TOKEN);
        if (count($codes) == 0) {
            sendMessage($chat_id, "📭 هیچ کد تخفیفی ثبت نشده است.");
            return;
        }
        $msg = "🏷 لیست کدهای تخفیف\n\n";
        $keyboard = ["inline_keyboard" => []];
        foreach ($codes as $c) {
            $remaining = intval($c["max_uses"]) - intval($c["used"]);
            $msg .= "🔹 <code>" . $c["code"] . "</code>\n";
            $msg .= "   💯 درصد: " . $c["percent"] . "%\n";
            $msg .= "   📊 استفاده: " . $c["used"] . "/" . $c["max_uses"] . " (باقی: " . $remaining . ")\n\n";
            $keyboard["inline_keyboard"][] = [[
                "text" => "🗑 حذف " . $c["code"],
                "callback_data" => "del_discount_" . $c["id"]
            ]];
        }
        $keyboard["inline_keyboard"][] = [["text" => "↩️ بازگشت", "callback_data" => "ba_back"]];
        sendMessage($chat_id, $msg, $keyboard);
    } catch (Exception $e) { dlog("showDiscountCodesList ERROR", $e->getMessage()); }
}

try { ensureVipTable(); } catch (Exception $e) { dlog("ensureVipTable FATAL", $e->getMessage()); }

try {
    $rawInput = file_get_contents("php://input");
    dlog("=== UPDATE RECEIVED ===", ["size" => strlen($rawInput)]);

    if (isset($_GET['cron']) && $_GET['cron'] === 'vip_sync') {
        $count = syncAllVipServices(BOT_TOKEN);
        echo "OK - Synced: $count";
        exit;
    }

    if (isset($_GET['cron']) && $_GET['cron'] === 'cleanup') {
        $count = cleanupExpiredServices(BOT_TOKEN, 2);
        echo "OK - Cleaned: $count";
        exit;
    }

    // اجرای خودکار پاکسازی هر ۶ ساعت یک‌بار
    try {
        $cleanupFlag = sys_get_temp_dir() . '/bot_cleanup_' . md5(BOT_TOKEN) . '.lock';
        $lastCleanup = file_exists($cleanupFlag) ? intval(file_get_contents($cleanupFlag)) : 0;
        if (time() - $lastCleanup > 21600) {
            @file_put_contents($cleanupFlag, time());
            cleanupExpiredServices(BOT_TOKEN, 2);
        }
    } catch (Exception $e) {}

    $update = json_decode($rawInput, true);
    if ($update === null) { dlog("Bad JSON", $rawInput); http_response_code(400); echo "Bad JSON"; exit; }

    $pdo = db();

    if (isset($update["message"])) {
        $chat_id = $update["message"]["chat"]["id"];
        $text = $update["message"]["text"] ?? "";
        $userId = $update["message"]["from"]["id"];
        $userUsername = $update["message"]["from"]["username"] ?? "";
        $firstName = $update["message"]["from"]["first_name"] ?? "";
        $displayName = !empty($userUsername) ? ('@' . $userUsername) : $firstName;
        dlog("MESSAGE", ["user_id" => $userId, "text" => $text]);

        if (strpos($text, "/start ") === 0) {
            $refCode = trim(str_replace("/start ", "", $text));
            if (!empty($refCode) && strpos($refCode, "REF") === 0) {
                $referrerId = getReferrerByCode(BOT_TOKEN, $refCode);
                if ($referrerId && $referrerId != $userId) {
                    if (!hasBeenReferred(BOT_TOKEN, $userId)) {
                        addReferralRelation(BOT_TOKEN, $referrerId, $userId);
                        giveReferralReward(BOT_TOKEN, $referrerId, $userId);
                        sendMessage($userId, "🎉 شما با لینک دعوت عضو شدید!");
                    }
                }
            }
        }

        $checkUser = $pdo->prepare("SELECT COUNT(*) FROM bot_wallets WHERE bot_token = ? AND telegram_id = ?");
        $checkUser->execute([BOT_TOKEN, $userId]);
        if ($checkUser->fetchColumn() == 0) addWalletBalance(BOT_TOKEN, $userId, 0, $displayName);
        getUserRefCode(BOT_TOKEN, $userId);

        if (!checkBotChannel(BOT_TOKEN, $userId) && !isBotAdmin(BOT_TOKEN, $userId)) {
            showChannelJoinMessage($chat_id);
            http_response_code(200); echo "OK"; exit;
        }

        if (isset($update["message"]["photo"])) {
            try {
                $photoId = end($update["message"]["photo"])["file_id"];
                $admins = getBotAdmins(BOT_TOKEN);
                $stmt = $pdo->prepare("SELECT state, temp_data FROM bot_user_states WHERE chat_id = ?");
                $stmt->execute([$chat_id]);
                $state = $stmt->fetch(PDO::FETCH_ASSOC);
                $caption = "🔔 رسید پرداخت\n\n🆔: <code>$userId</code>\n👤: $displayName";
                $paymentType = "unknown";
                $paymentData = "";
                if ($state && $state["state"] == "add_balance_photo") {
                    $caption = "💰 درخواست افزایش موجودی\n\n🆔: <code>$userId</code>\n👤: $displayName\n💳: " . number_format(intval($state["temp_data"])) . " تومان";
                    $paymentType = "balance";
                    $paymentData = $state["temp_data"];
                } else {
                    $stmt2 = $pdo->prepare("SELECT * FROM orders WHERE chat_id = ? AND status = 'pending' ORDER BY id DESC LIMIT 1");
                    $stmt2->execute([$chat_id]);
                    $order = $stmt2->fetch(PDO::FETCH_ASSOC);
                    if ($order) {
                        $planType = $order['plan_type'] ?? 'normal';
                        $planId = intval($order['plan_id']);
                        $planName = "نامشخص"; $planSize = ""; $planDays = ""; $typeText = "";
                        if ($planType == "unlimited") {
                            $stmtPlan = $pdo->prepare("SELECT * FROM bot_unlimited_plans WHERE id = ? AND bot_token = ?");
                            $stmtPlan->execute([$planId, BOT_TOKEN]);
                            $planData = $stmtPlan->fetch(PDO::FETCH_ASSOC);
                            if ($planData) { $planName = $planData["name"]; $planSize = "نامحدود"; $planDays = $planData["days"] . " روز"; }
                            $typeText = "♾ نامحدود";
                        } else {
                            $stmtPlan = $pdo->prepare("SELECT * FROM bot_plans WHERE id = ? AND bot_token = ?");
                            $stmtPlan->execute([$planId, BOT_TOKEN]);
                            $planData = $stmtPlan->fetch(PDO::FETCH_ASSOC);
                            if ($planData) { $planName = $planData["name"]; $planSize = $planData["size_gb"] . " گیگابایت"; $planDays = $planData["days"] . " روز"; }
                            $typeText = "📦 حجمی";
                        }
                        $caption = "🛒 درخواست خرید سرویس\n\n🆔: <code>$userId</code>\n👤: $displayName\n━━━━━━━━━━\n📌 پلن: $planName\n📊 نوع: $typeText\n";
                        if (!empty($planSize)) $caption .= "📦 حجم: $planSize\n";
                        if (!empty($planDays)) $caption .= "⏰ مدت: $planDays\n";
                        $caption .= "━━━━━━━━━━\n💰 مبلغ: " . number_format($order['price']) . " تومان\n📋 کد سفارش: <code>" . $order['order_id'] . "</code>";
                        $paymentType = "buy";
                        $paymentData = $order['order_id'];
                        $pdo->prepare("UPDATE orders SET photo_id = ? WHERE id = ?")->execute([$photoId, $order['id']]);
                    }
                }
                foreach ($admins as $admin) {
                    $keyboard = ["inline_keyboard" => [[
                        ["text" => "✅ تایید پرداخت", "callback_data" => "approve_payment_" . $chat_id . "_" . $paymentType . "_" . $paymentData],
                        ["text" => "❌ رد پرداخت", "callback_data" => "reject_payment_" . $chat_id]
                    ]]];
                    $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/sendPhoto";
                    $ch = curl_init($url);
                    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                    curl_setopt($ch, CURLOPT_POST, true);
                    curl_setopt($ch, CURLOPT_POSTFIELDS, ['chat_id' => $admin['telegram_id'], 'photo' => $photoId, 'caption' => $caption, 'parse_mode' => 'HTML', 'reply_markup' => json_encode($keyboard, JSON_UNESCAPED_UNICODE)]);
                    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                    curl_exec($ch);
                    curl_close($ch);
                }
                sendMessage($chat_id, "✅ رسید ارسال شد.");
            } catch (Exception $e) { dlog("PHOTO HANDLING ERROR", $e->getMessage()); }
            http_response_code(200); echo "OK"; exit;
        }

        $stmt = $pdo->prepare("SELECT state, temp_data FROM bot_user_states WHERE chat_id = ?");
        $stmt->execute([$chat_id]);
        $state = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($state && $state["state"] == "add_balance_amount") {
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            processAddBalance($chat_id, $userId, $text);
        }
        elseif ($state && $state["state"] == "waiting_review_comment") {
            $parts = explode("|", $state["temp_data"]);
            addReview(BOT_TOKEN, $userId, $userUsername ?: $firstName, $parts[1], intval($parts[0]), $text);
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            sendMessage($chat_id, "🙏 از نظر شما سپاسگزاریم!");
        }
        elseif ($state && $state["state"] == "ba_wallet_manage") {
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            if (strpos($text, "add:") === 0) { $parts = explode(":", $text); addWalletBalance(BOT_TOKEN, $parts[1], intval($parts[2])); sendMessage($chat_id, "✅ اضافه شد."); }
            elseif (strpos($text, "deduct:") === 0) { $parts = explode(":", $text); deductWalletBalance(BOT_TOKEN, $parts[1], intval($parts[2])); sendMessage($chat_id, "✅ کسر شد."); }
        }
        elseif ($state && $state["state"] == "apply_discount_input") {
            $parts = explode("|", $state["temp_data"]);
            $planId = intval($parts[0]);
            $planType = $parts[1];
            $code = trim($text);
            $discount = getDiscountCode(BOT_TOKEN, $code);
            if (!$discount) { $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "❌ کد تخفیف نامعتبر است."); }
            elseif (intval($discount["used"]) >= intval($discount["max_uses"])) { $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "❌ ظرفیت پر شده."); }
            elseif (hasUsedDiscount(BOT_TOKEN, $userId, $code)) { $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "❌ قبلاً استفاده کردید."); }
            else {
                $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "discount_applied", $planId . "|" . $planType . "|" . $code]);
                sendMessage($chat_id, "✅ کد تخفیف اعمال شد! " . $discount['percent'] . "%");
                showInvoice($chat_id, $userId, $planId, $planType);
            }
        }
        elseif ($state && $state["state"] == "user_search") {
            if (strpos($text, "search:") === 0) {
                $searchTerm = str_replace("search:", "", $text);
                $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
                $stmt = $pdo->prepare("SELECT DISTINCT telegram_id FROM bot_wallets WHERE bot_token = ? AND (telegram_id LIKE ? OR username LIKE ?) LIMIT 10");
                $stmt->execute([BOT_TOKEN, "%$searchTerm%", "%$searchTerm%"]);
                $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
                if (count($results) == 0) sendMessage($chat_id, "📭 یافت نشد.");
                else { $keyboard = ["inline_keyboard" => []]; foreach ($results as $r) $keyboard["inline_keyboard"][] = [["text" => "👤 " . $r["telegram_id"], "callback_data" => "user_info_" . $r["telegram_id"]]]; sendMessage($chat_id, "نتایج:", $keyboard); }
            }
        }
        elseif ($state && $state["state"] == "vip_price_input") {
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            $price = intval($text);
            if ($price >= 1) { updateBotSetting(BOT_TOKEN, 'vip_price_per_gb', $price); sendMessage($chat_id, "✅ تنظیم شد."); }
            showVipAdminPanel($chat_id);
        }
        elseif ($state && $state["state"] == "vip_min_input") {
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            $min = intval($text);
            if ($min >= 0) { updateBotSetting(BOT_TOKEN, 'vip_min_balance', $min); sendMessage($chat_id, "✅ تنظیم شد."); }
            showVipAdminPanel($chat_id);
        }
        elseif ($state && $state["state"] == "vip_days_input") {
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            $days = intval($text);
            if ($days >= 1) { updateBotSetting(BOT_TOKEN, 'vip_days', $days); sendMessage($chat_id, "✅ تنظیم شد."); }
            showVipAdminPanel($chat_id);
        }
        elseif ($state && $state["state"] == "ba_ref_balance_amount") {
            updateBotSetting(BOT_TOKEN, 'ref_reward_type', 'balance');
            updateBotSetting(BOT_TOKEN, 'ref_reward_amount', intval($text));
            $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_ref_new_share", ""]);
            sendMessage($chat_id, "🎁 سهم کاربر دعوت‌شده (درصد):");
        }
        elseif ($state && $state["state"] == "ba_ref_service_amount") {
            updateBotSetting(BOT_TOKEN, 'ref_reward_type', 'service');
            updateBotSetting(BOT_TOKEN, 'ref_reward_amount', intval($text));
            $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_ref_new_share", ""]);
            sendMessage($chat_id, "🎁 سهم کاربر دعوت‌شده (درصد):");
        }
        elseif ($state && $state["state"] == "ba_ref_new_share") {
            updateBotSetting(BOT_TOKEN, 'ref_new_user_share', intval($text));
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            sendMessage($chat_id, "✅ تنظیم شد.");
        }
        elseif ($state && $state["state"] == "ba_plan_name") { $pdo->prepare("UPDATE bot_user_states SET state = ?, temp_data = ? WHERE chat_id = ?")->execute(["ba_plan_size", $text, $chat_id]); sendMessage($chat_id, "📦 حجم (گیگابایت):"); }
        elseif ($state && $state["state"] == "ba_plan_size") { $pdo->prepare("UPDATE bot_user_states SET state = ?, temp_data = ? WHERE chat_id = ?")->execute(["ba_plan_days", $state["temp_data"] . "|" . $text, $chat_id]); sendMessage($chat_id, "⏰ مدت (روز):"); }
        elseif ($state && $state["state"] == "ba_plan_days") { $pdo->prepare("UPDATE bot_user_states SET state = ?, temp_data = ? WHERE chat_id = ?")->execute(["ba_plan_price", $state["temp_data"] . "|" . $text, $chat_id]); sendMessage($chat_id, "💰 قیمت (تومان):"); }
        elseif ($state && $state["state"] == "ba_plan_price") {
            $parts = explode("|", $state["temp_data"]);
            $pdo->prepare("INSERT INTO bot_plans (bot_token, name, size_gb, days, price) VALUES (?, ?, ?, ?, ?)")->execute([BOT_TOKEN, $parts[0], intval($parts[1]), intval($parts[2]), intval($text)]);
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            sendMessage($chat_id, "✅ پلن جدید اضافه شد!");
        }
        elseif ($state && $state["state"] == "ba_unlimited_name") { $pdo->prepare("UPDATE bot_user_states SET state = ?, temp_data = ? WHERE chat_id = ?")->execute(["ba_unlimited_days", $text, $chat_id]); sendMessage($chat_id, "⏰ مدت (روز):"); }
        elseif ($state && $state["state"] == "ba_unlimited_days") { $pdo->prepare("UPDATE bot_user_states SET state = ?, temp_data = ? WHERE chat_id = ?")->execute(["ba_unlimited_price", $state["temp_data"] . "|" . $text, $chat_id]); sendMessage($chat_id, "💰 قیمت (تومان):"); }
        elseif ($state && $state["state"] == "ba_unlimited_price") {
            $parts = explode("|", $state["temp_data"]);
            $pdo->prepare("INSERT INTO bot_unlimited_plans (bot_token, name, days, price, active) VALUES (?, ?, ?, ?, 1)")->execute([BOT_TOKEN, $parts[0], intval($parts[1]), intval($text)]);
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            sendMessage($chat_id, "✅ پلن نامحدود اضافه شد!");
        }
        elseif ($state && $state["state"] == "ba_set_card") { updateBotSetting(BOT_TOKEN, 'card_number', $text); $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "✅ شماره کارت تنظیم شد."); }
        elseif ($state && $state["state"] == "ba_set_prefix") { updateBotSetting(BOT_TOKEN, 'prefix', $text); $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "✅ پیشوند تنظیم شد."); }
        elseif ($state && $state["state"] == "ba_trial_limit_input") { $mb = intval($text); if ($mb >= 10 && $mb <= 500) { updateBotSetting(BOT_TOKEN, 'trial_limit', $mb * 1048576); sendMessage($chat_id, "✅ حجم تست تنظیم شد."); } else sendMessage($chat_id, "❌ بین ۱۰ تا ۵۰۰ مگابایت"); $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); }
        elseif ($state && $state["state"] == "ba_trial_days_input") { updateBotSetting(BOT_TOKEN, 'trial_days', intval($text)); $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "✅ مدت تست تنظیم شد."); }
        elseif ($state && $state["state"] == "ba_channel_input") { updateBotSetting(BOT_TOKEN, 'force_channel', $text); $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "✅ کانال تنظیم شد."); }
        elseif ($state && $state["state"] == "ba_support_input") { updateBotSetting(BOT_TOKEN, 'support_id', trim($text)); $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "✅ پشتیبانی تنظیم شد."); }
        elseif ($state && $state["state"] == "ba_discount_code") { $pdo->prepare("UPDATE bot_user_states SET state = ?, temp_data = ? WHERE chat_id = ?")->execute(["ba_discount_percent", $text, $chat_id]); sendMessage($chat_id, "🏷 درصد تخفیف:"); }
        elseif ($state && $state["state"] == "ba_discount_percent") { $pdo->prepare("UPDATE bot_user_states SET state = ?, temp_data = ? WHERE chat_id = ?")->execute(["ba_discount_uses", $state["temp_data"] . "|" . $text, $chat_id]); sendMessage($chat_id, "🔢 حداکثر تعداد استفاده:"); }
        elseif ($state && $state["state"] == "ba_discount_uses") {
            $parts = explode("|", $state["temp_data"]);
            createDiscountCode(BOT_TOKEN, $parts[0], intval($parts[1]), intval($text));
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            sendMessage($chat_id, "✅ کد تخفیف ساخته شد!");
        }
        elseif ($state && $state["state"] == "ba_broadcast_msg") {
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            $count = sendBroadcast($text);
            sendMessage($chat_id, "✅ پیام به $count نفر ارسال شد.");
        }
        elseif ($state && $state["state"] == "ba_add_admin_id") {
            $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]);
            addBotAdmin(BOT_TOKEN, $text, $text);
            sendMessage($chat_id, "✅ ادمین اضافه شد.");
        }
        else {
            if ($text == "/start" || $text == "↩️ بازگشت") showBotUserMenu($chat_id, $userId);
            elseif ($text == "/admin" || $text == "👤 پنل ادمین") { if (isBotAdmin(BOT_TOKEN, $userId)) showBotAdminPanel($chat_id); else sendMessage($chat_id, "❌ دسترسی ندارید."); }
            elseif ($text == "🎁 تست رایگان") startTrial($chat_id, $userId, $displayName);
            elseif ($text == "🛒 خرید سرویس") showBuyPlans($chat_id, $userId);
            elseif ($text == "🔄 تمدید سرویس") showRenewServices($chat_id, $userId);
            elseif ($text == "📦 سرویس‌های من") showMyServices($chat_id, $userId);
            elseif ($text == "👤 حساب کاربری") showAccount($chat_id, $userId);
            elseif ($text == "💰 افزایش موجودی") showAddBalance($chat_id);
            elseif ($text == "🎧 پشتیبانی") showSupport($chat_id);
            elseif ($text == "📚 راهنمای اتصال") showConnectionGuide($chat_id);
        }
    }

    if (isset($update["callback_query"])) {
        $callback = $update["callback_query"];
        $chat_id = $callback["message"]["chat"]["id"];
        $data = $callback["data"];
        $userId = $callback["from"]["id"];
        $userUsername = $callback["from"]["username"] ?? "";
        $firstName = $callback["from"]["first_name"] ?? "";
        $displayName = !empty($userUsername) ? ('@' . $userUsername) : $firstName;
        dlog("CALLBACK", ["user_id" => $userId, "data" => $data]);
        $ch = curl_init("https://api.telegram.org/bot" . BOT_TOKEN . "/answerCallbackQuery");
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, ["callback_query_id" => $callback["id"]]);
        curl_exec($ch);
        curl_close($ch);

        if ($data == "check_membership") {
            if (checkBotChannel(BOT_TOKEN, $userId)) { sendMessage($chat_id, "✅ عضویت شما تایید شد!"); showBotUserMenu($chat_id, $userId); }
            else { sendMessage($chat_id, "❌ هنوز عضو نشده‌اید."); showChannelJoinMessage($chat_id); }
        }
        elseif ($data == "menu_back") showBotUserMenu($chat_id, $userId);
        elseif ($data == "menu_buy") showBuyPlans($chat_id, $userId);
        elseif ($data == "menu_renew") showRenewServices($chat_id, $userId);
        elseif ($data == "menu_trial") startTrial($chat_id, $userId, $displayName);
        elseif ($data == "menu_services") showMyServices($chat_id, $userId);
        elseif ($data == "menu_account") showAccount($chat_id, $userId);
        elseif ($data == "menu_balance") showAddBalance($chat_id);
        elseif ($data == "menu_ref") showReferral($chat_id, $userId);
        elseif ($data == "menu_support") showSupport($chat_id);
        elseif ($data == "menu_guide") showConnectionGuide($chat_id);
        elseif ($data == "menu_admin") { if (isBotAdmin(BOT_TOKEN, $userId)) showBotAdminPanel($chat_id); }
        elseif ($data == "ba_vip_panel") { if (isBotAdmin(BOT_TOKEN, $userId)) showVipAdminPanel($chat_id); else sendMessage($chat_id, "❌ دسترسی ندارید."); }
        elseif ($data == "menu_vip") { if (!isVipActive(BOT_TOKEN)) sendMessage($chat_id, "❌ غیرفعال."); else showVipService($chat_id, $userId); }
        elseif ($data == "vip_buy") { if (isVipActive(BOT_TOKEN)) { createVipService($chat_id, $userId, $displayName); showVipService($chat_id, $userId); } }
        elseif ($data == "vip_refresh") { $vip = getUserVipService(BOT_TOKEN, $userId); if ($vip) syncVipUsage(BOT_TOKEN, $vip); showVipService($chat_id, $userId); }
        elseif ($data == "vip_qr") { $vip = getUserAnyVipService(BOT_TOKEN, $userId); if ($vip && !empty($vip['subscription_url'])) sendPhoto($chat_id, generateQR($vip['subscription_url']), "📱 QR Code"); }
        elseif ($data == "vip_delete") {
            $keyboard = ["inline_keyboard" => [[["text" => "✅ بله، حذف کن", "callback_data" => "vip_delete_confirm"], ["text" => "❌ انصراف", "callback_data" => "menu_vip"]]]];
            sendMessage($chat_id, "⚠️ آیا مطمئنید می‌خواهید سرویس ویژه را حذف کنید؟", $keyboard);
        }
        elseif ($data == "vip_delete_confirm") deleteVipService($chat_id, $userId);
        elseif ($data == "vip_reactivate") { reactivateVipService($chat_id, $userId); showVipService($chat_id, $userId); }
        elseif ($data == "vip_toggle") { if (isBotAdmin(BOT_TOKEN, $userId)) { $current = isVipActive(BOT_TOKEN); updateBotSetting(BOT_TOKEN, 'vip_active', $current ? 0 : 1); sendMessage($chat_id, $current ? "🔴 خاموش شد." : "🟢 روشن شد."); showVipAdminPanel($chat_id); } }
        elseif ($data == "vip_set_price") { if (isBotAdmin(BOT_TOKEN, $userId)) { $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "vip_price_input", ""]); sendMessage($chat_id, "💰 قیمت هر گیگ را به تومان وارد کنید:"); } }
        elseif ($data == "vip_set_min") { if (isBotAdmin(BOT_TOKEN, $userId)) { $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "vip_min_input", ""]); sendMessage($chat_id, "💵 حداقل موجودی را به تومان وارد کنید:"); } }
        elseif ($data == "vip_set_days") { if (isBotAdmin(BOT_TOKEN, $userId)) { $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "vip_days_input", ""]); sendMessage($chat_id, "⏰ مدت اعتبار را به روز وارد کنید:"); } }
        elseif ($data == "vip_sync_all") { if (isBotAdmin(BOT_TOKEN, $userId)) { $count = syncAllVipServices(BOT_TOKEN); sendMessage($chat_id, "✅ $count سرویس بروزرسانی شد."); showVipAdminPanel($chat_id); } }
        elseif ($data == "vip_list") { if (isBotAdmin(BOT_TOKEN, $userId)) showVipServicesList($chat_id); }
        elseif (strpos($data, "del_service_confirm_") === 0) { $serviceId = intval(str_replace("del_service_confirm_", "", $data)); deleteUserService($chat_id, $userId, $serviceId); }
        elseif (strpos($data, "del_service_") === 0) {
            $serviceId = intval(str_replace("del_service_", "", $data));
            $keyboard = ["inline_keyboard" => [[["text" => "✅ بله، حذف کن", "callback_data" => "del_service_confirm_" . $serviceId], ["text" => "❌ انصراف", "callback_data" => "menu_services"]]]];
            sendMessage($chat_id, "⚠️ آیا مطمئنید می‌خواهید این سرویس را حذف کنید؟\nغیرقابل بازگشت!", $keyboard);
        }
        elseif (strpos($data, "review_skip") === 0) { $pdo->prepare("DELETE FROM bot_user_states WHERE chat_id = ?")->execute([$chat_id]); sendMessage($chat_id, "باشه، بعداً نظر بدهید."); }
        elseif (strpos($data, "review_") === 0) {
            $parts = explode("_", $data);
            $rating = intval($parts[1]);
            $serviceUsername = $parts[2] ?? "";
            $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "waiting_review_comment", $rating . "|" . $serviceUsername]);
            sendMessage($chat_id, "💬 لطفاً نظر خود را بنویسید (یا 'ندارم'):");
        }
        elseif ($data == "ba_ref_reward") {
            $refRewardType = getBotSetting(BOT_TOKEN, 'ref_reward_type', 'balance');
            $refRewardAmount = getBotSetting(BOT_TOKEN, 'ref_reward_amount', '10000');
            $refNewShare = getBotSetting(BOT_TOKEN, 'ref_new_user_share', '50');
            $typeText = ($refRewardType == 'balance') ? 'موجودی' : 'کانفیگ';
            $amountText = ($refRewardType == 'balance') ? number_format($refRewardAmount) . ' تومان' : $refRewardAmount . ' گیگابایت';
            $msg = "🎁 تنظیم پاداش دعوت\n\n🎁 نوع: $typeText\n💰 مقدار: $amountText\n📊 سهم کاربر جدید: $refNewShare%";
            $keyboard = ["inline_keyboard" => [[["text" => "💰 پاداش موجودی", "callback_data" => "ba_ref_balance"]], [["text" => "📦 پاداش کانفیگ", "callback_data" => "ba_ref_service"]], [["text" => "↩️ بازگشت", "callback_data" => "ba_back"]]]];
            sendMessage($chat_id, $msg, $keyboard);
        }
        elseif ($data == "ba_ref_balance") { $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_ref_balance_amount", ""]); sendMessage($chat_id, "💰 مبلغ پاداش (تومان):"); }
        elseif ($data == "ba_ref_service") { $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_ref_service_amount", ""]); sendMessage($chat_id, "📦 حجم پاداش (گیگابایت):"); }
        elseif (strpos($data, "approve_payment_") === 0) {
            $cleanData = str_replace("approve_payment_", "", $data);
            $parts = explode("_", $cleanData, 3);
            $targetChatId = $parts[0];
            $paymentType = $parts[1] ?? "";
            $paymentData = $parts[2] ?? "";
            if ($paymentType == "balance") {
                $amount = intval($paymentData);
                addWalletBalance(BOT_TOKEN, $targetChatId, $amount);
                sendMessage($chat_id, "✅ تایید شد.");
                sendMessage($targetChatId, "✅ پرداخت تایید شد!\n💰 " . number_format($amount) . " تومان به کیف پول شما اضافه شد.");
            } elseif ($paymentType == "buy") {
                $orderId = $paymentData;
                $stmt = $pdo->prepare("SELECT * FROM orders WHERE order_id = ?");
                $stmt->execute([$orderId]);
                $order = $stmt->fetch(PDO::FETCH_ASSOC);
                if ($order) {
                    $planId = intval($order['plan_id']);
                    $planType = $order['plan_type'] ?? 'normal';
                    if ($planType == "unlimited") {
                        $stmt = $pdo->prepare("SELECT * FROM bot_unlimited_plans WHERE id = ?");
                        $stmt->execute([$planId]);
                        $plan = $stmt->fetch(PDO::FETCH_ASSOC);
                        $size = 0; $groupId = 2; $isUnlimited = 1;
                    } else {
                        $stmt = $pdo->prepare("SELECT * FROM bot_plans WHERE id = ?");
                        $stmt->execute([$planId]);
                        $plan = $stmt->fetch(PDO::FETCH_ASSOC);
                        $size = intval($plan["size_gb"] ?? 0); $groupId = 1; $isUnlimited = 0;
                    }
                    if ($plan) {
                        $prefix = getBotSetting(BOT_TOKEN, 'prefix', PREFIX);
                        $username = $prefix . "_" . substr(md5(time() . $targetChatId), 0, 8);
                        $days = intval($plan["days"]);
                        $expireTime = time() + ($days * 86400);
                        // Note برای خریدار
                        $buyerUsername = '';
                        try {
                            $stmtB = $pdo->prepare("SELECT username FROM bot_wallets WHERE bot_token = ? AND telegram_id = ?");
                            $stmtB->execute([BOT_TOKEN, $targetChatId]);
                            $buyerUsername = $stmtB->fetchColumn() ?: '';
                        } catch (Exception $e) {}
                        $result = callPanelAPI("POST", "/user", ["username" => $username, "status" => "active", "expire" => $expireTime, "group_ids" => [$groupId], "data_limit" => $isUnlimited ? 0 : ($size * 1024 * 1024 * 1024), "note" => buildServiceNote($targetChatId, $buyerUsername)]);
                        if ($result["status"] == 200 || $result["status"] == 201) {
                            $subUrl = $result["body"]["subscription_url"] ?? "";
                            if ($subUrl && strpos($subUrl, "http") !== 0) $subUrl = SUB_BASE_URL . $subUrl;
                            $stmt = $pdo->prepare("INSERT INTO bot_services (bot_token, telegram_id, username, plan_id, size_gb, days, price, subscription_url, is_unlimited, unlimited_plan_id, expire_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FROM_UNIXTIME(?))");
                            $stmt->execute([BOT_TOKEN, $targetChatId, $username, $planId, $size, $days, $order['price'], $subUrl, $isUnlimited, $isUnlimited ? $planId : null, $expireTime]);
                            $pdo->prepare("UPDATE orders SET status = 'confirmed' WHERE order_id = ?")->execute([$orderId]);
                            if (!empty($order['discount_code'])) markDiscountUsed(BOT_TOKEN, $targetChatId, $order['discount_code']);
                            sendMessage($chat_id, "✅ خرید تایید شد!");
                            $msg = "✅ خرید شما تایید شد!\n\n👤 <code>$username</code>\n📌 پلن: " . $plan["name"] . "\n";
                            $msg .= $isUnlimited ? "♾ نامحدود / ⏰ $days روز\n" : "📦 $size گیگابایت / ⏰ $days روز\n";
                            $msg .= "💰 پرداخت: " . number_format($order['price']) . " تومان\n";
                            if ($subUrl) { $msg .= "🔗 <code>$subUrl</code>"; sendPhoto($targetChatId, generateQR($subUrl), "📱 QR Code"); }
                            sendMessage($targetChatId, $msg);
                            requestReview($targetChatId, $username);
                        } else sendMessage($chat_id, "❌ خطا در ساخت سرویس.");
                    }
                }
            }
            $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/editMessageReplyMarkup";
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, ['chat_id' => $chat_id, 'message_id' => $callback["message"]["message_id"], 'reply_markup' => json_encode(["inline_keyboard" => []])]);
            curl_exec($ch);
            curl_close($ch);
        }
        elseif (strpos($data, "reject_payment_") === 0) {
            $targetChatId = str_replace("reject_payment_", "", $data);
            sendMessage($chat_id, "❌ رد شد.");
            sendMessage($targetChatId, "❌ پرداخت شما رد شد.");
            $url = "https://api.telegram.org/bot" . BOT_TOKEN . "/editMessageReplyMarkup";
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, ['chat_id' => $chat_id, 'message_id' => $callback["message"]["message_id"], 'reply_markup' => json_encode(["inline_keyboard" => []])]);
            curl_exec($ch);
            curl_close($ch);
        }
        elseif (strpos($data, "buy_plan_") === 0) showInvoice($chat_id, $userId, str_replace("buy_plan_", "", $data), "normal");
        elseif (strpos($data, "buy_unlimited_") === 0) showInvoice($chat_id, $userId, str_replace("buy_unlimited_", "", $data), "unlimited");
        elseif (strpos($data, "pay_wallet_") === 0) { $parts = explode("_", str_replace("pay_wallet_", "", $data)); payFromWallet($chat_id, $userId, $parts[0], intval($parts[1]), $displayName); }
        elseif (strpos($data, "apply_discount_") === 0) { $parts = explode("_", str_replace("apply_discount_", "", $data)); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "apply_discount_input", intval($parts[1]) . "|" . $parts[0]]); sendMessage($chat_id, "🏷 لطفاً کد تخفیف خود را وارد کنید:"); }
        elseif (strpos($data, "renew_service_") === 0) showRenewPlans($chat_id, str_replace("renew_service_", "", $data));
        elseif (strpos($data, "confirm_renew_") === 0) { $parts = explode("_", str_replace("confirm_renew_", "", $data)); renewService($chat_id, $userId, $parts[0], $parts[1], $parts[2], $displayName); }
        elseif (strpos($data, "service_detail_") === 0) showServiceDetail($chat_id, str_replace("service_detail_", "", $data));
        elseif (strpos($data, "show_qr_") === 0) { $pdo = db(); $stmt = $pdo->prepare("SELECT * FROM bot_services WHERE id = ? AND bot_token = ?"); $stmt->execute([str_replace("show_qr_", "", $data), BOT_TOKEN]); $s = $stmt->fetch(PDO::FETCH_ASSOC); if ($s && !empty($s["subscription_url"])) sendPhoto($chat_id, generateQR($s["subscription_url"]), "📱 QR Code - " . $s["username"]); }
        elseif ($data == "ba_card") { sendMessage($chat_id, "💳 لطفاً شماره کارت جدید را وارد کنید:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_set_card", ""]); }
        elseif ($data == "ba_prefix") { sendMessage($chat_id, "🔤 لطفاً پیشوند جدید را وارد کنید:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_set_prefix", ""]); }
        elseif ($data == "ba_trial_limit") { sendMessage($chat_id, "📦 حجم تست را به مگابایت وارد کنید (۱۰-۵۰۰):"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_trial_limit_input", ""]); }
        elseif ($data == "ba_trial_days") { sendMessage($chat_id, "⏰ مدت تست را به روز وارد کنید:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_trial_days_input", ""]); }
        elseif ($data == "ba_trial_reset") { resetAllTrials(BOT_TOKEN); sendMessage($chat_id, "✅ تست همه کاربران ریست شد."); }
        elseif ($data == "ba_add_plan") { sendMessage($chat_id, "📌 نام پلن جدید:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_plan_name", ""]); }
        elseif ($data == "ba_delete_plan") {
            $plans = getPlans(BOT_TOKEN);
            if (count($plans) == 0) sendMessage($chat_id, "📭 پلنی نیست.");
            else { $keyboard = ["inline_keyboard" => []]; foreach ($plans as $plan) $keyboard["inline_keyboard"][] = [["text" => "🗑 " . $plan["name"], "callback_data" => "del_plan_" . $plan["id"]]]; sendMessage($chat_id, "🗑 پلن برای حذف:", $keyboard); }
        }
        elseif (strpos($data, "del_plan_") === 0) { $pdo->prepare("DELETE FROM bot_plans WHERE id = ? AND bot_token = ?")->execute([str_replace("del_plan_", "", $data), BOT_TOKEN]); sendMessage($chat_id, "✅ حذف شد."); }
        elseif ($data == "ba_unlimited_plans") {
            $plans = getUnlimitedPlans(BOT_TOKEN, false);
            $msg = "♾ پلن‌های نامحدود:\n\n";
            if (count($plans) > 0) { foreach ($plans as $p) $msg .= ($p["active"] ? "✅" : "❌") . " " . $p["name"] . " - " . $p["days"] . " روز - " . number_format($p["price"]) . " تومان\n"; }
            else $msg .= "هنوز پلنی اضافه نشده.\n";
            $keyboard = ["inline_keyboard" => [[["text" => "➕ افزودن پلن نامحدود", "callback_data" => "ba_add_unlimited"], ["text" => "🗑 حذف پلن", "callback_data" => "ba_del_unlimited"]], [["text" => "🔄 فعال/غیرفعال", "callback_data" => "ba_toggle_unlimited"]], [["text" => "↩️ بازگشت", "callback_data" => "ba_back"]]]];
            sendMessage($chat_id, $msg, $keyboard);
        }
        elseif ($data == "ba_add_unlimited") { sendMessage($chat_id, "📌 نام پلن نامحدود:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_unlimited_name", ""]); }
        elseif ($data == "ba_del_unlimited") {
            $plans = getUnlimitedPlans(BOT_TOKEN, false);
            if (count($plans) == 0) sendMessage($chat_id, "📭 پلنی نیست.");
            else { $keyboard = ["inline_keyboard" => []]; foreach ($plans as $p) $keyboard["inline_keyboard"][] = [["text" => "🗑 " . $p["name"], "callback_data" => "del_unlimited_" . $p["id"]]]; sendMessage($chat_id, "🗑 پلن برای حذف:", $keyboard); }
        }
        elseif (strpos($data, "del_unlimited_") === 0) { $pdo->prepare("DELETE FROM bot_unlimited_plans WHERE id = ? AND bot_token = ?")->execute([str_replace("del_unlimited_", "", $data), BOT_TOKEN]); sendMessage($chat_id, "✅ حذف شد."); }
        elseif ($data == "ba_toggle_unlimited") {
            $plans = getUnlimitedPlans(BOT_TOKEN, false);
            if (count($plans) == 0) sendMessage($chat_id, "📭 پلنی نیست.");
            else { $keyboard = ["inline_keyboard" => []]; foreach ($plans as $p) $keyboard["inline_keyboard"][] = [["text" => ($p["active"] ? "✅ " : "❌ ") . $p["name"], "callback_data" => "toggle_unlimited_" . $p["id"]]]; sendMessage($chat_id, "🔄 برای تغییر وضعیت کلیک کنید:", $keyboard); }
        }
        elseif (strpos($data, "toggle_unlimited_") === 0) { $pdo->prepare("UPDATE bot_unlimited_plans SET active = 1 - active WHERE id = ? AND bot_token = ?")->execute([str_replace("toggle_unlimited_", "", $data), BOT_TOKEN]); sendMessage($chat_id, "✅ وضعیت تغییر کرد."); }
        elseif ($data == "ba_add_admin") { sendMessage($chat_id, "👤 آیدی عددی ادمین جدید:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_add_admin_id", ""]); }
        elseif ($data == "ba_remove_admin") {
            $admins = getBotAdmins(BOT_TOKEN);
            if (count($admins) == 0) sendMessage($chat_id, "📭 ادمینی نیست.");
            else { $keyboard = ["inline_keyboard" => []]; foreach ($admins as $admin) $keyboard["inline_keyboard"][] = [["text" => "🗑 " . $admin["telegram_id"], "callback_data" => "rm_admin_" . $admin["telegram_id"]]]; sendMessage($chat_id, "🗑 ادمین برای حذف:", $keyboard); }
        }
        elseif (strpos($data, "rm_admin_") === 0) { removeBotAdmin(BOT_TOKEN, str_replace("rm_admin_", "", $data)); sendMessage($chat_id, "✅ حذف شد."); }
        elseif ($data == "ba_channel") { sendMessage($chat_id, "📢 آیدی کانال را وارد کنید:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_channel_input", ""]); }
        elseif ($data == "ba_channel_remove") { updateBotSetting(BOT_TOKEN, 'force_channel', ''); updateBotSetting(BOT_TOKEN, 'channel_url', ''); sendMessage($chat_id, "✅ کانال حذف شد."); }
        elseif ($data == "ba_support") { sendMessage($chat_id, "🎧 آیدی پشتیبانی (بدون @):"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_support_input", ""]); }
        elseif ($data == "ba_discount") { sendMessage($chat_id, "🏷 کد تخفیف را وارد کنید:"); $pdo->prepare("REPLACE INTO bot_user_states (chat_id, state, temp_data) VALUES (?, ?, ?)")->execute([$chat_id, "ba_discount_code", ""]); }
        // ============ حذف کد تخفیف ============
        elseif ($data == "ba_discount_delete") { if (isBotAdmin(BOT_TOKEN, $userId)) showDiscountCodesList($chat_id); }
        elseif (strpos($data, "del_discount_") === 0) {
            if (isBotAdmin(BOT_TOKEN, $userId)) {
                $codeId = intval(str_replace("del_discount_", "", $data));
                if (deleteDiscountCode(BOT_TOKEN, $codeId)) sendMessage($chat_id, "✅ کد تخفیف حذف شد.");
                else sendMessage($chat_id, "❌ خطا در حذف.");
                showDiscountCodesList($chat_id);
            } else sendMessage($chat_id, "❌ دسترسی ندارید.");
        }
        elseif ($data == "ba_wallet") showWalletManagement($chat_id);
        elseif ($data == "ba_broadcast") startBroadcast($chat_id);
        elseif ($data == "ba_reviews") showReviews($chat_id);
        elseif ($data == "ba_report") showFullReport($chat_id);
        elseif ($data == "ba_users") showUserManagement($chat_id);
        elseif (strpos($data, "user_info_") === 0) showUserInfo($chat_id, str_replace("user_info_", "", $data));
        elseif ($data == "ba_back") showBotUserMenu($chat_id, $userId);
        else dlog("UNKNOWN CALLBACK", $data);
    }
} catch (Exception $e) {
    dlog("MAIN HANDLER EXCEPTION", ["message" => $e->getMessage(), "file" => $e->getFile(), "line" => $e->getLine()]);
} catch (Error $e) {
    dlog("MAIN HANDLER FATAL", ["message" => $e->getMessage(), "file" => $e->getFile(), "line" => $e->getLine()]);
}

http_response_code(200);
echo "OK";
BOTTEMPLATE;
    }
}

// ============================================================
// ============ توابع ساخت و مدیریت ربات ======================
// ============================================================

if (!function_exists('createBotFile')) {
    function createBotFile($botToken, $apiKey, $prefix, $botUsername, $ownerTelegramId = null) {
        try {
            handlerLog("createBotFile START", ["username" => $botUsername, "prefix" => $prefix]);
            if (!defined('BOT_BASE_PATH')) { handlerLog("createBotFile ERROR", "BOT_BASE_PATH not defined"); return false; }
            $botDir = BOT_BASE_PATH . '/' . $botUsername;
            if (!file_exists($botDir)) { if (!@mkdir($botDir, 0755, true)) { handlerLog("createBotFile ERROR", "Cannot create dir: $botDir"); return false; } }
            $template = getBotTemplate();
            if ($template === false) { handlerLog("createBotFile ERROR", "template not available"); return false; }
            $template = preg_replace('/^<\?php\s*/', '', $template);
            $template = ltrim($template);
            $botCode = "<?php\n";
            $botCode .= "// Auto-generated bot\n";
            $botCode .= "// Generated: " . date('Y-m-d H:i:s') . "\n\n";
            $botCode .= "define('BOT_TOKEN', " . var_export($botToken, true) . ");\n";
            $botCode .= "define('PANEL_API_KEY', " . var_export($apiKey, true) . ");\n";
            $botCode .= "define('PANEL_URL', " . var_export(defined('PANEL_URL') ? PANEL_URL : '', true) . ");\n";
            $botCode .= "define('SUB_BASE_URL', " . var_export(defined('PANEL_SUB_URL') ? PANEL_SUB_URL : '', true) . ");\n";
            $botCode .= "define('PREFIX', " . var_export($prefix, true) . ");\n";
            $botCode .= "define('DB_HOST', " . var_export(defined('DB_HOST') ? DB_HOST : 'localhost', true) . ");\n";
            $botCode .= "define('DB_USER', " . var_export(defined('DB_USER') ? DB_USER : '', true) . ");\n";
            $botCode .= "define('DB_PASS', " . var_export(defined('DB_PASS') ? DB_PASS : '', true) . ");\n";
            $botCode .= "define('DB_NAME', " . var_export(defined('DB_NAME') ? DB_NAME : '', true) . ");\n";
            $botCode .= "define('LOG_FILE', __DIR__ . '/debug_log.txt');\n";
            $botCode .= "define('VIP_DEFAULT_PRICE_PER_GB', 2000);\n";
            $botCode .= "define('VIP_DEFAULT_MIN_BALANCE', 20000);\n\n";
            $botCode .= $template;
            $targetFile = $botDir . '/index.php';
            $bytes = @file_put_contents($targetFile, $botCode);
            if ($bytes === false) { handlerLog("createBotFile ERROR", "Cannot write: $targetFile"); return false; }
            handlerLog("createBotFile OK", ["file" => $targetFile, "bytes" => $bytes]);
            if ($ownerTelegramId && function_exists('db')) {
                try { $pdo = db(); $stmt = $pdo->prepare("INSERT IGNORE INTO bot_admins (bot_token, telegram_id, username) VALUES (?, ?, ?)"); $stmt->execute([$botToken, $ownerTelegramId, (string)$ownerTelegramId]); }
                catch (Exception $e) { handlerLog("createBotFile admin ERROR", $e->getMessage()); }
            }
            return $botDir;
        } catch (Exception $e) {
            handlerLog("createBotFile EXCEPTION", ["message" => $e->getMessage(), "line" => $e->getLine()]);
            return false;
        }
    }
}

if (!function_exists('handleBotButton')) {
    function handleBotButton($chat_id, $userId) {
        try {
            handlerLog("handleBotButton", ["chat_id" => $chat_id, "user_id" => $userId]);
            if (!function_exists('db')) return;
            $pdo = db();
            $stmt = $pdo->prepare("SELECT * FROM bots WHERE telegram_id = ?");
            $stmt->execute([$userId]);
            $bot = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($bot) {
                $keyboard = ["inline_keyboard" => [[["text" => "🔄 تغییر توکن ربات", "callback_data" => "change_token"]], [["text" => "⬆️ بروزرسانی ربات", "callback_data" => "update_bot"]]]];
                sendMessage($chat_id, "🤖 ربات شما: @{$bot['bot_username']}\nلطفاً انتخاب کنید:", $keyboard);
            } else {
                sendMessage($chat_id, "🤖 لطفاً توکن ربات خود را ارسال کنید:");
                $pdo->prepare("INSERT INTO users (telegram_id, bot_state) VALUES (?, 'waiting_token') ON DUPLICATE KEY UPDATE bot_state = 'waiting_token'")->execute([$userId]);
            }
        } catch (Exception $e) { handlerLog("handleBotButton ERROR", ["message" => $e->getMessage(), "line" => $e->getLine()]); }
    }
}

if (!function_exists('updateBotFile')) {
    function updateBotFile($chat_id) {
        try {
            handlerLog("updateBotFile START", ["chat_id" => $chat_id]);
            if (!function_exists('db')) return;
            $pdo = db();
            $stmt = $pdo->prepare("SELECT * FROM bots WHERE telegram_id = ?");
            $stmt->execute([$chat_id]);
            $bot = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$bot) { sendMessage($chat_id, "❌ رباتی یافت نشد."); return; }
            $result = createBotFile($bot['bot_token'], $bot['api_key'], $bot['prefix'], $bot['bot_username'], $chat_id);
            if ($result === false) { sendMessage($chat_id, "❌ خطا در ساخت فایل."); return; }
            setWebhook($bot['bot_token'], $bot['bot_username']);
            sendMessage($chat_id, "✅ ربات با موفقیت بروزرسانی شد!\n\n🤖 @{$bot['bot_username']}");
        } catch (Exception $e) { handlerLog("updateBotFile ERROR", ["message" => $e->getMessage(), "line" => $e->getLine()]); }
    }
}

if (!function_exists('handleBotSetup')) {
    function handleBotSetup($chat_id, $text, $state) {
        try {
            handlerLog("handleBotSetup START", ["chat_id" => $chat_id, "state" => $state]);
            if (!function_exists('db')) return;
            $pdo = db();
            if ($state == 'waiting_token' || $state == 'waiting_token_replace') {
                $botToken = trim($text);
                $botInfo = getBotInfo($botToken);
                if (!$botInfo || !$botInfo['ok']) { sendMessage($chat_id, "❌ توکن نامعتبر. لطفاً دوباره تلاش کنید."); return; }
                $botUsername = $botInfo['result']['username'];
                handlerLog("handleBotSetup: username", $botUsername);
                if ($state == 'waiting_token_replace') {
                    $stmt = $pdo->prepare("SELECT * FROM bots WHERE telegram_id = ?");
                    $stmt->execute([$chat_id]);
                    $existingBot = $stmt->fetch(PDO::FETCH_ASSOC);
                    if (!$existingBot) { $pdo->prepare("UPDATE users SET bot_state = NULL WHERE telegram_id = ?")->execute([$chat_id]); return; }
                    $pdo->prepare("UPDATE bots SET bot_token = ?, bot_username = ? WHERE telegram_id = ?")->execute([$botToken, $botUsername, $chat_id]);
                    createBotFile($botToken, $existingBot['api_key'], $existingBot['prefix'], $botUsername, $chat_id);
                    setWebhook($botToken, $botUsername);
                    $pdo->prepare("UPDATE users SET bot_state = NULL WHERE telegram_id = ?")->execute([$chat_id]);
                    sendMessage($chat_id, "✅ توکن با موفقیت تغییر کرد!\n\n🤖 @$botUsername");
                } else {
                    $stmt = $pdo->prepare("SELECT main_admin_id, main_admin FROM users WHERE telegram_id = ?");
                    $stmt->execute([$chat_id]);
                    $userData = $stmt->fetch(PDO::FETCH_ASSOC);
                    $adminId = $userData['main_admin_id'] ?? null;
                    if (!$adminId && isset($userData['main_admin']) && function_exists('findAdminIdByUsername')) {
                        $adminInfo = findAdminIdByUsername($userData['main_admin']);
                        $adminId = $adminInfo['id'] ?? null;
                    }
                    if (!$adminId) { sendMessage($chat_id, "❌ ابتدا تست نمایندگی بگیرید."); return; }
                    $apiKeyResult = callPanelAPI('POST', '/api_key', ['name' => 'bot-' . $botUsername, 'admin_id' => intval($adminId), 'inherit_permissions' => true]);
                    $apiKey = $apiKeyResult['body']['api_key'] ?? null;
                    if (!$apiKey) { sendMessage($chat_id, "❌ خطا در ساخت API Key."); return; }
                    $pdo->prepare("UPDATE users SET bot_state = 'waiting_prefix', bot_temp_token = ?, bot_temp_username = ?, bot_temp_api_key = ? WHERE telegram_id = ?")->execute([$botToken, $botUsername, $apiKey, $chat_id]);
                    sendMessage($chat_id, "✅ ربات شناسایی شد: @$botUsername\n\n🔤 لطفاً پیشوند سرویس‌ها را وارد کنید:");
                }
            } elseif ($state == 'waiting_prefix') {
                $prefix = trim($text);
                if (empty($prefix)) { sendMessage($chat_id, "❌ پیشوند نامعتبر."); return; }
                $stmt = $pdo->prepare("SELECT bot_temp_token, bot_temp_username, bot_temp_api_key FROM users WHERE telegram_id = ?");
                $stmt->execute([$chat_id]);
                $temp = $stmt->fetch(PDO::FETCH_ASSOC);
                if (!$temp) { sendMessage($chat_id, "❌ خطا در بازیابی اطلاعات."); return; }
                $result = createBotFile($temp['bot_temp_token'], $temp['bot_temp_api_key'], $prefix, $temp['bot_temp_username'], $chat_id);
                if ($result === false) { sendMessage($chat_id, "❌ خطا در ساخت فایل ربات."); return; }
                setWebhook($temp['bot_temp_token'], $temp['bot_temp_username']);
                $pdo->prepare("INSERT INTO bots (telegram_id, bot_token, bot_username, api_key, prefix) VALUES (?, ?, ?, ?, ?)")->execute([$chat_id, $temp['bot_temp_token'], $temp['bot_temp_username'], $temp['bot_temp_api_key'], $prefix]);
                $pdo->prepare("UPDATE users SET bot_state = NULL, bot_temp_token = NULL, bot_temp_username = NULL, bot_temp_api_key = NULL WHERE telegram_id = ?")->execute([$chat_id]);
                sendMessage($chat_id, "✅ ربات با موفقیت ساخته شد!\n\n🤖 @{$temp['bot_temp_username']}\n🔤 پیشوند: $prefix");
            }
        } catch (Exception $e) {
            handlerLog("handleBotSetup ERROR", ["message" => $e->getMessage(), "line" => $e->getLine()]);
            if (function_exists('sendMessage')) sendMessage($chat_id, "❌ خطا: " . $e->getMessage());
        }
    }
}

handlerLog("=== bot_handler.php LOADED SUCCESSFULLY ===");