<?php
/**
 * ماژول «خدمات مجازی» (خرید استارز تلگرام / پرمیوم تلگرام / گیفت)
 * ------------------------------------------------------------
 * این فایل معادل PHP سورس gift.py است که برای هماهنگی کامل با ساختار
 * 
 * Mirzabot (توابع select/update/step، جدول user، کیف پول Balance،
 * کانال گزارش خرید sendMemberOrderReportChannel و ...) بازنویسی شده.
 *
 * نحوه اتصال:
 *   1) در index.php کنار سایر require_once ها این خط را اضافه کنید:
 *        require_once 'virtual_services.php';
 *   2) درست قبل از خط:
 *        if (in_array($from_id, $admin_ids)) require_once 'admin.php';
 *      این شرط را اضافه کنید (به‌صورت elseif به آخرین بلوک زنجیره وصل شود):
 *        } elseif (vsShouldHandle()) {
 *            vsDispatch();
 *        }
 *   3) در admin.php هم قبل از خط پایانی همین کار را برای پنل ادمین انجام دهید:
 *        } elseif (vsAdminShouldHandle()) {
 *            vsAdminDispatch();
 *        }
 *   (این‌ها به‌صورت خودکار در نسخه‌ی خروجی/زیپ نهایی اعمال شده‌اند.)
 *
 * قیمت‌گذاری لحظه‌ای Premium/Stars/Gift در فایل جداگانه‌ی virtual_pricing.php
 * پیاده‌سازی شده (تابع‌های vsPriceForPremium/vsPriceForStars/vsPriceForGift).
 */
require_once __DIR__ . '/virtual_pricing.php';

#-----------------[ جداول ]-------------------#
function vsEnsureTables()
{
    global $pdo;
    static $done = false;
    if ($done) return;
    $done = true;

    $pdo->exec("CREATE TABLE IF NOT EXISTS virtual_settings (
        name VARCHAR(100) NOT NULL PRIMARY KEY,
        value TEXT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

    $pdo->exec("CREATE TABLE IF NOT EXISTS virtual_orders (
        id INT AUTO_INCREMENT PRIMARY KEY,
        user_id BIGINT NOT NULL,
        username VARCHAR(255) NULL,
        type VARCHAR(20) NOT NULL,
        item_name VARCHAR(255) NOT NULL,
        recipient VARCHAR(255) NULL,
        quantity INT NOT NULL DEFAULT 1,
        price BIGINT NOT NULL DEFAULT 0,
        status VARCHAR(20) NOT NULL DEFAULT 'pending',
        admin_note VARCHAR(500) NULL,
        created_at DATETIME NOT NULL,
        updated_at DATETIME NULL,
        INDEX(user_id), INDEX(status)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

    $pdo->exec("CREATE TABLE IF NOT EXISTS virtual_terms_accept (
        user_id BIGINT NOT NULL PRIMARY KEY,
        accepted_at DATETIME NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
}

#-----------------[ تنظیمات (کلید/مقدار) ]-------------------#
function vsDefaultSettings()
{
    return [
        'vs_enabled'      => '1',
        // فعال/غیرفعال کردن مستقل هر محصول (علاوه بر سوییچ کلی vs_enabled)؛ شماره
        // مجازی از قبل تنظیم مستقل خودش (vn_enabled) را دارد.
        'vs_enabled_stars'   => '1',
        'vs_enabled_premium' => '1',
        'vs_enabled_gift'    => '1',
        'vs_star_min'     => '50',       // حداقل تعداد استار قابل خرید

        // ---- قیمت‌گذاری لحظه‌ای (virtual_pricing.php) ----
        // قیمت‌های پایه‌ی دلاری مرجع Fragment (همان اعدادی که در سورس price.py
        // به‌صورت ثابت آمده بودند). این‌ها فقط "پایه"‌اند؛ قیمت نهایی نمایشی از
        // پایه × نرخ لحظه‌ای دلار × (۱ + درصد سود) محاسبه می‌شود.
        'vs_base_usd_premium_3'  => '11.99',
        'vs_base_usd_premium_6'  => '15.99',
        'vs_base_usd_premium_12' => '28.99',
        'vs_base_usd_star'       => '0.015',   // قیمت هر Star به دلار

        // درصد سود گروهی — فقط همین سه عدد را ادمین تنظیم می‌کند
        'vs_profit_premium' => '10',
        'vs_profit_stars'   => '10',
        'vs_profit_gift'    => '10',

        // نرخ دلار به تومان: اگر vs_rate_api_url خالی باشد یا در دسترس نباشد،
        // از همین نرخ دستی استفاده می‌شود.
        'vs_usd_manual_rate' => '0',
        'vs_rate_api_url'    => 'https://swapwallet.app/api/v1/market/prices',
        'vs_rate_api_key'    => '',      // از پنل ادمین وارد کنید — داخل سورس ذخیره نمی‌شود
        'vs_rate_api_header' => 'x-api-key',
        'vs_rate_json_key'   => 'result.USDT/IRT',
        'vs_rate_cache_ttl'  => '60',    // نرخ دلار سریع نوسان دارد؛ کش کوتاه‌تر
        'vs_price_round_step'=> '1000',  // گرد کردن قیمت نهایی به نزدیک‌ترین (تومان)

        'vs_style_stars'  => 'primary',
        'vs_style_premium'=> 'success',
        'vs_style_gift'   => 'danger',
        'vs_style_self'   => 'primary',  // رنگ دکمه «خرید برای خودم» (پیش‌فرض آبی)
        'vs_style_vnum'   => 'success',  // رنگ دکمه «شماره مجازی» (پیش‌فرض سبز)
        'vs_icon_stars'   => '',   // آیدی ایموجی پریمیوم دکمه استارز
        'vs_icon_premium' => '',   // آیدی ایموجی پریمیوم دکمه پرمیوم
        'vs_icon_gift'    => '',   // آیدی ایموجی پریمیوم دکمه گیفت
        'vs_icon_vnum'    => '',   // آیدی ایموجی پریمیوم دکمه شماره مجازی
        'vs_terms_text'   => "با استفاده از خدمات مجازی این ربات (خرید استارز، پرمیوم تلگرام و گیفت) موارد زیر را می‌پذیرید:\n\n۱. تحویل سفارش‌ها به‌صورت دستی و طی حداکثر ۲۴ ساعت انجام می‌شود.\n۲. مسئولیت صحت آیدی/یوزرنیم گیرنده بر عهده خود کاربر است.\n۳. در صورت اشتباه بودن اطلاعات گیرنده، امکان بازگشت وجه وجود ندارد.\n۴. مبلغ سفارش‌های رد شده توسط ادمین، به کیف پول شما بازگردانده می‌شود.\n۵. قیمت‌ها بر اساس نرخ لحظه‌ای بازار تعیین و ممکن است بدون اطلاع قبلی تغییر کند.",
        // هر گیفت فقط تعداد استارزش مشخص است؛ قیمت تومانی هرگز به‌صورت دستی
        // ذخیره نمی‌شود و همیشه لحظه‌ای از vsPriceForGift() محاسبه می‌شود:
        // (تعداد استارز × قیمت لحظه‌ای هر استارز) + درصد سود گروه Gift.
        'vs_gifts'        => json_encode([
            ['name' => '🧸 خرس تدی',      'stars' => 15,  'icon' => null],
            ['name' => '💝 هدیه قلب',      'stars' => 15,  'icon' => null],
            ['name' => '🌹 گل رز',        'stars' => 25,  'icon' => null],
            ['name' => '🎁 باکس هدیه',     'stars' => 25,  'icon' => null],
            ['name' => '🎂 کیک تولد',      'stars' => 50,  'icon' => null],
            ['name' => '💐 دسته گل',       'stars' => 50,  'icon' => null],
            ['name' => '🚀 موشک',         'stars' => 50,  'icon' => null],
            ['name' => '💎 الماس',        'stars' => 100, 'icon' => null],
            ['name' => '💍 حلقه',         'stars' => 100, 'icon' => null],
            ['name' => '🏆 جام',          'stars' => 100, 'icon' => null],
        ], JSON_UNESCAPED_UNICODE),
    ];
}

function vsSetting($name, $default = null)
{
    global $pdo;
    vsEnsureTables();
    static $cache = null;
    if ($cache === null) {
        $cache = [];
        foreach ($pdo->query("SELECT name, value FROM virtual_settings")->fetchAll() as $row) {
            $cache[$row['name']] = $row['value'];
        }
    }
    if (array_key_exists($name, $cache)) return $cache[$name];
    $defaults = vsDefaultSettings();
    return $defaults[$name] ?? $default;
}

function vsSetSetting($name, $value)
{
    global $pdo;
    vsEnsureTables();
    $stmt = $pdo->prepare("INSERT INTO virtual_settings (name, value) VALUES (:n,:v)
        ON DUPLICATE KEY UPDATE value = :v2");
    $stmt->execute(['n' => $name, 'v' => $value, 'v2' => $value]);
}

#-----------------[ اضافه‌کردن خودکار دکمه «صفحه دوم» به کیبورد اصلی ]-------------------#
// این تابع قبلاً در هر ریکوئست اجرا می‌شد و اگر دکمه با متن دقیقاً برابر
// VS_MAIN_BUTTON_TEXT پیدا نمی‌کرد (مثلاً چون ادمین حذفش کرده بود، یا خودش
// یک دکمه‌ی مشابه با استایل دیگری ساخته بود)، دوباره یک دکمه‌ی جدید اضافه
// می‌کرد؛ همین باعث می‌شد دکمه‌ی حذف‌شده همیشه برگردد. حالا این رفتار پشت
// تنظیم vs_auto_main_button است و پیش‌فرض خاموش (off) است، یعنی اگر ادمین
// یک دکمه‌ی «صفحه دوم» را خودش دستی ساخته/چیده باشد (با callback_data
// vsmenu)، این تابع دیگر با آن تداخل نمی‌کند و چیزی اضافه/حذف نمی‌کند.
// برای فعال کردن دوباره‌ی افزودن خودکار، مقدار vs_auto_main_button را در
// جدول virtual_settings برابر "1" قرار بده: vsSetSetting('vs_auto_main_button', '1');
function vsEnsureMainButton()
{
    global $setting, $pdo;
    if (vsSetting('vs_auto_main_button', '0') !== '1') {
        return;
    }
    $raw = $setting['keyboardmain'] ?? null;
    if (!$raw) return;
    $kb = json_decode($raw, true);
    if (!is_array($kb) || !isset($kb['keyboard'])) return;

    $found = false;
    $changed = false;
    foreach ($kb['keyboard'] as $ri => $row) {
        foreach ($row as $ci => $btn) {
            if (($btn['text'] ?? '') === VS_MAIN_BUTTON_TEXT || ($btn['callback_data'] ?? '') === 'vsmenu') {
                $found = true;
                if (($btn['callback_data'] ?? '') !== 'vsmenu') {
                    $kb['keyboard'][$ri][$ci]['callback_data'] = 'vsmenu';
                    $changed = true;
                }
            }
        }
    }

    if (!$found) {
        $kb['keyboard'][] = [
            ['text' => VS_MAIN_BUTTON_TEXT, 'callback_data' => 'vsmenu', 'style' => vsSetting('vs_style_stars', 'primary')],
        ];
        $changed = true;
    }

    if (!$changed) return;

    $newJson = json_encode($kb, JSON_UNESCAPED_UNICODE);
    update("setting", "keyboardmain", $newJson, null, null);
    $setting['keyboardmain'] = $newJson;
}

define('VS_MAIN_BUTTON_TEXT', '🖥 صفحه دوم');

#-----------------[ کیبورد‌های میانبر ]-------------------#
function vsMenuKeyboard()
{
    $styleStars   = vsSetting('vs_style_stars', 'primary');
    $stylePremium = vsSetting('vs_style_premium', 'success');
    $styleGift    = vsSetting('vs_style_gift', 'danger');

    $btnStars   = ['text' => '️ خرید استارز تلگرام', 'callback_data' => 'vsstars', 'style' => $styleStars];
    $btnPremium = ['text' => ' خرید پرمیوم تلگرام', 'callback_data' => 'vspremium', 'style' => $stylePremium];
    $btnGift    = ['text' => ' خرید گیفت', 'callback_data' => 'vsgift', 'style' => $styleGift];

    $iconStars = sanitizeCustomEmojiId(vsSetting('vs_icon_stars'));
    if ($iconStars !== null) $btnStars['icon_custom_emoji_id'] = $iconStars;
    $iconPremium = sanitizeCustomEmojiId(vsSetting('vs_icon_premium'));
    if ($iconPremium !== null) $btnPremium['icon_custom_emoji_id'] = $iconPremium;
    $iconGift = sanitizeCustomEmojiId(vsSetting('vs_icon_gift'));
    if ($iconGift !== null) $btnGift['icon_custom_emoji_id'] = $iconGift;

    // دکمه‌ی «شماره مجازی» (ماژول مستقل virtual_number.php) — طبق درخواست، به‌صورت
    // یک ردیف مجزا (ردیف سوم) و با رنگ قابل‌تغییر از پنل ادمین (پیش‌فرض سبز) نمایش
    // داده می‌شود و مثل بقیه‌ی دکمه‌ها از ایموجی پریمیوم هم پشتیبانی می‌کند.
    $styleVnum = vsSetting('vs_style_vnum', 'success');
    $btnVnum = ['text' => ' شماره مجازی', 'callback_data' => 'vnmenu', 'style' => $styleVnum];
    $iconVnum = sanitizeCustomEmojiId(vsSetting('vs_icon_vnum'));
    if ($iconVnum !== null) $btnVnum['icon_custom_emoji_id'] = $iconVnum;

    // چیدمان افقی/ردیفی: هر ردیف دو دکمه (راست/چپ). محصولات بعدی که به این آرایه
    // اضافه شوند به‌صورت خودکار در ردیف بعدی و کنار هم قرار می‌گیرند.
    $items = [$btnStars, $btnPremium, $btnGift];
    $rows = array_chunk($items, 2); // ردیف ۱: استارز/پرمیوم — ردیف ۲: گیفت
    $rows[] = [$btnVnum];           // ردیف ۳: شماره مجازی (تنها، طبق درخواست)

    // ردیف ۴: خدمات شبکه‌های اجتماعی (ماژول مستقل smm_services.php، بر پایه‌ی API
    // واقعیِ apiaddress.com). طبق درخواست: راست = «خدمات تلگرام»، چپ = «خدمات
    // اینستاگرام». چون آرایه‌ی دکمه‌ها همیشه چپ‌به‌راست روی صفحه رندر می‌شود
    // (صرف‌نظر از راست‌چین بودن متن فارسی)، برای اینکه تلگرام سمت راست بیفتد باید
    // دومین (آخرین) آیتم آرایه باشد؛ اگر این فرض برخلاف انتظار شما بود، کافیست
    // ترتیب دو خط زیر را جابه‌جا کنید.
    if (function_exists('smmSetting')) {
        $styleTelegram  = smmSetting('smm_style_telegram', 'primary');
        $styleInstagram = smmSetting('smm_style_instagram', 'danger');
        $btnTelegram  = ['text' => ' خدمات تلگرام', 'callback_data' => 'smmplat_telegram', 'style' => $styleTelegram];
        $btnInstagram = ['text' => ' خدمات اینستاگرام', 'callback_data' => 'smmplat_instagram', 'style' => $styleInstagram];
        $iconTelegram = sanitizeCustomEmojiId(smmSetting('smm_icon_telegram'));
        if ($iconTelegram !== null) $btnTelegram['icon_custom_emoji_id'] = $iconTelegram;
        $iconInstagram = sanitizeCustomEmojiId(smmSetting('smm_icon_instagram'));
        if ($iconInstagram !== null) $btnInstagram['icon_custom_emoji_id'] = $iconInstagram;
        $rows[] = [$btnInstagram, $btnTelegram]; // چپ: اینستاگرام — راست: تلگرام
    }

    $rows[] = [['text' => '🔙 بازگشت', 'callback_data' => 'vsback']];

    return json_encode(['inline_keyboard' => $rows], JSON_UNESCAPED_UNICODE);
}

function vsBackToMenuKeyboard()
{
    return json_encode(['inline_keyboard' => [[['text' => '🔙 بازگشت', 'callback_data' => 'vsmenu']]]], JSON_UNESCAPED_UNICODE);
}

// کیبورد پرسش گیرنده: دکمه شیشه‌ای «خرید برای خودم» (رنگ قابل تغییر از پنل ادمین) + بازگشت
function vsRecipientKeyboard()
{
    $styleSelf = vsSetting('vs_style_self', 'primary');
    $btnSelf = ['text' => '🙋 خرید برای خودم', 'callback_data' => 'vsself', 'style' => $styleSelf];
    return json_encode([
        'inline_keyboard' => [
            [$btnSelf],
            [['text' => '🔙 بازگشت', 'callback_data' => 'vsmenu']],
        ],
    ], JSON_UNESCAPED_UNICODE);
}

// اگر متن «خودم» بود، یوزرنیم خود کاربر (به‌صورت @یوزرنیم) برگردانده می‌شود؛ اگر
// کاربر یوزرنیم نداشت، آیدی عددی او با # برگردانده می‌شود. در غیر این صورت متن ورودی (trim شده)
function vsResolveRecipient($text, $from_id, $username = null)
{
    $t = trim($text);
    return ($t === 'خودم') ? vsSelfRecipient($from_id, $username) : $t;
}

function vsSelfRecipient($from_id, $username = null)
{
    if ($username !== null && $username !== '' && $username !== 'NOT_USERNAME') {
        return '@' . $username;
    }
    return '#' . $from_id;
}

// برچسب نمایشی گیرنده در پیش‌فاکتور (اگر خود کاربر بود «خودم» نمایش داده می‌شود)
function vsRecipientLabel($recipient, $from_id, $username = null)
{
    return ($recipient === vsSelfRecipient($from_id, $username)) ? 'خودم' : htmlspecialchars($recipient);
}

// کیبورد انتخاب تعداد گیفت: ➖ (قرمز) / نمایش تعداد / ➕ (سبز) + تایید + بازگشت
function vsGiftQtyKeyboard()
{
    return json_encode([
        'inline_keyboard' => [
            [
                ['text' => '-[6026061458154984960]', 'callback_data' => 'vsgiftqtydec', 'style' => 'danger'],
                ['text' => '[6026026827833677079] تعداد', 'callback_data' => 'vsnoop'],
                ['text' => '+[6026160495805863139]', 'callback_data' => 'vsgiftqtyinc', 'style' => 'success'],
            ],
            [['text' => '[6026126123182593425] تایید تعداد و ادامه', 'callback_data' => 'vsgiftqtyok', 'style' => 'success']],
            [['text' => '🔙 بازگشت', 'callback_data' => 'vsgift']],
        ],
    ], JSON_UNESCAPED_UNICODE);
}

function vsShowGiftQty($from_id, $message_id, $idx, $qty)
{
    $gifts = json_decode(vsSetting('vs_gifts'), true) ?: [];
    $gift = $gifts[$idx] ?? null;
    if (!$gift) return;
    $qty = max(1, intval($qty));
    $unitPrice = vsPriceForGift($gift);
    if ($unitPrice === null) {
        Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
        return;
    }
    $total = $unitPrice * $qty;
    $text = "🎁 <b>خرید گیفت</b>\n\nگیفت انتخابی: {$gift['name']}\n💰 قیمت لحظه‌ای واحد: " . number_format($unitPrice) . " تومان\n\n🔢 تعداد: <b>{$qty}</b>\n💵 مبلغ کل: " . number_format($total) . " تومان\n\nبا دکمه‌های ➕ و ➖ تعداد را تنظیم و سپس تایید کنید:";
    Editmessagetext($from_id, $message_id, $text, vsGiftQtyKeyboard(), 'HTML');
}

function vsConfirmKeyboard($confirmData)
{
    return json_encode([
        'inline_keyboard' => [
            [
                ['text' => '✅ تایید و پرداخت', 'callback_data' => $confirmData, 'style' => 'success'],
                ['text' => '❌ انصراف', 'callback_data' => 'vsmenu', 'style' => 'danger'],
            ],
        ],
    ], JSON_UNESCAPED_UNICODE);
}

#-----------------[ قوانین (نمایش تدریجی / تایپ‌مانند) + تایید کاربر ]-------------------#
function vsUserAcceptedTerms($from_id)
{
    global $pdo;
    vsEnsureTables();
    $stmt = $pdo->prepare("SELECT user_id FROM virtual_terms_accept WHERE user_id = ?");
    $stmt->execute([$from_id]);
    return (bool) $stmt->fetchColumn();
}

function vsMarkTermsAccepted($from_id)
{
    global $pdo;
    vsEnsureTables();
    $stmt = $pdo->prepare("INSERT IGNORE INTO virtual_terms_accept (user_id, accepted_at) VALUES (?, NOW())");
    $stmt->execute([$from_id]);
}

function vsChunkWords($text, $steps = 12)
{
    $words = preg_split('/(\s+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE);
    $words = array_values(array_filter($words, fn($w) => $w !== ''));
    $total = count($words);
    if ($total === 0) return [$text];
    $steps = max(1, min($steps, $total));
    $perStep = (int) ceil($total / $steps);
    $chunks = [];
    for ($i = 0; $i < $total; $i += $perStep) {
        $chunks[] = implode('', array_slice($words, $i, $perStep));
    }
    return $chunks;
}

// نمایش تدریجی (افکت تایپ) متن قوانین طبق سبک جدید تلگرام، سپس دکمه‌ی تایید
function vsShowTermsTypewriter($from_id)
{
    $fullText = "📜 قوانین و مقررات استفاده از خدمات مجازی\n\n" . vsSetting('vs_terms_text');
    $chunks = vsChunkWords($fullText, 12);

    $current = '';
    $current .= $chunks[0];
    $res = sendmessage($from_id, $current . ' ▌', null, 'html');
    $msgId = $res['result']['message_id'] ?? null;

    for ($i = 1; $i < count($chunks); $i++) {
        $current .= $chunks[$i];
        usleep(180000); // ~۰.۱۸ ثانیه بین هر مرحله برای شبیه‌سازی تایپ زنده
        if ($msgId) {
            $suffix = ($i === count($chunks) - 1) ? '' : ' ▌';
            Editmessagetext($from_id, $msgId, $current . $suffix, json_encode(['inline_keyboard' => []]), 'html');
        }
    }

    if ($msgId) {
        $kb = json_encode([
            'inline_keyboard' => [[
                ['text' => '✅ قوانین را مطالعه کردم و می‌پذیرم', 'callback_data' => 'vstermsaccept', 'style' => 'success'],
            ]],
        ], JSON_UNESCAPED_UNICODE);
        Editmessagetext($from_id, $msgId, $current, $kb, 'html');
    }
}


function vsShouldHandle()
{
    global $text, $datain, $user;
    if ($text === VS_MAIN_BUTTON_TEXT) return true;
    if (is_string($datain) && strpos($datain, 'vs') === 0) return true;
    $step = $user['step'] ?? '';
    if (is_string($step) && strpos($step, 'vs_') === 0) return true;
    return false;
}

function vsClearProcessing($from_id)
{
    update("user", "Processing_value", "0", "id", $from_id);
    step('home', $from_id);
}

#-----------------[ ارسال به گروه گزارشات مخصوص ادمین (تاپیک‌های vsreport / vserror) ]-------------------#
// این دو تابع کاملا مجزا از sendMemberOrderReportChannel هستند:
//  - sendMemberOrderReportChannel → کانال عمومی «گزارش خرید» که کاربران عادی هم می‌بینند.
//  - vsSendGroupReport/vsSendGroupError → گروه فورومیِ داخلیِ ادمین‌ها (همان $setting['Channel_Report']
//    که buyreport/otherservice/errorreport و... هم در آن هستند)، در دو تاپیک اختصاصیِ جدید.
// اگر ادمین هنوز این دو تاپیک را نساخته باشد (یعنی هنوز یک‌بار «🖥 گزارشات ربات» را بعد از این
// آپدیت نزده)، پیام بدون message_thread_id و در تاپیک General گروه ارسال می‌شود؛ یعنی هیچ خطا/
// اختلالی در ربات ایجاد نمی‌شود و بقیه‌ی تاپیک‌های VPN دست‌نخورده باقی می‌مانند.
function vsSendGroupReport($text, $keyboard = null)
{
    global $setting, $vsGroupReportTopic;
    if (empty($setting['Channel_Report'])) return;
    $params = [
        'chat_id' => $setting['Channel_Report'],
        'text' => $text,
        'parse_mode' => 'HTML',
    ];
    if (!empty($vsGroupReportTopic)) {
        $params['message_thread_id'] = $vsGroupReportTopic;
    }
    if ($keyboard) {
        $params['reply_markup'] = $keyboard;
    }
    telegram('sendmessage', $params);
}

function vsSendGroupError($text)
{
    global $setting, $vsGroupErrorTopic;
    if (empty($setting['Channel_Report'])) return;
    $params = [
        'chat_id' => $setting['Channel_Report'],
        'text' => $text,
        'parse_mode' => 'HTML',
    ];
    if (!empty($vsGroupErrorTopic)) {
        $params['message_thread_id'] = $vsGroupErrorTopic;
    }
    telegram('sendmessage', $params);
}

#-----------------[ ثبت سفارش در دیتابیس + گزارش ]-------------------#
function vsCreateOrder($from_id, $username, $type, $itemName, $recipient, $qty, $price)
{
    global $pdo, $textbotlang, $setting;
    vsEnsureTables();

    $stmt = $pdo->prepare("INSERT INTO virtual_orders
        (user_id, username, type, item_name, recipient, quantity, price, status, created_at)
        VALUES (:u,:un,:t,:i,:r,:q,:p,'pending', NOW())");
    $stmt->execute([
        'u' => $from_id, 'un' => $username, 't' => $type, 'i' => $itemName,
        'r' => $recipient, 'q' => $qty, 'p' => $price,
    ]);
    $orderId = $pdo->lastInsertId();

    // توجه: برخلاف نسخه‌ی قبل، پیام «سفارش موفق» دیگر اینجا (لحظه‌ی ثبت سفارش/کسر
    // وجه) به کانال گزارشات عمومی (sendMemberOrderReportChannel) ارسال نمی‌شود؛
    // چون در آن لحظه هنوز ادمین کاری انجام نداده. این پیام حالا در
    // virtual_services_admin.php و دقیقا وقتی ادمین سفارش را «تایید و انجام شد»
    // می‌زند (vsadmindone_) ارسال می‌شود.

    // اطلاع به ادمین‌ها برای تایید دستی سفارش (پیام خصوصی به هر ادمین)
    global $admin_ids;
    $adminText = "🆕 <b>سفارش جدید خدمات مجازی</b>\n\n"
        . "👤 کاربر: <a href=\"tg://user?id={$from_id}\">{$from_id}</a>\n"
        . "📦 آیتم: {$itemName}\n"
        . "🎯 گیرنده: " . htmlspecialchars($recipient ?: '-') . "\n"
        . "🔢 تعداد: {$qty}\n"
        . "💰 مبلغ: " . number_format($price) . " تومان\n"
        . "🆔 شماره سفارش: #{$orderId}";
    $adminKb = json_encode([
        'inline_keyboard' => [[
            ['text' => '✅ تایید و انجام شد', 'callback_data' => 'vsadmindone_' . $orderId, 'style' => 'success'],
            ['text' => '❌ رد و بازگشت وجه', 'callback_data' => 'vsadminreject_' . $orderId, 'style' => 'danger'],
        ]],
    ], JSON_UNESCAPED_UNICODE);
    if (is_array($admin_ids)) {
        foreach ($admin_ids as $adminId) {
            sendmessage($adminId, $adminText, $adminKb, 'HTML');
        }
    }

    // همان گزارش، علاوه بر پیام خصوصی، در تاپیک «📱 خدمات مجازی» گروه گزارشات
    // ادمین هم ثبت می‌شود تا همه‌ی ادمین‌ها یک‌جا لیست سفارش‌ها را ببینند.
    vsSendGroupReport($adminText, $adminKb);

    return $orderId;
}

#-----------------[ Dispatcher اصلی سمت کاربر ]-------------------#
function vsDispatch()
{
    global $text, $datain, $from_id, $message_id, $user, $username, $keyboard, $pdo;

    vsEnsureTables();
    vsEnsureMainButton();

    if (vsSetting('vs_enabled', '1') !== '1' && $text === VS_MAIN_BUTTON_TEXT) {
        sendmessage($from_id, '⛔️ بخش خدمات مجازی در حال حاضر غیرفعال است.', $keyboard, 'html');
        return;
    }

    // ورود به منو با دکمه ثابت
    if ($text === VS_MAIN_BUTTON_TEXT) {
        if (!vsUserAcceptedTerms($from_id)) {
            vsClearProcessing($from_id);
            vsShowTermsTypewriter($from_id);
            return;
        }
        vsClearProcessing($from_id);
        sendmessage($from_id, "🖥 <b>صفحه دوم | خدمات مجازی</b>\n\nیکی از خدمات زیر را انتخاب کنید:", vsMenuKeyboard(), 'HTML');
        return;
    }

    // بازگشت به منوی اصلی ربات
    if ($datain === 'vsback') {
        deletemessage($from_id, $message_id);
        vsClearProcessing($from_id);
        sendmessage($from_id, 'به منوی اصلی بازگشتید.', $keyboard, 'html');
        return;
    }

    // تایید قوانین
    if ($datain === 'vstermsaccept') {
        vsMarkTermsAccepted($from_id);
        Editmessagetext($from_id, $message_id, "✅ قوانین با موفقیت پذیرفته شد.\n\n🖥 <b>صفحه دوم | خدمات مجازی</b>\n\nیکی از خدمات زیر را انتخاب کنید:", vsMenuKeyboard(), 'HTML');
        return;
    }

    // بازگشت به منوی خدمات مجازی
    if ($datain === 'vsmenu') {
        if (!vsUserAcceptedTerms($from_id)) {
            vsClearProcessing($from_id);
            vsShowTermsTypewriter($from_id);
            return;
        }
        vsClearProcessing($from_id);
        Editmessagetext($from_id, $message_id, "[6068627302772648694] <b>صفحه دوم | خدمات مجازی</b>\n\n یکی از خدمات زیر را انتخاب کنید[6332398995519840476]:", vsMenuKeyboard(), 'HTML');
        return;
    }

    #--------------- استارز ---------------#
    if ($datain === 'vsstars') {
        if (vsSetting('vs_enabled_stars', '1') !== '1') {
            Editmessagetext($from_id, $message_id, '⛔️ خرید استارز در حال حاضر توسط ادمین غیرفعال شده است.', vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        $min = intval(vsSetting('vs_star_min', 50));
        $unitPrice = vsPriceForStars(1);
        if ($unitPrice === null) {
            Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        Editmessagetext($from_id, $message_id,
            "[5330441210500765490] <b>خرید استارز تلگرام</b>\n\n[6069106664072553799]قیمت لحظه‌ای هر عدد: " . number_format($unitPrice) . " تومان\n[6069106664072553799]حداقل خرید: {$min} عدد\n\nتعداد استارز مورد نظر خود را عدد وارد کنید:",
            vsBackToMenuKeyboard(), 'HTML');
        step('vs_stars_qty', $from_id);
        return;
    }
    if ($datain === '' && ($user['step'] ?? '') === 'vs_stars_qty') {
        $qty = intval(preg_replace('/[^0-9]/', '', $text));
        $min = intval(vsSetting('vs_star_min', 50));
        if ($qty < $min) {
            sendmessage($from_id, "❌ عدد نامعتبر است. حداقل تعداد قابل خرید {$min} عدد استارز است.", vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        update("user", "Processing_value", (string) $qty, "id", $from_id);
        sendmessage($from_id, "👤 آیدی عددی یا یوزرنیم تلگرام گیرنده استارز را ارسال کنید (یا روی دکمه زیر بزنید):", vsRecipientKeyboard(), 'HTML');
        step('vs_stars_recipient', $from_id);
        return;
    }
    if ($datain === '' && ($user['step'] ?? '') === 'vs_stars_recipient') {
        $qty = intval($user['Processing_value']);
        $price = vsPriceForStars($qty);
        if ($price === null) {
            sendmessage($from_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            step('home', $from_id);
            return;
        }
        $recipient = vsResolveRecipient($text, $from_id, $username);
        update("user", "Processing_value_one", $recipient, "id", $from_id);
        sendmessage($from_id,
            "🧾 <b>پیش‌فاکتور</b>\n\n⭐️ تعداد استارز: {$qty}\n🆔 آیدی خریدار: <code>{$from_id}</code>\n🎯 گیرنده: " . vsRecipientLabel($recipient, $from_id, $username) . "\n💰 مبلغ قابل پرداخت: " . number_format($price) . " تومان\n\nدر صورت تایید، مبلغ از کیف پول شما کسر خواهد شد.",
            vsConfirmKeyboard('vsconfirm_stars'), 'HTML');
        step('vs_stars_confirm', $from_id);
        return;
    }
    if ($datain === 'vsconfirm_stars') {
        $qty = intval($user['Processing_value']);
        $recipient = $user['Processing_value_one'];
        // قیمت دوباره در همین لحظه (لحظه‌ی پرداخت) محاسبه می‌شود
        $price = vsPriceForStars($qty);
        if ($price === null) {
            Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        vsFinalizePurchase($from_id, $username, 'stars', $qty . ' عدد استارز تلگرام', $recipient, $qty, $price, $message_id);
        return;
    }

    #--------------- پرمیوم ---------------#
    if ($datain === 'vspremium') {
        if (vsSetting('vs_enabled_premium', '1') !== '1') {
            Editmessagetext($from_id, $message_id, '⛔️ خرید پرمیوم تلگرام در حال حاضر توسط ادمین غیرفعال شده است.', vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        $p3  = vsPriceForPremium(3);
        $p6  = vsPriceForPremium(6);
        $p12 = vsPriceForPremium(12);
        if ($p3 === null || $p6 === null || $p12 === null) {
            Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        $kb = json_encode([
            'inline_keyboard' => [  
                [['text' => "[5938043636796102625] ۳ ماهه | " . number_format($p3) . " تومان", 'callback_data' => 'vsprem_3', 'style' => 'success']],
                [['text' => "[5938043636796102625] ۶ ماهه | " . number_format($p6) . " تومان", 'callback_data' => 'vsprem_6', 'style' => 'success']],
                [['text' => "[5938193582694341035] ۱۲ ماهه | " . number_format($p12) . " تومان", 'callback_data' => 'vsprem_12', 'style' => 'success']],
                [['text' => '🔙 بازگشت', 'callback_data' => 'vsmenu']],
            ],
        ], JSON_UNESCAPED_UNICODE);
        Editmessagetext($from_id, $message_id, "[6332369420375040511] <b>خرید پرمیوم تلگرام</b>\n\nمدت زمان اشتراک را انتخاب کنید:", $kb, 'HTML');
        return;
    }
    if (preg_match('/^vsprem_(3|6|12)$/', $datain, $m)) {
        $months = $m[1];
        update("user", "Processing_value", $months, "id", $from_id);
        Editmessagetext($from_id, $message_id, "👤 آیدی عددی یا یوزرنیم تلگرام گیرنده پرمیوم را ارسال کنید (یا روی دکمه زیر بزنید):", vsRecipientKeyboard(), 'HTML');
        step('vs_premium_recipient', $from_id);
        return;
    }
    if ($datain === '' && ($user['step'] ?? '') === 'vs_premium_recipient') {
        $months = intval($user['Processing_value']);
        $price = vsPriceForPremium($months);
        if ($price === null) {
            sendmessage($from_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            step('home', $from_id);
            return;
        }
        $recipient = vsResolveRecipient($text, $from_id, $username);
        update("user", "Processing_value_one", $recipient, "id", $from_id);
        sendmessage($from_id,
            "🧾 <b>پیش‌فاکتور</b>\n\n💎 پرمیوم: {$months} ماهه\n🆔 آیدی خریدار: <code>{$from_id}</code>\n🎯 گیرنده: " . vsRecipientLabel($recipient, $from_id, $username) . "\n💰 مبلغ قابل پرداخت: " . number_format($price) . " تومان",
            vsConfirmKeyboard('vsconfirm_premium'), 'HTML');
        step('vs_premium_confirm', $from_id);
        return;
    }
    if ($datain === 'vsconfirm_premium') {
        $months = intval($user['Processing_value']);
        $recipient = $user['Processing_value_one'];
        // قیمت دوباره در همین لحظه (لحظه‌ی پرداخت) محاسبه می‌شود
        $price = vsPriceForPremium($months);
        if ($price === null) {
            Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        vsFinalizePurchase($from_id, $username, 'premium', 'پرمیوم تلگرام ' . $months . ' ماهه', $recipient, 1, $price, $message_id);
        return;
    }

    #--------------- گیفت ---------------#
    if ($datain === 'vsgift') {
        if (vsSetting('vs_enabled_gift', '1') !== '1') {
            Editmessagetext($from_id, $message_id, '⛔️ خرید گیفت در حال حاضر توسط ادمین غیرفعال شده است.', vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        $gifts = json_decode(vsSetting('vs_gifts'), true) ?: [];
        $rows = [];
        foreach ($gifts as $i => $g) {
            $gPrice = vsPriceForGift($g);
            $priceLabel = $gPrice === null ? 'نامشخص' : (number_format($gPrice) . ' تومان');
            $btn = ['text' => $g['name'] . ' | ' . $priceLabel, 'callback_data' => 'vsgiftpick_' . $i, 'style' => 'danger'];
            $icon = sanitizeCustomEmojiId($g['icon'] ?? null);
            if ($icon !== null) $btn['icon_custom_emoji_id'] = $icon;
            $rows[] = [$btn];
        }
        $rows[] = [['text' => '🔙 بازگشت', 'callback_data' => 'vsmenu']];
        Editmessagetext($from_id, $message_id, "[5280615440928758599] <b>خرید گیفت</b>\n\nیکی از گیفت‌ها را انتخاب کنید:", json_encode(['inline_keyboard' => $rows], JSON_UNESCAPED_UNICODE), 'HTML');
        return;
    }
    if (preg_match('/^vsgiftpick_(\d+)$/', $datain, $m)) {
        $idx = intval($m[1]);
        $gifts = json_decode(vsSetting('vs_gifts'), true) ?: [];
        if (!isset($gifts[$idx])) { return; }
        update("user", "Processing_value", (string) $idx, "id", $from_id);
        update("user", "Processing_value_four", "1", "id", $from_id);
        vsShowGiftQty($from_id, $message_id, $idx, 1);
        step('vs_gift_qty', $from_id);
        return;
    }
    // بدون عملکرد؛ فقط برای نمایش تعداد وسط دو دکمه ➕/➖ استفاده می‌شود
    if ($datain === 'vsnoop') {
        return;
    }
    if (in_array($datain, ['vsgiftqtyinc', 'vsgiftqtydec'], true)) {
        if (($user['step'] ?? '') !== 'vs_gift_qty') { return; }
        $idx = intval($user['Processing_value']);
        $qty = max(1, intval($user['Processing_value_four']));
        $qty = ($datain === 'vsgiftqtyinc') ? ($qty + 1) : max(1, $qty - 1);
        update("user", "Processing_value_four", (string) $qty, "id", $from_id);
        vsShowGiftQty($from_id, $message_id, $idx, $qty);
        return;
    }
    if ($datain === 'vsgiftqtyok') {
        if (($user['step'] ?? '') !== 'vs_gift_qty') { return; }
        $idx = intval($user['Processing_value']);
        $gifts = json_decode(vsSetting('vs_gifts'), true) ?: [];
        if (!isset($gifts[$idx])) { return; }
        Editmessagetext($from_id, $message_id, "👤 آیدی عددی یا یوزرنیم تلگرام گیرنده گیفت را ارسال کنید (یا روی دکمه زیر بزنید):", vsRecipientKeyboard(), 'HTML');
        step('vs_gift_recipient', $from_id);
        return;
    }
    if ($datain === '' && ($user['step'] ?? '') === 'vs_gift_recipient') {
        $idx = intval($user['Processing_value']);
        $qty = max(1, intval($user['Processing_value_four']));
        $gifts = json_decode(vsSetting('vs_gifts'), true) ?: [];
        $gift = $gifts[$idx] ?? null;
        if (!$gift) { return; }
        $unitPrice = vsPriceForGift($gift);
        if ($unitPrice === null) {
            sendmessage($from_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            step('home', $from_id);
            return;
        }
        $recipient = vsResolveRecipient($text, $from_id, $username);
        $totalPrice = $unitPrice * $qty;
        update("user", "Processing_value_one", $recipient, "id", $from_id);
        sendmessage($from_id,
            "🧾 <b>پیش‌فاکتور</b>\n\n🎁 گیفت: {$gift['name']}\n🔢 تعداد: {$qty}\n🆔 آیدی خریدار: <code>{$from_id}</code>\n🎯 گیرنده: " . vsRecipientLabel($recipient, $from_id, $username) . "\n💰 مبلغ قابل پرداخت: " . number_format($totalPrice) . " تومان",
            vsConfirmKeyboard('vsconfirm_gift'), 'HTML');
        step('vs_gift_confirm', $from_id);
        return;
    }
    if ($datain === 'vsconfirm_gift') {
        $idx = intval($user['Processing_value']);
        $qty = max(1, intval($user['Processing_value_four']));
        $gifts = json_decode(vsSetting('vs_gifts'), true) ?: [];
        $gift = $gifts[$idx] ?? null;
        if (!$gift) { return; }
        // قیمت دوباره در همین لحظه (لحظه‌ی پرداخت) محاسبه می‌شود
        $unitPrice = vsPriceForGift($gift);
        if ($unitPrice === null) {
            Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
            return;
        }
        $recipient = $user['Processing_value_one'];
        $totalPrice = $unitPrice * $qty;
        $itemName = $gift['name'] . ' × ' . $qty;
        vsFinalizePurchase($from_id, $username, 'gift', $itemName, $recipient, $qty, $totalPrice, $message_id);
        return;
    }

    #--------------- دکمه «خرید برای خودم» (مشترک بین استارز/پرمیوم/گیفت) ---------------#
    if ($datain === 'vsself') {
        $step = $user['step'] ?? '';
        $recipient = vsSelfRecipient($from_id, $username);

        if ($step === 'vs_stars_recipient') {
            $qty = intval($user['Processing_value']);
            $price = vsPriceForStars($qty);
            if ($price === null) {
                Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
                return;
            }
            update("user", "Processing_value_one", $recipient, "id", $from_id);
            Editmessagetext($from_id, $message_id,
                "🧾 <b>پیش‌فاکتور</b>\n\n⭐️ تعداد استارز: {$qty}\n🆔 آیدی خریدار: <code>{$from_id}</code>\n🎯 گیرنده: خودم (" . htmlspecialchars($recipient) . ")\n💰 مبلغ قابل پرداخت: " . number_format($price) . " تومان\n\nدر صورت تایید، مبلغ از کیف پول شما کسر خواهد شد.",
                vsConfirmKeyboard('vsconfirm_stars'), 'HTML');
            step('vs_stars_confirm', $from_id);
            return;
        }
        if ($step === 'vs_premium_recipient') {
            $months = intval($user['Processing_value']);
            $price = vsPriceForPremium($months);
            if ($price === null) {
                Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
                return;
            }
            update("user", "Processing_value_one", $recipient, "id", $from_id);
            Editmessagetext($from_id, $message_id,
                "🧾 <b>پیش‌فاکتور</b>\n\n💎 پرمیوم: {$months} ماهه\n🆔 آیدی خریدار: <code>{$from_id}</code>\n🎯 گیرنده: خودم (" . htmlspecialchars($recipient) . ")\n💰 مبلغ قابل پرداخت: " . number_format($price) . " تومان",
                vsConfirmKeyboard('vsconfirm_premium'), 'HTML');
            step('vs_premium_confirm', $from_id);
            return;
        }
        if ($step === 'vs_gift_recipient') {
            $idx = intval($user['Processing_value']);
            $qty = max(1, intval($user['Processing_value_four']));
            $gifts = json_decode(vsSetting('vs_gifts'), true) ?: [];
            $gift = $gifts[$idx] ?? null;
            if (!$gift) { return; }
            $unitPrice = vsPriceForGift($gift);
            if ($unitPrice === null) {
                Editmessagetext($from_id, $message_id, vsPriceUnavailableText(), vsBackToMenuKeyboard(), 'HTML');
                return;
            }
            $totalPrice = $unitPrice * $qty;
            update("user", "Processing_value_one", $recipient, "id", $from_id);
            Editmessagetext($from_id, $message_id,
                "🧾 <b>پیش‌فاکتور</b>\n\n🎁 گیفت: {$gift['name']}\n🔢 تعداد: {$qty}\n🆔 آیدی خریدار: <code>{$from_id}</code>\n🎯 گیرنده: خودم (" . htmlspecialchars($recipient) . ")\n💰 مبلغ قابل پرداخت: " . number_format($totalPrice) . " تومان",
                vsConfirmKeyboard('vsconfirm_gift'), 'HTML');
            step('vs_gift_confirm', $from_id);
            return;
        }
        return;
    }
}

#-----------------[ کسر از کیف‌پول + ثبت نهایی سفارش ]-------------------#
function vsFinalizePurchase($from_id, $username, $type, $itemName, $recipient, $qty, $price, $message_id)
{
    $balance = intval(select("user", "Balance", "id", $from_id)['Balance'] ?? 0);
    if ($balance < $price) {
        Editmessagetext($from_id, $message_id,
            "❌ موجودی کیف پول شما کافی نیست.\n\n💰 موجودی فعلی: " . number_format($balance) . " تومان\n💳 مبلغ مورد نیاز: " . number_format($price) . " تومان\n\nابتدا از بخش «کیف پول» حساب خود را شارژ کنید.",
            vsBackToMenuKeyboard(), 'HTML');
        vsClearProcessing($from_id);
        return;
    }
    update("user", "Balance", (string) ($balance - $price), "id", $from_id);
    $orderId = vsCreateOrder($from_id, $username, $type, $itemName, $recipient, $qty, $price);
    Editmessagetext($from_id, $message_id,
        "✅ سفارش شما با موفقیت ثبت شد.\n\n📦 {$itemName}\n💰 مبلغ کسر شده: " . number_format($price) . " تومان\n🆔 شماره سفارش: #{$orderId}\n\nسفارش شما به‌زودی توسط پشتیبانی پردازش و برای گیرنده ارسال می‌شود.",
        vsBackToMenuKeyboard(), 'HTML');
    vsClearProcessing($from_id);
}
