<?php

require_once __DIR__ . '/autoload.php';
require_once("Helpers/jdf.php");
require_once("env.php");
$state = $state ?? null;
$uid   = $uid ?? null;
$cb    = $cb ?? null;
$text  = $text ?? null;
$chat_id = $chat_id ?? null;
$mid = $mid ?? null;



// ---------------- CONFIG ----------------
$bot_token  = env('BOT_TOKEN');
$bot_username = env('BOT_USERNAME');
$telegram_secret = (string) env('TG_SECRET');
$secret = $_SERVER['HTTP_X_TELEGRAM_BOT_API_SECRET_TOKEN'] ?? '';
$api_url    = env('API_URL');

$db_host    = env('DB_HOST', '127.0.0.1');
$db_name    = env('DB_NAME');
$db_user    = env('DB_USER');
$db_pass    = env('DB_PASS');
$db_charset = env('DB_CHARSET', 'utf8mb4');

$admin_ids = array_map('intval', explode(',', env('ADMIN_IDS', '')));
// ---------------- DB ----------------
$dsn = "mysql:host={$db_host};dbname={$db_name};charset={$db_charset}";
$pdo = new PDO($dsn, $db_user, $db_pass, [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);

$tempGames = []; 

// ---------------- Tracker ----------------
$tracker = new BehaviorTracker($pdo);

// ---------------- SECURITY ----------------
if (!hash_equals($telegram_secret, $secret)) {
    http_response_code(403);
    exit;
}

// ---------------- BOOT ----------------
date_default_timezone_set('Asia/Tehran');
$raw = file_get_contents('php://input');
$update = json_decode($raw, true);
if (!$update) { http_response_code(200); exit; }

//========================================

if (isset($update['callback_query'])) {

    $cb = $update['callback_query'];

    $callback_id   = $cb['id'];
    $callback_data = $cb['data'];
    $data          = $cb['data'];

    $chat_id = $cb['message']['chat']['id'];
    $uid     = $cb['from']['id'];
    $mid     = $cb['message']['message_id'];

    $state = getState($pdo, $uid);
}

error_log(
    '[CALLBACK DATA] ' . ($data ?? 'NULL')
);


if (isset($update['message'])) {

    $msg = $update['message'];

    $chat_id = $msg['chat']['id'];
    $uid     = $msg['from']['id'];
    $mid     = $msg['message_id'] ?? null;

    $text           = trim($msg['text'] ?? '');
    $photo          = $msg['photo'] ?? null;
    $video          = $msg['video'] ?? null;
    $caption        = trim($msg['caption'] ?? '');
    $document       = $msg['document'] ?? null;
    $media_group_id = $msg['media_group_id'] ?? null;
    $user_shared    = $msg['user_shared'] ?? null;

    $state = getState($pdo, $uid);

    // ========================================
    // جلوگیری از پردازش پیام‌های گروه
    // ========================================

    $chat_type = $msg['chat']['type'] ?? '';

    if ($chat_type === 'group' || $chat_type === 'supergroup') {

    /*
        error_log(
            '[GROUP MESSAGE BLOCKED]' .
            ' | chat_id=' . $chat_id .
            ' | uid=' . $uid .
            ' | text=' . preg_replace(
                '/\s+/',
                ' ',
                $text
            )
        );
    */
        http_response_code(200);
        exit;
    }

// مقدار پیش‌فرض برای جلوگیری از هشدار "Undefined variable" در صورت نبود callback_query
if (!isset($data)) {
    $data = '';
}

/*
if (isset($uid) && isset($chat_id)) {
        if (
            !isset($data) ||
            $data !== 'check_force_join'
        ) {

            if (!checkForceJoin($pdo, $uid, $chat_id, $bot_token)) {
                exit;
            }
        }
    }
*/


    // ===========================
    // دستور /start
    // ===========================
if (preg_match('/^\/start(?:\s+(.*))?$/', $text, $m)) {

    $payload = trim($m[1] ?? '');

    // تعریف موقتی defaultGameName اگر تعریف نشده باشد
    if (!isset($defaultGameName)) {
        $defaultGameNameRow = $pdo->query("
            SELECT id, name
            FROM games
            WHERE is_default = 1
            LIMIT 1
        ")->fetch(PDO::FETCH_ASSOC);

        $defaultGameName = $defaultGameNameRow
            ? $defaultGameNameRow['name']
            : '';
    }

    $user = ensureUser($pdo, $msg['from'], $defaultGameName);

    // ==================== REFERRAL ====================
if (str_starts_with($payload, 'ref_')) {

        $refId = substr($payload, 4);

        $st = $pdo->prepare("
            SELECT *
            FROM referrals
            WHERE ref_id = ?
            LIMIT 1
        ");
        $st->execute([$refId]);

        $ref = $st->fetch(PDO::FETCH_ASSOC);

        if (!$ref) {
            sendMessage($chat_id, "❌ لینک دعوت معتبر نیست.");
            exit;
        }

        $referrerId = (int)$ref['referrer_id'];
        $eventId    = (int)$ref['event_id'];
        $newUserId  = (int)$msg['from']['id'];

        // جلوگیری از self referral
        if ($referrerId === $newUserId) {
            sendMessage($chat_id, "⚠️ نمی‌توانید از لینک دعوت خودتان استفاده کنید.");
            exit;
        }

        // اگر کاربر قبلاً در این ایونت به‌صورت referrer یا referred ثبت شده باشد
        $st = $pdo->prepare("
            SELECT id
            FROM referral_starts
            WHERE event_id = ?
            AND user_id = ?
            AND status = 'valid'
            LIMIT 1
        ");
        $st->execute([$eventId, $newUserId]);



        if ($st->fetch()) {
            sendMessage($chat_id, "⚠️ شما قبلا ثبت نام کرده اید.");
            exit;
        }



        $st = $pdo->prepare("
            SELECT id
            FROM referral_starts
            WHERE ref_id = ?
            AND referrer_id = ?
            AND user_id = ?
            AND event_id = ?
            LIMIT 1
        ");

        $st->execute([$refId, $referrerId, $newUserId, $eventId]);

        if (!$st->fetch()) {

            $pdo->prepare("
                INSERT INTO referral_starts (
                    ref_id,
                    referrer_id,
                    user_id,
                    event_id,
                    status
                )
                VALUES (?, ?, ?, ?, 'pending')
            ")->execute([
                $refId,
                $referrerId,
                $newUserId,
                $eventId
            ]);
        }

        // گرفتن اطلاعات ایونت
        $st = $pdo->prepare("
            SELECT private_channel, require_private_channel
            FROM events
            WHERE id=?
            LIMIT 1
        ");
        $st->execute([$eventId]);

        $event = $st->fetch(PDO::FETCH_ASSOC);

        if (!$event) {
            sendMessage($chat_id, "❌ ایونت پیدا نشد.");
            exit;
        }

        $st = $pdo->prepare("
            SELECT value, enabled
            FROM settings
            WHERE `key` = ?
            LIMIT 1
        ");

        $st->execute(['force_channels']);

        $forceJoin = $st->fetch(PDO::FETCH_ASSOC);

        $eventRequireJoin  = (bool)($event['require_private_channel'] ?? false);
        $globalRequireJoin = (bool)($forceJoin['enabled'] ?? false);

        $requiredChannels = [];

        // کانال‌های ایونت
        if ($eventRequireJoin) {

            $eventChannels = json_decode(
                $event['private_channel'] ?? '[]',
                true
            ) ?: [];

            foreach ($eventChannels as $channel) {

                if (!isset($channel['chat_id'])) {
                    continue;
                }

                $requiredChannels[$channel['chat_id']] = $channel;
            }
        }

        // کانال‌های سراسری
        if ($globalRequireJoin) {

            $globalChannels = json_decode(
                $forceJoin['value'] ?? '[]',
                true
            ) ?: [];

            foreach ($globalChannels as $channel) {

                if (!isset($channel['chat_id'])) {
                    continue;
                }

                $requiredChannels[$channel['chat_id']] = $channel;
            }
        }

        $requiredChannels = array_values($requiredChannels);

        // اگر هیچ کانالی برای بررسی وجود ندارد
        if (empty($requiredChannels)) {

            sendReferralSuccess($chat_id, $refId);
            exit;
        }

        // =============================
        // اگر عضویت اجباری است
        // =============================

        $text = "<b>🎉 خوش اومدی!</b>\n\n<blockquote> برای ثبت شدن دعوتت و تکمیل ورود به ربات، ابتدا در کانال‌های زیر عضو شو، سپس روی «بررسی عضویت» بزن.</blockquote>";
        $file_id = "Anime Girl - Boos Behet";

        $kb = buildForceJoinKeyboard(
            $bot_token,
            $newUserId,
            json_encode($requiredChannels, JSON_UNESCAPED_UNICODE),
            $eventId,
            "check_ref_join:$refId"
        );

        if ($kb !== null) {
            sendGif(
                $chat_id,
                $file_id,
                $text,
                $kb
            );

            exit;
        }

        // =============================
        // اگر عضو همه کانال‌ها بود
        // =============================
        sendReferralSuccess($chat_id, $refId);

        tryAutoRegisterReferrer(
            $pdo,
            $referrerId,
            $eventId,
            $bot_username
        );

        exit;
    }

    // ==================== SQUAD INVITE ====================
    if (str_starts_with($payload, 'squad_invite_')) {

        [, $eid, $leader_id] = explode('_', $payload, 3);

        handleSquadAccept(
            $pdo,
            $chat_id,
            $uid,
            (int)$eid,
            (int)$leader_id
        );

        exit;
    }

    // ==================== EVENT DIRECT JOIN ====================
    if (str_starts_with($payload, 'event_')) {

        $eid = 0;
        $invite = null;

        /*
        * لینک دعوتنامه:
        * event_invite_TOKEN
        */
        if (preg_match('/^event_invite_([A-Za-z0-9]+)$/', $payload, $m)) {

            $token = $m[1];

            $st = $pdo->prepare("
                SELECT *
                FROM event_registration_invites
                WHERE token = ?
                AND is_active = 1
                LIMIT 1
            ");

            $st->execute([$token]);

            $invite = $st->fetch(PDO::FETCH_ASSOC);

            if (!$invite) {
                sendMessage(
                    $chat_id,
                    '❌ این دعوتنامه نامعتبر یا غیرفعال است.'
                );
                exit;
            }

            $eid = (int)$invite['event_id'];

            /*
            * بررسی محدودیت استفاده
            */
            if (
                $invite['usage_limit'] !== null &&
                (int)$invite['used_count'] >= (int)$invite['usage_limit']
            ) {
                sendMessage(
                    $chat_id,
                    '❌ ظرفیت استفاده از این دعوتنامه تکمیل شده است.'
                );
                exit;
            }

        /*
        * لینک معمولی:
        * event_16
        */
        } elseif (preg_match('/^event_(\d+)$/', $payload, $m)) {

            $eid = (int)$m[1];

        } else {

            sendMessage(
                $chat_id,
                '❌ لینک ایونت نامعتبر است.'
            );
            exit;
        }

        if ($eid <= 0) {
            sendMessage(
                $chat_id,
                '❌ لینک ایونت نامعتبر است.'
            );
            exit;
        }

        processEventJoinRequest(
            $pdo,
            $chat_id,
            0,
            [],
            $uid,
            $eid,
            false,
            $bot_username,
            $invite
        );

        exit;
    }

    
    // ==================== EVENT DIRECT ID&Pass ====================
    if (preg_match('/^get_(\d+)_(id|pass|both)$/', $payload, $m)) {

        $eid = (int)$m[1];
        $check = $m[2];

        $st = $pdo->prepare('SELECT name FROM events WHERE id=?');
        $st->execute([$eid]);
        $event = $st->fetch(PDO::FETCH_ASSOC);


        if (!$event || $eid <= 0) {
            sendMessage($chat_id, '❌ لینک ایونت نامعتبر است.');
            return;
        }

        $userJoined   = isUserInEventStatus($pdo, $uid, $eid, 'accepted');
        $file_id = "Rick - Pish Miad";

        if ($userJoined) {
            $result = processEventGetCredentials($pdo, $chat_id, $uid, $eid, $check);
        } else {
            sendGif(
                $chat_id,
                $file_id,
                "<blockquote>❌ شما هنوز در این ایونت ثبت‌نام نکرده‌اید.</blockquote>",
                [
                    'inline_keyboard' => [
                        [
                            [
                                'text' => '✅ ثبت نام در ایونت',
                                'callback_data' => "ev_join:$eid",
                                'style' => 'success'
                            ]
                        ]
                    ]
                ]
            );
            exit;
        }

        sendMessage(
            $chat_id,
            $result['text'],
            [
                'inline_keyboard' => $result['inline_keyboard']
            ]
        );
        exit;
    }


    // ==================== NORMAL START ====================
    showWelcome($pdo, $chat_id, $uid, $user);
    exit;
}


    // ===========================
    // ثبت تیکت
    // ===========================
if (str_starts_with($state, 'waiting_ticket:')) {
    $parts = explode(':', $state);
    $dep   = $parts[1] ?? '';

    if (!empty($text)) {
        $subject = trim($text);

        // ذخیره state برای مرحله بعد (دریافت متن)
        setState($pdo, $uid, "waiting_ticket_message:$dep:$subject");

        sendMessage($chat_id, "📝 موضوع شما ثبت شد.\nحالا متن تیکت خود را وارد کنید:");
        exit;
    }

    sendMessage($chat_id, "⚠️ لطفاً موضوع تیکت را وارد کنید.");
    exit;
}


if (str_starts_with($state, 'waiting_ticket_message:')) {
    $parts   = explode(':', $state, 3);
    $dep     = $parts[1] ?? '';
    $subject = $parts[2] ?? '';
    $message = $text ?: $caption;

    if ($photo || $video || $document) {
        sendMessage($chat_id, "⚠️ در این مرحله فقط متن ارسال کن.");
        exit;
    }

    if (!empty($message)) {
        $tmp_ticket = [
            'dep'     => $dep,
            'subject' => $subject,
            'message' => $message,
            'media'   => [],
        ];

        $stmt = $pdo->prepare("UPDATE users SET temp = ? WHERE id = ?");
        $stmt->execute([json_encode($tmp_ticket, JSON_UNESCAPED_UNICODE), $uid]);

        setState($pdo, $uid, 'ticket_preview:');

        $kb = [
            'inline_keyboard' => [
                [['text'=>'✅ تایید','callback_data'=>'ticket_confirm']],
                [['text'=>'❌ لغو','callback_data'=>'ticket_cancel']],
                [['text'=>'📎 افزودن ضمیمه','callback_data'=>'ticket_add_attachment']]
            ]
        ];

        sendMessage($chat_id, "💬 پیش‌نمایش تیکت شما:\n\n"
            . "📝 موضوع: " . htmlspecialchars($subject) . "\n\n"
            . htmlspecialchars($message), $kb);
        exit;
    }

    sendMessage($chat_id, "⚠️ لطفاً متن تیکت را وارد کنید.");
    exit;
}



// ===========================
// هندلر waiting_ticket_attachment
// ===========================
if ($state === 'waiting_ticket_attachment:') {
    if ($photo || $video || $document) {
        $stmt = $pdo->prepare("SELECT temp FROM users WHERE id = ?");
        $stmt->execute([$uid]);
        $tmp_ticket = json_decode($stmt->fetchColumn(), true);

        if (!isset($tmp_ticket['media'])) {
            $tmp_ticket['media'] = [];
        }

        if ($photo) {
            $last_photo = end($photo);
            $tmp_ticket['media'][] = ['type'=>'photo','file_id'=>$last_photo['file_id']];
        }
        if ($video) {
            $tmp_ticket['media'][] = ['type'=>'video','file_id'=>$video['file_id']];
        }
        if ($document) {
            $tmp_ticket['media'][] = ['type'=>'document','file_id'=>$document['file_id']];
        }

        // اگر پیام قبلی با دکمه وجود داره → دکمه‌هاش رو حذف کن
        if (!empty($tmp_ticket['last_ticket_msg_id'])) {
            editMessageReplyMarkup($chat_id, $tmp_ticket['last_ticket_msg_id'], ['inline_keyboard'=>[]]);
        }

        // ارسال پیام جدید با دکمه شیشه‌ای
        $keyboard = [
            'inline_keyboard' => [
                [
                    ['text'=>"✅ ثبت", 'callback_data'=>"ticket_confirm"],
                    ['text'=>"❌ لغو", 'callback_data'=>"ticket_cancel"]
                ]
            ]
        ];
        $res = sendMessage($chat_id, "📎 ضمیمه اضافه شد (" . count($tmp_ticket['media']) . " فایل).\nلطفاً یکی از گزینه‌ها را انتخاب کنید:", $keyboard);

        // ذخیره شناسه پیام جدید
        if (isset($res['result']['message_id'])) {
            $tmp_ticket['last_ticket_msg_id'] = $res['result']['message_id'];
        }

        // ذخیره کل وضعیت در دیتابیس
        $stmt = $pdo->prepare("UPDATE users SET temp = ? WHERE id = ?");
        $stmt->execute([json_encode($tmp_ticket, JSON_UNESCAPED_UNICODE), $uid]);

        exit;
    }
}

// ============================ // اضافه کردن msg به تیکت // ============================
if (str_starts_with($state, 'addmsg:')) {
    $parts     = explode(':', $state);
    $ticket_id = (int) ($parts[1] ?? 0);

    // پیام کاربر
    $message = $text ?: $caption;

    // اگر کاربر فایل فرستاد (photo/video/document)
    if ($photo || $video || $document) {
        sendMessage($chat_id, "❌ در این مرحله فقط پیام متنی قابل قبول است.");
        exit;
    }

    // اگر پیام متنی معتبر بود
    if (!empty($message)) {
        $stmt = $pdo->prepare("
            INSERT INTO tickets_msg (ticket_id, user_id, message, created_at) 
            VALUES (?, ?, ?, NOW())
        ");
        $stmt->execute([$ticket_id, $uid, $message]);

        // ریست state
        setState($pdo, $uid, null);

        // تأیید برای کاربر
        sendMessage($chat_id, "✅ پیام شما با موفقیت به تیکت اضافه شد.");
        exit;
    }

    // اگر متن خالی بود
    sendMessage($chat_id, "⚠️ لطفاً یک پیام متنی وارد کنید.");
    exit;
}






    // ===========================
    // IGN برای ایونت / squad
    // ===========================
    if (str_starts_with($state, 'ign_Squadinput:')) {
        [, $game, $eid] = explode(':', $state);
        $eid = (int)$eid;

        if (strlen($text) > 24) {
            sendMessage($chat_id, "⚠️ IGN نمی‌تواند بیش از 24 کاراکتر باشد.");
            exit;
        }
        if (!preg_match('/^[a-zA-Z0-9]+$/', $text)) {
            sendMessage($chat_id, "⚠️ IGN فقط شامل حروف و اعداد انگلیسی باشد.");
            exit;
        }

        // ذخیره در users
        $st = $pdo->prepare("SELECT games FROM users WHERE id=?");
        $st->execute([$uid]);
        $games = json_decode($st->fetchColumn(), true) ?? [];
        $games[$game]['ign'] = $text;
        $st = $pdo->prepare("UPDATE users SET games=? WHERE id=?");
        $st->execute([json_encode($games, JSON_UNESCAPED_UNICODE), $uid]);

        clearState($pdo, $uid);

        sendMessage($chat_id, "✅ Nickname شما ذخیره شد و ثبت‌نام شما در ایونت تکمیل شد.");

        // اضافه به squad
        $squad = getSquad($pdo, $eid);
        $squad['leader_id'] = $squad['leader_id'] ?? null;
        $exists = array_filter($squad['members'] ?? [], fn($m) => $m['user_id'] == $uid);
        if (!$exists) {
            $squad['members'][] = [
                'user_id' => $uid,
                'joined_at' => date('Y-m-d H:i:s'),
                'status' => 'accepted'
            ];
            saveSquad($pdo, $eid, $squad);
        }
        // اطلاع‌رسانی به لیدر
        if ($squad['leader_id']) {
            sendMessage($squad['leader_id'], "✅ کاربر <code>$uid</code> IGN خود را ثبت کرد و به اسکواد پیوست.");
        }
        exit;
    }

    // ===========================
    // دریافت credentials
    // ===========================
    if (str_starts_with($state, 'edit_credentials:')) {
        $eid   = (int)explode(':', $state)[1];
        $lines = explode("\n", $text, 2);
        $id_line   = trim($lines[0] ?? '');
        $pass_line = trim($lines[1] ?? '');
        if (!$id_line || !$pass_line) {
            sendMessage($chat_id,"⚠️ لطفا دو خط بفرست: خط اول آیدی، خط دوم رمز.");
            exit;
        }
        $json = json_encode(['id'=>$id_line,'pass'=>$pass_line],JSON_UNESCAPED_UNICODE);
        $stmt = $pdo->prepare("UPDATE events SET id_pass = ? WHERE id = ?");
        $stmt->execute([$json,$eid]);

        setState($pdo,$uid,"confirm_credentials:$eid");

        sendMessage($chat_id,"🆔 آیدی: <b>$id_line</b>\n🔑 رمز: <b>$pass_line</b>\n\nآیا تایید می‌کنید؟",[
            'inline_keyboard'=>[
                [['text'=>'✅ تایید','callback_data'=>"confirm_credentials:$eid"], ['text'=>'❌ لغو','callback_data'=>"cancel_credentials:$eid"]]
            ]
        ]);
        exit;
    }

    // ===========================
    // حالت جستجو
    // ===========================
    $step = getUserStep($uid);
    if ($step && str_starts_with($step, 'waiting_for_search_query:')) {
        $parts = explode(':', $step);
        $eid   = (int)($parts[1] ?? 0);
        $query = trim($text);

        setUserStep($uid, null); // ریست
        showSearchResults($chat_id, $eid, $query);
        exit;
    }

    if ($step && str_starts_with($step, 'admin_player_msg:')) {
        $parts = explode(':', $step, 4);
        $eid = (int)($parts[1] ?? 0);
        $targetUid = (int)($parts[2] ?? 0);
        $message = trim($text);

        setUserStep($uid, null);

        if ($message === '') {
            sendMessage($chat_id, '⚠️ لطفاً متن پیام را وارد کنید.');
            exit;
        }

        sendMessage($targetUid, "✉️ پیام از ادمین ایونت #{$eid}:\n\n" . $message);
        editMessageText($chat_id, $mid, "✅ پیام شما با موفقیت به کاربر <code>{$targetUid}</code> ارسال شد.", [
            'inline_keyboard' => [[['text' => '🔙 بازگشت', 'callback_data' => 'admin_players:' . $eid]]]
        ]);
        exit;
    }

    if ($state && str_starts_with($state,'await_search') && $text) {
    setState($pdo, $uid, ''); // پاک کردن state

    $search = trim($text);

    // جستجوی واقعی
    $users = getUserList($pdo, 'search', $search, 0, 10);

    $rows = [];
    foreach ($users as $u) {
        $name = $u['username'] ?: $u['id'];
        $rows[] = [['text'=>$name, 'callback_data'=>"user_info:{$u['id']}:search:$search:0"]];
    }

    if (!$rows) {
        $rows[] = [['text'=>'❌ نتیجه‌ای یافت نشد','callback_data'=>'noop']];
    }

    $rows[] = [['text'=>'🔙 بازگشت','callback_data'=>'admin_manage_users']];
    sendMessage($chat_id, "🔎 نتایج جستجو برای: <b>$search</b>", ['inline_keyboard'=>$rows]);
    exit;
}


    // ===========================
    // اعلان
    // ===========================
    if ($state === 'ann_private_getid' && is_numeric($text)) {
        $target_id = (int)$text;
        setState($pdo, $uid, "ann_input:private:$target_id");
        sendMessage($chat_id, "✍️ حالا متن اعلان برای <code>$target_id</code> رو ارسال کن.");
        exit;
    }

    if (str_starts_with($state, 'ann_input:')) {
        $parts = explode(':', $state);
        $mode = $parts[1];
        $target_id = $parts[2] ?? null;

        $title   = $mode === 'private' ? "پیش‌نمایش اعلان (شخصی به $target_id)" : "پیش‌نمایش اعلان ($mode)";
        $preview = "<b>$title:</b>\n\n" . $text;

        // ساخت دکمه‌ها
        if ($mode === 'private') {
            $kb = ['inline_keyboard'=>[
                [['text'=>'✅ ارسال','callback_data'=>"ann_confirm:$mode:$target_id"], ['text'=>'📝 ویرایش','callback_data'=>"ann_input:$mode:$target_id"]],
                [['text'=>'🔙 لغو','callback_data'=>'admin_announcements']]
            ]];
            setState($pdo, $uid, "ann_preview:$mode:$target_id:" . base64_encode($text));
        } else {
            $kb = ['inline_keyboard'=>[
                [['text'=>'✅ ارسال','callback_data'=>"ann_confirm:$mode"], ['text'=>'📝 ویرایش','callback_data'=>"ann_input:$mode"]],
                [['text'=>'🔙 لغو','callback_data'=>'admin_announcements']]
            ]];
            setState($pdo, $uid, "ann_preview:$mode:" . base64_encode($text));
        }

        sendMessage($chat_id, $preview, $kb);
        exit;
    }

    // ===========================
    // squad invite
    // ===========================
if ($user_shared) {
    $shared_user_id = $user_shared['user_id'];

    if (str_starts_with($state, 'squad_invite_wait:')) {
        [, $eid] = explode(':', $state);
        

        $st = $pdo->prepare("SELECT id, invite_code FROM event_squads WHERE eid = ? AND leader_uid = ?");
        $st->execute([$eid, $uid]);
        $squad = $st->fetch(PDO::FETCH_ASSOC);

        if (!$squad) {
            sendMessage($chat_id, "❌ اسکواد شما یافت نشد یا شما لیدر نیستید.");
            setState($pdo, $uid, null);
            exit;
        }

        $inviteCode = $squad['invite_code'];
        $inviteLink = "https://t.me/$bot_username?start=squad_$inviteCode";

        // بررسی وجود کاربر
        $st = $pdo->prepare("SELECT id FROM users WHERE id = ?");
        $st->execute([$shared_user_id]);
        $target = $st->fetch(PDO::FETCH_ASSOC);

        $stDup = $pdo->prepare("
            SELECT id FROM event_invites 
            WHERE squad_id = ? AND target_uid = ? AND status = 'pending'
        ");
        $stDup->execute([$squad['id'], $shared_user_id]);

        if ($stDup->fetch(PDO::FETCH_ASSOC)) {
            sendMessage($chat_id,
                "⚠️ برای این کاربر قبلاً یک دعوت در حالت «در انتظار پذیرش» ثبت شده است.",
                ['parse_mode' => 'HTML']
            );
            setState($pdo, $uid, '');
            showSquad($pdo, $eid, $uid, $chat_id, $mid, true, $keyboard);

            exit;
        }


        if ($target) {
            $msg_text = "📨 شما به یک اسکواد در ایونت #$eid دعوت شده‌اید.\n👤 دعوت‌کننده: <code>$uid</code>";
            $kb = ['inline_keyboard' => [
                [['text' => '✅ پیوستن به اسکواد', 'url' => $inviteLink]]
            ]];
            sendMessage($shared_user_id, $msg_text, $kb, 'HTML');
            sendMessage($chat_id, "✅ دعوت برای کاربر <code>$shared_user_id</code> ارسال شد.", ['parse_mode' => 'HTML']);
            showSquad($pdo, $eid, $uid, $chat_id, $mid, true, $keyboard);


        } else {
            // گرفتن اطلاعات ایونت برای پیام دعوت
            $stEvent = $pdo->prepare("SELECT name, game, entry_fee, deadline FROM events WHERE id = ?");
            $stEvent->execute([$eid]);
            $event = $stEvent->fetch(PDO::FETCH_ASSOC);

            $title = htmlspecialchars($event['name'] ?? 'ایونت ناشناخته');
            $game = htmlspecialchars($event['game'] ?? '');
            $fee = $event['entry_fee'] > 0 ? "{$event['entry_fee']}" : 'رایگان';
            $deadline = htmlspecialchars($event['deadline'] ?? '-');

            $msg_text = "<blockquote><b>🎮 $title | $game \n</b></blockquote>"
                . "💰 ورودی: <b>$fee</b>\n"
                . "⏳ مهلت ثبت‌نام: <b>$deadline</b>\n\n"
                . "سلام! 👋\n"
                . "من دارم برای این ایونت یه اسکواد تشکیل می‌دم، اگه دوست داری با ما باشی خوشحال می‌شم جوین شی 🙌\n"
                . "روی دکمه زیر بزن تا مستقیم به تیم اضافه شی 👇";

            $kb = ['inline_keyboard' => [
                [['text' => '✅ پیوستن به اسکواد', 'url' => $inviteLink]]
            ]];

            sendMessage($chat_id, "📨 کاربر در سیستم ثبت نشده. می‌تونی پیام زیر رو برای اون بفرستی 👇", ['parse_mode' => 'HTML']);
            sendMessage($chat_id, $msg_text, $kb, 'HTML');
        }

        // فقط ذخیره user_id بدون name/username
        $stInvite = $pdo->prepare("
            INSERT INTO event_invites (squad_id, invite_code, sender_uid, target_uid, status)
            VALUES (?, ?, ?, ?, 'pending')
        ");
        $stInvite->execute([
            $squad['id'],
            $inviteCode,
            $uid,
            $shared_user_id
        ]);

        $stInvites = $pdo->prepare("SELECT target_uid FROM event_invites WHERE squad_id=? AND status='pending'");
        $stInvites->execute([$squad['id']]);
        $invites = $stInvites->fetchAll(PDO::FETCH_ASSOC);

        $keyboard = ['inline_keyboard' => []];
        foreach ($invites as $i) {
            $keyboard['inline_keyboard'][] = [['text' => "کاربر #".$i['target_uid'], 'callback_data' => 'invite:'.$i['target_uid']]];
        }


        setState($pdo, $uid, '');
        exit;
    }
}

if ($state === 'gallery_wait_media') {
    $msg = $update['message'];
    $file_id = null;
    $type = null;

    if (!empty($msg['photo'])) {
        $photo = end($msg['photo']);
        $file_id = $photo['file_id'];
        $type = 'photo';
    } elseif (!empty($msg['video'])) {
        $file_id = $msg['video']['file_id'];
        $type = 'video';
    } elseif (!empty($msg['animation'])) {
        $file_id = $msg['animation']['file_id'];
        $type = 'animation';
    } elseif (!empty($msg['document'])) {
        $file_id = $msg['document']['file_id'];
        $type = 'document';
    } elseif (!empty($msg['audio'])) {
        $file_id = $msg['audio']['file_id'];
        $type = 'audio';
    } else {
        sendMessage($chat_id, "❌ مدیای معتبر ارسال نکردید. لطفاً دوباره تلاش کنید.");
        exit;
    }

    // ذخیره رکورد گالری با title خالی
    $st = $pdo->prepare("INSERT INTO gallery (file_id, type, title, sender_uid) VALUES (?,?,NULL,?)");
    $st->execute([$file_id, $type, $uid]);

    $gallery_id = $pdo->lastInsertId();

    // ذخیره gallery_id در state
    setState($pdo, $uid, json_encode([
        'step' => 'gallery_wait_title',
        'gallery_id' => $gallery_id
    ]));

    sendMessage($chat_id, "✅ مدیا ذخیره شد.\nلطفاً یک نام برای فایل وارد کنید یا اگر نمی‌خواهید، کلمه 'عبور' را ارسال کنید:");
    exit;
}



if (str_contains($state, 'gallery_wait_title')) {
    $stateData = json_decode($state, true);
    $gallery_id = $stateData['gallery_id'] ?? null;

    if (!$gallery_id) {
        sendMessage($chat_id, "❌ خطا در ذخیره فایل. لطفاً دوباره مدیا ارسال کنید.");
        setState($pdo, $uid, null);
        exit;
    }

    $msg = $update['message'];
    $title = trim($msg['text'] ?? '');

    if (strtolower($title) === 'عبور') {
        $title = null;
    }

    // آپدیت اسم فایل
    $st = $pdo->prepare("UPDATE gallery SET title=? WHERE id=?");
    $st->execute([$title, $gallery_id]);

    sendMessage($chat_id, "✅ فایل شما با موفقیت در گالری ذخیره شد!");
    setState($pdo, $uid, '');
    exit;
}


    // ===========================
    // edit profile ign
    // ===========================

if (str_starts_with($state, 'ign_input:')) {

    $parts = explode(':', $state);
    $rowId  = (int)($parts[1] ?? 0);
    $direct = isset($parts[2]) && $parts[2] === 'true';
    $eid    = (int)($parts[3] ?? 0);

    $ign = trim($text);

    if (preg_match('/^\/\w+$/', $ign)) {
        sendMessage($chat_id, '⚠️ نام درون بازی معتبر نیست.');
        exit;
    }

    $ign = clean($ign, 64);

    if ($ign === '') {
        sendMessage($chat_id, '⚠️ نام درون بازی خالی است.');
        exit;
    }

    $st = $pdo->prepare('SELECT game FROM user_games WHERE id=? AND user_id=? LIMIT 1');
    $st->execute([$rowId, $uid]);
    $game = $st->fetchColumn();

    if (!$game) {
        setState($pdo, $uid, '');
        sendMessage($chat_id, '❌ بازی پیدا نشد.');
        exit;
    }

    $pdo->prepare(
        'UPDATE user_games SET ign=? WHERE id=? AND user_id=?'
    )->execute([$ign, $rowId, $uid]);

    setState($pdo, $uid, '');

    sendMessage(
        $chat_id,
        "✅ Nickname برای <b>" . htmlspecialchars($game) . "</b> ذخیره شد."
    );

    if ($direct) {

        processEventJoinRequest( $pdo, $chat_id, 0, [], $uid, $eid,false, $bot_username );

    } else {

        renderProfileIGN($pdo, $chat_id, $mid, $uid, true);

    }

    exit;
}


if (str_starts_with($state, 'gameid_input:')) {

    $parts = explode(':', $state);

    $rowId  = (int)($parts[1] ?? 0);
    $direct = isset($parts[2]) && $parts[2] === 'true';
    $eid    = (int)($parts[3] ?? 0);

    $gameid = trim($text);

    if (!preg_match('/^\d+$/', $gameid)) {
        sendMessage($chat_id, '⚠️ شناسه (ID) فقط باید شامل عدد باشد.');
        exit;
    }

    $gameid = substr($gameid, 0, 32);

    if ($gameid === '') {
        sendMessage($chat_id, '⚠️ شناسه (ID) خالی است.');
        exit;
    }

    $st = $pdo->prepare(
        'SELECT game FROM user_games WHERE id=? AND user_id=? LIMIT 1'
    );
    $st->execute([$rowId, $uid]);

    $game = $st->fetchColumn();

    if (!$game) {
        setState($pdo, $uid, '');
        sendMessage($chat_id, '❌ بازی پیدا نشد.');
        exit;
    }

    $pdo->prepare(
        'UPDATE user_games SET game_id=? WHERE id=? AND user_id=?'
    )->execute([$gameid, $rowId, $uid]);

    setState($pdo, $uid, '');

    sendMessage(
        $chat_id,
        "✅ ID برای <b>" . htmlspecialchars($game, ENT_QUOTES, 'UTF-8') . "</b> ذخیره شد."
    );

    if ($direct) {

        processEventJoinRequest(
            $pdo,
            $chat_id,
            0,
            [],
            $uid,
            $eid,
            false,
            $bot_username
        );

    } else {

        renderProfileIGN($pdo, $chat_id, $mid, $uid, true);

    }

    exit;
}

// ===========================
// admin_stages
// ===========================

if (str_starts_with($state, 'admin_stage_create:name:')) {

    $eid = (int) substr(
        $state,
        strlen('admin_stage_create:name:')
    );

    $name = trim($text);

    if ($name === '') {
        sendMessage(
            $chat_id,
            '❌ نام مرحله نمی‌تواند خالی باشد.'
        );
        return;
    }

    if (mb_strlen($name) > 100) {
        sendMessage(
            $chat_id,
            '❌ نام مرحله نباید بیشتر از ۱۰۰ کاراکتر باشد.'
        );
        return;
    }

    // ذخیره موقت نام مرحله
    setState(
        $pdo,
        $uid,
        'admin_stage_create:type:' .
        $eid .
        ':' .
        base64_encode($name)
    );

    sendMessage(
        $chat_id,
        "🎯 <b>نوع مرحله را انتخاب کنید:</b>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '🎯 Qualification',
                        'callback_data' => 'admin_stage_type:qualification:' . $eid
                    ]
                ],
                [
                    [
                        'text' => '👥 Group',
                        'callback_data' => 'admin_stage_type:group:' . $eid
                    ]
                ],
                [
                    [
                        'text' => '🥉 Playoff',
                        'callback_data' => 'admin_stage_type:playoff:' . $eid
                    ]
                ],
                [
                    [
                        'text' => '🏆 Final',
                        'callback_data' =>
                            'admin_stage_type:final:' . $eid
                    ]
                ],
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' => 'admin_stages:' . $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (
    str_starts_with($state, 'admin_bracket_create:name:')
    && isAdmin($uid)
) {
    $stageId = (int) substr(
        $state,
        strlen('admin_bracket_create:name:')
    );

    if ($stageId <= 0) {
        setState($pdo, $uid, '');
        sendMessage(
            $chat_id,
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    $name = trim($text ?? '');

    if ($name === '') {
        sendMessage(
            $chat_id,
            '❌ نام Bracket نمی‌تواند خالی باشد.'
        );
        return;
    }

    if (mb_strlen($name) > 100) {
        sendMessage(
            $chat_id,
            '❌ نام Bracket نباید بیشتر از 100 کاراکتر باشد.'
        );
        return;
    }

    /*
     * بررسی وجود Stage
     */
    $st = $pdo->prepare("
        SELECT id, name, status
        FROM tournament_stages
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([$stageId]);

    $stage = $st->fetch(PDO::FETCH_ASSOC);

    if (!$stage) {
        setState($pdo, $uid, '');

        sendMessage(
            $chat_id,
            '❌ Stage پیدا نشد.'
        );

        return;
    }

    /*
     * فقط Stageهای قابل مدیریت
     */
    if (
        !in_array(
            $stage['status'],
            ['pending', 'active'],
            true
        )
    ) {
        setState($pdo, $uid, '');

        sendMessage(
            $chat_id,
            '❌ این Stage در وضعیت فعلی امکان ساخت Bracket ندارد.'
        );

        return;
    }

    setState(
        $pdo,
        $uid,
        'admin_bracket_create:participants:'
        . $stageId
        . ':'
        . base64_encode($name)
    );

    sendMessage(
        $chat_id,
        "🏟 <b>{$name}</b>\n\n"
        . "👥 تعداد شرکت‌کنندگان Bracket را وارد کنید.\n\n"
        . "مثال:\n"
        . "<code>48</code>"
    );

    return;
}

if (
    str_starts_with($state, 'admin_bracket_create:participants:')
    && isAdmin($uid)
) {
    $parts = explode(':', $state, 4);

    $stageId = (int) ($parts[2] ?? 0);
    $encodedName = $parts[3] ?? '';

    $name = base64_decode(
        $encodedName,
        true
    );

    $participantCount = (int) trim($text ?? '');

    if ($stageId <= 0 || $name === false) {
        setState($uid, '');

        sendMessage(
            $chat_id,
            '❌ اطلاعات ساخت Bracket نامعتبر است.'
        );

        return;
    }

    if ($participantCount < 2) {
        sendMessage(
            $chat_id,
            '❌ حداقل 2 شرکت‌کننده لازم است.'
        );

        return;
    }

    /*
     * حداکثر فعلاً 64
     * چون ساختار فعلی تست‌ها تا 64 را پوشش می‌دهد.
     */
    if ($participantCount > 64) {
        sendMessage(
            $chat_id,
            '❌ حداکثر ظرفیت فعلی Bracket برابر 64 نفر است.'
        );

        return;
    }

    /*
     * بررسی Stage
     */
    $st = $pdo->prepare("
        SELECT id, name, status
        FROM tournament_stages
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([$stageId]);

    $stage = $st->fetch(PDO::FETCH_ASSOC);

    if (!$stage) {
        setState($uid, '');

        sendMessage(
            $chat_id,
            '❌ Stage پیدا نشد.'
        );

        return;
    }

    /*
     * محاسبه اندازه واقعی Bracket
     *
     * 48 نفر → 64
     * 32 نفر → 32
     * 24 نفر → 32
     * ...
     */
    $bracketSize = 1;

    while ($bracketSize < $participantCount) {
        $bracketSize *= 2;
    }

    /*
     * جلوگیری از ساخت Bracket تکراری
     */
    $st = $pdo->prepare("
        SELECT id
        FROM tournament_brackets
        WHERE stage_id = ?
          AND name = ?
        LIMIT 1
    ");

    $st->execute([
        $stageId,
        $name
    ]);

    if ($st->fetch(PDO::FETCH_ASSOC)) {
        sendMessage(
            $chat_id,
            "❌ Bracket دیگری با نام <b>{$name}</b> "
            . "در این Stage وجود دارد."
        );

        return;
    }

    /*
     * ایجاد Bracket
     */
    try {

        $st = $pdo->prepare("
            INSERT INTO tournament_brackets (
                stage_id,
                name,
                type,
                status,
                participant_count
            )
            VALUES (
                ?,
                ?,
                'single_elimination',
                'pending',
                ?
            )
        ");

        $st->execute([
            $stageId,
            $name,
            $participantCount
        ]);

        $bracketId =
            (int) $pdo->lastInsertId();

    } catch (Throwable $e) {

        sendMessage(
            $chat_id,
            '❌ خطا هنگام ایجاد Bracket: '
            . '<code>'
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES,
                'UTF-8'
            )
            . '</code>'
        );

        return;
    }

    setState($uid, '');

    $byeCount =
        $bracketSize - $participantCount;

    sendMessage(
        $chat_id,
        "✅ <b>Bracket با موفقیت ساخته شد.</b>\n\n"
        . "🏟 نام: <b>{$name}</b>\n"
        . "🎯 Stage: <b>{$stage['name']}</b>\n"
        . "👥 شرکت‌کنندگان: <code>{$participantCount}</code>\n"
        . "📐 اندازه Bracket: <code>{$bracketSize}</code>\n"
        . "🆓 BYE: <code>{$byeCount}</code>\n"
        . "🏷 نوع: <code>single_elimination</code>\n"
        . "📊 وضعیت: <code>pending</code>\n"
        . "🆔 ID: <code>#{$bracketId}</code>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '🏟 مدیریت Bracket',
                        'callback_data' =>
                            'admin_bracket:' . $bracketId
                    ]
                ],
                [
                    [
                        'text' => '🔙 Bracketهای Stage',
                        'callback_data' =>
                            'admin_stage_brackets:' . $stageId
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($state, 'admin_stage_create:br_match_size:')) {

    $parts = explode(
        ':',
        $state,
        5
    );

    $eid =
        (int) ($parts[2] ?? 0);

    $encodedName =
        $parts[3] ?? '';

    $type =
        $parts[4] ?? '';

    $name = base64_decode(
        $encodedName,
        true
    );

    $matchSize =
        (int) trim($text);

    if (
        $eid <= 0
        || $name === false
        || $name === ''
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات Stage نامعتبر است.'
        );

        return;
    }

    if ($matchSize < 2) {
        sendMessage(
            $chat_id,
            '❌ تعداد بازیکنان باید حداقل 2 نفر باشد.'
        );
        return;
    }

    if ($matchSize > 48) {
        sendMessage(
            $chat_id,
            '❌ حداکثر ظرفیت Custom Room فعلی 48 نفر است.'
        );
        return;
    }

    setState(
        $pdo,
        $uid,
        'admin_stage_create:br_matches:' .
        $eid .
        ':' .
        base64_encode($name) .
        ':' .
        $type .
        ':' .
        $matchSize
    );

    sendMessage(
        $chat_id,
        "🎮 <b>تعداد بازی را مشخص کنید:</b>\n\n"
        . "چند Custom Room برای هر بازیکن برگزار می‌شود؟\n\n"
        . "مثال:\n"
        . "<code>3</code>"
    );

    return;
}

if (
    str_starts_with(
        $state,
        'admin_stage_create:br_matches:'
    )
) {
    $parts = explode(
        ':',
        $state,
        6
    );

    $eid =
        (int) ($parts[2] ?? 0);

    $encodedName =
        $parts[3] ?? '';

    $type =
        $parts[4] ?? '';

    $matchSize =
        (int) ($parts[5] ?? 0);

    $name = base64_decode(
        $encodedName,
        true
    );

    /*
     * اعتبارسنجی State
     */
    if (
        $eid <= 0
        || $name === false
        || $name === ''
        || $type === ''
        || $matchSize < 2
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات Battle Royale نامعتبر است.'
        );

        return;
    }

    /*
     * دریافت تعداد بازی
     */
    $matchesPerPlayer =
        (int) trim($text ?? '');

    if ($matchesPerPlayer < 1) {
        sendMessage(
            $chat_id,
            "❌ تعداد بازی باید حداقل <code>1</code> باشد.\n\n"
            . "مثال:\n"
            . "<code>3</code>"
        );

        return;
    }

    if ($matchesPerPlayer > 20) {
        sendMessage(
            $chat_id,
            '❌ تعداد بازی نمی‌تواند بیشتر از ۲۰ باشد.'
        );

        return;
    }

    if (
        !in_array(
            $type,
            [
                'qualification',
                'group',
                'playoff',
                'final'
            ],
            true
        )
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ نوع Stage نامعتبر است.'
        );

        return;
    }

    if ($type === 'final') {

        // Final صعودکننده ندارد.
        // مستقیم برو مرحله Scoring.

        setState(
            $pdo,
            $uid,
            'admin_stage_create:br_scoring:' .
            $eid .
            ':' .
            base64_encode($name) .
            ':' .
            $type .
            ':' .
            $matchSize .
            ':' .
            $matchesPerPlayer .
            ':champion:0'
        );

        sendMessage(
            $chat_id,
            "🧮 <b>سیستم امتیازدهی Final را انتخاب کنید:</b>\n\n"
            . "برای Free Fire Battle Royale پیشنهاد می‌شود:\n"
            . "🏆 Placement + Kills",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' =>
                                '🏆 Placement + Kills',
                            'callback_data' =>
                                'admin_stage_scoring:placement_kills:' .
                                $eid
                        ]
                    ],
                    [
                        [
                            'text' =>
                                '🎯 Score مستقیم',
                            'callback_data' =>
                                'admin_stage_scoring:default:' .
                                $eid
                        ]
                    ],
                    [
                        [
                            'text' =>
                                '❌ انصراف',
                            'callback_data' =>
                                'admin_stages:' . $eid
                        ]
                    ]
                ]
            ]
        );

        return;
    }

    /*
     * ذخیره تعداد بازی و رفتن به
     * انتخاب قانون صعود
     */
    setState(
        $pdo,
        $uid,
        'admin_stage_create:br_advancement:' .
        $eid .
        ':' .
        base64_encode($name) .
        ':' .
        $type .
        ':' .
        $matchSize .
        ':' .
        $matchesPerPlayer
    );

    sendMessage(
        $chat_id,
        "📈 <b>قانون صعود را انتخاب کنید:</b>\n\n"
        . "🏅 <b>Top N</b>\n"
        . "تعداد مشخصی از نفرات صعود می‌کنند.\n\n"
        . "📊 <b>Percentage</b>\n"
        . "درصد مشخصی از نفرات صعود می‌کنند.\n\n"
        . "🎯 <b>Points</b>\n"
        . "صعود بر اساس حد امتیاز.",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '🏅 Top N',
                        'callback_data' =>
                            'admin_stage_advancement:top_n:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' => '📊 Percentage',
                        'callback_data' =>
                            'admin_stage_advancement:percentage:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' => '🎯 Points',
                        'callback_data' =>
                            'admin_stage_advancement:points:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' =>
                            'admin_stages:' . $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (
    str_starts_with(
        $state,
        'admin_stage_create:br_advancement_count:'
    )
) {
    $parts = explode(
        ':',
        $state,
        8
    );

    $eid =
        (int) ($parts[2] ?? 0);

    $encodedName =
        $parts[3] ?? '';

    $type =
        $parts[4] ?? '';

    $matchSize =
        (int) ($parts[5] ?? 0);

    $matchesPerPlayer =
        (int) ($parts[6] ?? 0);

    $advancementType =
        $parts[7] ?? '';

    $name = base64_decode(
        $encodedName,
        true
    );

    if (
        $eid <= 0
        || $name === false
        || $name === ''
        || $type === ''
        || $matchSize < 2
        || $matchesPerPlayer < 1
        || !in_array(
            $advancementType,
            [
                'top_n',
                'percentage',
                'points',
            ],
            true
        )
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات Stage نامعتبر است.'
        );

        return;
    }

    $value =
        (float) trim(
            (string) ($text ?? '')
        );

    if ($value <= 0) {
        sendMessage(
            $chat_id,
            '❌ مقدار باید بیشتر از صفر باشد.'
        );
        return;
    }

    /*
     * تعداد کل شرکت‌کنندگان Stage
     *
     * برای Stage اولیه:
     * accepted event_players
     */
    $st = $pdo->prepare("
        SELECT COUNT(*)
        FROM event_players
        WHERE ev_id = ?
          AND status = 'accepted'
    ");

    $st->execute([
        $eid
    ]);

    $stageParticipantCount =
        (int) $st->fetchColumn();

    if ($stageParticipantCount < 2) {
        sendMessage(
            $chat_id,
            '❌ حداقل 2 شرکت‌کننده پذیرفته‌شده برای این Stage وجود ندارد.'
        );
        return;
    }

    /*
     * اعتبارسنجی بر اساس نوع صعود
     */
    if ($advancementType === 'top_n') {

        /*
         * Top N:
         * تعداد صعودکنندگان کل Stage
         *
         * نه ظرفیت یک Room
         */
        if (
            $value != floor($value)
            || (int) $value < 1
            || (int) $value > $stageParticipantCount
        ) {
            sendMessage(
                $chat_id,
                "❌ برای Top N باید یک عدد صحیح بین "
                . "<code>1</code> و "
                . "<code>{$stageParticipantCount}</code> وارد کنید."
            );
            return;
        }

        $advancementValue =
            (int) $value;

    } elseif (
        $advancementType === 'percentage'
    ) {

        if (
            $value <= 0
            || $value > 100
        ) {
            sendMessage(
                $chat_id,
                '❌ درصد صعود باید بین 1 و 100 باشد.'
            );
            return;
        }

        $advancementValue =
            $value;

    } else {

        /*
         * Points
         */
        $advancementValue =
            $value;
    }

    /*
     * ذخیره موقت اطلاعات کامل Stage
     */
    setState(
        $pdo,
        $uid,
        'admin_stage_create:br_scoring:' .
        $eid .
        ':' .
        base64_encode($name) .
        ':' .
        $type .
        ':' .
        $matchSize .
        ':' .
        $matchesPerPlayer .
        ':' .
        $advancementType .
        ':' .
        $advancementValue
    );

    /*
     * انتخاب Scoring Strategy
     */
    sendMessage(
        $chat_id,
        "🧮 <b>سیستم امتیازدهی را انتخاب کنید:</b>\n\n"
        . "👥 شرکت‌کنندگان Stage: "
        . "<code>{$stageParticipantCount}</code>\n"
        . "🏠 ظرفیت هر Room: "
        . "<code>{$matchSize}</code>\n"
        . "📈 قانون صعود: "
        . "<code>{$advancementType}</code>\n"
        . "🔢 مقدار صعود: "
        . "<code>{$advancementValue}</code>\n\n"
        . "برای Free Fire Battle Royale پیشنهاد می‌شود:\n"
        . "🏆 Placement + Kills",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' =>
                            '🏆 Placement + Kills',
                        'callback_data' =>
                            'admin_stage_scoring:placement_kills:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' =>
                            '🎯 Score مستقیم',
                        'callback_data' =>
                            'admin_stage_scoring:default:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' =>
                            '❌ انصراف',
                        'callback_data' =>
                            'admin_stages:' .
                            $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (
    str_starts_with(
        $state,
        'admin_br_result:placement:'
    )
) {
    $parts = explode(
        ':',
        $state,
        4
    );

    $roomId =
        (int) ($parts[2] ?? 0);

    $roomParticipantId =
        (int) ($parts[3] ?? 0);

    if (
        $roomId <= 0
        || $roomParticipantId <= 0
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات نتیجه نامعتبر است.'
        );
        return;
    }

    $placement =
        (int) trim($text ?? '');

    if ($placement < 1) {
        sendMessage(
            $chat_id,
            '❌ Placement باید حداقل 1 باشد.'
        );
        return;
    }

    /*
     * ظرفیت واقعی Room
     */
    $st = $pdo->prepare("
        SELECT capacity
        FROM tournament_br_rooms
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomId
    ]);

    $capacity =
        (int) $st->fetchColumn();

    if ($capacity < 1) {
        sendMessage(
            $chat_id,
            '❌ Room پیدا نشد.'
        );
        return;
    }

    if ($placement > $capacity) {
        sendMessage(
            $chat_id,
            "❌ Placement نمی‌تواند بیشتر از "
            . "<code>{$capacity}</code> باشد."
        );
        return;
    }

    /*
     * بررسی اینکه همین بازیکن در Room هست.
     */
    $st = $pdo->prepare("
        SELECT id
        FROM tournament_br_room_participants
        WHERE id = ?
          AND room_id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomParticipantId,
        $roomId
    ]);

    if ($st->fetchColumn() === false) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ بازیکن در این Room پیدا نشد.'
        );
        return;
    }

    /*
     * رفتن به Kills
     */
    setState(
        $pdo,
        $uid,
        'admin_br_result:kills:' .
        $roomId .
        ':' .
        $roomParticipantId .
        ':' .
        $placement
    );

    sendMessage(
        $chat_id,
        "🏅 Placement: <code>{$placement}</code>\n\n"
        . "🔫 <b>تعداد Kills را وارد کنید:</b>\n\n"
        . "اگر Kill نداشته، وارد کنید:\n"
        . "<code>0</code>"
    );

    return;
}

if (
    str_starts_with(
        $state,
        'admin_br_result:kills:'
    )
) {
    $parts = explode(
        ':',
        $state,
        5
    );

    $roomId =
        (int) ($parts[2] ?? 0);

    $roomParticipantId =
        (int) ($parts[3] ?? 0);

    $placement =
        (int) ($parts[4] ?? 0);

    if (
        $roomId <= 0
        || $roomParticipantId <= 0
        || $placement <= 0
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات نتیجه نامعتبر است.'
        );

        return;
    }

    $kills =
        (int) trim($text ?? '');

    if ($kills < 0) {
        sendMessage(
            $chat_id,
            '❌ تعداد Kills نمی‌تواند منفی باشد.'
        );
        return;
    }

    /*
    * محاسبه Score با Strategy رسمی پروژه
    */
    $scoringStrategy =
        new \Tournament\Scoring\PlacementKillsStrategy();

    $score =
        $scoringStrategy->calculateScore([
            'placement' => $placement,
            'kills' => $kills,
        ]);
        

    /*
     * بررسی Room و بازیکن
     */
    $st = $pdo->prepare("
        SELECT
            rp.id AS room_participant_id,
            rp.room_id,
            tp.id AS tournament_participant_id,
            r.status AS room_status,
            r.capacity
        FROM tournament_br_room_participants rp
        INNER JOIN tournament_br_rooms r
            ON r.id = rp.room_id
        INNER JOIN tournament_participants tp
            ON tp.id = rp.tournament_participant_id
        WHERE rp.id = ?
          AND rp.room_id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomParticipantId,
        $roomId
    ]);

    $player =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$player) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ بازیکن این Room پیدا نشد.'
        );

        return;
    }

    if (
        !in_array(
            $player['room_status'],
            ['active', 'completed'],
            true
        )
    ) {
        sendMessage(
            $chat_id,
            '❌ این Room هنوز برای ثبت نتیجه آماده نیست.'
        );
        return;
    }

    if (
        $placement > (int) $player['capacity']
    ) {
        sendMessage(
            $chat_id,
            '❌ Placement از ظرفیت Room بیشتر است.'
        );
        return;
    }

    /*
     * بررسی تکراری نبودن Placement
     */
    $st = $pdo->prepare("
        SELECT COUNT(*)
        FROM tournament_br_results
        WHERE room_id = ?
          AND placement = ?
          AND room_participant_id <> ?
    ");

    $st->execute([
        $roomId,
        $placement,
        $roomParticipantId
    ]);

    if ((int) $st->fetchColumn() > 0) {
        sendMessage(
            $chat_id,
            "❌ Placement <code>{$placement}</code> قبلاً "
            . "برای بازیکن دیگری ثبت شده است."
        );
        return;
    }

    /*
     * ثبت یا بروزرسانی نتیجه
     *
     * فعلاً score = 0
     * محاسبه امتیاز را در مرحله بعد
     * به Scoring Engine وصل می‌کنیم.
     */
    $st = $pdo->prepare("
        SELECT id
        FROM tournament_br_results
        WHERE room_id = ?
          AND room_participant_id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomId,
        $roomParticipantId
    ]);

    $resultId =
        $st->fetchColumn();

    if ($resultId !== false) {

        $st = $pdo->prepare("
            UPDATE tournament_br_results
            SET
                placement = ?,
                kills = ?,
                score = ?,
                status = 'confirmed',
                updated_at = NOW()
            WHERE id = ?
        ");

        $st->execute([
            $placement,
            $kills,
            $score,
            (int) $resultId
        ]);

    } else {

        $st = $pdo->prepare("
            INSERT INTO tournament_br_results (
                room_id,
                room_participant_id,
                tournament_participant_id,
                placement,
                kills,
                score,
                status
            )
            VALUES (?, ?, ?, ?, ?, ?, 'confirmed')
        ");

        $st->execute([
            $roomId,
            $roomParticipantId,
            (int) $player['tournament_participant_id'],
            $placement,
            $kills,
            $score
        ]);
    }

    $scoreText =
            rtrim(
                rtrim(
                    number_format(
                        $score,
                        2,
                        '.',
                        ''
                    ),
                    '0'
                ),
                '.'
            );

    setState(
        $pdo,
        $uid,
        ''
    );

    sendMessage(
            $chat_id,
            "✅ <b>نتیجه ثبت شد.</b>\n\n"
            . "🏅 Placement: <code>{$placement}</code>\n"
            . "🔫 Kills: <code>{$kills}</code>\n"
            . "🧮 Score: <code>{$scoreText}</code>"
    );

    /*
     * بازگشت به لیست نتایج Room
     */
    renderAdminBRRoomResults(
        $pdo,
        $chat_id,
        $mid,
        $roomId
    );

    return;
}

if (
    str_starts_with(
        $state,
        'admin_br_room_credentials_id:'
    )
) {
    $roomId = (int) substr(
        $state,
        strlen('admin_br_room_credentials_id:')
    );

    $roomGameId =
        trim(
            (string) ($text ?? '')
        );

    if ($roomId <= 0) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ شناسه Room نامعتبر است.'
        );

        return;
    }

    if ($roomGameId === '') {
        sendMessage(
            $chat_id,
            '❌ Room ID نمی‌تواند خالی باشد.'
        );

        return;
    }

    if (mb_strlen($roomGameId) > 100) {
        sendMessage(
            $chat_id,
            '❌ Room ID بیش از حد طولانی است.'
        );

        return;
    }

    setState(
        $pdo,
        $uid,
        'admin_br_room_credentials_pass:' .
        $roomId .
        ':' .
        base64_encode($roomGameId)
    );

    sendMessage(
        $chat_id,
        "🔐 <b>Password</b> مربوط به Custom Room را ارسال کنید."
    );

    return;
}

if (
    str_starts_with(
        $state,
        'admin_br_room_credentials_pass:'
    )
) {
    $parts = explode(
        ':',
        $state,
        3
    );

    $roomId =
        (int) ($parts[1] ?? 0);

    $encodedRoomGameId =
        $parts[2] ?? '';

    $roomGameId =
        base64_decode(
            $encodedRoomGameId,
            true
        );

    $roomPassword =
        trim(
            (string) ($text ?? '')
        );

    if (
        $roomId <= 0
        || $roomGameId === false
        || $roomGameId === ''
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات Room نامعتبر است.'
        );

        return;
    }

    if ($roomPassword === '') {
        sendMessage(
            $chat_id,
            '❌ Password نمی‌تواند خالی باشد.'
        );

        return;
    }

    if (mb_strlen($roomPassword) > 100) {
        sendMessage(
            $chat_id,
            '❌ Password بیش از حد طولانی است.'
        );

        return;
    }

    $st = $pdo->prepare("
        UPDATE tournament_br_rooms
        SET
            room_game_id = ?,
            room_password = ?
        WHERE id = ?
    ");

    $st->execute([
        $roomGameId,
        $roomPassword,
        $roomId
    ]);

    setState(
        $pdo,
        $uid,
        ''
    );

    sendMessage(
        $chat_id,
        "✅ <b>اطلاعات Custom Room ذخیره شد.</b>\n\n"
        . "🆔 ID: <code>"
        . htmlspecialchars(
            $roomGameId,
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        . "</code>\n"
        . "🔐 Password: <code>"
        . htmlspecialchars(
            $roomPassword,
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        . "</code>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' =>
                            '🏠 مشاهده Room',
                        'callback_data' =>
                            'admin_br_room:' .
                            $roomId
                    ]
                ]
            ]
        ]
    );

    return;
}

//================invite====================

if (str_starts_with($state, 'admin_invite_name:')) {

    $eid = (int)substr(
        $state,
        strlen('admin_invite_name:')
    );

    if ($eid <= 0) {
        sendMessage(
            $chat_id,
            '❌ ایونت نامعتبر است.'
        );
        exit;
    }

    $name = trim($text);

    if ($name === '') {
        sendMessage(
            $chat_id,
            '❌ نام دعوتنامه نمی‌تواند خالی باشد.'
        );
        exit;
    }

    if (mb_strlen($name, 'UTF-8') > 100) {
        sendMessage(
            $chat_id,
            '❌ نام دعوتنامه حداکثر باید ۱۰۰ کاراکتر باشد.'
        );
        exit;
    }

    // دریافت temp
    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$uid]);

    $temp = json_decode(
        $st->fetchColumn() ?: '{}',
        true
    );

    if (
        !is_array($temp) ||
        !isset($temp['invite']) ||
        !is_array($temp['invite']) ||
        (int)($temp['invite']['eid'] ?? 0) !== $eid
    ) {
        sendMessage(
            $chat_id,
            '❌ اطلاعات ساخت دعوتنامه پیدا نشد.'
        );

        setState($pdo, $uid, '');

        exit;
    }

    // ذخیره نام
    $temp['invite']['title'] = $name;

    // ذخیره کل temp بدون حذف اطلاعات قبلی
    $st = $pdo->prepare("
        UPDATE users
        SET temp = ?
        WHERE id = ?
    ");

    $st->execute([
        json_encode(
            $temp,
            JSON_UNESCAPED_UNICODE |
            JSON_UNESCAPED_SLASHES
        ),
        $uid
    ]);

    // برگشت به منوی ساخت دعوتنامه
    setState(
        $pdo,
        $uid,
        'admin_invite_create:' . $eid
    );

    // نمایش مجدد منو
    renderInviteCreateMenu(
        $pdo,
        $chat_id,
        null,
        $eid
    );

    exit;
}


if (str_starts_with($state, 'admin_invite_limit:')) {

    $eid = (int)substr(
        $state,
        strlen('admin_invite_limit:')
    );

    $limitText = trim($text);

    if (!preg_match('/^\d+$/', $limitText)) {

        sendMessage(
            $chat_id,
            "❌ مقدار نامعتبر است.\n\n"
            . "لطفاً فقط عدد ارسال کنید."
        );

        exit;
    }

    $limit = (int)$limitText;

    if ($limit > 1000000) {

        sendMessage(
            $chat_id,
            "❌ حداکثر محدودیت استفاده ۱,۰۰۰,۰۰۰ است."
        );

        exit;
    }

    // دریافت temp فعلی
    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$uid]);

    $tempRaw = $st->fetchColumn();

    $temp = json_decode(
        $tempRaw ?: '{}',
        true
    );

    if (!is_array($temp)) {
        $temp = [];
    }

    // بررسی Draft دعوتنامه
    if (
        !isset($temp['invite']) ||
        (int)($temp['invite']['eid'] ?? 0) !== $eid
    ) {

        sendMessage(
            $chat_id,
            '❌ اطلاعات ساخت دعوتنامه پیدا نشد. دوباره شروع کنید.'
        );

        setState($pdo, $uid, '');

        exit;
    }

    // ذخیره محدودیت
    $temp['invite']['usage_limit'] =
        $limit === 0 ? null : $limit;

    // ذخیره کل temp بدون حذف اطلاعات قبلی
    $st = $pdo->prepare("
        UPDATE users
        SET temp = ?
        WHERE id = ?
    ");

    $st->execute([
        json_encode(
            $temp,
            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
        ),
        $uid
    ]);

    // برگشت به state اصلی ساخت دعوتنامه
    setState(
        $pdo,
        $uid,
        'admin_invite_create:' . $eid
    );

    /*
     * ساخت دوباره منوی دعوتنامه
     */

    $invite = $temp['invite'];

    $joinText = !empty($invite['skip_force_join'])
        ? '🚫 رد عضویت اجباری ✅'
        : '🚫 رد عضویت اجباری ❌';

    $refText = !empty($invite['skip_referral'])
        ? '👥 رد رفرال ✅'
        : '👥 رد رفرال ❌';

    $titleText = !empty($invite['title'])
        ? $invite['title']
        : 'تعیین نشده';

    $limitDisplay = $invite['usage_limit'] === null
        ? '♾ نامحدود'
        : number_format((int)$invite['usage_limit']);

    $txt  = "📨 <b>ساخت دعوتنامه جدید</b>\n\n";
    $txt .= "🆔 ایونت: <code>{$eid}</code>\n\n";

    $txt .= "⚙️ <b>تنظیمات دعوتنامه</b>\n";
    $txt .= "🏷 نام: <b>" . htmlspecialchars(
        $titleText,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    ) . "</b>\n";

    $txt .= "🔐 عضویت اجباری: "
        . (!empty($invite['skip_force_join']) ? '❌ رد می‌شود' : '✅ الزامی')
        . "\n";

    $txt .= "👥 رفرال: "
        . (!empty($invite['skip_referral']) ? '❌ رد می‌شود' : '✅ الزامی')
        . "\n";

    $txt .= "🔢 محدودیت استفاده: <b>{$limitDisplay}</b>\n\n";

    $txt .= "تنظیمات موردنظر را انتخاب کنید.";

    $ik = [
        [
            [
                'text' => $joinText,
                'callback_data' => "admin_invite_toggle_join:{$eid}"
            ]
        ],
        [
            [
                'text' => $refText,
                'callback_data' => "admin_invite_toggle_referral:{$eid}"
            ]
        ],
        [
            [
                'text' => '📝 تعیین نام دعوتنامه',
                'callback_data' => "admin_invite_name:{$eid}"
            ]
        ],
        [
            [
                'text' => '🔢 تعیین محدودیت استفاده',
                'callback_data' => "admin_invite_limit:{$eid}"
            ]
        ],
        [
            [
                'text' => '✅ ساخت دعوتنامه',
                'callback_data' => "admin_invite_save:{$eid}"
            ]
        ],
        [
            [
                'text' => '❌ لغو',
                'callback_data' => "admin_invites:{$eid}"
            ]
        ],
    ];

    sendMessage(
        $chat_id,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );

    exit;
}

if (
    str_starts_with(
        $state,
        'admin_br_room_schedule:'
    )
) {

    $roomId =
        (int) substr(
            $state,
            strlen(
                'admin_br_room_schedule:'
            )
        );

    if ($roomId <= 0) {

        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات Room نامعتبر است.'
        );

        return;
    }

    $input =
        trim(
            (string) ($text ?? '')
        );

    /*
     * فرمت:
     *
     * 1405/06/15 18:30
     */
    if (
        !preg_match(
            '/^(\d{4})[\/\-](\d{1,2})[\/\-](\d{1,2})\s+(\d{1,2}):(\d{2})$/',
            $input,
            $matches
        )
    ) {

        sendMessage(
            $chat_id,
            "❌ فرمت تاریخ و ساعت صحیح نیست.\n\n"
            . "فرمت صحیح:\n"
            . "<code>1405/06/15 18:30</code>"
        );

        return;
    }

    $jy =
        (int) $matches[1];

    $jm =
        (int) $matches[2];

    $jd =
        (int) $matches[3];

    $hour =
        (int) $matches[4];

    $minute =
        (int) $matches[5];

    /*
     * اعتبارسنجی ساعت
     */
    if (
        $hour < 0
        || $hour > 23
        || $minute < 0
        || $minute > 59
    ) {

        sendMessage(
            $chat_id,
            '❌ ساعت واردشده نامعتبر است.'
        );

        return;
    }

    /*
     * تبدیل Jalali → Gregorian
     */
    try {

    $gregorian =
        jalali_to_gregorian(
            $jy,
            $jm,
            $jd
        );

    $gy = (int) $gregorian[0];
    $gm = (int) $gregorian[1];
    $gd = (int) $gregorian[2];

    } catch (Throwable $e) {

        sendMessage(
            $chat_id,
            "❌ تاریخ جلالی نامعتبر است.\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );

        return;
    }

    $scheduledAt =
        sprintf(
            '%04d-%02d-%02d %02d:%02d:00',
            $gy,
            $gm,
            $gd,
            $hour,
            $minute
        );

    /*
     * بررسی وجود Room
     */
    $st = $pdo->prepare("
        SELECT
            id,
            stage_id
        FROM tournament_br_rooms
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomId
    ]);

    $room =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$room) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ Room پیدا نشد.'
        );

        return;
    }

    $stageId =
        (int) $room['stage_id'];

    /*
     * ذخیره زمان میلادی
     */
    $st = $pdo->prepare("
        UPDATE tournament_br_rooms
        SET
            scheduled_at = ?
        WHERE id = ?
    ");

    $st->execute([
        $scheduledAt,
        $roomId
    ]);

    setState(
        $pdo,
        $uid,
        ''
    );

    /*
     * نمایش تأیید
     */
    sendMessage(
        $chat_id,
        "✅ <b>زمان Custom Room تنظیم شد.</b>\n\n"
        . "📅 تاریخ: <b>"
        . sprintf(
            '%04d/%02d/%02d',
            $jy,
            $jm,
            $jd
        )
        . "</b>\n"
        . "🕒 ساعت: <b>"
        . sprintf(
            '%02d:%02d',
            $hour,
            $minute
        )
        . "</b>\n\n"
        . "💾 زمان در دیتابیس به صورت میلادی ذخیره شد."
    );

    renderAdminBRRooms(
        $pdo,
        $chat_id,
        $mid,
        $stageId,
        true
    );

    return;
}

//================search====================

if (
    str_starts_with(
        $state,
        'admin_br_result_search:'
    )
) {
    $roomId = (int) substr(
        $state,
        strlen('admin_br_result_search:')
    );

    if ($roomId <= 0) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ شناسه Room نامعتبر است.'
        );

        return;
    }

    /*
     * متن جستجو
     */
    $query = trim(
        (string) ($text ?? '')
    );

    if ($query === '') {
        sendMessage(
            $chat_id,
            '❌ عبارت جستجو نمی‌تواند خالی باشد.'
        );

        return;
    }

    /*
     * State مخصوص Search
     *
     * این State برای Pagination استفاده می‌شود.
     */
    setState(
        $pdo,
        $uid,
        'admin_br_result_search_query:' .
        $roomId .
        ':' .
        $query
    );


    /*
     * صفحه اول نتایج
     */
    renderAdminBRSearchResults(
        $pdo,
        $chat_id,
        $mid,
        $uid,
        $roomId,
        $query,
        1,
        false
    );

    return;

}



}

// ---------------- UTIL ----------------
function showWelcome($pdo, $chat_id, $uid, $user, $isEdit = false, $mid = 0) {

    $totalEvents = (int)$pdo->query("SELECT COUNT(*) FROM events WHERE status='active'")->fetchColumn();
    $totalPlayers = (int)$pdo->query("SELECT COUNT(DISTINCT user_id) FROM event_players")->fetchColumn();


    $totalPrizes = '—';

    $txt = "<blockquote>👋 سلام " . htmlspecialchars($user['first_name'] ?? '') . " | رقابت کن و جایزه ببر 🔫</blockquote>\n\n";
    $txt .= "🏆 هوراد همین حالا در حال اجرای <b><code>{$totalEvents}</code></b> ایونته...\n";
    $txt .= "🎟 تاکنون <b><code>{$totalPlayers}</code></b> بازیکن در ایونت‌ها شرکت کردن.\n";
    $txt .= "<blockquote>💰 جمع جوایز پرداختی: <b>{$totalPrizes}</b></blockquote>\n\n";
    $txt .= "✹<i> Enter the Arena!</i>";



    $hdr = mainHeaderInline($user);


    if ($isEdit && $mid > 0) {
        editMessageText($chat_id, $mid, $txt, $hdr);
    } else {
        sendMessage($chat_id, $txt, $hdr);
    }

    setState($pdo, $uid, '');
}


function apiRequest(string $method, array $params = []) : array {
    $api_url = "https://api.telegram.org/bot" . env('BOT_TOKEN') . "/";
    $ch = curl_init($api_url . $method);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
    curl_setopt($ch, CURLOPT_TIMEOUT, 20);
    $res = curl_exec($ch);
    if ($res === false) { curl_close($ch); return ['ok'=>false,'error'=>'curl_error']; }
    curl_close($ch);
    $j = json_decode($res, true);
    return is_array($j) ? $j : ['ok'=>false,'raw'=>$res];
}

function logSecurityEvent($type, $data, $uid = null){
    $log = [
        'time' => date('c'),
        'type' => $type,
        'uid'  => $uid,
        'data' => $data,
        'ip'   => $_SERVER['REMOTE_ADDR'] ?? null,
        'ua'   => $_SERVER['HTTP_USER_AGENT'] ?? null
    ];

    file_put_contents(
        __DIR__ . '/security.log',
        json_encode($log, JSON_UNESCAPED_UNICODE) . PHP_EOL,
        FILE_APPEND
    );
}

function detectInjection($text){
    $patterns = [
        // script واقعی
        '/<script\b[^>]*>/i',

        // event handler ها
        '/onerror\s*=/i',
        '/onload\s*=/i',
        '/onclick\s*=/i',

        // javascript protocol
        '/javascript:/i',

        // SQL injection
        '/union\s+select/i',
        '/drop\s+table/i',
        '/insert\s+into/i',
        '/delete\s+from/i',

        // PHP tags
        '/<\?php/i',
    ];

    foreach ($patterns as $p) {
        if (preg_match($p, $text)) {
            return true;
        }
    }

    return false;
}

function sendMessage( $chat_id, $data, $reply_markup = null, PDO $pdo = null) {

    // ---------------------------
    // Escape فقط برای دیتاهای کاربر
    // ---------------------------
    $safe = function ($text) {
        return htmlspecialchars(
            (string)$text,
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        );
    };

    if (is_string($data)) {

        if (detectInjection($data)) {
            logSecurityEvent('INJECTION_ATTEMPT', $data, $chat_id);
        }
    }

    if (is_string($data)) {

        if (detectInjection($data)) {
            logSecurityEvent('INJECTION_ATTEMPT', $data, $chat_id);
        }
    }
    

    // ---------------------------
    // JSON keyboard
    // ---------------------------
    $encodeKeyboard = function ($markup) {
        return json_encode($markup, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    };

    // ---------------------------
    // media types
    // ---------------------------
    $mediaTypes = ['photo', 'video', 'animation', 'document', 'audio'];

    // ---------------------------
    // CASE 1: TEXT STRING
    // ---------------------------
    if (is_string($data)) {

        $params = [
            'chat_id' => $chat_id,
            'text' => $data, // ❗ مهم: دست نزن (HTML باید سالم بمونه)
            'parse_mode' => 'HTML',
            'disable_web_page_preview' => true
        ];

        if ($reply_markup) {
            $params['reply_markup'] = $encodeKeyboard($reply_markup);
        }

        return apiRequest('sendMessage', $params);
    }

    // ---------------------------
    // CASE 2: ARRAY INPUT
    // ---------------------------
    if (is_array($data)) {

        $detectedType = null;
        $mediaValue = null;

        foreach ($mediaTypes as $t) {
            if (!empty($data[$t])) {
                $detectedType = $t;
                $mediaValue = $data[$t];
                break;
            }
        }

        // ---------------------------
        // MEDIA MESSAGE
        // ---------------------------
        if ($detectedType) {

            // DB lookup (safe + optional)
            if (
                $pdo &&
                is_string($mediaValue) &&
                !preg_match('/^[A-Za-z0-9\-_]{20,}$/', $mediaValue)
            ) {
                $st = $pdo->prepare("SELECT file_id FROM gallery WHERE title = ? LIMIT 1");
                $st->execute([$mediaValue]);
                $found = $st->fetchColumn();

                if ($found) {
                    $mediaValue = $found;
                }
            }

            $map = [
                'photo' => 'sendPhoto',
                'video' => 'sendVideo',
                'animation' => 'sendAnimation',
                'document' => 'sendDocument',
                'audio' => 'sendAudio'
            ];

            $method = $map[$detectedType] ?? 'sendMessage';

            $params = [
                'chat_id' => $chat_id,
                $detectedType => $mediaValue,
                'parse_mode' => $data['parse_mode'] ?? 'HTML'
            ];

            // caption (اگر از کاربر میاد فقط اینجا safe میشه)
            if (!empty($data['caption'])) {
                $params['caption'] = $safe($data['caption']);
            }

            if ($reply_markup) {
                $params['reply_markup'] = $encodeKeyboard($reply_markup);
            }

            return apiRequest($method, $params);
        }

        // ---------------------------
        // TEXT INSIDE ARRAY
        // ---------------------------
        if (!empty($data['text'])) {

            $params = [
                'chat_id' => $chat_id,
                'text' => $data['text'], // ❗ مهم: HTML template خراب نشه
                'parse_mode' => $data['parse_mode'] ?? 'HTML',
                'disable_web_page_preview' => true
            ];

            if ($reply_markup) {
                $params['reply_markup'] = $encodeKeyboard($reply_markup);
            }

            return apiRequest('sendMessage', $params);
        }
    }

    // ---------------------------
    // ERROR
    // ---------------------------
    error_log('[sendMessage] Invalid data: ' . print_r($data, true));

    return [
        'ok' => false,
        'error' => 'Invalid message format'
    ];
}



function sendGif($chat_id, $media, $caption = '', $reply_markup = null, $parse_mode = 'HTML')
{
    global $bot_token, $pdo;

    // اگر ورودی File ID نیست، از دیتابیس پیدا کن
    if (!preg_match('/^[A-Za-z0-9\-_]{20,}$/', $media)) {
        $st = $pdo->prepare("SELECT file_id FROM gallery WHERE title = ? LIMIT 1");
        $st->execute([$media]);
        $found = $st->fetchColumn();

        if ($found) {
            $media = $found;
        } else {
            return false;
        }
    }

    $data = [
        'chat_id'    => $chat_id,
        'animation'  => $media,
        'caption'    => $caption,
        'parse_mode' => $parse_mode
    ];

    if ($reply_markup) {
        $data['reply_markup'] = $reply_markup;
    }

    $ch = curl_init("https://api.telegram.org/bot{$bot_token}/sendAnimation");
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data, JSON_UNESCAPED_UNICODE));
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

function editGif($chat_id, $message_id, $data, $reply_markup = null) {
    global $pdo;

    // 🟢 بررسی وجود media
    $media = $data['media'] ?? '';

    if (!$media) {
        return editMessageText(
            $chat_id,
            $message_id,
            $data['caption'] ?? '',
            $reply_markup
        );
    }

    if (!preg_match('/^[A-Za-z0-9\-_]{20,}$/', $media)) {
        $st = $pdo->prepare("SELECT file_id FROM gallery WHERE title = ? LIMIT 1");
        $st->execute([$media]);
        $found = $st->fetchColumn();

        if ($found) {
            $media = $found;
        } else {
            return editMessageText(
                $chat_id,
                $message_id,
                $data['caption'] ?? '',
                $reply_markup
            );
        }
    }

    // 🟢 آماده‌سازی آرایه media برای API
    $mediaArray = [
        'type' => 'animation',
        'media' => $media
    ];

    if (!empty($data['caption']))
        $mediaArray['caption'] = $data['caption'];

    if (!empty($data['parse_mode']))
        $mediaArray['parse_mode'] = $data['parse_mode'];
    else
        $mediaArray['parse_mode'] = 'HTML';

    // 🟢 پارامترهای نهایی
    $params = [
        'chat_id' => $chat_id,
        'message_id' => $message_id,
        'media' => json_encode($mediaArray, JSON_UNESCAPED_UNICODE)
    ];

    if ($reply_markup)
        $params['reply_markup'] = json_encode($reply_markup, JSON_UNESCAPED_UNICODE);

    // فراخوانی API تلگرام
    return apiRequest('editMessageMedia', $params, 'POST');
}



function editMessageText2($chat_id, $message_id, $text, $reply_markup = null, $forceDelete = false) {
    if ($forceDelete) {
        // حذف پیام قبلی
        apiRequest('deleteMessage', [
            'chat_id' => $chat_id,
            'message_id' => $message_id
        ]);

        // ارسال پیام جدید متنی
        $params = [
            'chat_id' => $chat_id,
            'text' => $text,
            'parse_mode' => 'HTML',
            'disable_web_page_preview' => true
        ];
        if ($reply_markup) $params['reply_markup'] = json_encode($reply_markup, JSON_UNESCAPED_UNICODE);

        return apiRequest('sendMessage', $params);
    }

    $params = [
        'chat_id' => $chat_id,
        'message_id' => $message_id,
        'text' => $text,
        'parse_mode' => 'HTML',
        'disable_web_page_preview' => true
    ];
    if ($reply_markup) $params['reply_markup'] = json_encode($reply_markup, JSON_UNESCAPED_UNICODE);

    return apiRequest('editMessageText', $params);
}


function editMessageText($chat_id, $message_id, $data, $reply_markup = null) {
    // اگر ورودی فقط متن باشه (همون رفتار قبلی editMessageText)
    if (is_string($data)) {
        $params = [
            'chat_id' => $chat_id,
            'message_id' => $message_id,
            'text' => $data,
            'parse_mode' => 'HTML',
            'disable_web_page_preview' => true
        ];
        if ($reply_markup)
            $params['reply_markup'] = json_encode($reply_markup, JSON_UNESCAPED_UNICODE);

        return apiRequest('editMessageText', $params);
    }

    // در غیر این صورت فرض می‌کنیم مدیا هست
    if (is_array($data) && isset($data['type']) && isset($data['media'])) {
        $media = [
            'type' => $data['type'],
            'media' => $data['media'],
        ];

        if (!empty($data['caption']))
            $media['caption'] = $data['caption'];

        if (!empty($data['parse_mode']))
            $media['parse_mode'] = $data['parse_mode'];

        $params = [
            'chat_id' => $chat_id,
            'message_id' => $message_id,
            'media' => json_encode($media, JSON_UNESCAPED_UNICODE)
        ];

        if ($reply_markup)
            $params['reply_markup'] = json_encode($reply_markup, JSON_UNESCAPED_UNICODE);

        return apiRequest('editMessageMedia', $params, 'POST');
    }

    // اگر هیچکدوم نباشه خطا لاگ بشه برای دیباگ
    error_log('[editMessage] Invalid data type: ' . print_r($data, true));
    return false;
}


function deleteMessage($chat_id, $message_id) {
    return apiRequest('deleteMessage', [
        'chat_id' => $chat_id,
        'message_id' => $message_id
    ]);
}

function answerCb($callback_id, $text = '', $show_alert = false) {
    return apiRequest('answerCallbackQuery', [
        'callback_query_id' => $callback_id,
        'text' => $text,
        'show_alert' => $show_alert ? 1 : 0
    ]);
}

function sendDocument($chat_id, $file_path, $caption=''){
    $params = ['chat_id'=>$chat_id,'caption'=>$caption];
    if (class_exists('CURLFile')) $params['document'] = new CURLFile($file_path); else $params['document'] = '@'.$file_path;
    return apiRequest('sendDocument', $params);
}

function sendContent($chat_id, $type, $caption, $file_id = null){
    switch ($type){
        case 'text': return sendMessage($chat_id, $caption);
        case 'photo': return sendPhoto($chat_id, $file_id, $caption);
        case 'video': return sendVideo($chat_id, $file_id, $caption);
        case 'document': return sendDocument($chat_id, $file_id, $caption);
    }
    return false;
}

function sendPhoto($chat_id, $file_id, $caption = '', $reply_markup = null) {
    $params = ['chat_id' => $chat_id, 'photo' => $file_id, 'caption' => $caption, 'parse_mode' => 'HTML'];
    if ($reply_markup) $params['reply_markup'] = json_encode($reply_markup);
    return apiRequest('sendPhoto', $params);
}

function getPhotoFileIdFromMessage(array $message): ?string {
    if (!empty($message['photo']) && is_array($message['photo'])) {
        $last = end($message['photo']);
        return $last['file_id'] ?? null;
    }
    return null;
}

function editMessageReplyMarkup($chat_id, $message_id, $reply_markup = null) {
    global $bot_token;
    $url = "https://api.telegram.org/bot$bot_token/editMessageReplyMarkup";
    $post_fields = [
        'chat_id' => $chat_id,
        'message_id' => $message_id,
        'reply_markup' => json_encode($reply_markup)
    ];
    return json_decode(file_get_contents($url."?".http_build_query($post_fields)), true);
}

function toSuperscript(int $num): string {
    $map = ['0'=>'⁰','1'=>'¹','2'=>'²','3'=>'³','4'=>'⁴','5'=>'⁵','6'=>'⁶','7'=>'⁷','8'=>'⁸','9'=>'⁹'];
    return implode('', array_map(fn($d) => $map[$d] ?? '', str_split((string)$num)));
}

function getAdminAction($uid) {
    global $pdo;
    $st = $pdo->prepare("SELECT * FROM admin_actions WHERE admin_id=? LIMIT 1");
    $st->execute([$uid]);
    return $st->fetch(PDO::FETCH_ASSOC);
}

function clearAdminAction($uid) {
    global $pdo;
    $st = $pdo->prepare("DELETE FROM admin_actions WHERE admin_id=?");
    $st->execute([$uid]);
}


function clean(string $s, int $max = 400) : string {
    $s = trim($s);
    $s = preg_replace('/\s+/u',' ',$s);
    if (mb_strlen($s,'UTF-8') > $max) $s = mb_substr($s,0,$max,'UTF-8');
    return $s;
}
function jenc($v){ return json_encode($v, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); }
function jdec($s){ $r = json_decode($s, true); return is_array($r) ? $r : []; }
function isAdmin(int $uid): bool {
    global $admin_ids;
    return in_array($uid, $admin_ids, true);
}
function now(){ return date('Y-m-d H:i:s'); }

function toJalali($dateTime) {
    if (empty($dateTime)) return '-';
    $timestamp = strtotime($dateTime);
    return jdate("Y/m/d H:i", $timestamp);
}


function toSuperscriptDate($text) {
    $map = [
        '0'=>'⁰','1'=>'¹','2'=>'²','3'=>'³','4'=>'⁴',
        '5'=>'⁵','6'=>'⁶','7'=>'⁷','8'=>'⁸','9'=>'⁹',
        '/'=>'˙','-'=>'˙','.'=>'·'
    ];
    return strtr($text, $map);
}



function handleSquadAccept($pdo, $chat_id, $uid, $eid, $leader_id) {
    if (eventStarted($pdo, $eid)) {
        sendMessage($chat_id, "⛔ ایونت شروع شده. امکان پذیرش وجود ندارد.");
        return;
    }

    $st = $pdo->prepare("SELECT ev_ids FROM users WHERE id=?");
    $st->execute([$uid]);
    $ev_ids = json_decode($st->fetchColumn(), true) ?? [];
    $alreadyJoined = in_array($eid, $ev_ids);

    $st = $pdo->prepare("SELECT game, entry_fee, players FROM events WHERE id=?");
    $st->execute([$eid]);
    $e = $st->fetch();
    if (!$e) {
        sendMessage($chat_id, "❌ ایونت یافت نشد.");
        return;
    }

    $game = $e['game'];

    $st = $pdo->prepare("SELECT games FROM users WHERE id=?");
    $st->execute([$uid]);
    $games = json_decode($st->fetchColumn(), true) ?? [];
    $ign = $games[$game]['ign'] ?? '';

    if (!$alreadyJoined && !$ign) {
        setState($pdo, $uid, "ign_Squadinput:$game:$eid");
        sendMessage($chat_id, "🎮 لطفاً نام داخل بازی (IGN) خود را برای بازی <b>$game</b> ارسال کنید:");
        return;
    }

    $squad = getSquad($pdo, $eid);
    $squad['leader_id'] = (int)$leader_id;
    $exists = array_filter($squad['members'] ?? [], fn($m) => $m['user_id'] == $uid);
    if (!$exists) {
        $squad['members'][] = [
            'user_id'   => $uid,
            'joined_at' => date('Y-m-d H:i:s'),
            'status'    => 'accepted'
        ];
        saveSquad($pdo, $eid, $squad);
    }

    if (!$alreadyJoined) {
        if ((int)$e['entry_fee'] > 0) {
            sendMessage($chat_id, "💳 این ایونت رایگان نیست. ثبت‌نام فعلاً امکان‌پذیر نیست.");
            return;
        }

        $player = [
            'user_id'    => $uid,
            'ign'        => $ign,
            'joined_at'  => date('Y-m-d H:i:s'),
            'paid'       => 1,
            'pay_method' => null,
            'pay_time'   => date('Y-m-d H:i:s'),
            'pay_meta'   => null
        ];

        $players = json_decode($e['players'], true) ?? [];
        $exists = array_filter($players, fn($p) => $p['user_id'] == $uid);
        if (!$exists) {
            $players[] = $player;
            $st = $pdo->prepare("UPDATE events SET players=? WHERE id=?");
            $st->execute([json_encode($players), $eid]);
        }

        $ev_ids[] = $eid;
        $ev_ids = array_unique($ev_ids);
        $st = $pdo->prepare("UPDATE users SET ev_ids=? WHERE id=?");
        $st->execute([json_encode($ev_ids), $uid]);
    }

    sendMessage($leader_id, "✅ کاربر <code>$uid</code> دعوت شما را پذیرفت.");
    sendMessage($chat_id, "✅ شما به اسکواد اضافه شدید.");
}

//-----------------manage users--------------------

function getUserList(PDO $pdo, string $filterType = 'all', string $filterValue = '', int $page = 0, int $limit = 10): array {
    $page = max(0, (int)$page);
    $limit = max(1, (int)$limit);
    $offset = $page * $limit;

    $where = '';
    $params = [];

    switch($filterType){
        case 'id':
            $where = 'WHERE id = ?';
            $params[] = (int)$filterValue;
            break;
        case 'username':
            $where = 'WHERE username LIKE ?';
            $params[] = "%$filterValue%";
            break;
        case 'ign':
            $where = 'WHERE JSON_EXTRACT(games, "$.*.ign") LIKE ?';
            $params[] = "%$filterValue%";
            break;
        case 'game_id':
            $where = 'WHERE JSON_CONTAINS(games, ? , "$.*.game_id")';
            $params[] = (int)$filterValue;
            break;
        case 'search':   // 👈 اضافه شد
            $where = 'WHERE username LIKE ? 
                      OR CAST(id AS CHAR) LIKE ? 
                      OR JSON_EXTRACT(games, "$.*.ign") LIKE ? 
                      OR JSON_EXTRACT(games, "$.*.game_id") LIKE ?';
            $params[] = "%$filterValue%";
            $params[] = "%$filterValue%";
            $params[] = "%$filterValue%";
            $params[] = "%$filterValue%";
            break;
        case 'all':
        default:
            $where = '';
            break;
    }

    $sql = "SELECT * FROM users $where ORDER BY created_at DESC LIMIT $limit OFFSET $offset";
    $st = $pdo->prepare($sql);
    $st->execute($params);

    return $st->fetchAll(PDO::FETCH_ASSOC);
}




//------------------winner-------------------------

// اضافه کردن امتیاز به جدول ranking
function addRankingPoints(PDO $pdo, int $userId, string $game, int $points) {
    // Ensure user exists in users table
    if (!getUser($pdo, $userId)) {
        ensureUserById($pdo, $userId);
    }

    // Try to update existing ranking row
    $st = $pdo->prepare("UPDATE ranking SET points = points + ? WHERE user_id = ? AND game = ?");
    $st->execute([$points, $userId, $game]);

    // If no row was updated, insert a new ranking row
    if ($st->rowCount() === 0) {
        $ins = $pdo->prepare("INSERT INTO ranking (user_id, game, points) VALUES (?, ?, ?)");
        $ins->execute([$userId, $game, $points]);
    }
}

// اضافه کردن برنده‌ها به ستون winners جدول events
function addWinnersToEvent(PDO $pdo, int $eventId, array $winnerIds): array {
    $prizes = getEventPrizes($pdo, $eventId);
    $prizeKeys = array_keys($prizes);
    $prizeAmounts = array_values($prizes);

    $uniqueWinnerIds = array_values(array_unique(array_map('intval', $winnerIds)));
    $rankedWinners = [];

    foreach ($uniqueWinnerIds as $index => $userId) {
        $entry = ['user_id' => $userId];

        if (isset($prizeKeys[$index])) {
            $entry['rank'] = $prizeKeys[$index];
        }

        if (isset($prizeAmounts[$index])) {
            $entry['prize'] = (int)$prizeAmounts[$index];
        }

        $rankedWinners[] = $entry;
    }

    $st = $pdo->prepare("UPDATE events SET winners = ? , status = ? WHERE id = ?");
    $st->execute([json_encode($rankedWinners, JSON_UNESCAPED_UNICODE), 'finished', $eventId]);
    return $rankedWinners;
}

function normalizeWinnerIds(array $winners): array {
    $ids = [];
    foreach ($winners as $item) {
        if (is_array($item) && isset($item['user_id'])) {
            $ids[] = (int)$item['user_id'];
        } else {
            $ids[] = (int)$item;
        }
    }
    return array_values(array_unique($ids));
}

function buildWinnerCongratulationText(array $event, array $winner): string {
    $eventName = !empty($event['name']) ? $event['name'] : 'ایونت';
    $gameName = !empty($event['game']) ? "🎮 {$event['game']}\n" : '';
    $rank = $winner['rank'] ?? null;
    $prize = isset($winner['prize']) ? number_format((int)$winner['prize']) . ' تومان' : null;

    $text = "<blockquote>🎉 <b>تبریک! </b>";
    $text .= "شما موفق شدید مقام ";
    if ($rank) {
        $text .= "<b>{$rank}</b> در رویداد «{$eventName}» را کسب کنید.</blockquote>\n\n";
    } else {
        $text .= "<b>برنده</b> در رویداد «{$eventName}» انتخاب شدید.</blockquote>\n\n";
    }

   /* if ($gameName) {
       $text .= $gameName;
    }
    */

    if ($prize) {
        $text .= "🏆 مبلغ جایزه: <b>{$prize}</b>\n";
    }

    $text .= "📌 برای دریافت جایزه، با برگزار کننده در ارتباط باشید.";
    return $text;
}

function sendWinnerCongratulation(PDO $pdo, int $userId, int $eventId, array $winner, array $event): void {
    $text = buildWinnerCongratulationText($event, $winner);

    $kb = [
        'inline_keyboard' => [[
            ['text' => '📌 اطلاعات ایونت', 'callback_data' => "ev_view:$eventId:$userId:false", 'style' => 'primary']
        ]]
    ];

    // Ensure user row exists before sending message
    ensureUserById($pdo, $userId);

    sendGif($userId, 'Cat - Hooraaa', $text);
}

// ----------------- Squad -----------------

function showSquad(PDO $pdo, int $eid, int $uid, int $chat_id, int $mid, bool $hadBanner) {
    // بررسی شروع ایونت
    if (eventStarted($pdo, $eid)) {
        $text = "⛔ ایونت شروع شده. امکان مدیریت اسکواد وجود ندارد.";
        $kb = [['inline_keyboard' => [[
            ['text' => '🔙 بازگشت', 'callback_data' => "ev_view:$eid:$uid:$hadBanner"]
        ]]]];
        if ($hadBanner) {
            deleteMessage($chat_id, $mid);
            sendMessage($chat_id, $text, $kb);
        } else {
            editMessageText($chat_id, $mid, $text, $kb);
        }
        return;
    }

    // گرفتن اسکواد کاربر
    $st = $pdo->prepare("
        SELECT s.id AS squad_id, s.leader_uid
        FROM event_squads s
        LEFT JOIN event_players p ON p.squad_id = s.id
        WHERE s.eid = ? AND (s.leader_uid = ? OR p.user_id = ?)
        GROUP BY s.id
        LIMIT 1
    ");
    $st->execute([$eid, $uid, $uid]);
    $userSquad = $st->fetch(PDO::FETCH_ASSOC);

    if (!$userSquad) {
        $text = "❌ شما در هیچ اسکوادی نیستید.";
        $kb = [['inline_keyboard' => [[
            ['text' => '🔙 بازگشت', 'callback_data' => "ev_view:$eid:$uid:$hadBanner"]
        ]]]];
        if ($hadBanner) {
            deleteMessage($chat_id, $mid);
            sendMessage($chat_id, $text, $kb);
        } else {
            editMessageText($chat_id, $mid, $text, $kb);
        }
        return;
    }

    $squadId = $userSquad['squad_id'];
    $leader = $userSquad['leader_uid'];
    $isLeader = ($uid == $leader);

    // گرفتن اعضای واقعی اسکواد
    $st = $pdo->prepare("
        SELECT p.user_id, p.ign, p.status, u.username, u.first_name
        FROM event_players p
        LEFT JOIN users u ON u.id = p.user_id
        WHERE p.squad_id = ?
    ");
    $st->execute([$squadId]);
    $members = $st->fetchAll(PDO::FETCH_ASSOC);

    // گرفتن دعوتنامه‌های pending
    $stInv = $pdo->prepare("
        SELECT id, invite_code, target_uid, status
        FROM event_invites
        WHERE squad_id = ? AND status = 'pending'
    ");
    $stInv->execute([$squadId]);
    $pendingInvites = $stInv->fetchAll(PDO::FETCH_ASSOC);

    $limit = getEventLimit($pdo, $eid);
    $acceptedCount = count($members); // فقط اعضای واقعی جز محدودیت

    // گرفتن نام لیدر
    $stLeader = $pdo->prepare("SELECT username FROM users WHERE id = ?");
    $stLeader->execute([$leader]);
    $leaderData = $stLeader->fetch(PDO::FETCH_ASSOC);
    $leaderName = $leaderData['username'] ? '@' . $leaderData['username'] : 'بدون نام';

    $capacity = toSuperscriptDate("$limit.$acceptedCount");
    $text = "<blockquote>🏕 <b>مدیریت اسکواد شما $capacity | 👑 $leaderName</b></blockquote>\n\n";
    $text .= "👇 برای مدیریت اعضا روی نام آن‌ها کلیک کنید:\n";

    $ik = [];

    // مرتب‌سازی اعضا: لیدر، خود کاربر، بقیه
    usort($members, function($a, $b) use ($uid, $leader) {
        if ($a['user_id'] == $leader) return -1;
        if ($b['user_id'] == $leader) return 1;
        if ($a['user_id'] == $uid) return -1;
        if ($b['user_id'] == $uid) return 1;
        return 0;
    });

    // اضافه کردن اعضای واقعی
    foreach ($members as $m) {
        $statusEmoji = match($m['status']) {
            'accepted' => '✅',
            'pending' => '⏳',
            'rejected' => '❌',
            default => '',
        };

        $prefix = '';
        if ($m['user_id'] == $leader) $prefix = '👑 ';
        elseif ($m['user_id'] == $uid) $prefix = '🧍 ';

        $displayName = htmlspecialchars($m['ign'] ?: $m['name'] ?: $m['username'] ?: "کاربر");
        $btnText = "$prefix$displayName $statusEmoji";

        if ($isLeader) {
            $ik[] = [['text' => $btnText, 'callback_data' => "squad_member:$eid:$uid:{$m['user_id']}"]];
        } else {
            $ik[] = [['text' => $btnText, 'callback_data' => "squad_none"]];
        }
    }

    // اضافه کردن دعوتنامه‌های pending
foreach ($pendingInvites as $inv) {
    $displayName = "دعوت"; // مقدار پیش‌فرض

    if (!empty($inv['target_uid'])) {
        // گرفتن بازی ایونت
        $stEvent = $pdo->prepare("SELECT game FROM events WHERE id = ?");
        $stEvent->execute([$eid]);
        $eventGame = $stEvent->fetchColumn();

        // گرفتن ign از جدول user_games مطابق با بازی
        $stUserGame = $pdo->prepare("
            SELECT ign 
            FROM user_games 
            WHERE user_id = ? AND game = ? 
            LIMIT 1
        ");
        $stUserGame->execute([$inv['target_uid'], $eventGame]);
        $userGameData = $stUserGame->fetch(PDO::FETCH_ASSOC);

        if ($userGameData && !empty($userGameData['ign'])) {
            $displayName = htmlspecialchars($userGameData['ign']);
        } else {
            // fallback به name یا username از جدول users
            $stUser = $pdo->prepare("SELECT first_name, username FROM users WHERE id = ?");
            $stUser->execute([$inv['target_uid']]);
            $userData = $stUser->fetch(PDO::FETCH_ASSOC);
            $displayName = $userData['first_name'] ?: $userData['username'] ?: "دعوت";
        }
    } elseif (!empty($inv['user_shared'])) {
        $displayName = htmlspecialchars($inv['user_shared']);
    }

    $status = strtolower($inv['status'] ?? '');

    $statusEmoji = match($status) {
        'pending' => '⏳',
        'accepted' => '✅',
        'rejected' => '❌',
        default => '',
    };
    $inviteBtnText = "$statusEmoji $displayName | در انتظار پیوستن";

    if ($isLeader) {
        $ik[] = [['text' => $inviteBtnText, 'callback_data' => "squad_invite_member:$eid:$uid:{$inv['id']}"]];
    } else {
        $ik[] = [['text' => $inviteBtnText, 'callback_data' => "squad_none"]];
    }
}

    // دکمه دعوت جدید (جز محدودیت)
    if ($isLeader && $acceptedCount < $limit) {
        $ik[] = [['text' => '➕ دعوت عضو جدید', 'callback_data' => "squad_invite:$eid:$uid"]];
    }

    // دکمه بازگشت
    $ik[] = [['text' => '🔙 بازگشت', 'callback_data' => "ev_view:$eid:$uid:$hadBanner"]];

    $kb = ['inline_keyboard' => $ik];

    if ($hadBanner) {
        deleteMessage($chat_id, $mid);
        sendMessage($chat_id, $text, $kb, 'HTML');
    } else {
        editMessageText($chat_id, $mid, $text, $kb, 'HTML');
    }
}


// ----------------- DEFAULT GAME -----------------
$row = $pdo->query("SELECT id, name FROM games WHERE is_default = 1 LIMIT 1")->fetch(PDO::FETCH_ASSOC);
$defaultGameId = $row ? (int)$row['id'] : 0;
$defaultGameName = $row ? $row['name'] : '';

// ----------------- USER HELPERS -----------------
function ensureUser(PDO $pdo, array $from, string $defaultGameName) : array {
    $id = (int)($from['id'] ?? 0);
    $first = htmlspecialchars(substr($from['first_name'] ?? '', 0, 128));
    $username = htmlspecialchars(substr($from['username'] ?? '', 0, 64));
    if ($id <= 0) return [];

    // چک کردن کاربر موجود
    $st = $pdo->prepare('SELECT * FROM users WHERE id=?'); 
    $st->execute([$id]); 
    $u = $st->fetch();

    if ($u) {
        $pdo->prepare('UPDATE users SET first_name=?, username=? WHERE id=?')->execute([$first, $username, $id]);
        $u['first_name'] = $first; 
        $u['username'] = $username;
        return $u;
    }
    $publicId = generatePublicId($pdo);

    $pdo->prepare(
        'INSERT INTO users(id, public_id, first_name, username, current_game, games)
        VALUES (?, ?, ?, ?, ?, JSON_OBJECT())'
    )->execute([$id, $publicId, $first, $username, $defaultGameName]);

    return [
        'id' => $id,
        'public_id' => $publicId,
        'first_name' => $first,
        'username' => $username,
        'state' => '',
        'current_game' => $defaultGameName,
        'games' => '{}'
    ];
}

function generatePublicId(PDO $pdo): string {
    do {
        $publicId = (string) random_int(1000000000, 9999999999); // 10 رقم

        $st = $pdo->prepare("SELECT 1 FROM users WHERE public_id=? LIMIT 1");
        $st->execute([$publicId]);

    } while ($st->fetchColumn());

    return $publicId;
}

function ensureUserById(PDO $pdo, int $id): ?array {
    global $defaultGameName;
    $id = (int)$id;
    if ($id <= 0) return null;

    $st = $pdo->prepare('SELECT * FROM users WHERE id=?');
    $st->execute([$id]);
    $u = $st->fetch(PDO::FETCH_ASSOC);
    if ($u) return $u;

    // Insert minimal user record
    $first = '';
    $username = '';
    $pdo->prepare('INSERT INTO users(id, first_name, username, current_game, games) VALUES (?, ?, ?, ?, JSON_OBJECT())')
        ->execute([$id, $first, $username, $defaultGameName]);

    return ['id' => $id, 'first_name' => $first, 'username' => $username, 'state' => '', 'current_game' => $defaultGameName, 'games' => '{}'];
}


function getUser(PDO $pdo, int $id): ?array {
    $st = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $st->execute([$id]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    return $row ?: null;
}


function clearState($pdo, $uid) {
    setState($pdo, $uid, '');
}

function setState($pdo, $uid, $state) {
    $stmt = $pdo->prepare("UPDATE users SET state = ? WHERE id = ?");
    $stmt->execute([$state, $uid]);
}

function getState($pdo, $uid) {
    $stmt = $pdo->prepare("SELECT state FROM users WHERE id = ?");
    $stmt->execute([$uid]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    return $row['state'] ?? null;
}

function farsiNumber($number) {
    $en = ['0','1','2','3','4','5','6','7','8','9'];
    $fa = ['۰','۱','۲','۳','۴','۵','۶','۷','۸','۹'];
    return str_replace($en, $fa, $number);
}


function getAllUsers($pdo) {
    $st = $pdo->query("SELECT id FROM users WHERE active=1");
    return $st->fetchAll();
}

function setCurrentGame(PDO $pdo, int $id, string $game) {
    if ($game !== '') {  // فقط اگر بازی معتبر باشه
        $pdo->prepare('UPDATE users SET current_game=? WHERE id=?')->execute([$game,$id]);
    }
}

function listGames(PDO $pdo, bool $activeOnly = true) {
    $q = $activeOnly 
        ? 'SELECT id, name FROM games WHERE active=1 ORDER BY name' 
        : 'SELECT id, name FROM games ORDER BY name';
    $rows = $pdo->query($q)->fetchAll();
    return array_map(fn($r) => ['id'=>$r['id'], 'name'=>$r['name']], $rows);
}

//------------------ticket system---------------

function getMediaGroupItems(PDO $pdo, $uid, $media_group_id = null) {
    $tmp_ticket_json = getState($pdo, $uid);
    if (!$tmp_ticket_json) return [];

    $tmp_ticket = json_decode($tmp_ticket_json, true);
    if (!isset($tmp_ticket['media'])) return [];

    // اگر media_group_id مشخص نیست، اولین گروه رو برمی‌گردون
    if ($media_group_id === null) {
        $firstGroup = reset($tmp_ticket['media']);
        return $firstGroup ?: [];
    }

    // اگر گروه مشخص شد
    return $tmp_ticket['media'][$media_group_id] ?? [];
}

function sendMediaGroup($chat_id, $media_array) {
    global $bot_token;
    $url = "https://api.telegram.org/bot$bot_token/sendMediaGroup";

    $params = [
        'chat_id' => $chat_id,
        'media'   => json_encode($media_array)
    ];

    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
    $res = curl_exec($ch);
    curl_close($ch);

    return json_decode($res, true);
}

//------------------Profile Game-------------------------

function renderProfileIGN( PDO $pdo, int $chat_id, int $mid, int $uid, bool $sendInstead = false, array $cb = []): void {

    // همه گیم‌ها
    $allGames = listGames($pdo);

    // گیم‌های کاربر
    $st = $pdo->prepare("
        SELECT id, game, ign, game_id, active
        FROM user_games
        WHERE user_id=?
    ");
    $st->execute([$uid]);

    $userGames = [];
    foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $userGames[$row['game']] = $row;
    }

    $rows = [];

    foreach ($allGames as $g) {

        $gameName = is_array($g)
            ? $g['name']
            : $g;

        $userGame = $userGames[$gameName] ?? null;

        $active = (int)($userGame['active'] ?? 0);

        $rows[] = [[
            'text' => ($active ? '🟢 ' : '🔴 ') . $gameName,
            'callback_data' => 'game_toggle:' . urlencode($gameName)
        ]];

        if ($active && $userGame) {

            $gameRowId = (int)$userGame['id'];

            $ignText = !empty($userGame['ign'])
                ? '🎖 ' . $userGame['ign']
                : '➕ تنظیم NAME';

            $idText = !empty($userGame['game_id'])
                ? '🆔 ' . $userGame['game_id']
                : '➕ تنظیم ID';

            $rows[] = [
                [
                    'text' => $ignText,
                    'callback_data' => "edit_ign_input:$gameRowId"
                ],
                [
                    'text' => $idText,
                    'callback_data' => "edit_gameid_input:$gameRowId"
                ]
            ];
        }
    }

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

    $text =
        "<b>🎮 مدیریت بازی‌های من</b>\n\n" .
        "<blockquote expandable>" .
        "روی هر بازی بزن تا فعال یا غیرفعال شود.\n" .
        "🟢 فعال\n" .
        "🔴 غیرفعال\n\n" .
        "برای بازی‌های فعال می‌تونی Nickname و ID ثبت کنی.\n" .
        "اگه قبلاً ثبت کردی، فقط کافیه روش بزنی تا تغییرش بدی.".
        "</blockquote>";

    $kb = [
        'inline_keyboard' => $rows
    ];

    if ($sendInstead) {
        sendMessage($chat_id, $text, $kb);
    } else {
        editMessageText($chat_id, $mid, $text, $kb);
    }

    if (!empty($cb)) {
        answerCb($cb['id'], '');
    }
}



// ----------------- UI HELPERS -----------------
function mainHeaderInline(array $user){
$game = $user['current_game'] ?? 'none';
$row = [
        [['text'=>'🔥 ایونت‌ها','callback_data'=>'events_list:all:0', 'style'=>'primary']],
        [['text'=>'👤 پروفایل','callback_data'=>'profile_show'], ['text'=>'🏆 رنکینگ','callback_data'=>'rank_view:' . urlencode($game) . ':0:all']],
        [['text'=>'💬 پشتیبانی / ریپورت','callback_data'=>'noop']]
        //ticket_menu

    ];


    if (!empty($user['id']) && isAdmin((int)$user['id'])) {
        $row[] = [['text'=>'🛠️ پنل ادمین','callback_data'=>'admin_panel']];
    }

    return ['inline_keyboard' => $row];
}

//-----------------manage squad--------------------

function eventStarted(PDO $pdo, int $eid): bool {
    require_once 'Helpers/jdf.php';

    $st = $pdo->prepare("SELECT date_str FROM events WHERE id=?");
    $st->execute([$eid]);
    $date = trim((string)$st->fetchColumn());

    if (!$date) return false;

    // اگر فرمت جلالی بود (یعنی شامل "/" است)
    if (str_contains($date, '/')) {
        $parts = explode('/', $date);
        if (count($parts) < 3) return false; // داده ناقصه
        list($jy, $jm, $jd) = $parts;
        list($gy, $gm, $gd) = jalali_to_gregorian((int)$jy, (int)$jm, (int)$jd);
    } 
    // اگر فرمت میلادیه
    else {
        [$gy, $gm, $gd] = explode('-', substr($date, 0, 10)); // 2025-10-15
    }

    $start_ts = strtotime("$gy-$gm-$gd 00:00"); // چون ساعت نداری
    return time() >= $start_ts;
}




function normalizeMandatoryJoinChannels(string $raw): array {
    $raw = trim($raw);
    if ($raw === '') {
        return [];
    }

    $decoded = json_decode($raw, true);
    if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
        if (array_key_exists('title', $decoded) || array_key_exists('chat_id', $decoded) || array_key_exists('invite', $decoded)) {
            $decoded = [$decoded];
        }

        $channels = [];
        foreach ($decoded as $item) {
            if (!is_array($item)) {
                continue;
            }

            $channel = [];
            if (isset($item['title']) && $item['title'] !== '') {
                $channel['title'] = (string)$item['title'];
            }
            if (isset($item['chat_id']) && $item['chat_id'] !== '') {
                $channel['chat_id'] = is_numeric((string)$item['chat_id']) ? (int)$item['chat_id'] : (string)$item['chat_id'];
            }
            if (isset($item['invite']) && $item['invite'] !== '') {
                $channel['invite'] = (string)$item['invite'];
            }
            if (isset($item['username']) && $item['username'] !== '') {
                $channel['username'] = (string)$item['username'];
            }

            if (!empty($channel)) {
                $channels[] = $channel;
            }
        }

        return $channels;
    }

    if (preg_match('/^@\w+$/', $raw)) {
        return [[
            'title' => 'کانال',
            'username' => $raw
        ]];
    }

    $lines = preg_split('/\r\n|\n|\r/', $raw);
    $nonEmptyLines = [];
    foreach ($lines as $line) {
        $line = trim($line);
        if ($line !== '') {
            $nonEmptyLines[] = $line;
        }
    }

    $channels = [];
    for ($i = 0; $i < count($nonEmptyLines); $i += 3) {
        $chunk = array_slice($nonEmptyLines, $i, 3);
        if (count($chunk) === 0) {
            continue;
        }

        $channel = [];
        if (isset($chunk[0]) && $chunk[0] !== '') {
            $channel['title'] = $chunk[0];
        }
        if (isset($chunk[1]) && $chunk[1] !== '') {
            $channel['chat_id'] = is_numeric($chunk[1]) ? (int)$chunk[1] : $chunk[1];
        }
        if (isset($chunk[2]) && $chunk[2] !== '') {
            $channel['invite'] = $chunk[2];
        }

        if (!empty($channel)) {
            $channels[] = $channel;
        }
    }

    return $channels;
}

function getSquad($pdo, $eid) {
    $stmt = $pdo->prepare("SELECT squad FROM events WHERE id=?");
    $stmt->execute([$eid]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    $squads = json_decode($row['squad'] ?? '[]', true);
    if (!is_array($squads)) $squads = [];

    return $squads; // همیشه آرایه‌ای از اسکوادها برمی‌گرده
}


function saveSquad(PDO $pdo, int $eid, array $squads) {
    $pdo->prepare("UPDATE events SET squad=? WHERE id=?")->execute([json_encode($squads, JSON_UNESCAPED_UNICODE), $eid]);
}

function getEventLimit(PDO $pdo, int $eid): int {
    $st = $pdo->prepare("SELECT `limit` FROM events WHERE id=?");
    $st->execute([$eid]);
    return (int)$st->fetchColumn();
}

function resolveUserIdFromTelegram(string $input, string $bot_token): ?int {
    $input = trim($input);

    // اگر ورودی عددی بود، مستقیماً برگردون
    if (is_numeric($input)) {
        return (int)$input;
    }

    // حذف @ از اول یوزرنیم
    $username = ltrim($input, '@');

    // --- روش ۱: Scrape از t.me ---
    $tmeUrl = "https://t.me/$username";
    $ctx = stream_context_create(['http' => ['timeout' => 5, 'user_agent' => 'Mozilla/5.0']]);
    $html = @file_get_contents($tmeUrl, false, $ctx);

    if ($html && preg_match('/tg:\/\/user\?id=(\d+)/', $html, $m)) {
        return (int)$m[1];
    }

    // --- روش ۲: Telegram Bot API ---
    $url = "https://api.telegram.org/bot$bot_token/getChat?chat_id=@$username";
    $res = json_decode(@file_get_contents($url), true);

    if (isset($res['ok']) && $res['ok'] && isset($res['result']['id'])) {
        return (int)$res['result']['id'];
    }

    // --- هیچ نتیجه‌ای ---
    return null;
}






// ---------------- winner selction ----------------
function getEventPlayers(PDO $pdo, int $eid): array
{
    $st = $pdo->prepare("
        SELECT 
            ep.user_id,
            ep.ign,
            ep.ig_id,
            u.first_name
        FROM event_players ep
        JOIN users u ON u.id = ep.user_id
        WHERE ep.ev_id = ?
          AND ep.status = 'accepted'
        ORDER BY ep.id ASC
    ");

    $st->execute([$eid]);
    $players = $st->fetchAll(PDO::FETCH_ASSOC);

    return $players ?: [];
}

// ---------- helpers using admin_actions table ----------
function getSelectionSession(PDO $pdo, int $eid, int $adminId) {
    $st = $pdo->prepare("SELECT payload FROM admin_actions WHERE admin_id=? AND action='event_selection' AND event_id=? LIMIT 1");
    $st->execute([$adminId, $eid]);
    $r = $st->fetch(PDO::FETCH_ASSOC);
    if (!$r || empty($r['payload'])) return null;
    $payload = json_decode($r['payload'], true);
    if (!is_array($payload)) return null;
    return [
        'selections' => $payload['selections'] ?? [],
        'status'     => $payload['status'] ?? 'open',
        'filtered'   => isset($payload['filtered_map']) ? $payload['filtered_map'] : null
    ];
}

function saveSelectionSession(PDO $pdo, int $eid, int $adminId, array $selections, string $status='open', $filteredMap = null) {
    $payload = [
        'selections' => array_values($selections),
        'status'     => $status,
        'filtered_map' => $filteredMap === null ? null : array_values($filteredMap)
    ];
    $json = json_encode($payload, JSON_UNESCAPED_UNICODE);

    // Insert or update row in admin_actions
    // Use ON DUPLICATE KEY UPDATE relying on unique index (admin_id, action, event_id)
    $st = $pdo->prepare("INSERT INTO admin_actions (admin_id, action, event_id, payload)
        VALUES (?, 'event_selection', ?, ?)
        ON DUPLICATE KEY UPDATE payload = VALUES(payload), updated_at = CURRENT_TIMESTAMP
    ");
    $st->execute([$adminId, $eid, $json]);
}

function deleteSelectionSession(PDO $pdo, int $eid, int $adminId) {
    $st = $pdo->prepare("DELETE FROM admin_actions WHERE admin_id=? AND action='event_selection' AND event_id=?");
    $st->execute([$adminId, $eid]);
}

function getEventPrizes(PDO $pdo, int $eid): array {
    $st = $pdo->prepare('SELECT prizes FROM events WHERE id = ? LIMIT 1');
    $st->execute([$eid]);
    $row = $st->fetch(PDO::FETCH_ASSOC);
    if (!$row) {
        return [];
    }

    $prizeJson = $row['prizes'] ?? $row['prize'] ?? null;
    if (empty($prizeJson)) {
        return [];
    }

    $prizes = json_decode($prizeJson, true);
    if (!is_array($prizes)) {
        return [];
    }

    return $prizes;
}

function formatAdminSelectionPlayerLabel(array $player, int $playerId): string {
    if (!empty($player['ign'])) {
        return "🎮 " . $player['ign'] . " (" . ($player['ig_id'] ?: '-') . ")";
    }
    return "👤 " . ($player['first_name'] ?? "Player #{$playerId}");
}

function filterAdminSelectionPlayers(array $players, ?array $filteredIds): array {
    if ($filteredIds === null) {
        return $players;
    }

    $filteredIds = array_map('intval', array_values($filteredIds));
    return array_values(array_filter($players, function ($player) use ($filteredIds) {
        return in_array((int)($player['user_id'] ?? 0), $filteredIds, true);
    }));
}

function buildAdminSelectionKeyboard(array $players, array $selections, int $eid, ?callable $callbackBuilder = null): array {
    $ik = [];
    $callbackBuilder = $callbackBuilder ?? function (array $player) use ($eid) {
        return "admin_toggle_2:$eid:" . (int)($player['user_id'] ?? 0);
    };

    foreach ($players as $p) {
        $playerId = (int)($p['user_id'] ?? 0);
        $display = formatAdminSelectionPlayerLabel($p, $playerId);
        $checked = in_array($playerId, $selections, true) ? '✅ ' : '';
        $ik[] = [[
            'text' => $checked . $display,
            'callback_data' => $callbackBuilder($p)
        ]];
    }

    $ik[] = [
        [ 'text' => '🔚 ثبت/اتمام', 'callback_data' => "admin_confirm:$eid" ],
        [ 'text' => '🔙 بازگشت',     'callback_data' => "admin_ev:$eid" ],
        [ 'text' => '🔎 جستجو',      'callback_data' => "admin_start_search:$eid" ]
    ];

    return $ik;
}

function buildAdminSelectionPrizeSummary(PDO $pdo, int $eid, array $selections, array $allPlayers): string {
    if (empty($selections)) {
        return "👥 هیچ برنده‌ای انتخاب نشده است.";
    }

    $playerLabels = [];
    foreach ($allPlayers as $p) {
        $uid = (int)($p['user_id'] ?? 0);
        $playerLabels[$uid] = formatAdminSelectionPlayerLabel($p, $uid);
    }

    $prizes = getEventPrizes($pdo, $eid);
    $prizeKeys = array_keys($prizes);
    $prizeAmounts = array_values($prizes);

    $lines = [];
    foreach ($selections as $index => $selectedUid) {
        $position = $index + 1;
        $playerLabel = $playerLabels[$selectedUid] ?? "کاربر #{$selectedUid}";
        if (isset($prizeAmounts[$index])) {
            $prizeLabel = $prizeKeys[$index];
            $prizeAmount = number_format($prizeAmounts[$index]);
            $lines[] = "برنده {$position}: {$playerLabel} — {$prizeLabel}: <code>{$prizeAmount}</code>";
        } else {
            $lines[] = "برنده {$position}: {$playerLabel} — <i>جایزه ندارد</i>";
        }
    }

    return "🎁 جوایز انتخاب‌شده:\n" . implode("\n", $lines);
}

function renderAdminSelectionMenu(PDO $pdo, int $chat_id, int $mid, int $eid, array $players, array $selections, string $text = null, array $allPlayers = []): void {
    $baseText = $text ?? "🎯 انتخاب برنده — رویداد #{$eid}\n\n👥 انتخاب‌شده‌ها: " . count($selections);
    $summaryPlayers = $allPlayers ?: $players;
    $summary = buildAdminSelectionPrizeSummary($pdo, $eid, $selections, $summaryPlayers);
    $fullText = $baseText . "\n\n" . $summary;
    $keyboard = buildAdminSelectionKeyboard($players, $selections, $eid);

    editMessageText($chat_id, $mid, $fullText, [
        'inline_keyboard' => $keyboard
    ]);
}

function toggleAdminSelection(PDO $pdo, int $eid, int $adminId, int $userId): array {
    $sess = getSelectionSession($pdo, $eid, $adminId) ?? ['selections' => [], 'status' => 'open', 'filtered' => null];
    $selections = $sess['selections'];

    $pos = array_search($userId, $selections, true);
    if ($pos === false) {
        $selections[] = $userId;
    } else {
        array_splice($selections, $pos, 1);
    }

    saveSelectionSession($pdo, $eid, $adminId, $selections, $sess['status'], $sess['filtered']);
    return $selections;
}

// ---------------- RENDERERS ----------------
function renderProfile(PDO $pdo, array $user) {
    $uid = $user['id'];
    $publicId = $user['public_id'] ?? '—';
    $txt = '';

    // گرفتن بازی‌های فعال کاربر از جدول user_games
    $st = $pdo->prepare("SELECT game, ign, game_id, active FROM user_games WHERE user_id=? AND active=1");
    $st->execute([$uid]);
    $gamesData = $st->fetchAll(PDO::FETCH_ASSOC);

    $cg = $user['current_game'] ?: '—';

    $st2 = $pdo->prepare("SELECT balance FROM wallets WHERE user_id=? LIMIT 1");
    $st2->execute([$uid]);
    $balance = $st2->fetchColumn();

    if ($balance === false) {
        $pdo->prepare("INSERT INTO wallets (user_id, balance) VALUES (?, 0)")
            ->execute([$uid]);
        $balance = 0;
    }

    // متن پروفایل
    $ID  = "<code>$publicId</code>";

    if (!$gamesData) {
        $txt .= "<b>❌ هیچ گیمی اضافه نشده</b>\n\n";
        $txt .= "<blockquote><b>ⁱ ʜᴏʀᴀᴅ ɪᴅ ⌁ $ID </b></blockquote>";
        $txt .= "<blockquote>برای اضافه کردن گیم‌، به منوی <b>🔮مدیریت بازی‌ها </b>برو .</blockquote>";
    } else {
        $txt .= "<blockquote>🕹️ <b>اطلاعات بازی‌ها </b></blockquote>\n";
        foreach ($gamesData as $o) {
            $g   = $o['game'];
            $ign = $o['ign'] ?: '— ثبت نشده —';
            $id  = $o['game_id'] ?: '— ثبت نشده —';

            $txt .= "• <b>$g</b>\n";
            $txt .= "   ├ NAME: <code>$ign</code>\n";
            $txt .= "   └ ID: <code>$id</code>\n\n";
        }

        $txt .= "<blockquote><b>ⁱ ʜᴏʀᴀᴅ ɪᴅ ⌁ $ID </b></blockquote>";
    }

    // کیبورد
    $kb = [
        'inline_keyboard' => [
            [
                ['text'=>'🔮 مدیریت بازی‌ها','callback_data'=>'user_games'],
                ['text'=>'🗂️ ایونت‌های من','callback_data'=>'events_list:all:0:false:true']
            ],
            [
                ['text'=>'💰 کیف پول','callback_data'=>'noop']
                //wallet_main
            ],
            [['text'=>'🔙 بازگشت','callback_data'=>'home']]
        ]
    ];

    return [$txt, $kb];
}

function handleForceReferralRequirement(PDO $pdo, int $chat_id, int $mid, array $cb, int $uid, int $eid, array $event, string $bot_username): bool {
    $requiredRef = (int)($event['require_referral'] ?? 0);
    if ($requiredRef <= 0) {
        return true;
    }

    $st = $pdo->prepare(
        "SELECT COUNT(*) FROM referral_starts WHERE referrer_id = ? AND event_id = ? AND status = 'valid'"
    );
    $st->execute([$uid, $eid]);
    $validRefCount = (int)$st->fetchColumn();

    if ($validRefCount >= $requiredRef) {
        return true;
    }

    $refData = generateReferralLink($pdo, $bot_username, $uid, $eid);

    $msg = "<b>🏆 شرط حضور در ایونت</b>\n\n" .
        "👥 دعوت‌های تأییدشده: {$validRefCount} / {$requiredRef}\n" .
        "<blockquote expandable>🎯 برای تکمیل ثبت‌نام در این ایونت، باید حداقل <code>{$requiredRef}</code> نفر را از طریق لینک اختصاصی خود دعوت کنید.\n
        📨 لینک دعوت شما ساخته شده است. آن را برای دوستان خود ارسال کنید و از آن‌ها بخواهید روی لینک کلیک کرده و ربات را با همان لینک استارت کنند.\n
        ⚠️ تنها کاربرانی محاسبه می‌شوند که از لینک اختصاصی شما وارد ربات شوند؛ ارسال لینک به تنهایی بدون استارت کردن ربات توسط کاربر، ثبت نخواهد شد.</blockquote>";

    $shareUrl = 'https://t.me/share/url?url=' . rawurlencode($refData['link']) . '&text=' . rawurlencode(''); 

    $kb = [
        'inline_keyboard' => [
            [
                [
                    'text' => '📋 کپی لینک',
                    'copy_text' => [ 'text' => $refData['link'] ],
                    'style' => 'success'
                ],
                [
                    'text' => '📤 اشتراک‌گذاری',
                    'url' => $shareUrl,
                    'style' => 'primary'
                ]
            ],
            [
                [ 'text' => '🔄 بررسی وضعیت', 'callback_data' => "refresh_ev_join:$eid:$uid:1"],
                [ 'text' => '🔙 بازگشت', 'callback_data' => "ev_view:$eid" ]
            ]
        ]
    ];

    RegistrationProgress::setStep( $pdo, $eid, $uid, 'referral');

    editMessageText2($chat_id, $mid, $msg, $kb, true);
    if (isset($cb['id'])) {
        answerCb($cb['id'], '👥 شرط رفرال فعال است', true);
    }

    return false;
}

function processEventJoinRequest(
    PDO $pdo,
    int $chat_id,
    int $mid,
    array $cb,
    int $uid,
    int $eid,
    bool $hadBanner,
    string $bot_username,
    ?array $invite = null
): void {

    global $bot_token;

    // =========================================================
    // دریافت اطلاعات ایونت
    // =========================================================

    $st = $pdo->prepare("
        SELECT
            entry_fee,
            private_channel,
            require_referral,
            require_ign,
            require_game_id,
            require_private_channel,
            require_global_channel,
            game_code,
            game,
            type,
            deadline
        FROM events
        WHERE id = ?
    ");

    $st->execute([$eid]);
    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {

        if (isset($cb['id'])) {
            answerCb(
                $cb['id'],
                '❌ ایونت پیدا نشد.',
                true
            );
        } else {
            sendMessage(
                $chat_id,
                '❌ ایونت پیدا نشد.'
            );
        }

        return;
    }

    // =========================================================
    // بررسی deadline ایونت
    // =========================================================

    if (
        !empty($event['deadline']) &&
        strtotime($event['deadline']) <= time()
    ) {

        $msg = '❌ مهلت ثبت‌نام در این ایونت به پایان رسیده است.';

        if (!empty($cb['id'])) {

            answerCb(
                $cb['id'],
                $msg,
                true
            );

        } else {

            sendMessage(
                $chat_id,
                $msg
            );
        }

        return;
    }


    // =========================================================
    // اگر دعوتنامه جدید داریم، آن را برای ادامه مراحل ذخیره کن
    // =========================================================

    if ($invite !== null) {

        $st = $pdo->prepare("
            SELECT temp
            FROM users
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([$uid]);

        $temp = json_decode(
            $st->fetchColumn() ?: '{}',
            true
        );

        if (!is_array($temp)) {
            $temp = [];
        }

        $temp['event_registration_invite'] = [
            'id'       => (int)$invite['id'],
            'event_id' => $eid
        ];

        $st = $pdo->prepare("
            UPDATE users
            SET temp = ?
            WHERE id = ?
        ");

        $st->execute([
            json_encode(
                $temp,
                JSON_UNESCAPED_UNICODE |
                JSON_UNESCAPED_SLASHES
            ),
            $uid
        ]);
    }


    // =========================================================
    // اگر دعوتنامه از ورودی فعلی نیامده، از temp بازیابی کن
    // =========================================================

    if ($invite === null) {

        $st = $pdo->prepare("
            SELECT temp
            FROM users
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([$uid]);

        $temp = json_decode(
            $st->fetchColumn() ?: '{}',
            true
        );

        if (is_array($temp)) {

            $inviteId = (int)(
                $temp['event_registration_invite']['id'] ?? 0
            );

            $inviteEventId = (int)(
                $temp['event_registration_invite']['event_id'] ?? 0
            );

            if (
                $inviteId > 0 &&
                $inviteEventId === $eid
            ) {

                $st = $pdo->prepare("
                    SELECT *
                    FROM event_registration_invites
                    WHERE id = ?
                      AND event_id = ?
                      AND is_active = 1
                    LIMIT 1
                ");

                $st->execute([
                    $inviteId,
                    $eid
                ]);

                $invite = $st->fetch(PDO::FETCH_ASSOC) ?: null;
            }
        }
    }


    // =========================================================
    // شروط دعوتنامه
    // =========================================================

    $skipForceJoin = (
        $invite !== null &&
        (int)($invite['skip_force_join'] ?? 0) === 1
    );

    $skipReferral = (
        $invite !== null &&
        (int)($invite['skip_referral'] ?? 0) === 1
    );


    // =========================================================
    // بررسی ثبت نام قبلی
    // =========================================================

    $st = $pdo->prepare("
        SELECT status
        FROM event_players
        WHERE user_id = ?
          AND ev_id = ?
        LIMIT 1
    ");

    $st->execute([
        $uid,
        $eid
    ]);

    $player = $st->fetch(PDO::FETCH_ASSOC);

    if (
        $player &&
        in_array(
            $player['status'],
            ['accepted', 'pending', 'queue'],
            true
        )
    ) {

        [$t, $kb, $banner] =
            renderEventView(
                $pdo,
                $eid,
                $uid
            );

        if (!empty($cb['id'])) {

            answerCb(
                $cb['id'],
                '⚠️ قبلاً در این ایونت ثبت‌نام کرده‌اید.'
            );

        } else {

            sendMessage(
                $chat_id,
                '⚠️ قبلاً در این ایونت ثبت‌نام کرده‌اید.'
            );

            if ($banner) {

                sendPhoto(
                    $chat_id,
                    $banner,
                    $t,
                    $kb
                );

            } else {

                sendMessage(
                    $chat_id,
                    $t,
                    $kb
                );
            }
        }

        return;
    }


    // =========================================================
    // پرداخت
    // =========================================================

    if ((int)$event['entry_fee'] > 0) {

        $pay_kb = [
            'inline_keyboard' => [[
                [
                    'text' => '📩 ارسال رسید',
                    'callback_data' => 'pay_notify:' . $eid . ':card'
                ],
                [
                    'text' => '🔙 بازگشت',
                    'callback_data' => 'events_list:' . $event['type'] . ':0'
                ]
            ]]
        ];

        $msg = '✅ پیش‌ثبت‌نام شما انجام شد؛ لطفاً جهت تکمیل، رسید پرداختی خود را ارسال کنید.';

        if ($mid > 0) {

            editMessageText(
                $chat_id,
                $mid,
                $msg,
                $pay_kb
            );

        } else {

            sendMessage(
                $chat_id,
                $msg,
                $pay_kb
            );
        }

        if (!empty($cb['id'])) {
            answerCb(
                $cb['id'],
                '✅ پیش‌ثبت‌نام انجام شد'
            );
        }

        RegistrationProgress::setStep(
            $pdo,
            $eid,
            $uid,
            'payment'
        );

        return;
    }


    // =========================================================
    // عضویت اجباری
    // =========================================================

    if (
        !$skipForceJoin &&
        (
            (int)$event['require_private_channel'] === 1 ||
            (int)$event['require_global_channel'] === 1
        )
    ) {

        $privateChannels =
            json_decode(
                $event['private_channel'] ?? '[]',
                true
            ) ?: [];

        $globalChannels = [];

        $st = $pdo->prepare("
            SELECT value
            FROM settings
            WHERE `key` = 'force_channels'
            LIMIT 1
        ");

        $st->execute();

        $forceChannels = $st->fetchColumn();

        if ($forceChannels) {

            $decoded = json_decode(
                $forceChannels,
                true
            );

            if (is_array($decoded)) {
                $globalChannels = $decoded;
            }
        }

        $allChannels = array_merge(
            $privateChannels,
            $globalChannels
        );

        $kb = buildForceJoinKeyboard(
            $bot_token,
            $uid,
            json_encode(
                $allChannels,
                JSON_UNESCAPED_UNICODE |
                JSON_UNESCAPED_SLASHES
            ),
            $eid
        );

        $file_id = 'Two Cat - Poker Face';

        if ($kb !== null) {

            if ($mid > 0) {

                editGif(
                    $chat_id,
                    $mid,
                    [
                        'media' => $file_id,
                        'caption' => '⚠️ ابتدا عضو کانال‌های زیر شوید.',
                        'parse_mode' => 'HTML'
                    ],
                    $kb
                );

            } else {

                sendMessage(
                    $chat_id,
                    '⚠️ ابتدا عضو کانال‌های زیر شوید.',
                    $kb
                );
            }

            if (!empty($cb['id'])) {
                answerCb($cb['id'], '');
            }

            RegistrationProgress::setStep(
                $pdo,
                $eid,
                $uid,
                'force_join'
            );

            return;
        }
    }


    // =========================================================
    // رفرال
    // =========================================================

    if (!$skipReferral) {

        if (
            !handleForceReferralRequirement(
                $pdo,
                $chat_id,
                $mid,
                $cb,
                $uid,
                $eid,
                $event,
                $bot_username
            )
        ) {
            return;
        }
    }


    // =========================================================
    // IGN / Game ID
    // =========================================================

    if (
        !checkEventProfileRequirements(
            $pdo,
            $chat_id,
            $mid,
            $cb,
            $uid,
            $eid,
            $event,
            (int)($event['game_code'] ?? 0)
        )
    ) {
        return;
    }


    // =========================================================
    // ثبت نهایی
    // =========================================================

    RegistrationProgress::complete(
        $pdo,
        $eid,
        $uid
    );

    $res = userJoinEvent(
        $pdo,
        $uid,
        $eid
    );

    if (!$res['ok']) {

        if (isset($cb['id'])) {

            answerCb(
                $cb['id'],
                $res['msg'],
                true
            );

        } else {

            sendMessage(
                $chat_id,
                $res['msg']
            );
        }

        return;
    }


    // =========================================================
    // مصرف دعوتنامه
    // =========================================================

    if (
        $invite !== null &&
        !empty($invite['id'])
    ) {

        $st = $pdo->prepare("
            UPDATE event_registration_invites
            SET used_count = used_count + 1
            WHERE id = ?
              AND is_active = 1
              AND (
                  usage_limit IS NULL
                  OR used_count < usage_limit
              )
        ");

        $st->execute([
            (int)$invite['id']
        ]);


        // حذف invite از temp
        $st = $pdo->prepare("
            SELECT temp
            FROM users
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([$uid]);

        $temp = json_decode(
            $st->fetchColumn() ?: '{}',
            true
        );

        if (is_array($temp)) {

            unset(
                $temp['event_registration_invite']
            );

            $st = $pdo->prepare("
                UPDATE users
                SET temp = ?
                WHERE id = ?
            ");

            $st->execute([
                json_encode(
                    $temp,
                    JSON_UNESCAPED_UNICODE |
                    JSON_UNESCAPED_SLASHES
                ),
                $uid
            ]);
        }
    }


    // =========================================================
    // نمایش نتیجه
    // =========================================================

    [$t, $kb, $banner] =
        renderEventView(
            $pdo,
            $eid,
            $uid
        );

    if (!empty($cb['id'])) {

        answerCb(
            $cb['id'],
            '✅ شما در این ایونت ثبت‌نام شدید.'
        );
    }

    if ($mid > 0) {

        if ($banner) {

            $media = [
                'type' => 'photo',
                'media' => $banner,
                'caption' => $t,
                'parse_mode' => 'HTML'
            ];

            editMessageText(
                $chat_id,
                $mid,
                $media,
                $kb
            );

        } else {

            editMessageText(
                $chat_id,
                $mid,
                $t,
                $kb
            );
        }

    } else {

        if ($banner) {

            sendPhoto(
                $chat_id,
                $banner,
                $t,
                $kb
            );

        } else {

            sendMessage(
                $chat_id,
                $t,
                $kb
            );
        }
    }
}

function tryAutoRegisterReferrer(
    PDO $pdo,
    int $referrerId,
    int $eventId,
    string $botUsername = ''
): void {

    // ==============================
    // اطلاعات ایونت
    // ==============================

    $st = $pdo->prepare("
        SELECT
            COALESCE(require_referral, 0) AS require_referral
        FROM events
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([$eventId]);

    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        error_log(
            "AUTO REF REGISTER | Event not found | Event: {$eventId}"
        );
        return;
    }

    $requiredReferrals = (int)$event['require_referral'];

    error_log(
        "AUTO REF REGISTER | Referrer: {$referrerId} | Event: {$eventId} | Required: {$requiredReferrals}"
    );

    // ==============================
    // تعداد رفرال‌های معتبر
    // ==============================

    $st = $pdo->prepare("
        SELECT COUNT(*)
        FROM referral_starts
        WHERE event_id = ?
          AND referrer_id = ?
          AND status = 'valid'
    ");

    $st->execute([
        $eventId,
        $referrerId
    ]);

    $validReferrals = (int)$st->fetchColumn();

    error_log(
        "AUTO REF REGISTER | Valid referrals: {$validReferrals}"
    );

    // هنوز تعداد رفرال کامل نشده
    if ($validReferrals < $requiredReferrals) {
        return;
    }

    // ==============================
    // جلوگیری از اجرای مجدد
    // ==============================

    $st = $pdo->prepare("
        SELECT status
        FROM event_players
        WHERE user_id = ?
          AND ev_id = ?
        LIMIT 1
    ");

    $st->execute([
        $referrerId,
        $eventId
    ]);

    $player = $st->fetch(PDO::FETCH_ASSOC);

    if (
        $player &&
        in_array(
            $player['status'],
            ['accepted', 'pending', 'queue'],
            true
        )
    ) {
        error_log(
            "AUTO REF REGISTER | Already registered | Referrer: {$referrerId}"
        );

        return;
    }

    // ==============================
    // حد نصاب کامل شد
    // ==============================

    error_log(
        "AUTO REF REGISTER | START REGISTERING REFERRER | User: {$referrerId}"
    );

    processEventJoinRequest(
        $pdo,
        $referrerId,     // chat_id
        0,               // mid
        [],              // callback
        $referrerId,     // uid
        $eventId,
        false,
        $botUsername
    );

    error_log(
        "AUTO REF REGISTER | processEventJoinRequest FINISHED | User: {$referrerId}"
    );
}

function checkEventProfileRequirements( PDO $pdo,int $chat_id,int $mid, array $cb, int $uid, int $eid, array $event, int $game_code): bool {

    $needIgn    = !empty($event['require_ign']);
    $needGameId = !empty($event['require_game_id']);

    if (!$needIgn && !$needGameId) {
        return true;
    }

    // گرفتن یا ساخت رکورد بازی کاربر
    $st = $pdo->prepare("
        SELECT id, ign, game_id
        FROM user_games
        WHERE user_id = ?
        AND game_code = ?
        LIMIT 1
    ");
    $st->execute([$uid, $game_code]);

    $ug = $st->fetch(PDO::FETCH_ASSOC);

    if (!$ug) {

        $st = $pdo->prepare("
            INSERT INTO user_games
            (user_id, game_code, game, active)
            VALUES (?, ?, ?, 0)
        ");

        $st->execute([
            $uid,
            $game_code,
            $event['game']
        ]);

        $ug = [
            'id'      => (int)$pdo->lastInsertId(),
            'ign'     => '',
            'game_id' => ''
        ];
    }

    $userGameId = (int)$ug['id'];

    $ignMissing =
        $needIgn &&
        trim((string)($ug['ign'] ?? '')) === '';

    $gameIdMissing =
        $needGameId &&
        trim((string)($ug['game_id'] ?? '')) === '';

    if (!$ignMissing && !$gameIdMissing) {
        return true;
    }

    $rows = [[
        [
            'text' => '🔙 بازگشت',
            'callback_data' => "ev_view:$eid:$uid:false"
        ]
    ]];

    $g = htmlspecialchars($event['game']);

    // اول IGN
    if ($ignMissing) {

        setState(
            $pdo,
            $uid,
            "ign_input:$userGameId:true:$eid"
        );

        $msg  = "<blockquote>🎮 بازی انتخاب‌شده: <b>{$g}</b></blockquote>\n\n";
        $msg .= "📝 لطفاً نام درون بازی (Nickname) خود را ارسال کنید.";

        RegistrationProgress::setStep( $pdo, $eid, $uid, 'ign');

        editMessageText2(
            $chat_id,
            $mid,
            $msg,
            ['inline_keyboard' => $rows],
            true
        );

        if (!empty($cb['id'])) {
            answerCb($cb['id'], '');
        }

        return false;
    }

    // بعد Game ID
    if ($gameIdMissing) {

        setState(
            $pdo,
            $uid,
            "gameid_input:$userGameId:true:$eid"
        );

        $msg  = "<blockquote>🎮 بازی انتخاب‌شده: <b>{$g}</b></blockquote>\n\n";
        $msg .= "🆔 لطفاً شناسه بازی (Game ID) خود را ارسال کنید.";

        RegistrationProgress::setStep( $pdo, $eid, $uid, 'game_id');

        editMessageText2(
            $chat_id,
            $mid,
            $msg,
            ['inline_keyboard' => $rows],
            true
        );

        if (!empty($cb['id'])) {
            answerCb($cb['id'], '');
        }

        return false;
    }

    return true;
}

function processEventGetCredentials(PDO $pdo, int $chat_id, int $uid, int $eid, string $check = 'both'){

    $st = $pdo->prepare('SELECT id_pass, name FROM events WHERE id=?');
    $st->execute([$eid]);
    $row = $st->fetch(PDO::FETCH_ASSOC);

    if (!$row) {
        sendMessage($chat_id, '❌ ایونت پیدا نشد.');
        return;
    }

    $idPass = json_decode($row['id_pass'] ?? '[]', true);

    $id   = trim($idPass['id'] ?? '');
    $pass = trim($idPass['pass'] ?? '');
    $name = trim($row['name'] ?? 'ایونت');

    $lines = [];
    $row = [];

    array_unshift($lines, "<blockquote>📜 اطلاعات ایونت $name</blockquote>\n");

    // ================= ID =================
    if (($check === 'id' || $check === 'both')) {
        if (empty($id)) {
            sendMessage($chat_id, '❌ شناسه بازی ثبت نشده است.');
            return;
        }

        $lines[] = '✶ Room ID: <code>' . htmlspecialchars($id) . '</code>';

        $row[] = [
            'text' => '🆔 آیدی',
            'copy_text' => ['text' => $id],
            'style' => 'primary'
        ];
    }

    // ================= PASS =================
    if (($check === 'pass' || $check === 'both')) {
        if (empty($pass)) {
            sendMessage($chat_id, '❌ رمز عبور بازی ثبت نشده است.');
            return;
        }

        $lines[] = '✶ Password: <code>' . htmlspecialchars($pass) . '</code>';

        $row[] = [
            'text' => '🔑 رمز',
            'copy_text' => ['text' => $pass],
            'style' => 'primary'
        ];
    }

    $buttons = [$row];


    return [
        'text' => implode("\n", $lines),
        'inline_keyboard' => $buttons
    ];
}



function buildGamesToggleKbTemp(PDO $pdo, int $uid)
{
    $all = listGames($pdo);

    $st = $pdo->prepare("
        SELECT game, active
        FROM user_games
        WHERE user_id=?
    ");
    $st->execute([$uid]);

    $userGames = $st->fetchAll(PDO::FETCH_KEY_PAIR);

    $rows = [];

    foreach ($all as $g) {

        $gName = is_array($g)
            ? $g['name']
            : $g;

        $active = (int)($userGames[$gName] ?? 0);

        $rows[] = [[
            'text' => ($active ? '🟢 ' : '🔴 ') . $gName,
            'callback_data' => 'game_toggle:' . urlencode($gName)
        ]];
    }

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

    return [
        'inline_keyboard' => $rows
    ];
}






function renderEventsList(PDO $pdo, string $type, int $page = 0, int $uid = 0, array $selectedGameIds = [], bool $joined = false): array {
    $limit = 16;
    $offset = $page * $limit;
    $user = getUser($pdo, $uid);
    $st = $pdo->prepare("SELECT ev_id FROM event_players WHERE user_id=? AND status='accepted'");
    $st->execute([$uid]);
    $joinedIds = $st->fetchAll(PDO::FETCH_COLUMN); 

    $games = $pdo->query("SELECT id, name FROM games ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC) ?: [];
    $gameIdToName = array_column($games, 'name', 'id');
    $gameNameToId = array_flip($gameIdToName);
    $selectedGameNames = [];
    $selectedGameIdsNormalized = [];
    foreach ($selectedGameIds as $gameKey) {
        if (isset($gameIdToName[$gameKey])) {
            $selectedGameIdsNormalized[] = (string)$gameKey;
            $selectedGameNames[] = $gameIdToName[$gameKey];
        } elseif (isset($gameNameToId[$gameKey])) {
            $selectedGameIdsNormalized[] = (string)$gameNameToId[$gameKey];
            $selectedGameNames[] = $gameKey;
        }
    }
    $selectedGameIds = array_values(array_unique($selectedGameIdsNormalized));

    // --- شمارش ایونت‌ها بر اساس بازی ---
    $eventCounts = [];
    if ($joined && !empty($joinedIds)) {
        $placeholders = implode(',', array_fill(0, count($joinedIds), '?'));
        $stmt = $pdo->prepare("
            SELECT game, COUNT(*) AS cnt
            FROM events
            WHERE id IN ($placeholders) AND status IN ('active','finished')
            GROUP BY game
        ");
        $stmt->execute($joinedIds);
        $eventCounts = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
    } elseif (!$joined) {
        $stmt = $pdo->prepare("
            SELECT game, COUNT(*) AS cnt
            FROM events
            WHERE status='active' AND type=?
            GROUP BY game
        ");
        $stmt->execute([$type]);
        $eventCounts = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
    }

    // --- دکمه‌های فیلتر بازی‌ها ---
    $filterButtons = [];
    foreach ($games as $g) {
        $count = $eventCounts[$g['name']] ?? 0;
        if ($count <= 0) {
            continue;
        }

        $active = in_array((string)$g['id'], $selectedGameIds, true);
        $sup = mb_convert_kana(strtr((string)$count, [
            '0'=>'⁰','1'=>'¹','2'=>'²','3'=>'³','4'=>'⁴','5'=>'⁵','6'=>'⁶','7'=>'⁷','8'=>'⁸','9'=>'⁹'
        ]));

        $button = [
            'text' => ($active ? '🎮 ' : '🎮 ') . $g['name'] . " " . $sup,
            'callback_data' => 'events_filter:' . $g['id'] . ':' . $type . ':' . implode(',', $selectedGameIds) . ':' . ($joined ? 'true' : 'false')
        ];
        if ($active) {
            $button['style'] = 'success';
        }

        $filterButtons[] = $button;
    }

    $filterIk = count($filterButtons) > 1 ? [$filterButtons] : [];

    // --- ساخت کوئری ایونت‌ها ---
    $rows = [];
    $cnt = 0;
    $conditions = [];
    $params = [];

    if ($joined && !empty($joinedIds)) {
        $conditions[] = "id IN (" . implode(',', array_fill(0, count($joinedIds), '?')) . ")";
        $params = array_merge($params, $joinedIds);
        $conditions[] = "status IN ('active','finished')";
    } elseif (!$joined) {

        $conditions[] = "status='active'";

        if ($type !== 'all') {
            $conditions[] = "type=?";
            $params[] = $type;
        }
    }

    if (!empty($selectedGameNames)) {
        $conditions[] = "game IN (" . implode(',', array_fill(0, count($selectedGameNames), '?')) . ")";
        $params = array_merge($params, $selectedGameNames);
    }

    if (!empty($conditions)) {
        $sql = "SELECT SQL_CALC_FOUND_ROWS * FROM events WHERE " . implode(' AND ', $conditions) . " ORDER BY id DESC LIMIT $limit OFFSET $offset";
        $stmt = $pdo->prepare($sql);
        $stmt->execute($params);
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        $cnt = (int)($pdo->query('SELECT FOUND_ROWS() AS c')->fetch()['c'] ?? 0);
    }

    // --- متن توضیحی ---
    $hasMore = ($offset + count($rows)) < $cnt;
    $titleText = match ($type) {
        'tournament' => 'تورنومنت‌ها',
        'all'        => 'همه ایونت‌ها',
        default      => 'کاستوم‌ها',
    };

    $title = $joined
        ? "📜 <b>ایونت‌های من</b>"
        : "📋 <b>لیست {$titleText}</b>";

    // بخش نمایش بازی‌های انتخاب‌شده
    $gamesText = "";
    if (!empty($selectedGameNames)) {
        $gamesText = "🎮 <b>" . implode(', ', $selectedGameNames) . "</b>\n\n";
    }

    // بخش توضیحات
    if ($joined) {
        $description = !empty($selectedGameNames)
            ? "<blockquote>فقط ایونت‌هایی که در آن عضو هستید نمایش داده می‌شوند. برای مشاهده جزئیات روی نام هر ایونت کلیک کنید.</blockquote>"
            : "<blockquote>ایونت‌هایی که عضو هستید در اینجا نمایش داده می‌شوند. از لیست بالا می‌توانید بر اساس بازی فیلتر کنید.</blockquote>";
    } else {
        $description = !empty($selectedGameNames)
            ? "<blockquote>برای مشاهده جزئیات هر ایونت، روی نام آن کلیک کنید. می‌توانید بازی‌های بیشتری فیلتر کنید.</blockquote>"
            : "<blockquote>از فهرست بالا یک یا چند بازی را انتخاب کنید تا ایونت‌های مربوطه نمایش داده شوند.</blockquote>";
    }

    // مونتاژ نهایی متن
    $text = $title . "\n\n" . $gamesText . $description;


    // --- دکمه‌های ایونت‌ها ---
    $ik = [];

    for ($i = 0; $i < count($rows); $i++) {

        $r = $rows[$i];
        $prizeText = '';

        if (!empty($r['prizes'])) {

            $prizes = json_decode($r['prizes'], true);

            if (is_array($prizes)) {

                $totalPrize = 0;

                foreach ($prizes as $prize) {

                    if (is_array($prize)) {
                        $totalPrize += max(0, (int)($prize['value'] ?? 0));
                    } elseif (is_numeric($prize)) {
                        $totalPrize += max(0, (int)$prize);
                    }
                }

                if ($totalPrize > 0) {
                    $prizeText = ' | 💰 ' . number_format($totalPrize);
                }
            }
        }

        $label = ($r['type'] === 'tournament' ? '🏆 ' : '🎯 ')
            //. $r['game']. ' ⌁ ' 
            . ($r['name'] ?: 'بدون نام')
            . $prizeText;

        $ik[] = [[
            'text' => $label,
            'callback_data' => 'ev_view:' . $r['id'] . ':' . $uid . ':' . ($joined ? 'true' : 'false')
        ]];
    }

    if (empty($rows) && !empty($selectedGameNames)) {
        $ik[] = [[
            'text' => '❗️هیچ ایونتی یافت نشد',
            'callback_data' => 'noop'
        ]];
    }

    // --- صفحه‌بندی ---
    $pagination = [];
    if ($page > 0) {
        $pagination[] = [
            'text' => '⬅️ قبلی',
            'callback_data' => 'events_list:' . $type . ':' . ($page - 1) . ':' . implode(',', $selectedGames)
        ];
    }
    if ($hasMore) {
        $pagination[] = [
            'text' => 'بعدی ➡️',
            'callback_data' => 'events_list:' . $type . ':' . ($page + 1) . ':' . implode(',', $selectedGames)
        ];
    }
    if (!empty($pagination)) {
        $ik[] = $pagination;
    }

    $ik[] = [[
        'text' => '🔙 بازگشت', 
        'callback_data' => $joined ? 'profile_show':'home' 
    ]];

    return [$text, ['inline_keyboard' => array_merge($filterIk, $ik)]];
}

function toEventTimeText(string $eventDateTime): string {
    $now = time();
    $eventTime = strtotime($eventDateTime);
    $diff = $eventTime - $now;

    if ($diff < 60) { // کمتر از 1 دقیقه
        return '';
    } elseif ($diff < 3600) { // کمتر از 1 ساعت
        $mins = floor($diff / 60);
        return $mins . ' دقیقه';
    } elseif ($diff < 86400) { // کمتر از 24 ساعت
        $hours = floor($diff / 3600);
        $mins = floor(($diff % 3600) / 60);
        return $hours . ' ساعت' . ($mins > 0 ? ' و ' . $mins . ' دقیقه' : '');
    } elseif ($diff < 172800) { // بین 24 تا 48 ساعت
        return 'فردا';
    } elseif ($diff < 604800) { // کمتر از یک هفته
        $days = floor($diff / 86400);
        return $days . ' روز';
    } elseif ($diff < 2419200) { // کمتر از یک ماه (4 هفته)
        $weeks = floor($diff / 604800);
        return $weeks . ' هفته';
    } else { // بیشتر از یک ماه
        $months = floor($diff / 2419200);
        return $months . ' ماه';
    }
}

function isUserInEventStatus(PDO $pdo, int $uid, int $eid, string $status): bool {
    $st = $pdo->prepare('
        SELECT 1 
        FROM event_players 
        WHERE user_id=? AND ev_id=? AND status=? 
        LIMIT 1
    ');
    $st->execute([$uid, $eid, $status]);

    return (bool)$st->fetchColumn();
}




function renderEventView(PDO $pdo, int $eid, int $uid, bool $joined = false){
    $st = $pdo->prepare('SELECT * FROM events WHERE id=?');
    $st->execute([$eid]);
    $e = $st->fetch(PDO::FETCH_ASSOC);

    setstate($pdo, $uid,'');

    if (!$e) {
        return ['❌ رویداد پیدا نشد.', [
            'inline_keyboard' => [
                [['text'=>'🔙 بازگشت','callback_data'=>'events_home']]
            ]
        ], null];
    }

    $userJoined   = isUserInEventStatus($pdo, $uid, $eid, 'accepted');
    $userInQueue  = isUserInEventStatus($pdo, $uid, $eid, 'queue');

    $registrationDeadlinePassed = (
        !empty($e['deadline']) &&
        strtotime($e['deadline']) <= time()
    );


    // تعداد یونیک بازیکن‌ها
    $st = $pdo->prepare('SELECT COUNT(DISTINCT user_id) FROM event_players WHERE ev_id=? and status= ?');
    $st->execute([$eid, 'accepted']);
    $count = (int)$st->fetchColumn();

    $hasBanner = !empty($e['banner']) ? 1 : 0;
    $joinedTxt = '';

    if ($userJoined) {
        $joinedTxt = ' | ✅ شما ثبت‌نام کرده‌اید';
    }

    if ($userInQueue) {
        $joinedTxt = ' | ⚠️ شما در صف انتظار هستید';
    }

    // متن اصلی
    $modeName = '';
    switch ((int)$e['limit']){
        case 1: $modeName = 'Solo Mode'; break;
        case 2: $modeName = 'Duo Mode'; break;
        case 3: $modeName = 'Trio Mode'; break;
        case 4: $modeName = 'Squad Mode'; break;
    }

    $txt = "🏷 <b><code>#{$e['id']}</code> | {$e['name']}</b>\n\n";
    $txt .= "<blockquote>👥 <b>ظرفیت:</b> {$count}/{$e['capacity']} نفر{$joinedTxt}</blockquote>\n";
    $startDateTime = explode(' ', toJalali($e['date_str']), 2);
    $date = $startDateTime[0] ?? toJalali($e['date_str']);
    $time = $startDateTime[1] ?? '';
    $remainingText = toEventTimeText($e['date_str']);
    $txt .= "📆 <b>تاریخ شروع: </b> $date" . ($time ? " 🕒 $time" : "") . " \n";
    if ($e['deadline'] && strtotime($e['deadline']) > time()) {
        $deadlineDateTime = explode(' ', toJalali($e['deadline']), 2);
        $d = $deadlineDateTime[0] ?? toJalali($e['deadline']);
        $t = $deadlineDateTime[1] ?? '';
        $txt .= "⏳ <b>مهلت ثبت‌نام: </b> $d" . ($t ? " 🕒 $t" : "") . "\n";
    }
    $txt .= ($remainingText ? "<blockquote><b> {$remainingText} دیگه ․ ․ ․</b></blockquote>" : "") . "\n";
    $txt .= "🎮 <b>بازی:</b> {$e['game']}";
    if ($modeName) $txt .= " ({$modeName})";
    $txt .= "\n";
    $txt .= $e['entry_fee']>0 
        ? "💰 <b>ورودی:</b> <code>" . number_format($e['entry_fee']) . " تومان</code>\n"
        : "💸 <b>ورودی:</b> رایگان\n";

    if (!empty($e['prizes'])) {

        $prizes = json_decode($e['prizes'], true);

        if (is_array($prizes) && !empty($prizes)) {

            $totalPrizeValue = 0;
            $position = 1;

            $txt .= "\n🏆 <b>جوایز:</b>\n<blockquote expandable>";

            foreach ($prizes as $index => $prize) {

                if (is_array($prize)) {

                    $rank = trim((string)($prize['rank'] ?? 'جایزه'));
                    $title = trim((string)($prize['title'] ?? 'جایزه ویژه'));
                    $value = max(0, (int)($prize['value'] ?? 0));

                } else {

                    // پشتیبانی از فرمت قدیمی
                    $rank = (string)$index;
                    $value = max(0, (int)$prize);
                    $title = number_format($value) . ' تومان';
                }

                $totalPrizeValue += $value;

                $emoji = match ($position) {
                    1 => '🥇',
                    2 => '🥈',
                    3 => '🥉',
                    default => '🔹'
                };

                $txt .= "{$emoji} <b>{$rank}:</b> {$title}\n";

                $position++;
            }

            $txt .= "</blockquote>\n";
            /*
            if ($totalPrizeValue > 0) {
                $txt .= "💎 <b>ارزش کل جوایز:</b> <code>"
                    . number_format($totalPrizeValue)
                    . " تومان</code>\n";
            }
            */
        }
    }

    // وضعیت ثبت‌نام کاربر
    if (!$userJoined && !$userInQueue) {

        if ($registrationDeadlinePassed) {

            $txt .= "❌ <i><b>مهلت ثبت‌نام این ایونت به پایان رسیده است.</b></i>\n\n";

        } else {

            $txt .= "❓ <b>آیا می‌خواهید در این ایونت ثبت‌نام کنید؟</b>\n\n";

            RegistrationProgress::setStep(
                $pdo,
                $eid,
                $uid,
                'start'
            );
        }
    }

    // دکمه‌ها
    $ik = [];

    if (!$userJoined && !$userInQueue) {

        if (!$registrationDeadlinePassed) {

            $ik[] = [
                [
                    'text' => '📜 جزئیات ایونت',
                    'callback_data' => 'ev_userview:' . $eid . ':' . $uid . ':' . $hasBanner
                ],
                [
                    'text' => '➕ شرکت در ایونت',
                    'callback_data' => 'ev_join:' . $eid . ':' . $uid . ':' . $hasBanner,
                    'style' => 'success'
                ]
            ];

        } else {

            // deadline گذشته؛ فقط جزئیات نمایش داده شود
            $ik[] = [
                [
                    'text' => '📜 جزئیات ایونت',
                    'callback_data' => 'ev_userview:' . $eid . ':' . $uid . ':' . $hasBanner
                ]
            ];
        }

    } else {

        // فقط کاربر ثبت‌نام کامل شده
        if ($userJoined && !$userInQueue) {

            if ((int)($e['limit'] ?? 0) > 1) {

                $ik[] = [
                    [
                        'text' => '📜 جزئیات ایونت',
                        'callback_data' => 'ev_userview:' . $eid . ':' . $uid . ':' . $hasBanner
                    ],
                    [
                        'text' => '👥 اسکواد من',
                        'callback_data' => 'ev_squad:' . $eid . ':' . $uid . ':' . $hasBanner
                    ]
                ];

            } else {

                $ik[] = [
                    [
                        'text' => '📜 جزئیات ایونت',
                        'callback_data' => 'ev_userview:' . $eid . ':' . $uid . ':' . $hasBanner
                    ]
                ];
            }

            // وضعیت تورنومنت بازیکن (برای همه حالت‌ها)
            $ik[] = [
                [
                    'text' => '👤 وضعیت شما',
                    'callback_data' => 'user_tournament_status:' . $eid ,
                    'style' => 'primary'
                ]
            ];
        }
    }

    //$ik[] = [['text'=>'🔙 بازگشت','callback_data'=>'events_list:'.$e['type'].':0:'.($hasBanner ? 'true' : 'false')]];

    $ik[] = [[
        'text' => '🔙 بازگشت', 
        'callback_data' => $joined ? 'events_list:all:0:true:true' : 'events_list:'.$e['type'].':0:'.($hasBanner ? 'true' : 'false')
    ]];

    return [$txt, ['inline_keyboard'=>$ik], $e['banner'] ?? null];
}




function renderEventInfo(PDO $pdo, int $eid, int $uid): array {
    $st = $pdo->prepare('SELECT * FROM events WHERE id=?');
    $st->execute([$eid]);
    $e = $st->fetch(PDO::FETCH_ASSOC);

    $st = $pdo->prepare('
        SELECT 1 
        FROM event_players 
        WHERE user_id = ? 
          AND ev_id = ? 
          AND status = "accepted"
        LIMIT 1
    ');
    
    $st->execute([$uid, $eid]);
    $userJoined = (bool)$st->fetchColumn();


    if (!$e) {
        return ['❌ رویداد پیدا نشد.', [
            'inline_keyboard' => [
                [['text' => '🔙 بازگشت', 'callback_data' => 'home']]
            ]
        ]];
    }

    // استخراج رمز و شناسه (id_pass)
    $idPass = [];
    if (!empty($e['id_pass'])) {
        $idPass = json_decode($e['id_pass'], true) ?: [];
    }

    // شروع ساخت متن
    $txt = '';

    // توضیحات
    if (!empty($e['info'])) {
        $txt .= "📝 <b>توضیحات:</b>\n";
        $txt .= "<blockquote expandable>" . nl2br(htmlspecialchars(trim($e['info']))) . "</blockquote>\n\n";
    }

    // قوانین
    if (!empty($e['rules'])) {
        $txt .= "📜 <b>قوانین:</b>\n";
        $txt .= "<blockquote expandable>" . nl2br(htmlspecialchars(trim($e['rules']))) . "</blockquote>\n\n";
    }

    // رمز و شناسه
    if ($userJoined && !empty($idPass)) {
        $txt .= "🔑 <b>رمز و شناسه:</b>\n";
        $txt .= "<blockquote>ID: <code>{$idPass['id']}</code>\nPass: <code>{$idPass['pass']}</code></blockquote>\n\n";
    }

    $ik = [];

    if ($userJoined)
        $ik = [
                 [['text'=>'❌ لغو ثبت‌نام','callback_data'=>'ev_cancel:'.$eid,'style'=>'danger'],
                 ['text'=>'✏️ ویرایش اطلاعات','callback_data'=>'ev_edit:'.$eid.':'.$uid]],
                 [['text'=>'🔙 بازگشت','callback_data'=>'ev_view:'.$eid.':'.$uid]]
              ];
    else {
            $ik[] = [['text'=>'🔙 بازگشت','callback_data'=>'ev_view:'.$eid.':'.$uid]];
        }


    return [$txt, ['inline_keyboard' => $ik]];
}


function sendReferralSuccess($chat_id, $refId){
    global $pdo;

    // گرفتن اطلاعات رفرال
    $st = $pdo->prepare("
        SELECT referrer_id, event_id
        FROM referrals
        WHERE ref_id = ?
        LIMIT 1
    ");
    $st->execute([$refId]);

    $ref = $st->fetch(PDO::FETCH_ASSOC);

    if (!$ref) {
        return;
    }

    $referrerId = (int)$ref['referrer_id'];
    $eventId    = (int)$ref['event_id'];

    // تایید رفرال
    $pdo->prepare("
        UPDATE referral_starts
        SET status = 'valid'
        WHERE ref_id = ?
          AND user_id = ?
          AND event_id = ?
    ")->execute([
        $refId,
        $chat_id,
        $eventId
    ]);

    sendMessage($chat_id, "🎉 ورود شما ثبت شد!");
    sendMessage($referrerId, "🎉 یک کاربر از لینک شما وارد شد!");
}



function getUserIGN(PDO $pdo, int $uid, string $game): string {
    try {
        $st = $pdo->prepare("SELECT games FROM users WHERE id=?");
        $st->execute([$uid]);
        $row = $st->fetch(PDO::FETCH_ASSOC);

        if (!$row) {
            return '';
        }

        $data = json_decode($row['games'], true);
        if (!is_array($data)) {
            return '';
        }

        foreach ($data as $g => $info) {
            if (strcasecmp($g, $game) === 0) {
                return is_array($info) && isset($info['ign'])
                    ? $info['ign']
                    : (is_string($info) ? $info : '');
            }
        }

        return '';
    } catch (PDOException $e) {
        error_log("getUserIGN DB ERROR: " . $e->getMessage());
        return '';
    }
}

//--------------- 


function isUserInChannel(string $botToken, int $userId, string $chatIdOrUsername): bool
{
    if (!$chatIdOrUsername) {
        return false;
    }

    $url = "https://api.telegram.org/bot{$botToken}/getChatMember"
         . "?chat_id=" . urlencode($chatIdOrUsername)
         . "&user_id=" . $userId;

    $raw = @file_get_contents($url);


    $res = json_decode($raw, true);

    if (!($res['ok'] ?? false)) {
        return false;
    }

    $member = $res['result'] ?? [];
    $status = $member['status'] ?? '';


    if (in_array($status, ['creator', 'administrator', 'member'], true)) {
        return true;
    }

    if ($status === 'restricted') {
        return ($member['is_member'] ?? false) === true;
    }

    return false;
}

function checkForceJoin(PDO $pdo, int $userId, int $chatId, string $botToken): bool
{
    $channels = [
        '@HoradOfficial'
    ];

    $notJoined = [];

    foreach ($channels as $channel) {

        if (!isUserInChannel($botToken, $userId, $channel)) {
            $notJoined[] = $channel;
        }
    }

    if (!$notJoined) {
        return true;
    }

    $buttons = [];

    foreach ($notJoined as $channel) {

        $buttons[] = [[
            'text' => '📢 عضویت در کانال',
            'url'  => 'https://t.me/' . ltrim($channel, '@')
        ]];
    }

    $buttons[] = [[
        'text' => '✅ بررسی عضویت',
        'callback_data' => 'check_force_join'
    ]];

    sendMessage(
        $chatId,
        "⚠️ برای استفاده از ربات ابتدا در کانال‌های زیر عضو شوید.",
        [
            'inline_keyboard' => $buttons
        ]
    );

    return false;
}

function buildForceJoinKeyboard(string $botToken, int $userId, string $privateChannelJson, int $eid, ?string $callbackData = null): ?array{
    $channels = json_decode($privateChannelJson, true);

    if (!is_array($channels) || empty($channels)) {
        return null;
    }

    $keyboard = [];

    foreach ($channels as $ch) {

        $chatId   = $ch['chat_id'] ?? null;
        $username = $ch['username'] ?? null;
        $invite   = $ch['invite'] ?? null;
        $title    = $ch['title'] ?? '📢 عضویت در کانال';

        // اولویت چک عضویت: chat_id عددی > یوزرنیم بدون @
        if ($chatId) {
            $checkTarget = (string)$chatId;              // عدد منفی مثل -1002958275866
        } elseif ($username) {
            $checkTarget = ltrim($username, '@');        // حذف @ برای getChatMember
        } else {
            continue;
        }

        if (isUserInChannel($botToken, $userId, $checkTarget)) {
            continue;
        }

        // لینک عضویت: اولویت invite، بعد ساختن از یوزرنیم
        if ($invite) {
            $joinLink = $invite;
        } elseif ($username) {
            $joinLink = "https://t.me/" . ltrim($username, '@');
        } else {
            continue; // نه invite نه username → دکمه بدون لینک نمیسازیم
        }

        $keyboard[] = [[
            'text' => $title,
            'url'  => $joinLink
        ]];
    }

    if (empty($keyboard)) {
        return null;
    }

    $keyboard[] = [[
        'text'          => '✅ بررسی عضویت',
        'callback_data' => $callbackData ?? ('check_join:' . $eid),
        'style'         => 'primary'
    ]];

    return ['inline_keyboard' => $keyboard];
}


function generateReferralLink( PDO $pdo, string $bot_username, int $userId, int $eventId): array {

    // بررسی اگر قبلاً ref ساخته شده
    $st = $pdo->prepare("
        SELECT ref_id
        FROM referrals
        WHERE referrer_id = ?
        AND event_id = ?
        LIMIT 1
    ");
    $st->execute([$userId, $eventId]);
    $existing = $st->fetch(PDO::FETCH_ASSOC);

    if ($existing) {
        $refId = $existing['ref_id'];
    } else {

        // ساخت refId رندوم
        $refId = bin2hex(random_bytes(5)); // مثل: a93f1c8b2d

        $pdo->prepare("
            INSERT INTO referrals
            (ref_id, referrer_id, event_id, status)
            VALUES (?, ?, ?, 'active')
        ")->execute([$refId, $userId, $eventId]);
    }

    $link = "https://t.me/{$bot_username}?start=ref_{$refId}";

    return [
        'ref_id' => $refId,
        'link' => $link
    ];
}


// ---------------- PARTICIPANT / PAYMENT ----------------
function userJoinEvent(PDO $pdo, int $uid, int $eid, ?string $game = null): array
{
    try {

        // =========================
        // 1. گرفتن اطلاعات ایونت
        // =========================
        $st = $pdo->prepare("
            SELECT game, game_code, entry_fee, require_ign, require_game_id, `limit`, capacity
            FROM events
            WHERE id=?
            LIMIT 1
        ");
        $st->execute([$eid]);
        $event = $st->fetch(PDO::FETCH_ASSOC);

        if (!$event) {
            return [
                'ok' => false,
                'msg' => '❌ ایونت یافت نشد.'
            ];
        }

        $limit = (int)$event['limit'];
        $capacity = (int)$event['capacity'];

        // =========================
        // 2. گرفتن اطلاعات کاربر
        // =========================
        $st = $pdo->prepare("
            SELECT ign, game_id
            FROM user_games
            WHERE user_id = ?
            AND game_code = ?
            LIMIT 1
        ");
        $st->execute([$uid, $event['game_code']]);

        $userGame = $st->fetch(PDO::FETCH_ASSOC) ?: [];

        $ign    = trim($userGame['ign'] ?? '');
        $gameId = trim($userGame['game_id'] ?? '');

        // =========================
        // 3. بررسی وجود قبلی (فقط accepted بلاک می‌شود)
        // =========================
        $st = $pdo->prepare("
            SELECT id, status
            FROM event_players
            WHERE user_id=? AND ev_id=?
            LIMIT 1
        ");
        $st->execute([$uid, $eid]);

        $existing = $st->fetch(PDO::FETCH_ASSOC);

        if ($existing && $existing['status'] === 'accepted') {
            return [
                'ok' => false,
                'msg' => '⚠️ شما قبلاً ثبت‌نام کرده‌اید.'
            ];
        }

        // =========================
        // 4. بررسی الزامات پروفایل
        // =========================
        if (!empty($event['require_ign']) && !$ign) {
            return [
                'ok' => false,
                'msg' => '🎮 لطفاً IGN خود را ثبت کنید.'
            ];
        }

        if (!empty($event['require_game_id']) && !$gameId) {
            return [
                'ok' => false,
                'msg' => '🆔 لطفاً Game ID خود را ثبت کنید.'
            ];
        }

        // =========================
        // 5. قفل ظرفیت (جلوگیری از race condition)
        // =========================
        $pdo->beginTransaction();

        // قفل ردیف ایونت
        $st = $pdo->prepare("SELECT `limit`, capacity FROM events WHERE id=? FOR UPDATE");
        $st->execute([$eid]);

        $row = $st->fetch(PDO::FETCH_ASSOC);


        if (!$row) {
            throw new RuntimeException("Event #{$eid} not found.");
        }

        $limit = (int)($row['limit'] ?? 0);
        $capacity = (int)$row['capacity'];

        // شمارش اعضای accepted
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM event_players
            WHERE ev_id=? AND status='accepted'
        ");
        $st->execute([$eid]);

        $current = (int)$st->fetchColumn();

        $status = ($capacity > 0 && $current >= $capacity)
            ? 'queue'
            : 'accepted';

        // =========================
        // 7. اگر کاربر قبلاً بوده (canceled/queue)
        // =========================
        if ($existing) {

            $st = $pdo->prepare("
                UPDATE event_players
                SET status=?
                WHERE id=?
            ");
            $st->execute([$status, $existing['id']]);

        } else {

            // =========================
            // 8. ساخت squad فقط اگر accepted
            // =========================
            $squadId = null;

            if ($status === 'accepted' && $limit > 1) {
                $st = $pdo->prepare("
                    INSERT INTO event_squads (eid, leader_uid, status)
                    VALUES (?, ?, 'open')
                ");
                $st->execute([$eid, $uid]);
                $squadId = (int)$pdo->lastInsertId();
            }

            // =========================
            // 9. ثبت کاربر جدید
            // =========================
            $st = $pdo->prepare("
                INSERT INTO event_players
                (user_id, ig_id, ign, ev_id, tx_id, squad_id, status)
                VALUES (?, ?, ?, ?, NULL, ?, ?)
            ");

            $st->execute([
                $uid,
                $gameId ?: null,
                $ign ?: null,
                $eid,
                $squadId,
                $status
            ]);
        }

        $pdo->commit();

        // =========================
        // 10. آپدیت user_games
        // =========================
        $st = $pdo->prepare("
            UPDATE user_games
            SET active = 1
            WHERE user_id=? AND game_code=?
        ");
        $st->execute([$uid, $event['game_code']]);

        // =========================
        // 11. خروجی
        // =========================
        return [
            'ok' => true,
            'msg' => $status === 'queue'
                ? '⚠️ ظرفیت پر است، شما در صف انتظار قرار گرفتید.'
                : '✅ ثبت‌نام شما انجام شد.',
            'status' => $status
        ];

    } catch (Throwable $e) {

        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        error_log("userJoinEvent error: " . $e->getMessage());

        return [
            'ok' => false,
            'msg' => '❌ خطای سیستمی رخ داد.'
        ];
    }
}






function handlePaymentPhotoReceivedByPid(PDO $pdo, int $uid, int $chat_id, ?int $eid, int $pid, string $file_id) {
    if ($eid !== null && $eid > 0) {
        // تراکنش مربوط به ایونت
        $st = $pdo->prepare("SELECT * FROM transactions WHERE id=? AND user_id=? AND event_id=? AND status='pending' LIMIT 1");
        $st->execute([$pid, $uid, $eid]);
    } else {
        // تراکنش معمولی (Topup) با event_id=NULL
        $st = $pdo->prepare("SELECT * FROM transactions WHERE id=? AND user_id=? AND event_id IS NULL AND status='pending' LIMIT 1");
        $st->execute([$pid, $uid]);
    }

    $p = $st->fetch(PDO::FETCH_ASSOC);
    if (!$p) {
        sendMessage($chat_id, "❌ رکورد پرداخت یافت نشد یا وضعیت آن دیگر pending نیست. لطفاً دوباره تلاش کنید.");
        return;
    }

    // اگر file_id قبلاً ثبت شده، به کاربر اطلاع بده
    if (!empty($p['file_id'])) {
        sendMessage($chat_id, "ℹ️ شما قبلاً یک رسید ارسال کرده‌اید. ابتدا آن را ارسال به ادمین یا لغو کنید.");
        return;
    }

    $st = $pdo->prepare("SELECT first_name FROM users WHERE id=? LIMIT 1");
    $st->execute([$uid]);
    $user = $st->fetch(PDO::FETCH_ASSOC);

    // ذخیره file_id
    $pdo->prepare("UPDATE transactions SET file_id=? WHERE id=?")->execute([$file_id, $pid]);
    $p['file_id'] = $file_id;
    $firstName = htmlspecialchars($user['first_name'] ?? 'کاربر');
    $displayAmount = $p['amount']; // TopUp همیشه از amount

  
    
if (!empty($p['game'])) {
    // تراکنش مربوط به ایونت
    $caption = "<b>📎 پیش‌نمایش رسید شما</b>\n\n";
    $caption .= "<blockquote>";
    $caption .= "🎮 بازی: <b>" . htmlspecialchars($p['game']) . "</b>\n";
    $caption .= "🆔 IGN: <code>" . htmlspecialchars($p['ign']) . "</code>\n";
    $caption .= "💵 مبلغ ورودی: <b>" . number_format($p['entry_fee']) . " تومان</b>\n";
    $caption .= "</blockquote>\n\n";
} else {
    // تراکنش TopUp
    $caption = "🎉 <b>{$firstName} عزیز، شارژ کیف پول شما در راه است!</b>\n\n";
    $caption .= "<blockquote>";
    $caption .= "💵 مبلغ مورد نظر: <b>" . number_format($displayAmount) . " تومان</b>\n";
    $caption .= "🕓 تاریخ درخواست: <b>" . jdate('Y/m/d') . "</b>\n\n";
    $caption .= "🔹 وضعیت: پیش‌نمایش رسید\n";
    $caption .= "🔹 مرحله بعد: تایید توسط ادمین\n";
    $caption .= "</blockquote>\n\n";
    $caption .= "💡 نکته: پس از ارسال رسید، موجودی کیف پول شما سریعاً بروزرسانی خواهد شد.\n\n";
}

   
    $inline_kb = [
        'inline_keyboard' => [
            [
                ['text'=>'✅ ارسال به ادمین','callback_data'=>'send_to_admin:'.$p['id']],
                ['text'=>'❌ لغو','callback_data'=>'cancel_transactions:'.$p['id']]
            ]
        ]
    ];

    // ارسال عکس پیش‌نمایش به کاربر
    sendPhoto($chat_id, $p['file_id'], $caption, $inline_kb);

    // تغییر state برای مرحله تایید نهایی
    setState($pdo, $uid, 'awaiting_user_confirm:'.$p['id']);
}




// ---------------- RANKING ----------------
function awardPoints(PDO $pdo, int $user_id, string $game, int $delta, int $event_id=null){
    // upsert ranking
    $st = $pdo->prepare('SELECT * FROM ranking WHERE user_id=? AND game=?'); $st->execute([$user_id,$game]); $r = $st->fetch();
    if ($r) {
        $new = (int)$r['points'] + $delta;
        $last = jdec($r['last_10']); array_unshift($last, ['event_id'=>$event_id,'delta'=>$delta,'at'=>now()]); $last = array_slice($last,0,10);
        $pdo->prepare('UPDATE ranking SET points=?, last_10=? WHERE id=?')->execute([$new, jenc($last), $r['id']]);
    } else {
        $last = [['event_id'=>$event_id,'delta'=>$delta,'at'=>now()]];
        $pdo->prepare('INSERT INTO ranking (user_id, game, points, last_10) VALUES (?,?,?,?)')->execute([$user_id,$game,$delta,jenc($last)]);
    }
}

function getTopRanking(PDO $pdo, string $game, string $timeFilter='all', int $limit=10, int $offset=0) {
    $whereTime = '';

    switch($timeFilter) {
        case 'daily':
            $whereTime = " AND created_at >= CURDATE()";
            break;
        case 'weekly':
            $whereTime = " AND created_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
            break;
        case 'monthly':
            $whereTime = " AND created_at >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)";
            break;
        default:
            $whereTime = '';
    }

    // LIMIT و OFFSET مستقیم داخل کوئری قرار می‌گیرند
    $sql = "SELECT user_id, SUM(points) as total_points
            FROM ranking
            WHERE game = ? $whereTime
            GROUP BY user_id
            ORDER BY total_points DESC
            LIMIT $limit OFFSET $offset";

    $st = $pdo->prepare($sql);
    $st->execute([$game]);
    return $st->fetchAll(PDO::FETCH_ASSOC);
}


// گرفتن امتیاز خود کاربر در بازه زمانی
function getUserRankingPoints(PDO $pdo, int $userId, string $game, string $timeFilter='all') {
    $whereTime = '';

    switch($timeFilter) {
        case 'daily':
            $whereTime = " AND created_at >= CURDATE()";
            break;
        case 'weekly':
            $whereTime = " AND created_at >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)";
            break;
        case 'monthly':
            $whereTime = " AND created_at >= DATE_SUB(CURDATE(), INTERVAL 1 MONTH)";
            break;
    }

    $sql = "SELECT SUM(points) as total_points
            FROM ranking
            WHERE user_id=? AND game=? $whereTime";
    $st = $pdo->prepare($sql);
    $st->execute([$userId, $game]);
    return (int)($st->fetchColumn() ?: 0);
}



// ---------------- ADMIN ACTIONS (archive/restore/finish/export) ----------------
function archiveEvent(PDO $pdo, int $admin_id, int $eid){
    $st=$pdo->prepare('SELECT * FROM events WHERE id=?'); $st->execute([$eid]); $e=$st->fetch(); if(!$e) return false;
    $pdo->prepare('INSERT INTO event_archives (event_id, snapshot) VALUES (?,?)')->execute([$eid, jenc($e)]);
    $pdo->prepare('UPDATE events SET status=? WHERE id=?')->execute(['archived',$eid]);
    $pdo->prepare('INSERT INTO admin_actions (admin_id, action, meta) VALUES (?,?,?)')->execute([$admin_id,'archive', jenc(['event_id'=>$eid])]);
    return true;
}
function restoreEvent(PDO $pdo, int $eid) {
    // گرفتن وضعیت فعلی
    $st = $pdo->prepare('SELECT status FROM events WHERE id=? LIMIT 1');
    $st->execute([$eid]);
    $e = $st->fetch(PDO::FETCH_ASSOC);
    if (!$e) return false;

    // فقط اگر وضعیت archive یا finished باشد
    if (!in_array($e['status'], ['archived', 'finished'])) {
        return false; // رویداد در حالت فعال است یا وضعیت نامعتبر
    }

    // تغییر وضعیت به active
    $st = $pdo->prepare('UPDATE events SET status=? WHERE id=?');
    $st->execute(['active', $eid]);

    return true;
}


function finishEventAndAward(PDO $pdo, int $admin_id, int $eid, array $winners){
    $st=$pdo->prepare('SELECT * FROM events WHERE id=?'); $st->execute([$eid]); $e=$st->fetch(); if(!$e) return false;
    // mark finished
    $pdo->prepare('UPDATE events SET status=? WHERE id=?')->execute(['finished',$eid]);
    // award points to winners
    foreach($winners as $w){ // $w = ['user_id'=>id, 'points'=>int]
        awardPoints($pdo, (int)$w['user_id'], $e['game'], (int)$w['points'], $eid);
    }
    $pdo->prepare('INSERT INTO admin_actions (admin_id, action, meta) VALUES (?,?,?)')->execute([$admin_id,'finish', jenc(['event_id'=>$eid,'winners'=>$winners])]);
    return true;
}

function exportEventCSV(PDO $pdo, int $eid){
    $st=$pdo->prepare('SELECT * FROM events WHERE id=?'); $st->execute([$eid]); $e=$st->fetch(); if(!$e) return null;
    $players = jdec($e['players']);
    $fn = sys_get_temp_dir().'/event_'.$eid.'_'.time().'.csv';
    $f = fopen($fn,'w');
    fputcsv($f, ['event_id','type','game','name','user_id','ign','joined_at','paid','pay_method','pay_time']);
    foreach($players as $p) fputcsv($f, [$eid,$e['type'],$e['game'],$e['name'],$p['user_id']??'',$p['ign']??'',$p['joined_at']??'',$p['paid']??'',$p['pay_method']??'',$p['pay_time']??'']);
    fclose($f);
    return $fn;
}

function exportMultipleEventsCSV(PDO $pdo, array $eventIds): ?string {
    $tmpFile = '/tmp/events_export_'.time().'.csv';
    $fh = fopen($tmpFile, 'w');
    if (!$fh) return null;

    // واکشی ستون‌ها
    $columns = ['id','type','name','info','game','creator_id','status','date_str','entry_fee','currency','private_channel','players','points_for_winner','meta','created_at','winners'];

    // هدر CSV
    fputcsv($fh, $columns);

    foreach ($eventIds as $eid) {
        $st = $pdo->prepare('SELECT '.implode(',', $columns).' FROM events WHERE id=?');
        $st->execute([$eid]);
        $row = $st->fetch(PDO::FETCH_ASSOC);
        if (!$row) continue;

        // ستون players و winners را JSON encode می‌کنیم تا در یک سلول CSV باشد
        $row['players'] = json_encode(jdec($row['players'] ?? '[]'), JSON_UNESCAPED_UNICODE);
        $row['winners'] = json_encode(jdec($row['winners'] ?? '[]'), JSON_UNESCAPED_UNICODE);

        fputcsv($fh, $row);
    }

    fclose($fh);
    return $tmpFile;
}

//----------------admin search player----------------------



function showSearchResults($chat_id, $eid, $query, $page = 1) {
    global $pdo;

    // گرفتن ایونت و پلیرها
    $st = $pdo->prepare("SELECT players FROM events WHERE id=?");
    $st->execute([$eid]);
    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        sendMessage($chat_id, "❌ ایونت پیدا نشد.");
        return;
    }

    $players = json_decode($event['players'], true) ?: [];

    // فیلتر کردن بازیکن‌ها
    $query = strtolower(trim($query));
    $filtered = array_filter($players, function($p) use ($query) {
        return strpos(strtolower($p['ign']), $query) !== false 
            || strpos(strtolower((string)$p['user_id']), $query) !== false;
    });

    $filtered = array_values($filtered); // ریسِت ایندکس

    if (!$filtered) {
        sendMessage($chat_id, "❌ بازیکنی با این مشخصات پیدا نشد.");
        return;
    }

    // صفحه‌بندی
    $limit = 10;
    $offset = ($page - 1) * $limit;
    $pageResults = array_slice($filtered, $offset, $limit);

    // ساخت دکمه‌ها
    $buttons = [];
    foreach ($pageResults as $p) {
        $name = $p['ign'] ?: 'بدون نام';
        $uid  = $p['user_id'];
        $buttons[] = [[
            'text' => "$name (ID:$uid)", 
            'callback_data' => "admin_player_info:$eid:$uid"
        ]];
    }

    // دکمه صفحه‌بندی
    $pagination = [];
    if ($page > 1) {
        $pagination[] = ['text' => '⬅️ قبلی', 'callback_data' => "search_player_page:$eid:" . ($page - 1) . ":$query"];
    }
    if (count($filtered) > $page * $limit) {
        $pagination[] = ['text' => 'بعدی ➡️', 'callback_data' => "search_player_page:$eid:" . ($page + 1) . ":$query"];
    }
    if ($pagination) {
        $buttons[] = $pagination;
    }

    $kb = ['inline_keyboard' => $buttons];
    sendMessage($chat_id, "🔍 نتایج جستجو در ایونت #$eid برای: `$query`", $kb);
}


// ذخیره وضعیت کاربر
function setUserStep($user_id, $step) {
    global $pdo;
    $sql = "UPDATE users SET step = :step WHERE id = :id";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([
        ':step' => $step,
        ':id'   => $user_id
    ]);
}

// گرفتن وضعیت فعلی کاربر
function getUserStep($user_id) {
    global $pdo;
    $sql = "SELECT step FROM users WHERE id = :id LIMIT 1";
    $stmt = $pdo->prepare($sql);
    $stmt->execute([':id' => $user_id]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);
    return $row ? $row['step'] : null;
}


//---------------------------------
//==============={transaction system}===================

function handleWalletTopupAmount($pdo, $uid, $chat_id, $mid, $amount) {
    if ($amount <= 0) {
        sendMessage($uid, "❌ مبلغ نامعتبر است.");
        return;
    }

    $trackingCode = generateTrackingCode($pdo);

    // ثبت تراکنش در حالت pending
    $st = $pdo->prepare("
        INSERT INTO transactions 
        (user_id, amount, reason, status, tracking_code, created_at) 
        VALUES (?, ?, 'topup', 'pending', ?, NOW())
    ");
    $st->execute([$uid, $amount, $trackingCode]);
    $pid = $pdo->lastInsertId();

    // پیام درخواست رسید
    $txt = "🧾 درخواست افزایش موجودی به مبلغ <b>".number_format($amount)." تومان</b> ثبت شد.\n\n".
           "📌 کد پیگیری: <code>$trackingCode</code>\n\n".
           "لطفاً تصویر رسید پرداخت را ارسال کنید.\n".
           "پس از ارسال، پیش‌نمایش برای شما نمایش داده می‌شود.";

    $kb = [
        'inline_keyboard' => [
            [['text'=>'📎 ارسال رسید','callback_data'=>"wallet_topup_proof:{$uid}:{$pid}"]],
            [['text'=>'🔙 بازگشت','callback_data'=>"wallet_topup_cancel:{$pid}"]]
        ]
    ];

    $stmt = $pdo->prepare("SELECT state FROM users WHERE id=? LIMIT 1");
    $stmt->execute([$uid]);
    $state = $stmt->fetchColumn();

    if ($state === 'awaiting_topup_amount') {
        sendMessage($uid, $txt, $kb);
    } else {
        editMessageText($chat_id, $mid, $txt, $kb);
    }
    setState($pdo, $uid, '');
}




function generateTrackingCode(PDO $pdo, string $prefix = 'TRX', int $minLength = 6, int $maxLength = 9): string {
    do {
        // طول رندوم بین min و max
        $length = random_int($minLength, $maxLength);
        // تولید رشته رندوم امن به صورت hex (2 کاراکتر برای هر بایت)
        $bytes = ceil($length / 2); // چون هر بایت دو حرف hex میده
        $randomHex = strtoupper(substr(bin2hex(random_bytes($bytes)), 0, $length));

        $code = $prefix . '-' . $randomHex;

        // چک یونیک بودن در دیتابیس
        $stmt = $pdo->prepare("SELECT 1 FROM transactions WHERE tracking_code = ? LIMIT 1");
        $stmt->execute([$code]);
        $exists = (bool) $stmt->fetchColumn();

    } while ($exists); // اگر تکراری بود دوباره بساز

    return $code;
}

function setCooldown($pdo, $uid, $action, $seconds) {
    $stmt = $pdo->prepare("SELECT cooldown FROM users WHERE id = ?");
    $stmt->execute([$uid]);
    $cooldown = json_decode($stmt->fetchColumn() ?? '{}', true);
    
    $cooldown[$action] = time() + $seconds;

    $stmt = $pdo->prepare("UPDATE users SET cooldown = ? WHERE id = ?");
    $stmt->execute([json_encode($cooldown, JSON_UNESCAPED_UNICODE), $uid]);
}

function checkCooldown($pdo, $uid, $action, $callback_id = null) {
    $stmt = $pdo->prepare("SELECT cooldown FROM users WHERE id = ?");
    $stmt->execute([$uid]);
    $cooldown = json_decode($stmt->fetchColumn() ?? '{}', true);
    $now = time();

    if (isset($cooldown[$action]) && $cooldown[$action] > $now) {
        $remaining = $cooldown[$action] - $now;
        if ($callback_id) {
            answerCb($callback_id, "⏳ لطفاً $remaining ثانیه دیگر صبر کنید.");
        }
        return $remaining;
    }
    return 0;
}




// ---------------- UPDATE HANDLING ----------------
$message = $update['message'] ?? null;
$callback = $update['callback_query'] ?? null;

$data    = '';
$text    = '';
$state   = '';
$uid     = 0;
$chat_id = 0;
$mid     = 0;
$cb      = $callback;

if (isset($update['callback_query'])) {
    $callback_id = $update['callback_query']['id'];
    $callback_data = $update['callback_query']['data'];
    $chat_id = $update['callback_query']['message']['chat']['id'];
    }

if ($message) {
    $from     = $message['from'] ?? [];
    $user     = ensureUser($pdo, $from, $defaultGameName);
    $uid      = (int)($user['id'] ?? 0);
    $chat_id  = (int)($message['chat']['id'] ?? 0);
    $mid      = (int)($message['message_id'] ?? 0);
    $text     = trim($message['text'] ?? '');
    $data     = '';
    $state    = getState($pdo, $uid);

    if (isAdmin($uid) && preg_match('/^edit_(name|info|game|date_str|points_for_winner):([0-9]+)$/', $state, $m)) {
        $field = $m[1];
        $eid = (int)$m[2];
        $val = trim($text);

        if ($val === '') {
            setState($pdo, $uid, '');
            answerCb($cb['id'], "⚠️ هیچ متنی ارسال نشد. هیچ تغییری اعمال نشد.");
            exit;
        }

        $skip = mb_strtolower($val) === 'عبور';
        $updated = false;

        if ($field === 'name') {
            if (!$skip) {
                $pdo->prepare('UPDATE events SET name = ? WHERE id = ?')->execute([$val, $eid]);
                $updated = true;
            }
        } elseif ($field === 'info') {
            if (!$skip) {
                $pdo->prepare('UPDATE events SET info = ? WHERE id = ?')->execute([$val, $eid]);
                $updated = true;
            }
        } elseif ($field === 'game') {
            if (!$skip) {
                $pdo->prepare('UPDATE events SET game = ? WHERE id = ?')->execute([$val, $eid]);
                $updated = true;
            }
        } elseif ($field === 'date_str') {
            if (!$skip) {
                if (preg_match('/^(\d{4})\/(\d{2})\/(\d{2})\s*-\s*(\d{1,2}):(\d{2})(?::(\d{2}))?$/u', $val, $m2)) {
                    $second = $m2[6] ?? '00';
                    list($gy, $gm, $gd) = jalali_to_gregorian((int)$m2[1], (int)$m2[2], (int)$m2[3]);
                    $dateStr = sprintf('%04d-%02d-%02d %02d:%02d:%02d', $gy, $gm, $gd, (int)$m2[4], (int)$m2[5], (int)$second);
                    $pdo->prepare('UPDATE events SET date_str = ? WHERE id = ?')->execute([$dateStr, $eid]);
                    $updated = true;
                } else {
                    sendMessage($chat_id, "⚠️ فرمت تاریخ درست نیست. دوباره وارد کنید.");
                    exit;
                }
            }
        } elseif ($field === 'points_for_winner') {
            if (!$skip) {
                $points = (int)preg_replace('/\D+/', '', $val);
                $pdo->prepare('UPDATE events SET points_for_winner = ? WHERE id = ?')->execute([$points, $eid]);
                $updated = true;
            }
        }

        setState($pdo, $uid, '');
        sendMessage($chat_id, $updated ? "✅ اطلاعات رویداد به‌روزرسانی شد." : "ℹ️ هیچ تغییری ثبت نشد.");
        exit;
    }

}

elseif ($callback) {
    $from     = $callback['from'] ?? [];
    $user     = ensureUser($pdo, $from, $defaultGameName);
    $uid      = (int)($user['id'] ?? 0);
    $chat_id  = (int)($callback['message']['chat']['id'] ?? 0);
    $mid      = (int)($callback['message']['message_id'] ?? 0);
    $data     = $callback['data'] ?? '';
    $text     = '';
    $state    = getState($pdo, $uid);
}

if ($data === 'home' || $data === 'profile_back') {
    if (!isset($cb) || !is_array($cb)) exit;
    
    $uid = (int)($cb['from']['id'] ?? 0);
    if ($uid <= 0) exit;

    $chat_id = (int)($cb['message']['chat']['id'] ?? 0);
    $mid = (int)($cb['message']['message_id'] ?? 0);
    if ($chat_id <= 0 || $mid <= 0) exit;

    $user = ensureUser($pdo, $cb['from'], $defaultGameName);

    showWelcome($pdo, $chat_id, $uid, $user, true, $mid); // حالت edit
    answerCb($cb['id'], '🔙 بازگشت انجام شد');
    exit;
}




if ($state && str_starts_with($state, 'awaiting_transactions_proof:')) {
    // state فرمت: awaiting_transactions_proof:{eid}:{pid}
    $parts = explode(':', $state);
    $eid = (int)$parts[1];
    $pid = isset($parts[2]) ? (int)$parts[2] : 0;

    // شناسه کاربر
    $uid = $message['from']['id'] ?? 0;
    if (!$uid) {
        // fallback اگر شناسه پیدا نشد
        exit;
    }

    // فقط photo قبول میشه
    $file_id = getPhotoFileIdFromMessage($message); // تابع پیشنهادی قبلی
    if (!$file_id) {
        // نوتیف واضح به کاربر و هنوز در همان حالت باقی بمونه
        sendMessage($chat_id, "⚠️ فقط یک <b>عکس</b> از رسید پذیرفته می‌شود. لطفاً تصویر رسید را ارسال کنید.\nاگر می‌خواهید لغو کنید از دکمهٔ بازگشت استفاده کنید.");
        exit;
    }

    // عکس معتبر — ذخیره و پیش‌نمایش
    handlePaymentPhotoReceivedByPid($pdo, (int)$uid, $chat_id, $eid, $pid, $file_id);
    exit;
}


if ($state === 'admin_add_game' && isAdmin($uid)) {
    $name = clean($text,64);
    if ($name === '') { 
        sendMessage($chat_id, '⚠️ نام گیم معتبر نیست.'); 
        exit; 
    }

    // بررسی وجود گیم
    $stmt = $pdo->prepare('SELECT COUNT(*) FROM games WHERE name = ?');
    $stmt->execute([$name]);
    if ($stmt->fetchColumn() > 0) {
        sendMessage($chat_id, "⚠️ گیم «".htmlspecialchars($name)."» از قبل وجود دارد.");
        exit;
    }

    // اگر وجود نداشت، اضافه شود
    $pdo->prepare('INSERT INTO games (name, active) VALUES (?,1)')->execute([$name]);
    setState($pdo,$uid,''); 
    sendMessage($chat_id, "✅ گیم «".htmlspecialchars($name)."» افزوده شد."); 
    exit;
}

if (str_starts_with($state,'create:') && isAdmin($uid)) {
    $parts = explode(':', $state); // create:type:eid:step
    $type = $parts[1] ?? 'tournament';
    $eid  = (int)($parts[2] ?? 0);
    $step = $parts[3] ?? 'name';
    $val  = trim($text);

    // اگر کاربر "عبور" زد، مرحله بعد برو و چیزی ذخیره نکن
    $skip = mb_strtolower($val) === 'عبور';

    switch ($step) {
        case 'name':
            if (!$skip) {
                $val = mb_substr($val,0,512);
                $pdo->prepare('UPDATE events SET name=? WHERE id=?')->execute([$val,$eid]);
            }
            setState($pdo,$uid,"create:$type:$eid:info");
            sendMessage($chat_id, "📝 <b>توضیحات رو ارسال کنید</b>\n\nمثال:<blockquote> یک تورنمنت هیجان‌انگیز با جوایز عالی </blockquote>", ['parse_mode'=>'HTML']);
            exit;

    case 'info':
        if (!$skip) {
            $val = mb_substr($val,0,1024);
            $pdo->prepare('UPDATE events SET info=? WHERE id=?')->execute([$val,$eid]);
        }
        setState($pdo,$uid,"create:$type:$eid:banner");
        sendMessage($chat_id, "🖼 <b>بنر ایونت را ارسال کنید</b>\n\n📌 فقط عکس تلگرام (نه فایل و نه لینک).", ['parse_mode'=>'HTML']);
        exit;

    case 'banner':
        if (!$skip) {
            if (!empty($msg['photo'])) {
                // گرفتن بزرگ‌ترین سایز photo
                $photo = end($msg['photo']);
                $file_id = $photo['file_id'];
                $pdo->prepare('UPDATE events SET banner=? WHERE id=?')->execute([$file_id,$eid]);
            } else {
                sendMessage($chat_id, "⚠️ لطفاً یک عکس ارسال کنید (نه فایل یا لینک).");
                exit;
            }
        }
        setState($pdo,$uid,"create:$type:$eid:rules");
        sendMessage($chat_id, "📜 <b>قوانین رو ارسال کنید</b>\n\nمثال:<blockquote> همه شرکت‌کنندگان باید بالای 18 سال باشند </blockquote>", ['parse_mode'=>'HTML']);
        exit;


            case 'rules':
                if (!$skip) {
                    $pdo->prepare('UPDATE events SET rules=? WHERE id=?')->execute([$val,$eid]);
                }
                setState($pdo,$uid,"create:$type:$eid:join");
                sendMessage($chat_id, "🔒 <b>جوین اجباری خصوصی را وارد کنید</b>\n\nمثال چندخطی:\n<blockquote>کانال اول\n-1002958275866\nhttps://t.me/+DH_EZZffNTk1YjVk\n\nکانال دوم\n-1001575068270\nhttps://t.me/HoradOfficial</blockquote>\n\nیا به صورت JSON:\n<code>[{\"title\":\"کانال اول\",\"chat_id\":-1002958275866,\"invite\":\"https://t.me/+DH_EZZffNTk1YjVk\"}]</code>", ['parse_mode'=>'HTML']);
                exit;

            case 'join':
                if (!$skip) {
                    $val = mb_substr($val,0,2048);
                    $channels = normalizeMandatoryJoinChannels($val);
                    $json = json_encode($channels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                    $requireJoin = !empty($channels) ? 1 : 0;
                    $pdo->prepare('UPDATE events SET private_channel=?, require_private_channel=? WHERE id=?')->execute([$json ?: '[]', $requireJoin, $eid]);
                } else {
                    $pdo->prepare('UPDATE events SET private_channel=?, require_private_channel=? WHERE id=?')->execute(['[]', 0, $eid]);
                }
                setState($pdo,$uid,"create:$type:$eid:date");
                sendMessage($chat_id, "📅 <b>تاریخ و ساعت رو وارد کنید</b>\n\n فرمت: <blockquote><code>  yyyy/mm/dd - hh:mm:ss </code></blockquote> ", ['parse_mode'=>'HTML']);
                exit;
    
    case 'date':
        if (!$skip) {
            // فرمت ورودی: 1404/03/12 - 13:05 یا 1404/03/12 - 13:05:30
            if (preg_match('/^(\d{4})\/(\d{2})\/(\d{2})\s*-\s*(\d{1,2}):(\d{2})(?::(\d{2}))?$/u', $val, $m)) {
                $second = $m[6] ?? '00';

                // تبدیل شمسی به میلادی با jdf
                list($gy,$gm,$gd) = jalali_to_gregorian((int)$m[1],(int)$m[2],(int)$m[3]);

                $dateStr = sprintf('%04d-%02d-%02d %02d:%02d:%02d',$gy,$gm,$gd,(int)$m[4],(int)$m[5],(int)$second);
                $pdo->prepare('UPDATE events SET date_str=? WHERE id=?')->execute([$dateStr,$eid]);
            } else {
                sendMessage($chat_id,"⚠️ فرمت تاریخ صحیح نیست. دوباره وارد کنید.");
                exit;
            }
        }
        setState($pdo,$uid,"create:$type:$eid:deadline");
        sendMessage($chat_id, "⏳ <b>مهلت ثبت نام رو وارد کنید</b>\n\n فرمت: <blockquote><code>  yyyy/mm/dd - hh:mm:ss </code></blockquote> ", ['parse_mode'=>'HTML']);
        exit;


    case 'deadline':
        if (!$skip) {
            if (preg_match('/^(\d{4})\/(\d{2})\/(\d{2})\s*-\s*(\d{1,2}):(\d{2})(?::(\d{2}))?$/u', $val, $m)) {
                $second = isset($m[6]) ? (int)$m[6] : 0;

                list($gy, $gm, $gd) = jalali_to_gregorian((int)$m[1], (int)$m[2], (int)$m[3]);

                $datetime = sprintf('%04d-%02d-%02d %02d:%02d:%02d', $gy, $gm, $gd, (int)$m[4], (int)$m[5], $second);

                // ذخیره در دیتابیس
                $pdo->prepare('UPDATE events SET deadline=? WHERE id=?')->execute([$datetime, $eid]);
            } else {
                sendMessage($chat_id,"⚠️ فرمت تاریخ صحیح نیست. دوباره وارد کنید.");
                exit;
            }
        }

        // مرحله بعد: ظرفیت
        setState($pdo, $uid, "create:$type:$eid:capacity");
        sendMessage($chat_id, "👥 <b>ظرفیت شرکت‌کنندگان را وارد کنید</b>\n <blockquote> فقط عدد صحیح. </blockquote>", ['parse_mode'=>'HTML']);
        exit;


            case 'capacity':
                if (!$skip) {
                    $cap = (int)preg_replace('/\D+/', '', $val);
                    $pdo->prepare('UPDATE events SET capacity=? WHERE id=?')->execute([$cap,$eid]);
                }
                setState($pdo,$uid,"create:$type:$eid:limit");
                sendMessage($chat_id, "❌ <b>محدودیت اسکواد را وارد کنید.</b>\n <blockquote> فقط عدد صحیح. </blockquote>", ['parse_mode'=>'HTML']);
                exit;

            case 'limit':
                if (!$skip) {
                    $lmt = (int)preg_replace('/\D+/', '', $val);
                    $pdo->prepare('UPDATE events SET `limit`=? WHERE id=?')->execute([$lmt,$eid]);
                }
                setState($pdo,$uid,"create:$type:$eid:points");
                sendMessage($chat_id, "⭐ <b>امتیاز برنده را وارد کنید</b>\n <blockquote> فقط عدد صحیح. </blockquote>", ['parse_mode'=>'HTML']);
                exit;

            case 'points':
                if (!$skip) {
                    $pts = (int)preg_replace('/\D+/', '', $val);
                    $pdo->prepare('UPDATE events SET points_for_winner=? WHERE id=?')->execute([$pts,$eid]);
                }
                setState($pdo,$uid,"create:$type:$eid:fee");
                sendMessage($chat_id, "💳 <b>ورودی (تومان) را وارد کنید</b>\n <blockquote> فقط عدد صحیح. </blockquote>", ['parse_mode'=>'HTML']);
                exit;

            case 'fee':
                if (!$skip) {
                    $fee = (int)preg_replace('/\D+/', '', $val);
                    $pdo->prepare('UPDATE events SET entry_fee=? WHERE id=?')->execute([$fee,$eid]);
                }
                setState($pdo,$uid,"create:$type:$eid:prizes");
                sendMessage(
                    $chat_id,
                    "🏆 <b>جوایز ایونت را وارد کنید</b>\n\n"
                    . "📌 <b>جایزه نقدی:</b>\n"
                    . "<code>جایگاه: مبلغ</code>\n"
                    . "<blockquote>اول:1000000\nدوم:500000</blockquote>\n\n"
                    . "🎁 <b>سایر جوایز:</b>\n"
                    . "<code>جایگاه: عنوان جایزه | ارزش</code>\n"
                    . "<blockquote>اول: هدست گیمینگ | 2500000\nدوم: گیفت کارت | 500000</blockquote>\n\n"
                    . "💎 <b>ارزش جایزه برای محاسبه ارزش کل جوایز استفاده می‌شود.</b>",
                    ['parse_mode' => 'HTML']
                );
                exit;

            case 'prizes':

                if (!$skip) {

                    $lines = preg_split('/\r\n|\r|\n/', trim($val));

                    $prizes = [];

                    foreach ($lines as $line) {

                        $line = trim($line);

                        if ($line === '') {
                            continue;
                        }

                        // ---------------------------
                        // جدا کردن رتبه و اطلاعات جایزه
                        // مثال:
                        // اول: 1000000
                        // اول: هدست گیمینگ | 2500000
                        // ---------------------------
                        if (!preg_match('/^(.+?)\s*:\s*(.+)$/u', $line, $m)) {
                            continue;
                        }

                        $rank = trim($m[1]);
                        $prizeData = trim($m[2]);

                        // ---------------------------
                        // حالت جایزه نقدی
                        // مثال:
                        // اول: 1000000
                        // ---------------------------
                        if (preg_match('/^\d[\d,\s]*$/u', $prizeData)) {

                            $value = (int)preg_replace('/\D+/', '', $prizeData);

                            if ($value <= 0) {
                                continue;
                            }

                            $prizes[] = [
                                'rank'  => $rank,
                                'type'  => 'cash',
                                'title' => number_format($value) . ' تومان',
                                'value' => $value
                            ];

                            continue;
                        }

                        // ---------------------------
                        // حالت جایزه غیرنقدی
                        // مثال:
                        // اول: هدست گیمینگ | 2500000
                        // ---------------------------
                        if (preg_match('/^(.+?)\s*\|\s*([\d,\s]+)$/u', $prizeData, $parts)) {

                            $title = trim($parts[1]);
                            $value = (int)preg_replace('/\D+/', '', $parts[2]);

                            if ($title === '' || $value <= 0) {
                                continue;
                            }

                            $prizes[] = [
                                'rank'  => $rank,
                                'type'  => 'other',
                                'title' => $title,
                                'value' => $value
                            ];
                        }
                    }

                    if (empty($prizes)) {

                        sendMessage(
                            $chat_id,
                            "❌ <b>هیچ جایزه معتبری پیدا نشد.</b>\n\n"
                            . "نمونه:\n"
                            . "<blockquote>اول:1000000\n"
                            . "دوم: هدست گیمینگ | 2500000</blockquote>",
                            ['parse_mode' => 'HTML']
                        );

                        exit;
                    }

                    $pdo->prepare(
                        'UPDATE events SET prizes=? WHERE id=?'
                    )->execute([
                        json_encode(
                            $prizes,
                            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
                        ),
                        $eid
                    ]);
                }

                $pdo->prepare('UPDATE events SET status=? WHERE id=?')->execute(['active',$eid]);

                setState($pdo,$uid,'');
                sendMessage($chat_id, "✅ رویداد ثبت شد و فعال شد.");
                showWelcome($pdo, $chat_id, $uid, $user);
                exit;
        }
}

if ($data === 'noop') {
    answerCb($cb['id'], '');
    exit;
}


if ($data === 'game_switch'){
        $games = listGames($pdo); $rows = [];
        
        foreach ($games as $g) {
        $rows[] = [['text' => $g['name'], 'callback_data' => 'set_game:'.urlencode($g['name'])]];
        }

        $rows[] = [['text'=>'🔙 بازگشت','callback_data'=>'home']]; editMessageText($chat_id,$mid,'🎮 بازی دلخواه را انتخاب کنید:', ['inline_keyboard'=>$rows]); answerCb($cb['id'],''); exit;
    }

if (strpos($data, 'set_game:') === 0) {
    $g = urldecode(substr($data, 9));
    setCurrentGame($pdo, $uid, $g);
    answerCb($cb['id'], '🎮 بازی پیش‌فرض تنظیم شد');
    $u = getUser($pdo, $uid);
    editMessageText($chat_id, $mid, "👋 سلام <b>" . htmlspecialchars($u['first_name'] ?? '') . "</b>", mainHeaderInline($u));
    exit;
}

if ($data === 'profile_show') {
    [$txt,$kb] = renderProfile($pdo, getUser($pdo,$uid));
    editMessageText($chat_id,$mid,$txt,$kb);
    answerCb($cb['id'],'');
    exit;
}

if ($data === 'wallet_main') {
    // پیام حرفه‌ای و راهنما
    $text  = "💰 <b>مدیریت کیف پول</b>\n\n";
    $text .= "<blockquote>";
    $text .= "اینجا می‌تونی موجودی حساب خودت رو افزایش، برداشت وجه انجام بدی و تاریخچه تراکنش‌ها رو ببینی.\n\n";
    $text .= "</blockquote>";

    // کیبورد زیرمجموعه شیشه‌ای
    $kb = [
        'inline_keyboard' => [
            [
                ['text'=>'➖ برداشت وجه','callback_data'=>'wallet_withdraw'],
                ['text'=>'➕ افزایش موجودی','callback_data'=>'wallet_topup']
            ],
            [
                ['text'=>'📜 تاریخچه تراکنش‌ها','callback_data'=>'wallet_history']
            ],
            [
                ['text'=>'⬅️ بازگشت','callback_data'=>'profile_show']
            ]
        ]
    ];

    // ارسال یا ویرایش پیام
    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'], '');
    exit;
}

if ($data === 'profile_games') {
    renderProfileGames($pdo, $chat_id, $mid, $uid);
    answerCb($cb['id'], '');
    exit;
}

function renderProfileGames(PDO $pdo, int $chat_id, int $mid, int $uid, bool $sendInstead = false): void
{
    $text  = "<b>🎮 مدیریت بازی‌های من</b>\n\n";
    $text .= "<blockquote>";
    $text .= "برای افزودن یا حذف هر بازی، روی دکمه‌اش بزن.\n";
    $text .= "🟢 سبز = فعال (افزوده‌شده)\n";
    $text .= "🔴 قرمز = غیرفعال (حذف‌شده)\n";
    $text .= "</blockquote>";


    if ($sendInstead) {
        sendMessage($chat_id, $text, buildGamesToggleKbTemp($pdo, $uid));
    } else {
        editMessageText($chat_id, $mid, $text, buildGamesToggleKbTemp($pdo, $uid));
    }
}


if ($data ==='user_games'){
    renderProfileIGN($pdo, $chat_id, $mid, $uid, false, $cb);
    answerCb($cb['id'], '');
    exit;
}


if (str_starts_with($data, 'game_toggle:')) {

    $gName = urldecode(substr($data, 12));

    // بررسی وجود رکورد
    $st = $pdo->prepare("
        SELECT id, active
        FROM user_games
        WHERE user_id=? AND game=?
        LIMIT 1
    ");
    $st->execute([$uid, $gName]);

    $row = $st->fetch(PDO::FETCH_ASSOC);

    if ($row) {

        // تغییر وضعیت
        $newStatus = $row['active'] ? 0 : 1;

        $pdo->prepare("
            UPDATE user_games
            SET active=?
            WHERE id=?
        ")->execute([
            $newStatus,
            $row['id']
        ]);

    } else {

        // گرفتن game_code از جدول games
        $stGame = $pdo->prepare("
            SELECT id
            FROM games
            WHERE name=?
            LIMIT 1
        ");
        $stGame->execute([$gName]);

        $gameCode = (int)$stGame->fetchColumn();

        // اولین بار فعال شود
        $newStatus = 1;

        $pdo->prepare("
            INSERT INTO user_games
            (user_id, game, game_code, active)
            VALUES (?,?,?,?)
        ")->execute([
            $uid,
            $gName,
            $gameCode,
            $newStatus
        ]);
    }

    answerCb(
        $cb['id'],
        $newStatus
            ? '🟢 بازی فعال شد'
            : '🔴 بازی غیرفعال شد'
    );

    // رفرش همان منوی مدیریت بازی‌ها
    renderProfileIGN(
        $pdo,
        $chat_id,
        $mid,
        $uid,
        false
    );

    exit;
}




/*
if ($data === 'profile_games_save') {
    // گرفتن وضعیت temp
    $st = $pdo->prepare("SELECT temp FROM users WHERE id=? LIMIT 1");
    $st->execute([$uid]);
    $row = $st->fetch(PDO::FETCH_ASSOC);

    $temp = $row['temp'] ? jdec($row['temp']) : [];

    foreach ($temp as $gName => $info) {
        // بررسی وجود گیم در جدول user_games
        $st2 = $pdo->prepare("SELECT id FROM user_games WHERE user_id=? AND game=? LIMIT 1");
        $st2->execute([$uid, $gName]);
        $row2 = $st2->fetch(PDO::FETCH_ASSOC);

        if ($row2) {
            // اگر وجود داشت → فقط وضعیت active را به روز کن
            $pdo->prepare("UPDATE user_games SET active=? WHERE id=?")
                ->execute([$info['active'], $row2['id']]);
         } else {

            $stGame = $pdo->prepare("SELECT id FROM games WHERE name=? LIMIT 1");
            $stGame->execute([$gName]);
            $gameId = (int)$stGame->fetchColumn();

            $pdo->prepare("
                INSERT INTO user_games
                (user_id, game, game_code, active)
                VALUES (?,?,?,?)
            ")->execute([
                $uid,
                $gName,
                $gameId,
                $info['active']
            ]);
        }
    }

    // پاک کردن temp
    $pdo->prepare("UPDATE users SET temp=NULL WHERE id=?")->execute([$uid]);

    answerCb($cb['id'], '✅ تغییرات ذخیره شد');

    // رندر پروفایل با اطلاعات جدید
    [$txt, $kb] = renderProfile($pdo, getUser($pdo, $uid));
    editMessageText($chat_id, $mid, $txt, $kb);
    exit;
}
*/



if (str_starts_with($data, 'profile_ign')) {
    $parts = explode(':', $data);
    $flag = isset($parts[1]) && $parts[1] === 'true';
    $st = $pdo->prepare('SELECT game FROM user_games WHERE user_id=? and active=1');
    $st->execute([$uid]);
    $ug = $st->fetchAll(PDO::FETCH_ASSOC);

    if (!$ug) {
        answerCb($cb['id'], '⚠️ ابتدا گیم را اضافه کنید');
    }

    if($flag){
        deleteMessage($chat_id, $mid);
    } else {
        answerCb($cb['id'], '');
    }
    renderProfileIGN($pdo, $chat_id, $mid, $uid, $flag);
    exit;
}


if (str_starts_with($data, 'edit_ign_input:')) {

    $rowId = (int)explode(':', $data, 2)[1];

    $st = $pdo->prepare("SELECT game FROM user_games WHERE id=? AND user_id=?");
    error_log("ROW_ID = " . $rowId);
    $st->execute([$rowId, $uid]);
    $g = $st->fetchColumn();

    if (!$g) {
        answerCb($cb['id'], 'بازی پیدا نشد');
        exit;
    }

    setState($pdo, $uid, 'ign_input:' . $rowId);

    answerCb($cb['id'], '✍️ منتظر IGN جدید هستم...');

    $msg  = "<blockquote>🎮 بازی انتخاب‌شده: <b>" . htmlspecialchars($g) . "</b></blockquote>\n\n";
    $msg .= "📝 لطفاً نام درون بازی (Nickname) خود را ارسال کنید.\n";

    $file_id = 'Dog - Amade khedmat';

    editGif($chat_id, $mid, [
        'media' => $file_id,
        'caption' => $msg,
        'parse_mode' => 'HTML'
        ], [
        'inline_keyboard' => [
            [['text' => '🔙 بازگشت به پروفایل', 'callback_data' => 'profile_ign:true']]
        ]
    ]);


    exit;
}

if (str_starts_with($data, 'edit_gameid_input:')) {

    $rowId = (int)explode(':', $data, 2)[1];

    $st = $pdo->prepare("SELECT game FROM user_games WHERE id=? AND user_id=?");
    $st->execute([$rowId, $uid]);
    $g = $st->fetchColumn();

    if (!$g) {
        answerCb($cb['id'], 'بازی پیدا نشد');
        exit;
    }

    setState($pdo, $uid, 'gameid_input:' . $rowId);

    answerCb($cb['id'], '✍️ منتظر ID جدید هستم...');

    $msg  = "<blockquote>🎮 بازی انتخاب‌شده: <b>" . htmlspecialchars($g) . "</b></blockquote>\n\n";
    $msg .= "🔢 لطفاً شناسه (ID) خود را ارسال کنید.\n";

    $file_id = 'Dog - Amade khedmat';

    editGif($chat_id, $mid, [
        'media' => $file_id,
        'caption' => $msg,
        'parse_mode' => 'HTML'
        ], [
        'inline_keyboard' => [
            [['text' => '🔙 بازگشت به پروفایل', 'callback_data' => 'profile_ign:true']]
        ]
    ]);

    exit;
}



if (preg_match('/^wallet_history(?::(\d+))?(?::([a-z]+))?$/', $data, $m)) {
    $page = isset($m[1]) ? (int)$m[1] : 1;
    $filter = isset($m[2]) ? strtolower($m[2]) : 'all'; // فیلتر نوع تراکنش
    $perPage = 10;
    $offset = ($page - 1) * $perPage;

    // ساخت شرط فیلتر
    $filterCondition = '';
    $filterValues = [$uid];
    if ($filter !== 'all') {
        $filterCondition = " AND reason = ?";
        $filterValues[] = $filter;
    }

    // گرفتن کل تعداد تراکنش‌ها
    $st = $pdo->prepare("SELECT COUNT(*) FROM transactions WHERE user_id=? AND status='approved' $filterCondition");
    $st->execute($filterValues);
    $total = (int)$st->fetchColumn();
    $totalPages = max(1, ceil($total / $perPage));

    // گرفتن تراکنش‌ها
    $st = $pdo->prepare("
        SELECT id, reason, amount, created_at 
        FROM transactions 
        WHERE user_id=? AND status='approved' $filterCondition
        ORDER BY created_at DESC 
        LIMIT $perPage OFFSET $offset
    ");
    $st->execute($filterValues);
    $transactions = $st->fetchAll(PDO::FETCH_ASSOC);


    if ($total == 0) {
    $txt = "⛔ <b>هیچ تراکنشی یافت نشد</b>\n\n";
    $txt .= "💳 در حال حاضر تراکنشی برای حساب شما ثبت نشده است.\n";
    $txt .= "پس از انجام تراکنش‌های جدید، دوباره این بخش را بررسی کنید.\n\n";
    $txt .= "<blockquote>📝 <b>راهنما:</b>\n• تراکنش‌ها شامل شارژ، برداشت و ایونت می‌شوند.\n• با استفاده از دکمه زیر می‌توانید به منوی اصلی بازگردید.</blockquote>";

    $keyboard = [
        [['text' => '📭 تراکنشی ندارید', 'callback_data' => 'profile_show']]
    ];

    editMessageText($chat_id, $mid, $txt, ['inline_keyboard' => $keyboard]);
    answerCb($cb['id'], '');
    exit;
}



    $txt = "📜 <b>تاریخچه تراکنش‌های شما</b> | <b>صفحه {$page} از {$totalPages}</b>\n\n";
    $txt .= "💳 در این بخش می‌توانید تمامی تراکنش‌های انجام‌شده در حساب خود را مشاهده کنید.\n";
    $txt .= "برای یافتن سریع‌تر تراکنش‌ها می‌توانید از فیلترهای زیر استفاده کنید 👇\n\n";
    $txt .= "<blockquote>📝 <b>راهنما:</b>\n• با انتخاب یکی از فیلترهای زیر، فقط همان نوع تراکنش نمایش داده می‌شود.\n• با استفاده از ⏪ قبلی و ⏩ بعدی می‌توانید بین صفحات جابه‌جا شوید.\n• روی هر تراکنش بزنید تا جزئیات کامل آن نمایش داده شود.</blockquote>\n\n";


    // فیلتر دسته‌بندی
    $filterRow = [
        ['text' => '💰 شارژ', 'callback_data' => "wallet_history:1:topup"],
        ['text' => '📤 برداشت', 'callback_data' => "wallet_history:1:withdraw"],
        ['text' => '🎟 ایونت', 'callback_data' => "wallet_history:1:efee"],
        ['text' => '📋 همه', 'callback_data' => "wallet_history:1:all"],
    ];

    $keyboard = [$filterRow];

    // ساخت دکمه‌های تراکنش‌ها (دو ستونه)
    $row = [];
    foreach ($transactions as $tx) {
        $amount = number_format($tx['amount']);
        $time = date('H:i', strtotime($tx['created_at'] . ' +3 hours 30 minutes')); // تبدیل UTC به +3:30
        $sign = in_array(strtolower($tx['reason']), ['topup','deposit']) ? '+' : '-';

        switch (strtolower($tx['reason'])) {
            case 'topup':
            case 'deposit':
                $emoji = '💰';
                $typeText = "شارژ";
                break;
            case 'withdraw':
                $emoji = '📤';
                $typeText = "برداشت";
                break;
            case 'efee':
                $emoji = '🎟';
                $typeText = "ایونت";
                break;
            default:
                $emoji = '🔸';
                $typeText = "سایر";
                break;
        }

        $btnText = "{$sign}{$amount} | {$typeText} 🕒 {$time}";
        $row[] = ['text' => "{$emoji} {$btnText}", 'callback_data' => "tx_view:{$tx['id']}"];

        if (count($row) == 2) {
            $keyboard[] = $row;
            $row = [];
        }
    }
    if (!empty($row)) $keyboard[] = $row;

    // صفحه‌بندی
    $navRow = [];
    if ($page > 1) {
        $navRow[] = ['text' => '⏪ قبلی', 'callback_data' => "wallet_history:" . ($page - 1) . ":{$filter}"];
    }
    if ($page < $totalPages) {
        $navRow[] = ['text' => '⏩ بعدی', 'callback_data' => "wallet_history:" . ($page + 1) . ":{$filter}"];
    }
    if (!empty($navRow)) $keyboard[] = $navRow;

    // دکمه بازگشت
    $keyboard[] = [
        ['text'=>'🔙 بازگشت','callback_data'=>'profile_show']
    ];

    editMessageText($chat_id, $mid, $txt, ['inline_keyboard' => $keyboard]);
    answerCb($cb['id'], '');
    exit;
}


// هندلر نمایش جزئیات تراکنش
if (preg_match('/^tx_view:(\d+)$/', $data, $m)) {
    $txId = (int)$m[1];

    // گرفتن تراکنش
    $st = $pdo->prepare("SELECT * FROM transactions WHERE id=? AND user_id=? LIMIT 1");
    $st->execute([$txId, $uid]);
    $tx = $st->fetch(PDO::FETCH_ASSOC);

    if (!$tx) {
        editMessageText($chat_id, $mid, "❌ تراکنش یافت نشد یا دسترسی ندارید.");
        answerCb($cb['id'], '');
        exit;
    }

    // جزئیات پایه
    $date = jdate('Y/m/d', strtotime($tx['created_at']));
    $amount = number_format($tx['amount']);
    $userId = $tx['user_id'];

    // وضعیت تراکنش
    $statusText = "";
    switch (strtolower($tx['status'])) {
        case 'approved': $statusText = "✅ تأیید شده"; break;
        case 'pending': $statusText = "⏳ در انتظار تأیید"; break;
        case 'rejected': $statusText = "❌ رد شده"; break;
        default: $statusText = $tx['status']; break;
    }
    $approvedDate = $tx['time_approved'] ? jdate('Y/m/d H:i', strtotime($tx['time_approved'])) : "ثبت نشده";

    // نوع تراکنش
    $reason = strtolower($tx['reason']);
    $reasonText = "";
    $extraInfo = "";

    switch ($reason) {
        case 'topup':
        case 'deposit':
            $reasonText = "شارژ حساب";
            $amount = "+{$amount} تومان";
            break;

        case 'withdraw':
            $reasonText = "برداشت وجه";
            $amount = "-{$amount} تومان";
            $extraInfo = "<blockquote dir='rtl'>🏦 شماره شبا مقصد: {$tx['withdraw_to']}\n📅 تاریخ برداشت: {$approvedDate}</blockquote>";
            break;

        case 'efee':
            $reasonText = "پرداخت ورودی ایونت";
            $amount = "-{$amount} تومان";
            if (!empty($tx['event_id'])) {
                $evSt = $pdo->prepare("SELECT name, game, date_str FROM events WHERE id=? LIMIT 1");
                $evSt->execute([$tx['event_id']]);
                $event = $evSt->fetch(PDO::FETCH_ASSOC);
                if ($event) {
                    $eventDate = isset($event['date_str']) ? jdate('Y/m/d', strtotime($event['date_str'])) : "ثبت نشده";
                    $extraInfo = "<blockquote dir='rtl'>🆔 آیدی ایونت: {$tx['event_id']}\n🏷️ نام ایونت: {$event['name']}\n🕹️ گیم: {$event['game']}\n📅 تاریخ برگزاری: {$eventDate}</blockquote>";
                }
            }
            break;

        default:
            $reasonText = "سایر تراکنش‌ها";
            break;
    }

    // ساخت متن پیام
    $txt = "🧾 <b>جزئیات تراکنش #{$tx['id']}</b>\n\n";
    $txt .= "📅 تاریخ ثبت: {$date}\n";
    $txt .= "💰 مبلغ: {$amount}\n";
    $txt .= "📌 نوع: {$reasonText}\n";
    $txt .= "🧍 شناسه کاربر: {$userId}\n\n";
    $txt .= "📝 وضعیت: {$statusText}\n";
    $txt .= "🕓 تاریخ تأیید: {$approvedDate}\n\n";
    $txt .= $extraInfo;

    // دکمه بازگشت
    $kb = [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>'wallet_history:1']]
        ]
    ];

    editMessageText($chat_id, $mid, $txt, $kb);
    answerCb($cb['id'], '');
    exit;
}

// قبل از هر کاری، بررسی cooldown
if (checkCooldown($pdo, $uid, 'wallet_topup', $callback['id'] ?? null)) {
    exit;
}

// منوی شارژ
if ($data === 'wallet_topup') {
    $chat_id = $callback['message']['chat']['id'];
    $uid = $callback['from']['id'];

    $txt = "💳 <b>افزایش موجودی</b>\n\nلطفاً مبلغ مورد نظر خود را انتخاب کنید:";

    $kb = [
        'inline_keyboard' => [
            [
                ['text'=>'50,000 تومان','callback_data'=>'wallet_topup_amount:50000'],
                ['text'=>'100,000 تومان','callback_data'=>'wallet_topup_amount:100000']
            ],
            [
                ['text'=>'مبلغ دلخواه 💰','callback_data'=>'wallet_topup_custom']
            ],
            [
                ['text'=>'🔙 بازگشت','callback_data'=>'profile_show']
            ]
        ]
    ];

    editMessageText($chat_id, $callback['message']['message_id'], $txt, $kb);
    exit;
}

// مبلغ دلخواه
if ($data === 'wallet_topup_custom') {
    $chat_id = $callback['message']['chat']['id'];
    $uid = $callback['from']['id'];

    setState($pdo, $uid, 'awaiting_topup_amount');
    error_log("State after setting: " . $pdo->query("SELECT state FROM users WHERE id=$uid")->fetchColumn());


    $txt = "💰 لطفاً مبلغ مورد نظر برای شارژ کیف پول را به صورت عدد وارد کنید (حداقل ۱۵,۰۰۰ تومان).";
    $kb = [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>'wallet_topup']]
        ]
    ];

    editMessageText($chat_id, $callback['message']['message_id'], $txt, $kb);
    exit;
}

// دریافت مبلغ از کاربر
if ($state === 'awaiting_topup_amount') {
    $uid = $message['from']['id'];
    $chat_id = $message['chat']['id'];
    $text = trim($message['text']);
    $mid = $message['message_id'];

    if (!is_numeric($text) || (int)$text <= 0) {
        // دوباره همون حالت رو نگه می‌داریم تا کاربر مبلغ جدید بزنه
        setState($pdo, $uid, 'awaiting_topup_amount');
        sendMessage($uid, "⚠️ لطفاً فقط یک عدد معتبر و مثبت وارد کنید (حداقل ۱۵,۰۰۰ تومان).");
        exit;
    }

    $amount = (int)$text;

    if ($amount < 15000) {
        // دوباره همون حالت رو نگه می‌داریم
        setState($pdo, $uid, 'awaiting_topup_amount');
        sendMessage($uid, "⚠️ حداقل مبلغ شارژ کیف پول ۱۵,۰۰۰ تومان است.\nلطفاً مبلغ جدیدی وارد کنید:");
        exit;
    }

    // مبلغ معتبر، تابع هندلر رو صدا بزن
    handleWalletTopupAmount($pdo, $uid, $chat_id, $mid, $amount);
    exit;
}

// انتخاب مبلغ از منوی inline
if (str_starts_with($data, 'wallet_topup_amount:')) {
    $chat_id = $callback['message']['chat']['id'];
    $uid = $callback['from']['id'];
    $mid = $callback['message']['message_id'];

    $parts = explode(':', $data);
    $amount = (int)$parts[1];

    handleWalletTopupAmount($pdo, $uid, $chat_id, $mid, $amount);
    exit;
}


if (str_starts_with($data, 'wallet_topup_cancel:')) {
    $chat_id = $callback['message']['chat']['id'];
    $uid = $callback['from']['id'];

    $parts = explode(':', $data);
    $pid = (int)$parts[1];

    // فقط همان تراکنش مشخص را کنسل کن
    $st = $pdo->prepare("UPDATE transactions SET status='cancelled' WHERE id=? AND user_id=? AND status='pending'");
    $st->execute([$pid, $uid]);

    // ۳۰ ثانیه lock روی action
    setCooldown($pdo, $uid, 'wallet_topup', 30);

    // نمایش پروفایل کاربر بعد از لغو
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id=? LIMIT 1");
    $stmt->execute([$uid]);
    $user = $stmt->fetch(PDO::FETCH_ASSOC);

    list($txt, $kb) = renderProfile($pdo, $user);

    editMessageText($chat_id, $callback['message']['message_id'], $txt, $kb);

    // اطلاع به کاربر
    answerCb($callback['id'], "❌ تراکنش لغو شد. ۳۰ ثانیه صبر کنید.");
    exit;
}





// 📎 هندلر دکمه ارسال رسید برای Topup
if (preg_match('/^wallet_topup_proof:(\d+):(\d+)$/', $data, $m)) {
    $uid = (int)$m[1];
    $pid = (int)$m[2];
    $chat_id = $callback['message']['chat']['id'];
    $mid = $callback['message']['message_id'];

    // تغییر state به حالت منتظر دریافت عکس
    setState($pdo, $uid, "awaiting_topup_proof:{$pid}");

    $txt = "📎 لطفاً <b>تصویر رسید پرداخت</b> خود را ارسال کنید.\n\n".
           "⚠️ فقط فرمت عکس پذیرفته می‌شود. در صورت انصراف روی «بازگشت» بزنید.";

    $kb = [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>'profile']]
        ]
    ];

    editMessageText($chat_id, $mid, $txt, $kb);
    exit;
}

// 🖼️ هندلر دریافت عکس رسید Topup
if ($state && str_starts_with($state, 'awaiting_topup_proof:')) {
    $parts = explode(':', $state);
    $pid = isset($parts[1]) ? (int)$parts[1] : 0;

    $uid = $message['from']['id'] ?? 0;
    $chat_id = $message['chat']['id'] ?? 0;
    if (!$uid || !$chat_id || !$pid) {
        exit;
    }

    // دریافت file_id از عکس
    $file_id = getPhotoFileIdFromMessage($message);
    if (!$file_id) {
        sendMessage($chat_id, "⚠️ فقط یک عکس از رسید قابل قبول است. لطفاً مجدداً تلاش کنید یا با دکمه بازگشت لغو نمایید.");
        exit;
    }

    // چون topup ایونت نداره، eid = 0 می‌ذاریم
    handlePaymentPhotoReceivedByPid($pdo, $uid, $chat_id, 0, $pid, $file_id);
    exit;
}



/* / ======== خانه رویدادها ========
if ($data === 'events_home') {

    // گرفتن تعداد ایونت‌ها از دیتابیس
    $stmt = $pdo->query("SELECT type, COUNT(*) as count FROM events WHERE status='active' GROUP BY type");
    $counts = ['tournament' => 0, 'custom' => 0];
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        $counts[$row['type']] = $row['count'];
    }

    $txt = "🎮 <b>ایونت‌های فعال</b>\n\n";
    $txt .= "<blockquote>در این بخش می‌توانید تورنومنت‌ها و کاستوم‌های فعال را مشاهده کنید و در آن‌ها شرکت کنید. برای شروع روی یکی از گزینه‌ها کلیک کنید.</blockquote>";

    $keyboard = [
        'inline_keyboard' => [
            [
                ['text'=>"🏆 تورنومنت‌ها  ".toSuperscript("{$counts['tournament']}"),'callback_data'=>'events_list:tournament:0'],
                ['text'=>"🎯 کاستوم‌ها ".toSuperscript("{$counts['custom']}"),'callback_data'=>'events_list:custom:0']
            ],
            [
                ['text'=>'🔙 بازگشت','callback_data'=>'home']
            ]
        ]
    ];

    editMessageText($chat_id, $mid, $txt, $keyboard);
    answerCb($cb['id'], '');
    exit;
}

*/

// ======== لیست رویدادها ========
if (str_starts_with($data, 'events_list:')) {

    $parts = explode(':', $data);

    $type  = $parts[1];
    $page  = (int)($parts[2] ?? 0);
    $hadBanner = isset($parts[3]) && $parts[3] === 'true';
    $joined    = isset($parts[4]) && $parts[4] === 'true';

    $sql = "SELECT 1 FROM events WHERE status='active'";
    $params = [];

    if ($type !== 'all') {
        $sql .= " AND type=?";
        $params[] = $type;
    }

    $stmt = $pdo->prepare($sql . " LIMIT 1");
    $stmt->execute($params);

    if (!$stmt->fetchColumn()) {
        answerCb($cb['id'], '❌ هیچ ایونت فعالی وجود ندارد.');
        exit;
    }

    $u = getUser($pdo, $uid);
    $selectedGames = $u['current_game'] ? [$u['current_game']] : [];

    [$t, $kb] = renderEventsList($pdo, $type, $page, $uid, $selectedGames, $joined);

    if ($hadBanner) {
        deleteMessage($chat_id, $mid);
        sendMessage($chat_id, $t, $kb);
    } else {
        editMessageText($chat_id, $mid, $t, $kb);
    }

    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'events_filter:')) {
    [$null, $gameName, $type, $selectedStr, $joinedStr] = array_pad(explode(':', $data, 5), 5, '');
    $uid = $callback['from']['id'];

    // لیست فعلی بازی‌ها از کال‌بک قبلی
    $selectedGames = $selectedStr ? explode(',', $selectedStr) : [];

    // تغییر وضعیت انتخاب (اضافه یا حذف)
    if (in_array($gameName, $selectedGames)) {
        $selectedGames = array_values(array_diff($selectedGames, [$gameName]));
    } else {
        $selectedGames[] = $gameName;
    }

    // تشخیص حالت joined (true/false)
    $joined = in_array(strtolower($joinedStr), ['1', 'true'], true);

    // رندر مجدد
    [$txt, $ik] = renderEventsList($pdo, $type, 0, $uid, $selectedGames, $joined);

    editMessageText($chat_id, $mid, $txt, $ik);
    answerCb($cb['id'], '');
    exit;
}

// ======== مشاهده جزئیات رویداد ========
if (str_starts_with($data, 'ev_view:')) {

    $parts = explode(':', $data);

    $eid    = (int)($parts[1] ?? 0);
    $uid_p  = (int)($parts[2] ?? 0);
    $joined = isset($parts[3]) && $parts[3] === 'true';

    [$t, $kb, $banner] = renderEventView($pdo, $eid, $uid_p, $joined);

    if ($banner) {
        $media = [
            'type' => 'photo',
            'media' => $banner,
            'caption' => $t,
            'parse_mode' => 'HTML'
        ];
        editMessageText($chat_id, $mid, $media, $kb);
    } else {
        editMessageText($chat_id, $mid, $t, $kb);
    }

    answerCb($cb['id'], '');
    exit;
}




if (str_starts_with($data, 'ev_userview:')) {
    $parts = explode(':', $data);
    $eid = (int)$parts[1];
    $uid = (int)$parts[2];
    $hadBanner = isset($parts[3]) ? (bool)$parts[3] : false; 


    [$t, $kb] = renderEventInfo($pdo, $eid, $uid);

    if ($hadBanner) {

        deleteMessage($chat_id, $mid);
        sendMessage($chat_id, $t, $kb);

    } else {

        editMessageText($chat_id, $mid, $t, $kb);

    }

    answerCb($cb['id'], '');
    exit;
}




// ======== مشاهده توضیحات ========
if (str_starts_with($data, 'ev_info:')) {
    $eid = (int)substr($data, 8);
    $st  = $pdo->prepare('SELECT info FROM events WHERE id=?');
    $st->execute([$eid]);
    $info = $st->fetchColumn() ?: '—';

    editMessageText(
        $chat_id,
        $mid,
        '🧾 توضیحات:\n'.htmlspecialchars($info),
        ['inline_keyboard'=>[['text'=>'🔙 بازگشت','callback_data'=>'ev_view:'.$eid]]]
    );
    answerCb($cb['id'], '');
    exit;
}



// ======== ثبت نام در رویداد ========
if (str_starts_with($data, 'ev_join:')) {
    $parts = explode(':', $data);
    $eid = (int)$parts[1];
    $uid = (int)$parts[2];
    $hadBanner = false;
    $source = null;

    if (isset($parts[3])) {

        if ($parts[3] === 'reminder') {

            $source = 'reminder';
            $tracker->reminderClicked(
                $eid,
                $uid
            );

        } else {

            $hadBanner = (bool)$parts[3];

            $source = $parts[4] ?? null;
        }
    }

    processEventJoinRequest($pdo, $chat_id, $mid, $cb, $uid, $eid, $hadBanner, $bot_username);
    exit;
}

if (str_starts_with($data, 'refresh_ev_join:')) {
    $parts = explode(':', $data);
    $eid = (int)$parts[1];
    $uid = (int)$parts[2];
    $hadBanner = isset($parts[3]) ? (bool)$parts[3] : false;

    processEventJoinRequest($pdo, $chat_id, $mid, $cb, $uid, $eid, $hadBanner, $bot_username);
    exit;
}

 if ($data === 'ready_event') {
        $responses = [
            '🚨 شروع نزدیکه، آماده باش!',
            '😉 جوووووون بــــابــــا',
        ];
        $msg = $responses[array_rand($responses)];

        answerCb($cb['id'], "{$msg}", true); // درشت و بولد
    }



if (str_starts_with($data, 'check_join:')) {

    $eid = (int)explode(':', $data)[1];

    $st = $pdo->prepare("
        SELECT id, private_channel, require_private_channel
        FROM events
        WHERE id=?
    ");
    $st->execute([$eid]);

    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        answerCb($cb['id'], '❌ ایونت پیدا نشد.', true);
        exit;
    }

    $st = $pdo->prepare("
        SELECT value, enabled
        FROM settings
        WHERE `key` = 'force_channels'
        LIMIT 1
    ");
    $st->execute();
    $forceJoin = $st->fetch(PDO::FETCH_ASSOC);

    $eventRequireJoin  = (bool)($event['require_private_channel'] ?? false);
    $globalRequireJoin = (bool)($forceJoin['enabled'] ?? false);

    $requiredChannels = [];

    if ($eventRequireJoin) {
        $eventChannels = json_decode($event['private_channel'] ?? '[]', true) ?: [];
        foreach ($eventChannels as $channel) {
            if (!isset($channel['chat_id'])) {
                continue;
            }
            $requiredChannels[$channel['chat_id']] = $channel;
        }
    }

    if ($globalRequireJoin) {
        $globalChannels = json_decode($forceJoin['value'] ?? '[]', true) ?: [];
        foreach ($globalChannels as $channel) {
            if (!isset($channel['chat_id'])) {
                continue;
            }
            $requiredChannels[$channel['chat_id']] = $channel;
        }
    }

    $requiredChannels = array_values($requiredChannels);

    $kb = buildForceJoinKeyboard(
        $bot_token,
        $uid,
        json_encode($requiredChannels, JSON_UNESCAPED_UNICODE),
        $eid,
        'check_join:' . $eid
    );

    if ($kb !== null) {

        editMessageReplyMarkup(
            $chat_id,
            $mid,
            $kb
        );

        answerCb(
            $cb['id'],
            '⚠️ هنوز عضو همه کانال‌ها نشده‌اید.',
            true
        );

        exit;
    }

    processEventJoinRequest($pdo, $chat_id, $mid, $cb, $uid, $eid, false, $bot_username ?? BOT_USERNAME);
    exit;
}


if (strpos($data, 'check_ref_join:') === 0) {

    $refId = explode(':', $data, 2)[1];

    $st = $pdo->prepare("
        SELECT *
        FROM referrals
        WHERE ref_id = ?
        LIMIT 1
    ");
    $st->execute([$refId]);

    $ref = $st->fetch(PDO::FETCH_ASSOC);

    if (!$ref) {

        answerCallbackQuery(
            $callback_query_id,
            "❌ لینک دعوت معتبر نیست.",
            true
        );
        exit;
    }

    $st = $pdo->prepare("
        SELECT value, enabled
        FROM settings
        WHERE `key` = 'force_channels'
        LIMIT 1
    ");

    $st->execute();

    $forceJoin = $st->fetch(PDO::FETCH_ASSOC);

    $eventId = (int)$ref['event_id'];

    $st = $pdo->prepare("
        SELECT private_channel, require_private_channel
        FROM events
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$eventId]);

    $event = $st->fetch(PDO::FETCH_ASSOC);

    $file_id = 'Cat - Poker Face';
    $txt = "<b>👀 به نظر می‌رسد هنوز عضویت شما کامل نشده است.</b>\n\n<blockquote>لطفاً در کانال‌های زیر عضو شوید و سپس دوباره روی «بررسی عضویت» بزنید.</blockquote>";


    if (!$event) {

        answerCallbackQuery(
            $callback_query_id,
            "❌ ایونت پیدا نشد.",
            true
        );
        exit;
    }

    $eventRequireJoin  = (bool)($event['require_private_channel'] ?? false);
    $globalRequireJoin = (bool)($forceJoin['enabled'] ?? false);

    $requiredChannels = [];

    // کانال‌های ایونت
    if ($eventRequireJoin) {

        $eventChannels = json_decode(
            $event['private_channel'] ?? '[]',
            true
        ) ?: [];

        foreach ($eventChannels as $channel) {

            if (!isset($channel['chat_id'])) {
                continue;
            }

            $requiredChannels[$channel['chat_id']] = $channel;
        }
    }

    // کانال‌های سراسری
    if ($globalRequireJoin) {

        $globalChannels = json_decode(
            $forceJoin['value'] ?? '[]',
            true
        ) ?: [];

        foreach ($globalChannels as $channel) {

            if (!isset($channel['chat_id'])) {
                continue;
            }

            $requiredChannels[$channel['chat_id']] = $channel;
        }
    }

    $requiredChannels = array_values($requiredChannels);

    $kb = buildForceJoinKeyboard(
        $bot_token,
        $uid,
        json_encode($requiredChannels, JSON_UNESCAPED_UNICODE),
        $eventId,
        "check_ref_join:$refId"
    );

    if ($kb !== null) {
        editGif($chat_id, $mid, [
        'media' => $file_id,
        'caption' => $txt,
        'parse_mode' => 'HTML'
        ], $kb);

        answerCb($cb['id'], '❌ هنوز در همه کانال‌ها عضو نشده‌اید.');
        exit;
    }

    // ثبت نهایی رفرال
    $st = $pdo->prepare("
        UPDATE referral_starts
        SET status='valid'
        WHERE ref_id = ?
          AND user_id = ?
          AND event_id = ?
    ");

    $st->execute([
        $refId,
        $uid,
        $eventId
    ]);

    answerCb($cb['id'], '✅ عضویت تأیید شد.');


    deleteMessage($chat_id, $mid);

    // پیام به دعوت‌شده
    sendMessage(
        $uid,
        "✅ عضویت شما تأیید شد."
    );

    // پیام به دعوت‌کننده
    sendMessage(
        $ref['referrer_id'],
        "🎉 یک نفر از لینک دعوت شما عضو شد."
    );

    tryAutoRegisterReferrer(
        $pdo,
        $ref['referrer_id'],
        $eventId,
        $bot_username
    );

    exit;
}

// ========cancel event========

if (str_starts_with($data, 'ev_cancel:')) {
    [, $eid] = explode(':', $data);
    $eid = (int)$eid;
    $hadBanner = true;

    $file_id = 'Braking Bad - Persepolis';
    $txt = "❓ آیا مطمئن هستید که می‌خواهید ثبت‌نام خود را در ایونت <code>$eid</code> لغو کنید؟";
    $kb = ['inline_keyboard' => [
        [['text'=>'✅ بله، لغو کن','callback_data'=>'ev_cancel_confirm:' . $eid,'style'=>'success']],
        [['text'=>'🔙 خیر، بازگشت','callback_data'=>'ev_userview:' . $eid . ':' . $uid . ':' . $hadBanner,'style'=>'danger']]
    ]];

    editGif($chat_id, $mid, [
        'media' => $file_id,
        'caption' => $txt,
        'parse_mode' => 'HTML'
    ], $kb);
    answerCb($cb['id'], '');
    exit;
}

  
if (str_starts_with($data, 'ev_cancel_confirm:')) {
    [, $eid] = explode(':', $data);
    $eid = (int)$eid;

    $st = $pdo->prepare("UPDATE event_players SET status=? WHERE user_id=? AND ev_id=?");
    $st->execute(['canceled', $uid, $eid]);


    deleteMessage($chat_id, $mid);
    showWelcome($pdo, $chat_id, $uid, $user);
    answerCb($cb['id'], '✅ ثبت‌نام شما در ایونت لغو شد.');
    exit;
}



//------------------------------------
if (str_starts_with($data, 'ev_squad:')) {
    [, $eid, $uid, $hadBanner] = array_pad(explode(':', $data), 4, null);
    showSquad($pdo, (int)$eid, (int)$uid, $chat_id, $mid, (bool)$hadBanner);
    exit;
}


if (str_starts_with($data, 'squad_member:')) {
    [, $eid, $uid, $targetUid] = explode(':', $data);

    // بررسی اینکه کاربر لیدر است
    $st = $pdo->prepare("SELECT leader_uid FROM event_squads WHERE eid=? AND (leader_uid=? OR EXISTS(SELECT 1 FROM event_players WHERE user_id=? AND squad_id=event_squads.id))");
    $st->execute([$eid, $uid, $uid]);
    $squad = $st->fetch(PDO::FETCH_ASSOC);

    if (!$squad || $squad['leader_uid'] != $uid) {
        answerCallbackQuery($cbid, '');
        exit;
    }

    // گرفتن اطلاعات بازیکن
    $st = $pdo->prepare("SELECT ign FROM event_players WHERE user_id=? LIMIT 1");
    $st->execute([$targetUid]);
    $player = $st->fetch(PDO::FETCH_ASSOC);

    $ign = htmlspecialchars($player['ign'] ?? 'نامشخص');
    $t = "👤 <b>$ign</b>\nمدیریت بازیکن:";

    $kb = [
        'inline_keyboard' => [
            [
                ['text' => '👑 انتقال لیدری', 'callback_data' => "squad_leader:$eid:$uid:$targetUid"],
                ['text' => '🗑 حذف از اسکواد', 'callback_data' => "squad_remove:$eid:$uid:$targetUid"]
            ],
            [
                ['text' => '📋 اطلاعات بیشتر', 'callback_data' => "squad_info:$eid:$uid:$targetUid"]
            ],
            [
                ['text' => '🔙 بازگشت', 'callback_data' => "ev_squad:$eid:$uid:$hadBanner"]
            ]
        ]
    ];

    editMessageText($chat_id, $mid, $t, $kb, 'HTML');
    exit;
}



if (str_starts_with($data, 'squad_invite:')) {
    [, $eid] = explode(':', $data);

    if (eventStarted($pdo, $eid)) {
        editMessageText($chat_id, $mid, "⛔ ایونت شروع شده. امکان دعوت وجود ندارد.", [
            'inline_keyboard' => [[['text'=>'🔙 بازگشت','callback_data'=>'ev_squad:' . $eid]]]
        ]);
        exit;
    }

    // ✅ چک محدودیت دعوت‌ها
    $stLimit = $pdo->prepare("
        SELECT COUNT(*) 
        FROM event_invites i
        JOIN event_squads s ON s.id = i.squad_id
        WHERE s.eid = ? AND s.leader_uid = ? AND i.status = 'pending'
    ");
    $stLimit->execute([$eid, $uid]);
    $invite_count = $stLimit->fetchColumn();

    if ($invite_count >= 10) {
        answerCb($cb['id'], '', false);
        sendMessage($chat_id, [
            'text' => "<b>⚠️ حداکثر تعداد دعوت برای این ایونت 10 نفر است.</b>\n\n"
                . "<blockquote>لطفاً یکی از دعوت‌های قبلی را حذف کنید.</blockquote>",
            'parse_mode' => 'HTML'
        ]);
        exit;
    }

    $inlineKeyboard = [
        'inline_keyboard' => [
            [['text' => '👥 انتخاب از مخاطبین', 'callback_data' => 'squad_invite_contact:' . $eid]],
            [['text' => '🔙 بازگشت', 'callback_data' => 'ev_squad:' . $eid]]
        ]
    ];

    $file_id = 'Jim Carrey Typing'; 
    sendMessage($chat_id, [
        'animation' => $file_id,
        'caption' => "👤 لطفاً یکی از گزینه‌های زیر را برای دعوت وارد کنید:\n\n"
            . "<blockquote>• آیدی عددی کاربر (مثلاً <code>123456789</code>)\n"
            . "• یوزرنیم کاربر (مثلاً <code>@example</code>)\n"
            . "• یا از دکمه‌ی زیر برای انتخاب از مخاطبین استفاده کنید 👇</blockquote>",
        'parse_mode' => 'HTML'
    ], $inlineKeyboard);

    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'squad_invite_contact:')) {
    [, $eid] = explode(':', $data);

    setState($pdo, $uid, "squad_invite_wait:$eid");
    $replyKeyboard = [
        'keyboard' => [
            [[
                'text' => '👥 انتخاب از مخاطبین',
                'request_user' => ['request_id' => 1]
            ]],
            [['text' => '🔙 بازگشت']]
        ],
        'resize_keyboard' => true,
        'one_time_keyboard' => false
    ];

    // ارسال پیام با کیبورد
    sendMessage($chat_id, [
        'text' => "📱 لطفاً از کیبورد پایین برای انتخاب مخاطب استفاده کن.",
    ], $replyKeyboard);

    answerCb($cb['id'], '');
    exit;
}




if (str_starts_with($data, 'squad_invite_member:')) {
    [, $eid, $leader_uid, $invite_id] = explode(':', $data);

    $st = $pdo->prepare("SELECT * FROM event_invites WHERE id=? LIMIT 1");
    $st->execute([$invite_id]);
    $inv = $st->fetch(PDO::FETCH_ASSOC);

    if (!$inv) {
        answerCb($cb['id'], "❌ این دعوت‌نامه یافت نشد");
        exit;
    }

    $target_uid = $inv['target_uid'];

    // گرفتن نام و یوزرنیم از جدول users
    $st = $pdo->prepare("SELECT first_name, username FROM users WHERE id=? LIMIT 1");
    $st->execute([$target_uid]);
    $u = $st->fetch(PDO::FETCH_ASSOC);

    $fullName = !empty($u['first_name']) ? $u['first_name'] : '—';
    $username = !empty($u['username']) ? '@' . $u['username'] : '—';

    $statusText = match($inv['status']) {
        'pending' => '⏳ در انتظار پاسخ',
        'accepted' => '✅ پذیرفته شده',
        'rejected' => '❌ رد شده',
        'cancelled' => '🚫 لغو شده',
        default => '—'
    };

    $txt = "🎟 <b>جزئیات دعوت‌نامه | $statusText</b>\n\n"
         . "👤 نام: <b>$fullName</b>\n"
         . "💠 یوزرنیم: <b>$username</b>\n"
         . "📅 ارسال‌شده: <code>{$inv['created_at']}</code>\n";

    $ik = [
        [
            ['text' => '📨 ارسال مجدد', 'callback_data' => "invite_resend:$invite_id"],
            ['text' => '🗑 لغو دعوت', 'callback_data' => "invite_cancel:$invite_id"]
        ],
        [
            ['text'=>'🔙 بازگشت','callback_data'=>"ev_squad:$squad_id"]
        ]
    ];

    editMessageText($chat_id, $mid, $txt, [
        'parse_mode' => 'HTML',
        'inline_keyboard' => $ik
    ]);

    answerCb($cb['id'], '');
}

if (str_starts_with($data, 'invite_cancel:')) {
    [, $invite_id] = explode(':', $data);

    // به جای حذف، فقط وضعیت را تغییر می‌دهیم
    $st = $pdo->prepare("UPDATE event_invites SET status='cancelled' WHERE id=?");
    $st->execute([$invite_id]);

    answerCb($cb['id'], '✅ دعوت‌نامه لغو شد');

    // آپدیت پیام اسکواد لیدر
    showSquad($pdo, $squad_id, $uid, $chat_id, $mid, true);
    exit;
}

if (str_starts_with($data, 'invite_resend:')) {
    [, $invite_id] = explode(':', $data);

    $st = $pdo->prepare("SELECT * FROM event_invites WHERE id=? LIMIT 1");
    $st->execute([$invite_id]);
    $inv = $st->fetch(PDO::FETCH_ASSOC);

    if (!$inv) {
        answerCb($cb['id'], '❌ دعوت‌نامه یافت نشد');
        exit;
    }

    $target_uid = $inv['target_uid'];

    // بررسی وجود کاربر در جدول users
    $stUser = $pdo->prepare("SELECT first_name, username FROM users WHERE id=? LIMIT 1");
    $stUser->execute([$target_uid]);
    $user = $stUser->fetch(PDO::FETCH_ASSOC);

    if (!$user || empty($target_uid)) {
        // کاربر ثبت نشده
        $txt = "⚠️ کاربر در سیستم ثبت نشده. لطفاً ابتدا دعوت‌نامه را به او ارسال کنید.";
        $ik = [
            [['text'=>'📨 نمایش دعوت‌نامه','callback_data'=>"show_invite:$invite_id"]],
            [['text'=>'🔙 بازگشت','callback_data'=>"ev_squad:{$inv['squad_id']}"]]
        ];

        editMessageText($chat_id, $mid, $txt, [
            'parse_mode'=>'HTML',
            'inline_keyboard'=>$ik
        ]);
        answerCb($cb['id'], '');
        exit;
    }

    // چک محدودیت ۱۵ دقیقه بین ارسال‌ها
    $lastUpdate = strtotime($inv['updated_at'] ?? '2000-01-01 00:00:00');
    if (time() - $lastUpdate < 15 * 60) {
        answerCb($cb['id'], '⏳ امکان ارسال مجدد تا ۱۵ دقیقه دیگر وجود ندارد', true);
        exit;
    }

    // ارسال دعوتنامه به کاربر
    $inviteLink = "https://t.me/$bot_username?start=squad_{$inv['invite_code']}";
    $msg_text = "📨 شما دعوت شده‌اید به اسکواد!\nبرای پیوستن روی لینک زیر بزنید:\n$inviteLink";

    sendMessage($target_uid, $msg_text, [
        'inline_keyboard'=>[[['text'=>'✅ پیوستن به اسکواد','url'=>$inviteLink]]]
    ]);

    // آپدیت زمان ارسال مجدد
    $stUpdate = $pdo->prepare("UPDATE event_invites SET updated_at=NOW(), status='pending' WHERE id=?");
    $stUpdate->execute([$invite_id]);

    answerCb($cb['id'], '📨 دعوت‌نامه دوباره ارسال شد');

    // آپدیت پیام لیدر
    showSquad($pdo, $inv['squad_id'], $uid, $chat_id, $mid, true);
    exit;
}

if (str_starts_with($data, 'squad_accept:')) {
    [, $eid, $leader_id] = explode(':', $data);
    $eid = (int)$eid;
    $leader_id = (int)$leader_id;

    // بررسی شروع ایونت
    if (eventStarted($pdo, $eid)) {
        sendMessage($chat_id, "⛔ ایونت شروع شده. امکان پذیرش وجود ندارد.");
        exit;
    }

    // بررسی ثبت‌نام قبلی کاربر
    $st = $pdo->prepare("SELECT ev_ids FROM users WHERE id=?");
    $st->execute([$uid]);
    $ev_ids = json_decode($st->fetchColumn(), true) ?? [];
    $alreadyJoined = in_array($eid, $ev_ids);

    // گرفتن اطلاعات ایونت
    $st = $pdo->prepare("SELECT game, entry_fee, currency, players, squad FROM events WHERE id=?");
    $st->execute([$eid]);
    $e = $st->fetch(PDO::FETCH_ASSOC);
    if (!$e) {
        sendMessage($chat_id, "❌ ایونت یافت نشد.");
        exit;
    }

    $game = $e['game'];

    // بررسی IGN کاربر
    $st = $pdo->prepare("SELECT games FROM users WHERE id=?");
    $st->execute([$uid]);
    $games = json_decode($st->fetchColumn(), true) ?? [];
    $ign = $games[$game]['ign'] ?? '';

    if (!$alreadyJoined && !$ign) {
        setState($pdo, $uid, "ign_Squadinput:$game:$eid");
        sendMessage($chat_id, "🎮 لطفاً نام داخل بازی (IGN) خود را برای بازی <b>$game</b> ارسال کنید:");
        exit;
    }

    // گرفتن لیست اسکوادها
    $squads = json_decode($e['squad'] ?? '[]', true);
    if (!is_array($squads)) $squads = [];

    // پیدا کردن اسکواد مربوط به لیدر
    $found = false;
    foreach ($squads as &$squad) {
        if ((int)$squad['leader_id'] === $leader_id) {
            $exists = array_filter($squad['members'] ?? [], fn($m) => $m['user_id'] == $uid);
            if (!$exists) {
                $squad['members'][] = [
                    'user_id'   => $uid,
                    'joined_at' => date('Y-m-d H:i:s'),
                    'status'    => 'accepted'
                ];
            }
            $found = true;
            break;
        }
    }
    unset($squad);

    if (!$found) {
        sendMessage($chat_id, "❌ اسکواد موردنظر یافت نشد.");
        exit;
    }

    // 🔹 حذف اسکوادهای خالی فقط برای همین کاربر (لیدر خودش)
    foreach ($squads as $index => $sq) {
        if ((int)$sq['leader_id'] === $uid && empty($sq['members'])) {
            unset($squads[$index]);
        }
    }
    $squads = array_values($squads); // مرتب‌سازی اندیس‌ها بعد از حذف

    // ذخیره اسکوادها
    $st = $pdo->prepare("UPDATE events SET squad=? WHERE id=?");
    $st->execute([json_encode($squads, JSON_UNESCAPED_UNICODE), $eid]);

    // ثبت‌نام در ایونت اگر قبلاً انجام نشده
    if (!$alreadyJoined) {
        if ((int)$e['entry_fee'] > 0) {
            sendMessage($chat_id, "💳 این ایونت رایگان نیست. ثبت‌نام فعلاً امکان‌پذیر نیست.");
            exit;
        }

        $player = [
            'user_id'    => $uid,
            'ign'        => $ign,
            'joined_at'  => date('Y-m-d H:i:s'),
            'paid'       => 1,
            'pay_method' => null,
            'pay_time'   => date('Y-m-d H:i:s'),
            'pay_meta'   => null
        ];

        $players = json_decode($e['players'], true) ?? [];
        $exists = array_filter($players, fn($p) => $p['user_id'] == $uid);
        if (!$exists) {
            $players[] = $player;
            $st = $pdo->prepare("UPDATE events SET players=? WHERE id=?");
            $st->execute([json_encode($players, JSON_UNESCAPED_UNICODE), $eid]);
        }

        $ev_ids[] = $eid;
        $ev_ids = array_unique($ev_ids);
        $st = $pdo->prepare("UPDATE users SET ev_ids=? WHERE id=?");
        $st->execute([json_encode($ev_ids, JSON_UNESCAPED_UNICODE), $uid]);
    }

    // پیام‌های نهایی
    sendMessage($leader_id, "✅ کاربر <code>$uid</code> دعوت شما را پذیرفت.");
    sendMessage($chat_id, "✅ شما به اسکواد اضافه شدید.");
    exit;
}




if (str_starts_with($data, 'squad_reject:')) {
    [, $eid, $leader_id] = explode(':', $data);
    sendMessage($leader_id, "❌ کاربر <code>$uid</code> دعوت شما را رد کرد.");
    sendMessage($chat_id, "⛔ دعوت‌نامه رد شد.");
    exit;
}

if (str_starts_with($data, 'squad_reject:')) {
    [, $eid, $leader_id] = explode(':', $data);
    sendMessage($leader_id, "❌ کاربر <code>$uid</code> دعوت شما را رد کرد.");
    sendMessage($chat_id, "⛔ دعوت‌نامه رد شد.");
    exit;
}


if (str_starts_with($data, 'ev_edit:')) {
    [, $eid, $uid] = explode(':', $data);
    $eid = (int)$eid;

 //   $txt = "✏️ ویرایش اطلاعات ثبت‌نام شما در ایونت <code>$eid</code>\n(در آینده این بخش را کامل می‌کنیم)";
 //   $kb = ['inline_keyboard' => [
 //       [['text'=>'🔙 بازگشت','callback_data'=>'ev_userview:' . $eid.':'.$uid]]
 //  ]];

 //   editMessageText($chat_id, $mid, $txt, $kb);
    answerCb($cb['id'], '❌');
    exit;
}



// ======== ثبت اطلاع پرداخت ========
if (str_starts_with($data, 'pay_notify:')) {
    $parts  = explode(':', $data);
    $eid    = (int)$parts[1];
    $method = $parts[2] ?? 'card';
    $reason = 'Efee';

    // --- گرفتن اطلاعات ایونت برای مبلغ ورودی
    $st = $pdo->prepare("SELECT entry_fee FROM events WHERE id=? LIMIT 1");
    $st->execute([$eid]);
    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        if ($cb && isset($cb['id'])) {
            answerCb($cb['id'], '❌ ایونت پیدا نشد.', true);
        } else {
            sendMessage($chat_id, '❌ ایونت پیدا نشد.');
        }
        exit;
    }

    $entry_fee = (int)$event['entry_fee'];

    if ($entry_fee <= 0) {
        // ایونت رایگان — همان رفتار قبلی
        [$t, $kb] = renderEventView($pdo, $eid, $uid);
        editMessageText($chat_id, $mid, $t, $kb);
        if ($cb && isset($cb['id'])) answerCb($cb['id'], '');
        exit;
    }

    // --- ایجاد رکورد transactions با status='pending'
    $st = $pdo->prepare("INSERT INTO transactions 
        (user_id, event_id, amount, method, reason)
        VALUES (?,?,?,?,?)");
    $st->execute([$uid, $eid, $entry_fee, $method, $reason]);
    $pid = (int)$pdo->lastInsertId();

    // ذخیره state با pid
    setState($pdo, $uid, 'awaiting_transactions_proof:'.$eid.':'.$pid);

    // پیام به کاربر
    $text = "📎 لطفاً <b>فقط یک عکس</b> از رسید پرداخت ارسال کنید.\n\n"
          . "توضیح: ارسال متن یا فایل غیرتصویری پذیرفته نمی‌شود.\n\n"
          . "پس از ارسال عکس، پیش‌نمایش برای شما نمایش داده می‌شود و سپس می‌توانید آن را برای ادمین ارسال کنید.";
    $kb = ['inline_keyboard'=>[
        [['text'=>'🔙 بازگشت','callback_data'=>'ev_view:'.$eid]]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    if ($cb && isset($cb['id'])) answerCb($cb['id'], '✅ اکنون لطفاً عکس رسید را ارسال کنید.');
    exit;
}






if (str_starts_with($data, 'send_to_admin:')) {
    $pid = (int) substr($data, strlen('send_to_admin:'));

    // گرفتن رکورد تراکنش
    $st = $pdo->prepare("SELECT * FROM transactions WHERE id=? LIMIT 1");
    $st->execute([$pid]);
    $p = $st->fetch(PDO::FETCH_ASSOC);

    if (!$p) {
        answerCb($cb['id'] ?? null, '❌ رکورد یافت نشد', true);
        exit;
    }

    if (!empty($p['sent_to_admin_at'])) {
        answerCb($cb['id'] ?? null, 'ℹ️ این رسید قبلاً برای ادمین ارسال شده است.', true);
        exit;
    }

    if (empty($p['file_id'])) {
        answerCb($cb['id'] ?? null, '❌ هنوز عکسی ثبت نشده است.', true);
        exit;
    }

    // مارک کردن رکورد به عنوان ارسال شده
    $pdo->prepare("UPDATE transactions SET sent_to_admin_at = NOW() WHERE id = ?")->execute([$pid]);

    // گرفتن اطلاعات کاربر
    $st = $pdo->prepare("SELECT first_name, username FROM users WHERE id=? LIMIT 1");
    $st->execute([$p['user_id']]);
    $user = $st->fetch(PDO::FETCH_ASSOC);
    $firstName = $user['first_name'] ?? 'کاربر';
    $username = !empty($user['username']) ? '@'.$user['username'] : '—';

    // پیام کاربر
    $chat_id = $p['user_id'];
    $newText = "📤 رسید شما برای ادمین ارسال شد.\n🔔 لطفاً منتظر تایید ادمین بمانید.";
    sendMessage($chat_id, $newText, ['inline_keyboard' => []]);
    answerCb($cb['id'], '');

    // ارسال پیام به ادمین
    foreach (ADMIN_IDS as $admin_chat_id) {
        if (strtolower($p['reason']) === 'topup') {
            $adminText = "💰 <b>درخواست شارژ کیف پول جدید</b>\n\n";
            $adminText .= "<blockquote>";
            $adminText .= "👤 کاربر: <b>{$firstName}</b> | {$username}\n";
            $adminText .= "👤 آیدی: <code>{$p['user_id']}</code>\n";
            $adminText .= "💵 مبلغ درخواست شده: <b>" . number_format($p['amount']) . " تومان</b>\n";
            $adminText .= "🕓 تاریخ ثبت: <b>" . jdate('Y/m/d H:i', strtotime($p['created_at'])) . "</b>\n";
            $adminText .= "🔹 وضعیت: در انتظار تایید ادمین\n";
            $adminText .= "</blockquote>\n\n";
            $adminText .= "✅ برای تایید شارژ، «تایید پرداخت» را فشار دهید.\n";
            $adminText .= "❌ برای رد، «رد پرداخت» را فشار دهید.";
        } else {
            $adminText = "💰 <b>رسید جدید برای بررسی</b>\n\n";
            $adminText .= "<blockquote>";
            $adminText .= "👤 کاربر: <b>{$firstName}</b> | {$username}\n";
            $adminText .= "👤 آیدی: <code>{$p['user_id']}</code>\n";
            $adminText .= "🎮 بازی: <b>{$p['game']}</b>\n";
            $adminText .= "🆔 IGN: <code>{$p['ign']}</code>\n";
            $adminText .= "💵 مبلغ ورودی: <b>" . number_format($p['entry_fee']) . " تومان</b>\n";
            $adminText .= "🕓 تاریخ ثبت: <b>{$p['created_at']}</b>\n";
            $adminText .= "🔹 وضعیت: در انتظار تایید ادمین\n";
            $adminText .= "</blockquote>\n\n";
            $adminText .= "✅ برای تایید پرداخت، «تایید پرداخت» را فشار دهید.\n";
            $adminText .= "❌ برای رد پرداخت، «رد پرداخت» را فشار دهید.";
        }

        $adminKb = [
            'inline_keyboard' => [
                [
                    ['text' => '✅ تایید پرداخت', 'callback_data' => 'admin_transactions_approve:'.$pid],
                    ['text' => '❌ رد پرداخت',    'callback_data' => 'admin_transactions_reject:'.$pid]
                ]
            ]
        ];

        sendPhoto($admin_chat_id, $p['file_id'], $adminText, $adminKb);
    }

    exit;
}

if ($data === 'check_force_join') {

    if (checkForceJoin($pdo, $uid, $chat_id, $bot_token)) {

        answerCb(
            $callback_id,
            '✅ عضویت شما تایید شد.'
        );

        deleteMessage($chat_id, $mid);
    }

    exit;
}


if (str_starts_with($data, 'admin_transactions_')) {
    [$action, $pid] = explode(':', substr($data, strlen('admin_transactions_')));
    $pid = (int)$pid;

    // دریافت رکورد پرداخت
    $st = $pdo->prepare("SELECT * FROM transactions WHERE id=?");
    $st->execute([$pid]);
    $p = $st->fetch(PDO::FETCH_ASSOC);

    if (!$p) { 
        answerCb($cb['id'],'❌ رکورد یافت نشد',true); 
        exit; 
    }

    if ($p['status'] === 'approved') {
        answerCb($cb['id'], 'ℹ️ این پرداخت قبلاً تأیید شده است.', true);
        exit;
    }

    if ($p['status'] === 'rejected') {
        answerCb($cb['id'], '❌ این پرداخت قبلاً رد شده است.', true);
        exit;
    }

    if ($action === 'approve') {
        // تایید پرداخت
        $pdo->prepare("UPDATE transactions SET status='approved', time_approved=NOW() WHERE id=?")->execute([$pid]);

        if (strtolower($p['reason']) === 'topup') {
            // افزایش موجودی کیف پول
            $st = $pdo->prepare("SELECT balance FROM wallets WHERE user_id=? LIMIT 1");
            $st->execute([$p['user_id']]);
            $balance = $st->fetchColumn() ?: 0;

            $newBalance = $balance + $p['amount'];
            $pdo->prepare("UPDATE wallets SET balance=? WHERE user_id=?")->execute([$newBalance, $p['user_id']]);

            // اطلاع به کاربر
            sendMessage($p['user_id'], "✅ شارژ کیف پول شما با موفقیت انجام شد.\n💰 موجودی فعلی: ".number_format($newBalance)." تومان");
            answerCb($cb['id'], '');
        } else {
            // پردازش پرداخت ایونت (Efee)
            $st = $pdo->prepare("SELECT * FROM events WHERE id=?");
            $st->execute([$p['event_id']]);
            $e = $st->fetch(PDO::FETCH_ASSOC);

            if (!$e) {
                answerCb($cb['id'], '❌ ایونت پیدا نشد', true);
                exit;
            }

            // افزودن کاربر به ev_ids
            $st = $pdo->prepare("SELECT ev_ids, games FROM users WHERE id=? LIMIT 1");
            $st->execute([$p['user_id']]);
            $user = $st->fetch(PDO::FETCH_ASSOC);

            $ev_ids = json_decode($user['ev_ids'], true);
            if (!is_array($ev_ids)) $ev_ids = [];
            if (!in_array($e['id'], $ev_ids)) {
                $ev_ids[] = $e['id'];
                $pdo->prepare("UPDATE users SET ev_ids=? WHERE id=?")
                    ->execute([json_encode($ev_ids, JSON_UNESCAPED_UNICODE), $p['user_id']]);
            }

            $userGames = json_decode($user['games'] ?? '{}', true);
            $eventGame = $e['game'];
            $ign = $userGames[$eventGame]['ign'] ?? '';
            $uidInGame = $userGames[$eventGame]['id'] ?? '';

            // اضافه کردن پلیر به ایونت
            $players = json_decode($e['players'], true) ?: [];
            $players[] = [
                'user_id'   => $p['user_id'],
                'ign'       => $ign,
                'uid_in_game' => $uidInGame,
                'joined_at' => $p['joined_at'],
                'paid'      => 1,
                'pay_method'=> $p['method'],
                'pay_time'  => date('Y-m-d H:i:s'),
                'pay_meta'  => $p['text_proof'] ?? null
            ];

            // بروزرسانی squad در صورت نیاز
            if ((int)$e['limit'] > 1) {
                $squad = json_decode($e['squad'], true) ?: [];
                $alreadyLeader = false;
                foreach ($squad as $sq) {
                    if ((int)$sq['leader_id'] === (int)$p['user_id']) {
                        $alreadyLeader = true;
                        break;
                    }
                }
                if (!$alreadyLeader) {
                    $squad[] = [
                        'leader_id' => (int)$p['user_id'],
                        'members'   => []
                    ];
                }

                $pdo->prepare("UPDATE events SET players=?, squad=? WHERE id=?")
                    ->execute([
                        json_encode($players, JSON_UNESCAPED_UNICODE),
                        json_encode($squad, JSON_UNESCAPED_UNICODE),
                        $e['id']
                    ]);
            } else {
                $pdo->prepare("UPDATE events SET players=? WHERE id=?")
                    ->execute([json_encode($players, JSON_UNESCAPED_UNICODE), $e['id']]);
            }

            sendMessage($p['user_id'], "✅ پرداخت شما تایید شد و ثبت‌نام کامل انجام شد.");
            answerCb($cb['id'], '');
        }
    } elseif ($action === 'reject') {
        // رد پرداخت
        $pdo->prepare("UPDATE transactions SET status='rejected' WHERE id=?")->execute([$pid]);
        sendMessage($p['user_id'], "❌ پرداخت شما رد شد. لطفاً دوباره تلاش کنید.");
        answerCb($cb['id'], "❌ پرداخت رد شد");
    }

    exit;
}







    // ranking
if (str_starts_with($data,'rank_view:')) {
    $parts = explode(':',$data);
    $game = urldecode($parts[1]);
    $page = (int)($parts[2] ?? 0);
    $timeFilter = $parts[3] ?? 'all'; // all, daily, weekly, monthly

    $limit = 10;
    $offset = $page * $limit;

    // گرفتن 10 نفر برتر صفحه فعلی
    $topUsers = getTopRanking($pdo, $game, $timeFilter, $limit, $offset);

    // بررسی وجود صفحه بعدی
    $nextCheck = getTopRanking($pdo, $game, $timeFilter, $limit, ($page+1)*$limit);
    $hasMorePages = !empty($nextCheck);

   $txt = "🏅 رنکینگ <b>".htmlspecialchars($game)."</b>\n\n";
$foundUser = false;
$displayRank = 1;
$prevPoints = null;

foreach($topUsers as $index => $r){
    $ign = getUserIGN($pdo, (int)$r['user_id'], $game) ?: '—';
    $points = $r['total_points'];

    if($prevPoints !== null && $points < $prevPoints){
        $displayRank++;
    }

    if($r['user_id'] == $uid){
        $txt .= "<blockquote>$displayRank. " . htmlspecialchars($ign) . " " . toSuperscript($points) . "</blockquote>\n";
        $foundUser = true;
    } else {
        $txt .= $displayRank . '. ' . htmlspecialchars($ign) . ' ' . toSuperscript($points) . "\n";
    }

    $prevPoints = $points;
}


    // اگر کاربر جز ۱۰ نفر نبود
    if(!$foundUser){
        $mypoints = getUserRankingPoints($pdo, $uid, $game, $timeFilter);
        $txt .= "<blockquote>$displayRank. " . htmlspecialchars($ign) . " " . toSuperscript($mypoints) . "</blockquote>\n";
    }

    // ساخت دکمه‌ها
    $keyboard = [];

    // فیلترهای زمانی فقط در صفحه اول
    if($page === 0){
$keyboard[] = [
    ['text'=> ($timeFilter==='all' ? '☜ ' : '') .'همه زمان 🕰️','callback_data'=>'rank_view:'.urlencode($game).':0:all'],
    ['text'=> ($timeFilter==='monthly' ? '☜ ' : '') .'ماهانه 📇','callback_data'=>'rank_view:'.urlencode($game).':0:monthly']
];
$keyboard[] = [
    ['text'=> ($timeFilter==='weekly' ? '☜ ' : '') .'هفتگی 📆','callback_data'=>'rank_view:'.urlencode($game).':0:weekly'],
    ['text'=> ($timeFilter==='daily' ? '☜ ' : '') .'روزانه ☀️','callback_data'=>'rank_view:'.urlencode($game).':0:daily']
];



    }

    // دکمه‌های صفحه‌بندی هوشمند
    $pageButtons = [];
    if($page > 0){
        $pageButtons[] = ['text'=>'⬅️ قبلی','callback_data'=>'rank_view:'.urlencode($game).':'.($page-1).':'.$timeFilter];
    }
    if($hasMorePages){
        $pageButtons[] = ['text'=>'بعدی ➡️','callback_data'=>'rank_view:'.urlencode($game).':'.($page+1).':'.$timeFilter];
    }
    if($pageButtons){
        $keyboard[] = $pageButtons;
    }

    // دکمه بازگشت
    $keyboard[] = [['text'=>'🔙 بازگشت','callback_data'=>'home']];

    editMessageText($chat_id, $mid, $txt, ['inline_keyboard'=>$keyboard]);
    answerCb($cb['id'],'');
    exit;
}



    // admin panel
if ($data === 'admin_panel') {

    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    $kb = [
        'inline_keyboard' => [

            // 🏆 COMPETITIONS
            [
                ['text' => '➕ ساخت تورنومنت', 'callback_data' => 'admin_create:tournament','style'=>'success'],
                ['text' => '➕ ساخت کاستوم', 'callback_data' => 'admin_create:custom','style'=>'success']
            ],

            // 🎮 CONTENT
            [
                ['text' => '🎮 مدیریت گیم‌ها', 'callback_data' => 'admin_games'],
                ['text' => '🎯 مدیریت ایونت‌ها', 'callback_data' => 'admin_events_menu']
            ],

            // 👥 USERS
            [
                ['text' => '👥 کاربران', 'callback_data' => 'admin_manage_users']
            ],

            // 📢 SYSTEM
            [
                ['text' => '📢 اعلان‌ها', 'callback_data' => 'admin_announcements'],
                ['text' => '🤖 تنظیمات ربات', 'callback_data' => 'admin_bot']
            ],

            // 🔥 ADVANCED
            [
                ['text' => '📊 آمار کلی ربات', 'callback_data' => 'admin_stats']
            ],

            // 🔙
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'home']
            ]
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        "🛠 <b>پنل مدیریت هوراد</b>\n\n📊 به داشبورد مدیریتی خوش آمدید",
        $kb
    );

    answerCb($cb['id'], '');
    exit;
}


// ==================== STATS PANEL ====================

if ($data === 'admin_stats') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $kb = ['inline_keyboard'=>[
        [['text'=>'👁 نگاه کلی','callback_data'=>'stats_overview']],
        [['text'=>'🎯 آمار ایونت‌ها','callback_data'=>'stats_events'],['text'=>'💰 آمار تراکنش‌ها','callback_data'=>'stats_transactions']],
        [['text'=>'👥 آمار کاربران','callback_data'=>'stats_users'],['text'=>'🏆 برترین‌ها','callback_data'=>'stats_top']],
        [['text'=>'🔗 آمار رفرال','callback_data'=>'stats_referral'],['text'=>'📋 لاگ ادمین','callback_data'=>'stats_adminlog']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_panel']]
    ]];

    editMessageText($chat_id, $mid, "📊 *پنل آمار ربات*\n\nیک بخش را انتخاب کنید:", $kb);
    answerCb($cb['id'],'');
    exit;
}

// ---------- Overview ----------
if ($data === 'stats_overview') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $totalUsers    = $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn();
    $activeUsers   = $pdo->query("SELECT COUNT(*) FROM users WHERE active=1")->fetchColumn();
    $todayUsers    = $pdo->query("SELECT COUNT(*) FROM users WHERE DATE(created_at)=CURDATE()")->fetchColumn();
    $weekUsers     = $pdo->query("SELECT COUNT(*) FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)")->fetchColumn();
    $monthUsers    = $pdo->query("SELECT COUNT(*) FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)")->fetchColumn();

    $totalEvents   = $pdo->query("SELECT COUNT(*) FROM events")->fetchColumn();
    $activeEvents  = $pdo->query("SELECT COUNT(*) FROM events WHERE status='active'")->fetchColumn();
    $finishedEvents= $pdo->query("SELECT COUNT(*) FROM events WHERE status='finished'")->fetchColumn();

    $totalTx       = $pdo->query("SELECT COUNT(*) FROM transactions")->fetchColumn();
    $pendingTx     = $pdo->query("SELECT COUNT(*) FROM transactions WHERE status='pending'")->fetchColumn();
    $approvedTx    = $pdo->query("SELECT COUNT(*) FROM transactions WHERE status='approved'")->fetchColumn();
    $totalIncome   = $pdo->query("SELECT COALESCE(SUM(entry_fee),0) FROM transactions WHERE status='approved'")->fetchColumn();

    $totalGames    = $pdo->query("SELECT COUNT(*) FROM games WHERE active=1")->fetchColumn();

    $text  = "👁 *نگاه کلی به ربات*\n";
    $text .= "━━━━━━━━━━━━━━━\n\n";
    $text .= "👤 *کاربران*\n";
    $text .= "├ کل: `{$totalUsers}` نفر\n";
    $text .= "├ فعال: `{$activeUsers}` نفر\n";
    $text .= "├ امروز: `{$todayUsers}` نفر\n";
    $text .= "├ ۷ روز اخیر: `{$weekUsers}` نفر\n";
    $text .= "└ ۳۰ روز اخیر: `{$monthUsers}` نفر\n\n";
    $text .= "🎯 *ایونت‌ها*\n";
    $text .= "├ کل: `{$totalEvents}`\n";
    $text .= "├ فعال: `{$activeEvents}`\n";
    $text .= "└ پایان‌یافته: `{$finishedEvents}`\n\n";
    $text .= "💰 *تراکنش‌ها*\n";
    $text .= "├ کل: `{$totalTx}`\n";
    $text .= "├ در انتظار: `{$pendingTx}`\n";
    $text .= "├ تایید‌شده: `{$approvedTx}`\n";
    $text .= "└ درآمد کل: `{$totalIncome}` تومان\n\n";
    $text .= "🎮 *بازی‌های فعال*: `{$totalGames}`\n";

    $kb = ['inline_keyboard'=>[
        [['text'=>'🔄 بروزرسانی','callback_data'=>'stats_overview']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_stats']]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'],'');
    exit;
}

// ---------- Events ----------
if ($data === 'stats_events') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $byGame = $pdo->query("
        SELECT game, COUNT(*) as cnt
        FROM events
        GROUP BY game
        ORDER BY cnt DESC
        LIMIT 5
    ")->fetchAll(PDO::FETCH_ASSOC);

    $topEvents = $pdo->query("
        SELECT e.name, COUNT(ep.id) as players
        FROM events e
        LEFT JOIN event_players ep ON ep.ev_id = e.id AND ep.status='accepted'
        GROUP BY e.id
        ORDER BY players DESC
        LIMIT 5
    ")->fetchAll(PDO::FETCH_ASSOC);

    $freeEvents = $pdo->query("SELECT COUNT(*) FROM events WHERE entry_fee=0")->fetchColumn();
    $paidEvents = $pdo->query("SELECT COUNT(*) FROM events WHERE entry_fee>0")->fetchColumn();

    $text  = "🎯 *آمار ایونت‌ها*\n";
    $text .= "━━━━━━━━━━━━━━━\n\n";
    $text .= "💸 رایگان: `{$freeEvents}` | پولی: `{$paidEvents}`\n\n";
    $text .= "🎮 *پرطرفدارترین بازی‌ها:*\n";
    foreach ($byGame as $i => $row) {
        $num = $i + 1;
        $text .= "{$num}. {$row['game']} — `{$row['cnt']}` ایونت\n";
    }
    $text .= "\n🏅 *پرشرکت‌کننده‌ترین ایونت‌ها:*\n";
    foreach ($topEvents as $i => $row) {
        $num = $i + 1;
        $text .= "{$num}. {$row['name']} — `{$row['players']}` نفر\n";
    }

    $kb = ['inline_keyboard'=>[
        [['text'=>'🔄 بروزرسانی','callback_data'=>'stats_events']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_stats']]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'],'');
    exit;
}

// ---------- Transactions ----------
if ($data === 'stats_transactions') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $pending   = $pdo->query("SELECT COUNT(*) FROM transactions WHERE status='pending'")->fetchColumn();
    $approved  = $pdo->query("SELECT COUNT(*) FROM transactions WHERE status='approved'")->fetchColumn();
    $rejected  = $pdo->query("SELECT COUNT(*) FROM transactions WHERE status='rejected'")->fetchColumn();
    $incomeAll = $pdo->query("SELECT COALESCE(SUM(entry_fee),0) FROM transactions WHERE status='approved'")->fetchColumn();
    $incomeMonth = $pdo->query("SELECT COALESCE(SUM(entry_fee),0) FROM transactions WHERE status='approved' AND created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)")->fetchColumn();
    $incomeToday = $pdo->query("SELECT COALESCE(SUM(entry_fee),0) FROM transactions WHERE status='approved' AND DATE(created_at)=CURDATE()")->fetchColumn();

    $topEvents = $pdo->query("
        SELECT e.name, SUM(t.entry_fee) as income, COUNT(t.id) as cnt
        FROM transactions t
        JOIN events e ON e.id = t.event_id
        WHERE t.status='approved'
        GROUP BY t.event_id
        ORDER BY income DESC
        LIMIT 5
    ")->fetchAll(PDO::FETCH_ASSOC);

    $text  = "💰 *آمار تراکنش‌ها*\n";
    $text .= "━━━━━━━━━━━━━━━\n\n";
    $text .= "📋 *وضعیت:*\n";
    $text .= "├ در انتظار: `{$pending}`\n";
    $text .= "├ تایید‌شده: `{$approved}`\n";
    $text .= "└ رد‌شده: `{$rejected}`\n\n";
    $text .= "💵 *درآمد:*\n";
    $text .= "├ امروز: `{$incomeToday}` تومان\n";
    $text .= "├ ۳۰ روز اخیر: `{$incomeMonth}` تومان\n";
    $text .= "└ کل: `{$incomeAll}` تومان\n\n";
    $text .= "🏆 *پردرآمدترین ایونت‌ها:*\n";
    foreach ($topEvents as $i => $row) {
        $num = $i + 1;
        $text .= "{$num}. {$row['name']} — `{$row['income']}` تومان ({$row['cnt']} نفر)\n";
    }

    $kb = ['inline_keyboard'=>[
        [['text'=>'🔄 بروزرسانی','callback_data'=>'stats_transactions']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_stats']]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'],'');
    exit;
}

// ---------- Users ----------
if ($data === 'stats_users') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $total     = $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn();
    $active    = $pdo->query("SELECT COUNT(*) FROM users WHERE active=1")->fetchColumn();
    $today     = $pdo->query("SELECT COUNT(*) FROM users WHERE DATE(created_at)=CURDATE()")->fetchColumn();
    $week      = $pdo->query("SELECT COUNT(*) FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)")->fetchColumn();
    $month     = $pdo->query("SELECT COUNT(*) FROM users WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)")->fetchColumn();
    $withWins  = $pdo->query("SELECT COUNT(*) FROM users WHERE wins > 0")->fetchColumn();
    $avgJoins  = $pdo->query("SELECT ROUND(AVG(joins),1) FROM users WHERE joins > 0")->fetchColumn();

    $text  = "👥 *آمار کاربران*\n";
    $text .= "━━━━━━━━━━━━━━━\n\n";
    $text .= "├ کل کاربران: `{$total}`\n";
    $text .= "├ کاربران فعال: `{$active}`\n";
    $text .= "├ عضو امروز: `{$today}`\n";
    $text .= "├ عضو ۷ روز اخیر: `{$week}`\n";
    $text .= "├ عضو ۳۰ روز اخیر: `{$month}`\n";
    $text .= "├ کاربران با حداقل ۱ برد: `{$withWins}`\n";
    $text .= "└ میانگین شرکت در ایونت: `{$avgJoins}`\n";

    $kb = ['inline_keyboard'=>[
        [['text'=>'🔄 بروزرسانی','callback_data'=>'stats_users']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_stats']]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'],'');
    exit;
}

// ---------- Top Players ----------
if ($data === 'stats_top') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $topScore = $pdo->query("
        SELECT first_name, username, score
        FROM users ORDER BY score DESC LIMIT 5
    ")->fetchAll(PDO::FETCH_ASSOC);

    $topWins = $pdo->query("
        SELECT first_name, username, wins
        FROM users ORDER BY wins DESC LIMIT 5
    ")->fetchAll(PDO::FETCH_ASSOC);

    $topJoins = $pdo->query("
        SELECT first_name, username, joins
        FROM users ORDER BY joins DESC LIMIT 5
    ")->fetchAll(PDO::FETCH_ASSOC);

    $medals = ['🥇','🥈','🥉','4️⃣','5️⃣'];

    $text  = "🏆 *برترین کاربران*\n";
    $text .= "━━━━━━━━━━━━━━━\n\n";

    $text .= "⭐️ *بیشترین امتیاز:*\n";
    foreach ($topScore as $i => $u) {
        $name = $u['username'] ? '@'.$u['username'] : $u['first_name'];
        $text .= "{$medals[$i]} {$name} — `{$u['score']}` امتیاز\n";
    }

    $text .= "\n🏅 *بیشترین برد:*\n";
    foreach ($topWins as $i => $u) {
        $name = $u['username'] ? '@'.$u['username'] : $u['first_name'];
        $text .= "{$medals[$i]} {$name} — `{$u['wins']}` برد\n";
    }

    $text .= "\n🎮 *بیشترین شرکت:*\n";
    foreach ($topJoins as $i => $u) {
        $name = $u['username'] ? '@'.$u['username'] : $u['first_name'];
        $text .= "{$medals[$i]} {$name} — `{$u['joins']}` بار\n";
    }

    $kb = ['inline_keyboard'=>[
        [['text'=>'🔄 بروزرسانی','callback_data'=>'stats_top']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_stats']]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'],'');
    exit;
}

// ---------- Referral ----------
if ($data === 'stats_referral') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $totalRef   = $pdo->query("SELECT COUNT(*) FROM referral_starts")->fetchColumn();
    $pendingRef = $pdo->query("SELECT COUNT(*) FROM referral_starts WHERE status='pending'")->fetchColumn();
    $validRef   = $pdo->query("SELECT COUNT(*) FROM referral_starts WHERE status='valid'")->fetchColumn();

    $topReferrers = $pdo->query("
        SELECT u.first_name, u.username, COUNT(rs.id) as cnt
        FROM referral_starts rs
        JOIN users u ON u.id = rs.referrer_id
        WHERE rs.status='valid'
        GROUP BY rs.referrer_id
        ORDER BY cnt DESC
        LIMIT 5
    ")->fetchAll(PDO::FETCH_ASSOC);

    $medals = ['🥇','🥈','🥉','4️⃣','5️⃣'];

    $text  = "🔗 *آمار رفرال*\n";
    $text .= "━━━━━━━━━━━━━━━\n\n";
    $text .= "├ کل رفرال‌ها: `{$totalRef}`\n";
    $text .= "├ در انتظار: `{$pendingRef}`\n";
    $text .= "└ تایید‌شده: `{$validRef}`\n\n";
    $text .= "🏆 *پرفعال‌ترین دعوت‌کننده‌ها:*\n";

    if (empty($topReferrers)) {
        $text .= "هنوز رفرال تایید‌شده‌ای وجود ندارد.\n";
    } else {
        foreach ($topReferrers as $i => $r) {
            $name = $r['username'] ? '@'.$r['username'] : $r['first_name'];
            $text .= "{$medals[$i]} {$name} — `{$r['cnt']}` دعوت\n";
        }
    }

    $kb = ['inline_keyboard'=>[
        [['text'=>'🔄 بروزرسانی','callback_data'=>'stats_referral']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_stats']]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'],'');
    exit;
}

// ---------- Admin Log ----------
if ($data === 'stats_adminlog') {
    if (!isAdmin($uid)) { answerCb($cb['id'],'⛔️', true); exit; }

    $logs = $pdo->query("
        SELECT aa.action, aa.created_at, u.first_name, u.username
        FROM admin_actions aa
        LEFT JOIN users u ON u.id = aa.admin_id
        ORDER BY aa.created_at DESC
        LIMIT 10
    ")->fetchAll(PDO::FETCH_ASSOC);

    $text  = "📋 *آخرین اکشن‌های ادمین*\n";
    $text .= "━━━━━━━━━━━━━━━\n\n";

    if (empty($logs)) {
        $text .= "هیچ لاگی ثبت نشده است.\n";
    } else {
        foreach ($logs as $log) {
            $name = $log['username'] ? '@'.$log['username'] : ($log['first_name'] ?? 'نامشخص');
            $date = date('y/m/d H:i', strtotime($log['created_at']));
            $text .= "👤 {$name}\n";
            $text .= "⚡️ `{$log['action']}`\n";
            $text .= "🕐 {$date}\n";
            $text .= "───────────\n";
        }
    }

    $kb = ['inline_keyboard'=>[
        [['text'=>'🔄 بروزرسانی','callback_data'=>'stats_adminlog']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_stats']]
    ]];

    editMessageText($chat_id, $mid, $text, $kb);
    answerCb($cb['id'],'');
    exit;
}

// ==================== END STATS PANEL ====================


//===================ticket=====================

if (str_starts_with($data, 'ticket_menu')) {


    $text = "📩 منوی پشتیبانی\n\n";
    $text .= "یکی از گزینه‌های زیر را انتخاب کنید:";

    $keyboard = [
        'inline_keyboard' => [
            [
                ['text' => '📌 پیگیری تیکت', 'callback_data' => 'check_ticket_page_1'],
                ['text' => '📝 ثبت تیکت', 'callback_data' => 'create_ticket'],
            ],
            [
                ['text' => '☎️ ارتباط با ما', 'callback_data' => 'contact_us'],
            ],
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'home'],
            ],
        ]
    ];

    editMessageText($chat_id, $mid, $text, $keyboard, 'HTML');
}



if (str_starts_with($data, 'create_ticket')) {

    $text  = "📌 لطفا دپارتمان مورد نظر خود را انتخاب کنید:\n\n";
    $text .= "<blockquote expandable>🎯 <b>پشتیبانی فنی (ربات)</b>
    در صورت بروز مشکل یا باگ در ربات از این بخش استفاده کنید.

    🎟 <b>پشتیبانی ایونت</b>
    مشکلات ثبت‌نام، ورود یا قوانین ایونت‌ها را اینجا پیگیری کنید.

    💳 <b>امور مالی / پرداخت‌ها</b>
    اگر پرداخت شما انجام نشده یا تراکنش ناقص بوده، این بخش را انتخاب کنید.

    🚨 <b>گزارش تخلف / ریپورت پلیر</b>
    برای گزارش تقلب یا رفتار غیرمجاز بازیکنان استفاده کنید.

    📢 <b>انتقاد، شکایت و پیشنهادات</b>
    پیشنهادات یا شکایات خود را اینجا ارسال کنید.

    </blockquote>\n";


    $kb = [
        'inline_keyboard' => [
            [
                ['text' => '🛠 پشتیبانی فنی', 'callback_data' => 'dept:bot'],
                ['text' => '🎟 پشتیبانی ایونت', 'callback_data' => 'dept:event'],
            ],
            [
                ['text' => '💳 امور مالی', 'callback_data' => 'dept:finance'],
            ],
            [
                ['text' => '🚨 ریپورت پلیر', 'callback_data' => 'dept:report'],
                ['text' => '📢 انتقاد / شکایات', 'callback_data' => 'dept:complaint'],
            ],
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'ticket'],
            ],
        ]
    ];

    editMessageText($chat_id, $mid, $text, $kb, 'HTML');
}

if (str_starts_with($data, 'dept:')) {
    $parts = explode(':', $data, 4);
    $dep   = $parts[1];

    $kb = [
        'inline_keyboard' => [
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'create_ticket']
            ]
        ]
    ];

    setState($pdo, $uid, "waiting_ticket:$dep");
    editMessageText($chat_id, $mid, '📝 لطفاً متن تیکت خود را ارسال کنید:', $kb);
    exit;
}


if ($data === 'ticket_confirm') {
    $stmt = $pdo->prepare("SELECT temp FROM users WHERE id = ?");
    $stmt->execute([$uid]);
    $tmp_ticket = json_decode($stmt->fetchColumn(), true);

    $message = $tmp_ticket['message'] ?? '';
    $status = 'pending';
    $dep = !empty($tmp_ticket['dep']) ? $tmp_ticket['dep'] : 'general';
    $subject = $tmp_ticket['subject'] ?? '';

    $stmt = $pdo->prepare("INSERT INTO tickets (user_id, subject, department, message, file_id, status) VALUES (?, ?, ?, ?, ?, ?)");
    $stmt->execute([
        $uid,
        $subject,
        $dep,
        $message,
        !empty($tmp_ticket['media']) ? json_encode($tmp_ticket['media'], JSON_UNESCAPED_UNICODE) : null,
        $status
    ]);

    // پاکسازی temp و state
    $stmt = $pdo->prepare("UPDATE users SET temp = NULL WHERE id = ?");
    $stmt->execute([$uid]);
    clearState($pdo, $uid);

    // حذف پیام پیش‌نمایش و کیبورد
    deleteMessage($chat_id, $mid);
    $removeKeyboard = [
        'reply_markup' => json_encode([
            'remove_keyboard' => true
        ])
    ];
    sendMessage($chat_id, "✅ تیکت شما با موفقیت ثبت شد.", $removeKeyboard);

    exit;
}



if ($data === 'ticket_cancel') {
    $stmt = $pdo->prepare("UPDATE users SET temp = NULL, state = NULL WHERE id = ?");
    $stmt->execute([$uid]);

    deleteMessage($chat_id, $mid);
    $removeKeyboard = ['remove_keyboard' => true];
    sendMessage($chat_id, "❌ فرآیند ارسال تیکت لغو شد.", null, $removeKeyboard);

    // بازگشت به منوی اصلی
    if (function_exists('showTicketMenu')) {
        showTicketMenu($chat_id, $mid);
    }

    exit;
}



    if ($data === 'ticket_add_attachment') {
        setState($pdo, $uid, 'waiting_ticket_attachment:');
        sendMessage($chat_id, "📎 لطفاً عکس یا ویدیو/سند خود را ارسال کنید.\n📌 می‌توانید چند ضمیمه اضافه کنید و در نهایت با تایید پیش‌نمایش را ببینید.");
        exit;
    }


if (str_starts_with($data, 'check_ticket_page_')) {
    $parts = explode('_', $data);
    $page = intval(end($parts));
    if ($page < 1) $page = 1;

    $limit = 5;
    $offset = ($page - 1) * $limit;

    $stmt = $pdo->prepare("SELECT id, id, status FROM tickets WHERE user_id = ? ORDER BY created_at DESC LIMIT $limit OFFSET $offset");
    $stmt->execute([$uid]);
    $tickets = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $stmt2 = $pdo->prepare("SELECT COUNT(*) FROM tickets WHERE user_id = ?");
    $stmt2->execute([$uid]);
    $total = $stmt2->fetchColumn();
    $total_pages = ceil($total / $limit);

    $text = "📂 لیست تیکت‌های شما (صفحه $page از $total_pages):\n\n";
    $keyboard = ['inline_keyboard' => []];

    foreach ($tickets as $t) {
        $status_icon = [
            'open' => '🟢 باز',
            'pending' => '🟡 در انتظار پاسخ',
            'closed' => '🔴 بسته'
        ][$t['status']] ?? $t['status'];

        $keyboard['inline_keyboard'][] = [
            ['text' => "#{$t['id']} | $status_icon", 'callback_data' => "ticket_detail_{$t['id']}"]
        ];
    }

    // صفحه‌بندی
    $nav = [];
    if ($page > 1) $nav[] = ['text' => "◀️ صفحه قبل", 'callback_data' => "check_ticket_page_" . ($page - 1)];
    if ($page < $total_pages) $nav[] = ['text' => "▶️ صفحه بعد", 'callback_data' => "check_ticket_page_" . ($page + 1)];
    if (!empty($nav)) $keyboard['inline_keyboard'][] = $nav;

    // بازگشت
    $keyboard['inline_keyboard'][] = [
        ['text' => "🔙 بازگشت", 'callback_data' => 'ticket_menu']
    ];

    editMessageText($chat_id, $mid, $text, $keyboard, 'HTML');
}


// نمایش جزئیات تیکت
if (str_starts_with($data, 'ticket_detail_')) {
    $id = (int) str_replace('ticket_detail_', '', $data);

    // گرفتن همه پیام‌های مربوط به این تیکت
    $stmt = $pdo->prepare("SELECT * FROM tickets WHERE id = ? ORDER BY created_at ASC");
    $stmt->execute([$id]);
    $messages = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($qid) {
    answerCb($qid, '❌ تیکت یافت نشد');
}


    // رکورد اول = اطلاعات اصلی تیکت
    $main = $messages[0];

    $text  = "📝 موضوع: " . htmlspecialchars($main['subject']) . "\n";
    $text .= "📂 دپارتمان: " . htmlspecialchars($main['department']) . "\n";
    $text .= "📌 وضعیت: " . htmlspecialchars($main['status']) . "\n";
    $text .= "📅 تاریخ: " . $main['created_at'] . "\n\n";

    // پیام اول
    $msg = $main['message'];
    if (mb_strlen($msg) > 200) {
        $short = mb_substr($msg, 0, 200) . "...";
        $text .= "پیام کاربر:\n" . $short . "\n";
    } else {
        $text .= "پیام کاربر:\n" . $msg . "\n";
    }

    // پیام‌های بعدی
    foreach (array_slice($messages, 1) as $m) {
        $from = ($m['user_id'] == $main['user_id']) ? "👤 کاربر" : "🛠 پشتیبان";
        $msg = $m['message'];
        if (mb_strlen($msg) > 200) {
            $msg = mb_substr($msg, 0, 200) . "...";
        }
        $text .= "\n$from:\n" . $msg . "\n";
    }


    $hasAttachment = false;
foreach ($messages as $m) {
    if (!empty($m['file_id'])) {
        $hasAttachment = true;
        break;
    }
}

// دکمه‌ها
$keyboard = [
    'inline_keyboard' => []
];

if ($hasAttachment) {
    $keyboard['inline_keyboard'][] = [
        ['text' => '📎 نمایش ضمیمه‌ها', 'callback_data' => 'ticket_attachments_' . $id],
    ];
}

$keyboard['inline_keyboard'][] = [
    ['text' => '➕ افزودن پیام', 'callback_data' => 'ticket_addmsg_' . $id],
    ['text' => '🔒 بستن تیکت', 'callback_data' => 'ticket_close_' . $id],
];

$keyboard['inline_keyboard'][] = [
    ['text' => '📄 نمایش کل پیام', 'callback_data' => 'ticket_fullmsg_' . $id],
];

$keyboard['inline_keyboard'][] = [
    ['text' => '🔙 بازگشت', 'callback_data' => 'check_ticket_page_1'],
];
        


    editMessageText($chat_id, $mid, $text, $keyboard, 'HTML');
}

// هندلر نمایش ضمیمه‌ها
if (str_starts_with($data, 'ticket_attachments_')) {
    $id = (int) str_replace('ticket_attachments_', '', $data);

    $stmt = $pdo->prepare("SELECT file_id FROM tickets WHERE id = ? LIMIT 1");
    $stmt->execute([$id]);
    $file_json = $stmt->fetchColumn();

    if (!$file_json) {
        answerCb($cb['id'], '❌ ضمیمه‌ای یافت نشد');
        exit;
    }

    $files = json_decode($file_json, true);
    if (!$files || !is_array($files) || count($files) == 0) {
        answerCb($cb['id'], '❌ ضمیمه‌ای یافت نشد');
        exit;
    }

    $media_group = [];
    $documents = [];

    foreach ($files as $f) {
        if ($f['type'] === 'photo') {
            $media_group[] = ['type' => 'photo', 'media' => $f['file_id']];
        } elseif ($f['type'] === 'video') {
            $media_group[] = ['type' => 'video', 'media' => $f['file_id']];
        } elseif ($f['type'] === 'document') {
            $documents[] = $f['file_id'];
        }
    }

    // ارسال گالری
    if (count($media_group) > 0) {
        sendMediaGroup($chat_id, $media_group);
    }

    // ارسال داکیومنت‌ها
    foreach ($documents as $doc_id) {
        apiRequest('sendDocument', [
            'chat_id' => $chat_id,
            'document' => $doc_id
        ]);
    }
}



// ============================
// هندلر افزودن پیام به تیکت
// ============================


if (str_starts_with($data, 'ticket_addmsg_')) {
    $ticket_id = (int) str_replace('ticket_addmsg_', '', $data);

    // تغییر state برای کاربر
    setState($pdo, $uid, "addmsg:$ticket_id");

    // دکمه بازگشت
    $kb = [
        'inline_keyboard' => [
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'ticket_detail_' . $ticket_id]
            ]
        ]
    ];

    // ویرایش پیام قبلی به جای ارسال پیام جدید
    editMessageText($chat_id, $mid, "✍️ لطفاً پیام متنی خود را برای این تیکت وارد کنید.", $kb);
    exit;
}









//------------------manage users-----------------------

if ($data === 'admin_manage_users') {
    $kb = ['inline_keyboard'=>[
        [['text'=>'🔍 جستجوی کاربر','callback_data'=>'user_search'],['text'=>'📃 لیست کاربران','callback_data'=>'user_list:all::0']],  // جستجو و لیست ترکیب شده
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_panel']]
    ]];

    editMessageText($chat_id,$mid,'👥 مدیریت کاربران:', $kb);
    answerCb($cb['id'],'');
    clearState($pdo, $uid);
    exit;
}

if (str_starts_with($data,'user_list')) {
    [$action, $filterType, $filterValue, $page] = explode(':',$data) + [null,'','',0];
    $page = (int)$page;

    $users = getUserList($pdo, $filterType, $filterValue, $page, 10);
    $rows = [];

$rows = [];
$temp = [];

foreach ($users as $i => $u) {
    $name = $u['username'] ?: $u['id'];
    $temp[] = ['text'=>$name,'callback_data'=>"user_info:{$u['id']}:$filterType:$filterValue:$page"];

    // هر دو تا دکمه یک ردیف شد
    if (count($temp) == 2) {
        $rows[] = $temp;
        $temp = [];
    }
}

// اگه تعداد کاربرها فرد بود، دکمه آخر رو هم اضافه کن
if (!empty($temp)) {
    $rows[] = $temp;
}


    // صفحه‌بندی
    $nav = [];
    if ($page > 0) $nav[] = ['text'=>'⬅️ قبلی','callback_data'=>"user_list:$filterType:$filterValue:".($page-1)];
    if (count($users) == 10 && ($page+1)*10 < 100) $nav[] = ['text'=>'➡️ بعدی','callback_data'=>"user_list:$filterType:$filterValue:".($page+1)];
    if ($nav) $rows[] = $nav;

    $rows[] = [['text'=>'🔙 بازگشت','callback_data'=>'admin_manage_users']];
    editMessageText($chat_id,$mid,"لیست کاربران:", ['inline_keyboard'=>$rows]);
    answerCb($cb['id'],'');
    exit;
}


if (str_starts_with($data,'user_search')) {
    setState($pdo,$uid,'await_search');
    editMessageText(
        $chat_id,
        $mid,
        '✍️ مقدار جستجو را ارسال کنید:',
        ['inline_keyboard'=>[
            [['text'=>'🔙 بازگشت','callback_data'=>'admin_manage_users']]
        ]]
    );
    answerCb($cb['id'], '');   // 👈 اینجا رو اضافه کن
    exit;
}




if (str_starts_with($data,'user_info:')){
    [, $uidSelected, $filterType, $filterValue, $page] = explode(':',$data) + [null,0,'','',0];
    $uidSelected = (int)$uidSelected;

    $user = getUser($pdo,$uidSelected);
    if (!$user) {
        answerCb($cb['id'],'❌ کاربر یافت نشد');
        exit;
    }

    $isBanned = (int)($user['is_banned'] ?? 0);
    $statusText = $isBanned ? '🔴 بن شده' : '🟢 فعال';
    $gameNames = implode(', ', array_keys(jdec($user['games'])));


    $txt = "<blockquote>👤 اطلاعات کاربر:\n";
    $txt .= "آیدی: <code>{$user['id']}</code>\n";
    $txt .= "یوزرنیم: @{$user['username']}\n";
    $txt .= "</blockquote>";
   

    $txt .= "<blockquote>";
    $txt .= "گیم ها: {$gameNames}\n";
    $txt .= "</blockquote>\n\n";


    $txt .= "اطلاعات گیم :\n";
    foreach(jdec($user['games']) as $g=>$o){
        $txt .= "- $g: ".$o['ign']."\n";
    }

    $kb = ['inline_keyboard'=>[
        [['text'=>$statusText,'callback_data'=>"toggle_ban:{$uidSelected}"]],
        [['text'=>'⭐ تغییر نقش','callback_data'=>"role:{$uidSelected}"], ['text'=>'📊 آمار','callback_data'=>"user_stats:{$uidSelected}"]],
        [['text'=>'📑 تاریخچه','callback_data'=>"history:{$uidSelected}"]],
        [['text'=>'➕ امتیاز','callback_data'=>"add_points:{$uidSelected}"], ['text'=>'➖ کسر امتیاز','callback_data'=>"remove_points:{$uidSelected}"]],
        [['text'=>'💰 امتیاز گروهی','callback_data'=>"group_points:{$uidSelected}"]],
        [['text'=>'🔙 بازگشت','callback_data'=>"user_list:$filterType:$filterValue:$page"]]
    ]];

    editMessageText($chat_id,$mid,$txt,$kb);
    answerCb($cb['id'],'');
    exit;
}


if (str_starts_with($data,'toggle_ban:')) {
    [, $uidSelected] = explode(':',$data) + [0];
    $uidSelected = (int)$uidSelected;

    $user = getUser($pdo, $uidSelected);
    if (!$user) {
        answerCb($cb['id'],'❌ کاربر یافت نشد');
        exit;
    }

    // تغییر وضعیت بن
    $newStatus = $user['is_banned'] ? 0 : 1;
    $st = $pdo->prepare("UPDATE users SET is_banned = ? WHERE id = ?");
    $st->execute([$newStatus, $uidSelected]);

    // متن وضعیت جدید
    $statusText = $newStatus ? '🔴 بن شده' : '🟢 فعال';

    // متن پیام با دو بلوک مانند درخواستت
    $txt = "<blockquote>👤 اطلاعات کاربر:\n";
    $txt .= "آیدی: <code>{$user['id']}</code>\n";
    $txt .= "یوزرنیم: @{$user['username']}\n";
    $txt .= "</blockquote>";


    $txt .= "اطلاعات گیم ها:\n";
    foreach(jdec($user['games']) as $g=>$o){
        $txt .= "- $g: ".$o['ign']."\n";
    }


    // کیبورد
    $kb = ['inline_keyboard'=>[
        [['text'=>$statusText,'callback_data'=>"toggle_ban:{$uidSelected}"]],
        [['text'=>'⭐ تغییر نقش','callback_data'=>"role:{$uidSelected}"], ['text'=>'📊 آمار','callback_data'=>"user_stats:{$uidSelected}"]],
        [['text'=>'📝 ویرایش پروفایل','callback_data'=>"edit_profile:{$uidSelected}"]],
        [['text'=>'📑 تاریخچه','callback_data'=>"history:{$uidSelected}"]],
        [['text'=>'➕ امتیاز','callback_data'=>"add_points:{$uidSelected}"], ['text'=>'➖ کسر امتیاز','callback_data'=>"remove_points:{$uidSelected}"]],
        [['text'=>'💰 امتیاز گروهی','callback_data'=>"group_points:{$uidSelected}"]],
        [['text'=>'🔙 بازگشت','callback_data'=>"user_list:$filterType:$filterValue:$page"]]
    ]];

    editMessageText($chat_id, $mid, $txt, $kb);
    answerCb($cb['id'],'وضعیت کاربر تغییر کرد ✅');
    exit;
}

//----

if (str_starts_with($data, 'user_stats:')) {
    [, $uidSelected] = explode(':', $data) + [null, 0];
    $uidSelected = (int)$uidSelected;

    $user = getUser($pdo, $uidSelected);
    if (!$user) {
        answerCb($cb['id'], '❌ کاربر یافت نشد');
        exit;
    }

    // ------------------ ایونت‌ها ------------------
    $userEventIds = json_decode($user['ev_ids'] ?? '[]', true);
    if (!is_array($userEventIds)) $userEventIds = [];
    $totalAll = count($userEventIds);        // همه ایونت‌ها
    $totalNonActive = 0;                      // غیر Active
    $winCount = 0;
    $entryAll = 0;
    $entryNonActive = 0;
    $entryWins = 0;

    if ($totalAll > 0) {
        $inQuery = implode(',', array_fill(0, count($userEventIds), '?'));
        $stmt = $pdo->prepare("SELECT id, winners, status, entry_fee, squad FROM events WHERE id IN ($inQuery)");
        $stmt->execute($userEventIds);
        $events = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $leaderCount = 0;
        $leaderWins = 0;

        foreach ($events as $ev) {
            $status = $ev['status'] ?? '';
            $winners = json_decode($ev['winners'] ?? '[]', true);
            if (!is_array($winners)) $winners = [];
            $winnerIds = normalizeWinnerIds($winners);

            $isEntry = ($ev['entry_fee'] ?? 0) > 0;
            if ($isEntry) $entryAll++;

            // فقط ایونت غیر Active برای محاسبات وین
            if ($status !== 'active') {
                $totalNonActive++;
                if ($isEntry) $entryNonActive++;
                if (in_array($uidSelected, $winnerIds, true)) {
                    $winCount++;
                    if ($isEntry) $entryWins++;
                }

                // بخش لیدری
                $squads = json_decode($ev['squad'] ?? '[]', true);
                if (is_array($squads)) {
                    foreach ($squads as $s) {
                        if (($s['leader_id'] ?? 0) == $uidSelected) {
                            $leaderCount++;
                            if (in_array($uidSelected, $winnerIds, true)) $leaderWins++;
                        }
                    }
                }
            }
        }
    }

    $winRate = $totalNonActive > 0 ? $winCount / $totalNonActive : 0;
    $entryWinRate = $entryNonActive > 0 ? $entryWins / $entryNonActive : 0;
    $leaderWinRate = $leaderCount > 0 ? $leaderWins / $leaderCount : 0;

    // ------------------ امتیازها ------------------
    $stmt = $pdo->prepare("SELECT SUM(points) as total_points, MAX(points) as max_point FROM ranking WHERE user_id = ?");
    $stmt->execute([$uidSelected]);
    $score = $stmt->fetch(PDO::FETCH_ASSOC);
    $totalPoints = (int)($score['total_points'] ?? 0);
    $maxPoint = (int)($score['max_point'] ?? 0);

    // ------------------ مالی / تراکنش ------------------
    $stmt = $pdo->prepare("
        SELECT status, COUNT(*) as count, SUM(CASE WHEN status='approved' THEN entry_fee ELSE 0 END) as total_amount
        FROM transactions
        WHERE user_id = ?
        GROUP BY status
    ");
    $stmt->execute([$uidSelected]);
    $transactions = $stmt->fetchAll(PDO::FETCH_ASSOC);

    $approvedCount = $pendingCount = $rejectedCount = 0;
    $totalPaidAmount = 0;
    foreach ($transactions as $p) {
        $status = $p['status'];
        if ($status === 'approved') {
            $approvedCount = (int)$p['count'];
            $totalPaidAmount = (int)$p['total_amount'];
        } elseif ($status === 'pending') {
            $pendingCount = (int)$p['count'];
        } elseif ($status === 'rejected') {
            $rejectedCount = (int)$p['count'];
        }
    }

    // ------------------ متن گزارش ------------------
    $txt = "<blockquote>";
    $txt .= "<b>📊 آمار ایونت‌ها</b>\n";
    $txt .= "🔹 تعداد کل ایونت: <b>$totalAll</b>\n";
    $txt .= "🏆 تعداد وین : <b>$winCount</b>\n";
    $txt .= "📈 وین‌ریت: <b>" . round($winRate, 2) . "</b>";
    $txt .= "</blockquote>\n";
    $txt .= "<blockquote>";
    $txt .= "💰 ایونت ورودی‌دار: <b>$entryAll</b>\n";
    $txt .= "🏅 وین ورودی‌دار: <b>$entryWins</b>\n";
    $txt .= "📊 وین‌ریت: <b>" . round($entryWinRate, 2) . "</b>\n";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "<b>🎯 لیدری</b>\n";
    $txt .= "🔹 تعداد لیدری: <b>$leaderCount</b>\n";
    $txt .= "🏆 بردهای لیدری: <b>$leaderWins</b>\n";
    $txt .= "📊 وین‌ریت لیدری: <b>" . round($leaderWinRate, 2) . "</b>\n";
    $txt .= "</blockquote>";

    $txt .= "<blockquote>";
    $txt .= "<b>⭐ امتیازها</b>\n";
    $txt .= "🔹 امتیاز کل: <b>$totalPoints</b>\n";
    $txt .= "📌 بیشترین امتیاز: <b>$maxPoint</b>\n";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "<b>💰 مالی / تراکنش</b>\n";
    $txt .= "✅ تایید شده: <b>$approvedCount</b>\n";
    $txt .= "⏳ معلق: <b>$pendingCount</b>\n";
    $txt .= "❌ رد شده: <b>$rejectedCount</b>\n";
    $txt .= "💵 مجموع مبلغ پرداختی: <b>$totalPaidAmount</b>\n";
    $txt .= "</blockquote>\n";


    $kb = ['inline_keyboard' => [
        [['text' => '🔙 بازگشت', 'callback_data' => "user_info:$uidSelected"]],
    ]];

    editMessageText($chat_id, $mid, $txt, $kb);
    answerCb($cb['id'], '');
    exit;
}


if (str_starts_with($data, 'user_tournament_status:')) {

    error_log(
        '[USER STATUS] Handler reached | data=' . $data
    );

    $eid = (int) substr(
        $data,
        strlen('user_tournament_status:')
    );

    error_log(
        '[USER STATUS] eid=' . $eid .
        ' uid=' . $uid .
        ' mid=' . $mid
    );

    answerCb(
        $cb['id'],
        '⏳ در حال دریافت وضعیت...'
    );

    try {

        error_log(
            '[USER STATUS] Calling render function'
        );

        renderUserTournamentStatus(
            $pdo,
            $chat_id,
            $mid,
            $eid,
            $uid
        );

        error_log(
            '[USER STATUS] Render completed'
        );

    } catch (Throwable $e) {

        error_log(
            '[USER STATUS ERROR] '
            . $e->getMessage()
            . "\n"
            . $e->getTraceAsString()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ خطا:\n\n<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'user_leaderboard:')) {

    $parts =
        explode(
            ':',
            $data
        );

    $eid =
        (int) (
            $parts[1]
            ?? 0
        );

    $page =
        (int) (
            $parts[2]
            ?? 1
        );

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه ایونت نامعتبر است.'
        );

        return;
    }

    if ($page < 1) {
        $page = 1;
    }

    answerCb(
        $cb['id']
    );

    try {

        renderUserLeaderboard(
            $pdo,
            $chat_id,
            $mid,
            $eid,
            $uid,
            $page
        );

    } catch (Throwable $e) {

        error_log(
            '[USER LEADERBOARD HANDLER ERROR] '
            . $e->getMessage()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>نمایش رتبه‌بندی انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'user_games:')) {

    $eid = (int) substr(
        $data,
        strlen('user_games:')
    );

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه ایونت نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id']
    );

    try {

        renderUserGames(
            $pdo,
            $chat_id,
            $mid,
            $eid,
            $uid
        );

    } catch (Throwable $e) {

        error_log(
            '[USER GAMES HANDLER ERROR] '
            . $e->getMessage()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>نمایش بازی‌های شما انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

//-------------------------------------
if ($data === 'admin_games') {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    $rows  = [];
    $grows = $pdo->query('SELECT * FROM games ORDER BY active DESC, name ASC')->fetchAll();

    foreach ($grows as $gr) {
        $rows[] = [[
            'text'          => ($gr['active'] ? '🟢 ' : '🔴 ') . $gr['name'],
            'callback_data' => 'admin_toggle:' . $gr['id']
        ]];
    }

    // دکمه‌های انتهایی
    $rows[] = [
        ['text' => '➕ افزودن گیم', 'callback_data' => 'admin_add_game'],
        ['text' => '✖️ حذف گیم', 'callback_data' => 'admin_delete_game'],
        ['text' => '🔙 بازگشت',     'callback_data' => 'admin_panel']
    ];

    editMessageText($chat_id, $mid, '🎮 مدیریت گیم‌ها', [
        'inline_keyboard' => $rows
    ]);

    answerCb($cb['id'], '');
    exit;
}



if ($data === 'admin_delete_game') {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    $rows  = [];
    $grows = $pdo->query('SELECT * FROM games ORDER BY active DESC, name ASC')->fetchAll();

    foreach ($grows as $gr) {
        $rows[] = [[
            'text'          => ($gr['active'] ? '🟢 ' : '🔴 ') . $gr['name'],
            'callback_data' => 'delete_toggle:' . $gr['id']
        ]];
    }

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

    editMessageText($chat_id, $mid, '🗑 حذف گیم‌ها (فقط غیرفعال‌ها قابل حذف هستند)', [
        'inline_keyboard' => $rows
    ]);

    answerCb($cb['id'], '');
    exit;
}


// کلیک روی گیم در منوی حذف
if (str_starts_with($data, 'delete_toggle:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️', true);
        exit;
    }

    $gid = (int) substr($data, 14);

    $st = $pdo->prepare('SELECT active, name FROM games WHERE id = ?');
    $st->execute([$gid]);
    $g = $st->fetch();

    if (!$g) {
        answerCb($cb['id'], 'پیدا نشد');
        exit;
    }

    if ($g['active']) {
        // گیم فعال → فقط اخطار
        answerCb($cb['id'], '⚠️ فقط گیم‌های غیرفعال قابل حذف هستند.');
    } else {
        // گیم غیرفعال → حذف
        $pdo->prepare('DELETE FROM games WHERE id = ?')->execute([$gid]);
        answerCb($cb['id'], "🗑 گیم «" . htmlspecialchars($g['name']) . "» حذف شد.");
    }

    // بازسازی منوی حذف
    $rows  = [];
    $grows = $pdo->query('SELECT * FROM games ORDER BY active DESC, name ASC')->fetchAll();

    foreach ($grows as $gr) {
        $rows[] = [[
            'text'          => ($gr['active'] ? '🟢 ' : '🔴 ') . $gr['name'],
            'callback_data' => 'delete_toggle:' . $gr['id']
        ]];
    }

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

    editMessageText($chat_id, $mid, '🗑 حذف گیم‌ها (فقط غیرفعال‌ها قابل حذف هستند)', [
        'inline_keyboard' => $rows
    ]);

    exit;
}
//-------------------------admin toggle winner--------------//

if (str_starts_with($data, 'admin_toggle_2:')) {

    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️', true);
        exit;
    }

    $parts = explode(':', $data);
    $eid    = (int)($parts[1] ?? 0);
    $userId = (int)($parts[2] ?? 0);

    if ($eid <= 0 || $userId <= 0) {
        answerCb($cb['id'], 'خطا', true);
        exit;
    }

    $players = getEventPlayers($pdo, $eid);
    if (empty($players)) {
        answerCb($cb['id'], 'پیدا نشد', true);
        exit;
    }

    $sess = getSelectionSession($pdo, $eid, $uid) ?? ['selections' => [], 'status' => 'open', 'filtered' => null];

    $selections = toggleAdminSelection($pdo, $eid, $uid, $userId);
    $filteredPlayers = filterAdminSelectionPlayers($players, $sess['filtered']);

    renderAdminSelectionMenu(
        $pdo,
        $chat_id,
        $mid,
        $eid,
        $filteredPlayers,
        $selections,
        null,
        $players
    );

    answerCb($cb['id'], '');
    exit;
}



if (str_starts_with($data, 'admin_confirm:')) {
    if (!isAdmin($uid)) { 
        answerCb($cb['id'], '⛔️', true); 
        exit; 
    }

    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);

    $sess = getSelectionSession($pdo, $eid, $uid);
    if (!$sess || empty($sess['selections'])) {
        answerCb($cb['id'], 'هیچ برنده‌ای انتخاب نشده است.', true);
        exit;
    }

    $selectedUserIds = $sess['selections'];
    $players = getEventPlayers($pdo, $eid);
    if ($players === null) { 
        answerCb($cb['id'], 'پیدا نشد'); 
        exit; 
    }

    // اطلاعات ایونت (limit, squad, points_for_winner, name, game)
    $st = $pdo->prepare("SELECT `limit`, squad, points_for_winner, name, game FROM events WHERE id = ?");
    $st->execute([$eid]);
    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        answerCb($cb['id'], 'ایونت یافت نشد', true);
        exit;
    }

    $limit  = (int)$event['limit'];
    $points = (int)$event['points_for_winner'];
    $squads = json_decode($event['squad'], true) ?: [];

    $finalWinners = [];

    // پردازش برنده‌ها
    foreach ($selectedUserIds as $selectedUserId) {

        $selectedUserId = (int)$selectedUserId;

        if ($limit > 1) {

            foreach ($squads as $squad) {

                $memberIds = [$squad['leader_id']];

                foreach ($squad['members'] as $m) {
                    $memberIds[] = $m['user_id'];
                }

                if (in_array($selectedUserId, $memberIds, true)) {

                    foreach ($memberIds as $uidWinner) {
                        addRankingPoints($pdo, $uidWinner, $eid, $points);
                        $finalWinners[] = $uidWinner;
                    }

                    break;
                }
            }

        } else {
            addRankingPoints($pdo, $selectedUserId, $eid, $points);
            $finalWinners[] = $selectedUserId;
        }
    }

    error_log("WINNERS INPUT:");
    error_log(print_r($finalWinners, true));
    // ذخیره نهایی برنده‌ها در جدول events
    $rankedWinners = [];
    if (!empty($finalWinners)) {
        $rankedWinners = addWinnersToEvent($pdo, $eid, $finalWinners);
    }

    // ارسال پیام تبریک به برنده‌ها
    foreach ($rankedWinners as $winner) {
        sendWinnerCongratulation($pdo, (int)$winner['user_id'], $eid, $winner, $event);
    }

    // پاک کردن نشست
    deleteSelectionSession($pdo, $eid, $uid);

    editMessageText($chat_id, $mid, "عملیات ثبت/اتمام انجام شد. تعداد برندگان: " . count($finalWinners));
    answerCb($cb['id'], '✅ ثبت شد');
    exit;
}

//====================================================

if (str_starts_with($data, 'admin_bot')) {
    $txt = "🤖 پنل مدیریت ربات:\nاز دکمه‌ها برای دسترسی به بخش‌های مختلف استفاده کنید.";

    $ik = [
        [
            ['text' => '🗂 گالری', 'callback_data' => 'admin_gallery']
        ],
        [
            ['text' => '🔙 بازگشت', 'callback_data' => 'admin_panel']
        ]
    ];

    editMessageText($chat_id, $mid, $txt, [
        'parse_mode' => 'HTML',
        'inline_keyboard' => $ik
    ]);

    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'admin_gallery')) {
    // پیام به کاربر که مدیا بفرسته
    sendMessage($chat_id, "🗂 لطفاً مدیای خود را ارسال کنید تا در گالری ذخیره شود.\nمی‌توانید عکس، ویدیو، GIF یا فایل بفرستید.");

    // ست کردن حالت برای دریافت مدیا
    setState($pdo, $uid, 'gallery_wait_media');

    answerCb($cb['id'], '');
    exit;
}


//--------------------profile events------------------

if (str_starts_with($data, 'profile_events:')) {
    // 1. استخراج پارامترها
    $parts = explode(':', $data);
    $uid   = (int)($parts[1] ?? $uid);
    $page  = max(1, (int)($parts[2] ?? 1));
    $type  = $parts[3] ?? 'active'; // active, finished, active+finished, none
    $limit = 9;
    $offset = ($page - 1) * $limit;

    // 2. مدیریت فیلترهای انتخاب شده
    $selected = explode('+', $type);
    $selected = array_filter($selected, fn($t) => $t !== 'none' && !empty($t)); 
    
    // 3. دریافت لیست آیدی ایونت‌های کاربر از جدول users
    $stmt = $pdo->prepare("SELECT ev_ids FROM users WHERE id = ?");
    $stmt->execute([$uid]);
    $userRow = $stmt->fetch(PDO::FETCH_ASSOC);
    
    $eventIds = [];
    if ($userRow && $userRow['ev_ids']) {
        // فرض می‌کنیم ev_ids یک JSON Array است: [id1, id2, ...]
        $eventIds = json_decode($userRow['ev_ids'], true) ?: [];
    }

    // اگر کاربر در هیچ ایونتی جوین نداده باشد
    if (empty($eventIds)) {
        $events = [];
    } else {
        $eventIdsList = implode(',', $eventIds); // برای استفاده در کوئری SQL
        
        // 4. ساخت شرط WHERE برای فیلتر وضعیت
        $statusConditions = '';
        $params = [];
        
        if (!empty($selected)) {
            $statusConditions = ' AND LOWER(status) IN (';
            $statusConditions .= str_repeat('?,', count($selected) - 1) . '?)';
            $params = array_map('strtolower', $selected);
        } else {
            // اگر هیچ فیلتری انتخاب نشده، لیستی خالی برگردان
            $events = [];
            goto skip_query; // پرش به مرحله بعد (ساخت پیام)
        }
        
        // 5. کوئری دیتابیس برای دریافت ایونت‌های کاربر بر اساس ev_ids و فیلتر وضعیت
        // ⚠️ مهم: از IN() برای چک کردن ev_ids استفاده می‌شود
        $sql = "SELECT id, name, game, status, type, date_str 
                FROM events 
                WHERE id IN ({$eventIdsList}) 
                {$statusConditions}
                ORDER BY date_str DESC 
                LIMIT " . ($limit + 1) . " OFFSET {$offset}";
        
        $stmt = $pdo->prepare($sql);
        
        // ترکیب پارامترهای status با event_idsList (اگرچه ev_idsList مستقیماً در کوئری جایگذاری شده)
        // اجرای کوئری با پارامترهای status
        $stmt->execute($params); 
        $events = $stmt->fetchAll(PDO::FETCH_ASSOC); 
    }
    
    skip_query: // لیبل برای پرش در صورت عدم انتخاب فیلتر
    
    // 6. ساخت دکمه‌های فیلتر (همان منطق قبلی برای Callback Data)
    $filterRow = [];
    $allFilters = [
        'active'   => 'جاری 🟢',
        'finished' => 'پایان‌یافته 🟠'
    ];

    foreach ($allFilters as $filterName => $filterLabel) {
        $isActive = in_array($filterName, $selected);

        if ($isActive) {
            $newSelected = array_diff($selected, [$filterName]);
            $newType = $newSelected ? implode('+', $newSelected) : 'none';
            $buttonText = "{$filterLabel} ⬤"; // انتخاب‌شده
        } else {
            $newSelected = array_unique(array_merge($selected, [$filterName]));
            $newType = implode('+', array_filter($newSelected, fn($v) => $v !== 'none'));
            if (empty($newType)) $newType = $filterName;
            $buttonText = "{$filterLabel} ○"; // غیرفعال
        }

        $filterRow[] = [
            'text' => $buttonText,
            'callback_data' => "profile_events:{$uid}:1:{$newType}"
        ];
    }


    // 7. ساخت متن پیام
    $labels = [];
    if (in_array('active', $selected))   $labels[] = 'جاری';
    if (in_array('finished', $selected)) $labels[] = 'پایان‌یافته';
    $labelText = $labels ? implode(' و ', $labels) : 'بدون فیلتر';

    $txt = "📋 <b>ایونت‌های {$labelText}</b> | <b>صفحه {$page}</b>\n\n";
    $txt .= "<blockquote>📝 راهنما:\n"
        ."• با دکمه‌های بالا، ایونت‌های <b>جاری</b> یا <b>پایان‌یافته</b> را فیلتر کنید.\n"
        ."• می‌توانید چند فیلتر را هم‌زمان فعال کنید.\n"
        ."• روی نام هر ایونت بزنید تا جزئیات آن را ببینید.</blockquote>\n\n";


    // 8. ساخت دکمه‌های لیست و صفحه‌بندی
    $keyboard = [$filterRow];
    $currentType = $selected ? implode('+', $selected) : 'none';

    if (!empty($events)) {
    foreach ($events as $e) {
        $statusEmoji = (strtolower($e['status']) == 'active') ? '✦' : '⨂';
        $typeEmoji   = ($e['type'] === 'custom') ? '🎯' : (($e['type'] === 'tournament') ? '🏆' : '');

        // استخراج فقط تاریخ از date_str
        $datePart = '';
        if (!empty($e['date_str'])) {
            $datePart = explode(' ', $e['date_str'])[0]; // جداکردن تاریخ از ساعت
            $dateSup  = toSuperscriptDate($datePart);
        } else {
            $dateSup = '';
        }

        // ساخت متن دکمه
        $btnText = "{$typeEmoji} " . ($e['name'] ?: 'بدون نام') . " • " . $e['game'] . " {$statusEmoji}";

        $keyboard[] = [[
            'text' => $btnText,
            'callback_data' => 'ev_userview:' . $e['id']
        ]];
    }
    } else {
        $txt .= "❌ ایونتی برای این کاربر با فیلتر‌های انتخابی یافت نشد.";
    }

    $paginationRow = [];

    if (count($events) > $limit) {
        array_pop($events); 
        $paginationRow[] = [
            'text' => '⏩ بعدی',
            'callback_data' => "profile_events:{$uid}:" . ($page + 1) . ":{$currentType}"
        ];
    }

    if ($page > 1) {
        array_unshift($paginationRow, [
            'text' => '⏪ قبلی',
            'callback_data' => "profile_events:{$uid}:" . ($page - 1) . ":{$currentType}"
        ]);
    }

    if (!empty($paginationRow)) $keyboard[] = $paginationRow;

    // 10. بازگشت
    $keyboard[] = [['text' => '🔙 بازگشت', 'callback_data' => 'profile_back']];

    editMessageText($chat_id, $mid, $txt, ['inline_keyboard' => $keyboard]);
    exit;
}





if(str_starts_with($data, 'event_cancel_')){
    $eid = (int)substr($data, 13);

    $stmt = $pdo->prepare("SELECT players, status FROM events WHERE id = ?");
    $stmt->execute([$eid]);
    $event = $stmt->fetch(PDO::FETCH_ASSOC);
    if(!$event){ editMessageText($chat_id, $mid, "❌ ایونت یافت نشد."); exit; }

    if($event['status'] !== 'active'){
        answerCb($cb['id'], "❌ این ایونت دیگر قابل لغو نیست.", true);
        exit;
    }

    $players = json_decode($event['players'], true) ?: [];
    $newPlayers = array_filter($players, fn($p) => $p['user_id'] != $uid);

    $stmt = $pdo->prepare("UPDATE events SET players = ? WHERE id = ?");
    $stmt->execute([json_encode(array_values($newPlayers), JSON_UNESCAPED_UNICODE), $eid]);

    answerCb($cb['id'], "✅ شما از ایونت خارج شدید.", true);

    // بازگشت به لیست ایونت‌ها
    $data = 'events_current';
    // می‌تونی هندلر لیست ایونت‌ها را فراخوانی کنی یا پیام را دوباره رندر کنی
    exit;
}

if(str_starts_with($data, 'event_manage_')){
    $eid = (int)substr($data, 13);
    // این قسمت برای لیدر یا ادمین است
    // می‌توان قابلیت اضافه/حذف عضو، تغییر IGN، یا نمایش امتیاز تیم را اضافه کرد
    editMessageText($chat_id, $mid, "🛡️ مدیریت اسکواد در حال آماده‌سازی است.", [
        'reply_markup'=>['inline_keyboard'=>[['text'=>'🔙 بازگشت','callback_data'=>'event_'.$eid]]]
    ]);
    exit;
}



//---------------------search player-------------------//


// admin_start_search:
if (str_starts_with($data, 'admin_start_search:')) {
    if (!isAdmin($uid)) { answerCb($cb['id'], '⛔️', true); exit; }
    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);

    // set session to awaiting_search
    $sess = getSelectionSession($pdo, $eid, $uid) ?? ['selections'=>[], 'status'=>'open', 'filtered'=>null];
    saveSelectionSession($pdo, $eid, $uid, $sess['selections'], 'awaiting_search', $sess['filtered']);

    // درخواست متن از ادمین (می‌تونی از sendMessage با force_reply استفاده کنی)
    sendMessage($chat_id, "🔎 متن جستجو را ارسال کنید (با ign یا telegram_id). مثلا: f");
    answerCb($cb['id'], '');
    exit;
}

// سپس در هندلر پیام‌های عادی (جایی که پیام‌های متنی چک میشه):
// اگر admin و وضعیت awaiting_search باشه => اعمال فیلتر
function handleAdminTextMessage(PDO $pdo, int $fromId, string $text, int $chat_id, int $mid): void {
    if (!isAdmin($fromId)) return;
    $st = $pdo->prepare("SELECT event_id, payload FROM admin_actions WHERE admin_id=? AND action='event_selection' AND JSON_EXTRACT(payload, '$.status') = 'awaiting_search' LIMIT 1");
    $st->execute([$fromId]);
    $r = $st->fetch(PDO::FETCH_ASSOC);
    if (!$r) return; // نه جستجو در جریان است

    $eid = (int)$r['event_id'];
    $players = getEventPlayers($pdo, $eid);
    if ($players === null) {
        sendMessage($chat_id, "رویداد پیدا نشد.");
        return;
    }

    $q = mb_strtolower(trim($text));
    $filteredMap = [];
    foreach ($players as $p) {
        $hay = mb_strtolower((string)($p['ign'] ?? '') . ' ' . (string)($p['telegram_id'] ?? ''));
        if ($q === '' || mb_strpos($hay, $q) !== false) {
            $filteredMap[] = (int)$p['user_id'];
        }
    }

    $sess = getSelectionSession($pdo, $eid, $fromId) ?? ['selections'=>[], 'status'=>'open', 'filtered'=>null];
    saveSelectionSession($pdo, $eid, $fromId, $sess['selections'], 'open', $filteredMap);

    $filteredPlayers = filterAdminSelectionPlayers($players, $filteredMap);
    $messageText = "نتایج جستجو برای «{$text}»: " . count($filteredPlayers) . " مورد";

    renderAdminSelectionMenu(
        $pdo,
        $chat_id,
        $mid,
        $eid,
        $filteredPlayers,
        $sess['selections'],
        $messageText
    );

    sendMessage($chat_id, "نتایج نمایش داده شد. برای بازگشت روی «بازگشت» بزنید.");
}



    if (str_starts_with($data, 'admin_toggle:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️', true);
        exit;
    }

    $gid = (int) substr($data, 13);

    // وضعیت فعلی را بگیر
    $st = $pdo->prepare('SELECT active FROM games WHERE id = ?');
    $st->execute([$gid]);
    $g = $st->fetch();

    if (!$g) {
        answerCb($cb['id'], 'پیدا نشد');
        exit;
    }

    // تغییر وضعیت
    $new = $g['active'] ? 0 : 1;
    $pdo->prepare('UPDATE games SET active = ? WHERE id = ?')->execute([$new, $gid]);

    answerCb($cb['id'], $new ? 'فعال شد' : 'غیرفعال شد');

    // بازسازی لیست
    $rows  = [];
    $grows = $pdo->query('SELECT * FROM games ORDER BY active DESC, name ASC')->fetchAll();

    foreach ($grows as $gr) {
        $rows[] = [[
            'text'          => ($gr['active'] ? '🟢 ' : '🔴 ') . $gr['name'],
            'callback_data' => 'admin_toggle:' . $gr['id']
        ]];
    }

    // دکمه‌های انتهایی
    $rows[] = [
        ['text' => '➕ افزودن گیم', 'callback_data' => 'admin_add_game'],
        ['text' => '✖️ حذف گیم', 'callback_data' => 'admin_delete_game'],
        ['text' => '🔙 بازگشت',     'callback_data' => 'admin_panel']
    ];

    editMessageText($chat_id, $mid, '🎮 مدیریت گیم‌ها', [
        'inline_keyboard' => $rows
    ]);

    exit;
}

    if ($data === 'admin_add_game') {
    setState($pdo, $uid, 'admin_add_game'); // تنظیم حالت کاربر

    // ارسال پیام جدید با متن و دکمه‌های شیشه‌ای
    editMessageText(
        $chat_id,
        $mid,
        "📌 لطفاً نام گیم جدید را وارد کنید:",
        [
            'inline_keyboard' => [
                [
                    ['text' => '🔙 بازگشت', 'callback_data' => 'admin_panel'],
            
                ]
            ]
        ]
    );

    exit;
}


if (str_starts_with($data,'admin_create:')) { 
    if (!isAdmin($uid)) { 
        answerCb($cb['id'],'⛔️',true); 
        exit; 
    }

    $type = substr($data, 13); 
    $games = listGames($pdo); 
    $rows = [];

    foreach ($games as $g) {
        $gameName = $g['name'] ?? ''; 
        if ($gameName === '') continue; 
        $rows[] = [
            ['text' => $gameName, 'callback_data' => 'admin_create_game:'.$type.':'.$g['id']]
        ];
    }

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

    editMessageText($chat_id, $mid, 'انتخاب بازی برای ساخت رویداد:', ['inline_keyboard'=>$rows]);
    answerCb($cb['id'],''); 
    exit; 
}
    
if (str_starts_with($data,'admin_create_game:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    $parts = explode(':', $data, 4);
    $type  = $parts[1] ?? 'tournament';
    $gameId = (int)($parts[2] ?? 0);

    $stmt = $pdo->prepare('SELECT name FROM games WHERE id = ? LIMIT 1');
    $stmt->execute([$gameId]);

    $game = $stmt->fetchColumn();

    if (!$game) {
        answerCb($cb['id'], '❌ بازی پیدا نشد', true);
        exit;
    }

    // ایجاد رکورد اولیه رویداد
    $pdo->prepare('INSERT INTO events (type, game, game_code, creator_id, status) VALUES (?,?,?,?, "pending")')
        ->execute([$type, $game, $gameId, $uid]);

    $eid = (int) $pdo->lastInsertId();
    setState($pdo, $uid, "create:$type:$eid:name");

    // ساخت reply_markup به صورت جداگانه (خواناتر و امن‌تر)
    $kb = [
        'inline_keyboard' => [
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'admin_panel']
            ]
        ]
    ];

    editMessageText($chat_id, $mid, '📛 نام رویداد را ارسال کنید یا عبور کنید', $kb);
    answerCb($cb['id'], '');
    exit;
}

if ($data === 'admin_events_menu') {
    $kb = ['inline_keyboard'=>[
        [['text'=>'🗃️ لیست ایونت‌ها','callback_data'=>'admin_events:active:0'],['text'=>'🔍 جستجو','callback_data'=>'admin_ev_search']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_panel']],
    ]];

    editMessageText($chat_id,$mid,'🎯 مدیریت ایونت‌ها', $kb);
    answerCb($cb['id'],''); 
    exit;
}

if (str_starts_with($data, 'admin_events')) {
    // محدود به 9 قسمت برای جلوگیری از انفجار
    $parts = explode(':', $data, 9);

    // بارگذاری لیست بازی‌ها برای تعیین طول بخش games
    $allGames = $pdo->query("SELECT id, name FROM games ORDER BY id ASC")->fetchAll(PDO::FETCH_ASSOC);
    $gameCount = count($allGames);

    // پیش‌فرض‌ها (بیت‌ها)
    $defaultStatuses = array_fill(0, 3, 0); // active, archived, finished
    $defaultTypes    = array_fill(0, 2, 0); // tournament, custom
    $defaultGames    = array_fill(0, $gameCount, 0);

    // خواندن ورودی (ممکن است بعضی بخش‌ها خالی یا به شکل نامی ارسال شده باشند)
    $statusesPart = $parts[1] ?? '';
    $typesPart    = $parts[2] ?? '';
    $gamesPart    = $parts[3] ?? '';
    $page         = max(0, (int)($parts[4] ?? 0));
    $filters      = max(0, (int)($parts[5] ?? 0));
    $gamesPage    = max(0, (int)($parts[6] ?? 0));
    $action       = $parts[7] ?? '';
    $subIndex     = isset($parts[8]) && $parts[8] !== '' ? (int)$parts[8] : '';

    // اگر statusesPart شامل نام وضعیت است (مثلاً "active|archived")، تبدیل به بیت کن
    $nameToStatusIndex = ['active'=>0,'archived'=>1,'finished'=>2];
    if ($statusesPart !== '' && preg_match('/[a-zA-Z]/', $statusesPart)) {
        $bits = array_fill(0, 3, 0);
        foreach (explode('|', $statusesPart) as $p) {
            $p = trim($p);
            if ($p === '') continue;
            if (isset($nameToStatusIndex[$p])) $bits[$nameToStatusIndex[$p]] = 1;
        }
        $statusesPart = implode('|', $bits);
    }

    // نرمالایز تابع برای تبدیل رشته بیت به رشته هم‌طول
    $normalizeStrBits = function($part, $defaultArr) use ($gameCount) {
        if ($part === null || $part === '') return implode('|', $defaultArr);
        $bits = array_map(fn($v)=> (intval($v) ? 1 : 0), explode('|', $part));
        if (count($bits) < count($defaultArr)) $bits = array_merge($bits, array_fill(0, count($defaultArr) - count($bits), 0));
        elseif (count($bits) > count($defaultArr)) $bits = array_slice($bits, 0, count($defaultArr));
        return implode('|', $bits);
    };

    $statusesStr = $normalizeStrBits($statusesPart, $defaultStatuses);
    $typesStr    = $normalizeStrBits($typesPart, $defaultTypes);
    $gamesStr    = $normalizeStrBits($gamesPart, $defaultGames);

    $callbackData = implode(':', [
        'admin_events',
        $statusesStr,
        $typesStr,
        $gamesStr,
        $page,
        $filters,
        $gamesPage,
        $action,
        $subIndex === '' ? '' : (string)$subIndex
    ]);

    handleAdminEvents($pdo, $chat_id, $mid, $uid, $callbackData, null);
    exit;
}




if ($data === 'admin_ev_search') {
    // رفتن به حالت جستجو
    setState($pdo, $uid, 'awaiting_search');
    answerCb($cb['id'], '');
    sendMessage($chat_id, "🔍 عبارت مورد نظر برای جستجو را بفرستید (می‌تونی اسم ایونت یا آیدی اون رو وارد کنی):");
    exit;
}

if (getState($pdo, $uid) === 'awaiting_search' && isset($text)) {
    // دریافت عبارت جستجو از پیام کاربر
    $searchTerm = trim($text);
    setState($pdo, $uid, ''); // حالت رو خالی کن

    // اجرای لیست ایونت‌ها با عبارت جستجو
    handleAdminEvents($pdo, $chat_id, $mid, $uid, "admin_events:active:0:0:0", $searchTerm);
    exit;
}


function handleAdminEvents(PDO $pdo, $chat_id, $mid, $uid, $data, $searchTerm = null) {
    global $cb;

    if (!isAdmin($uid)) {
        if (isset($cb['id'])) answerCb($cb['id'], '⛔️ فقط ادمین‌ها دسترسی دارند');
        return;
    }

    // پارس callback با محدودیت 9 قسمت
    $parts = explode(':', $data, 9);
    if (!isset($parts[0]) || $parts[0] !== 'admin_events') return;

    // بارگذاری بازی‌ها (برای هم‌طول‌سازی و نمایش)
    $allGames = $pdo->query("SELECT id, name FROM games ORDER BY id ASC")->fetchAll(PDO::FETCH_ASSOC);
    $gameCount = count($allGames);

    // پیش‌فرض‌ها
    $defaultStatuses = array_fill(0, 3, 0);
    $defaultTypes    = array_fill(0, 2, 0);
    $defaultGames    = array_fill(0, $gameCount, 0);

    // خواندن بخش‌ها
    $statusesPart = $parts[1] ?? implode('|', $defaultStatuses);
    $typesPart    = $parts[2] ?? implode('|', $defaultTypes);
    $gamesPart    = $parts[3] ?? implode('|', $defaultGames);
    $page         = max(0, (int)($parts[4] ?? 0));
    $filters      = max(0, (int)($parts[5] ?? 0));
    $gamesPage    = max(0, (int)($parts[6] ?? 0));
    $action       = $parts[7] ?? '';
    $subIndex     = isset($parts[8]) && $parts[8] !== '' ? (int)$parts[8] : null;

    // نرمالایز بیت‌ها به آرایه با طول ثابت
    $normBits = function($part, $defaultArr) {
        $bits = $part === null || $part === '' ? $defaultArr : array_map(fn($v)=> (intval($v) ? 1 : 0), explode('|', $part));
        if (count($bits) < count($defaultArr)) $bits = array_merge($bits, array_fill(0, count($defaultArr) - count($bits), 0));
        elseif (count($bits) > count($defaultArr)) $bits = array_slice($bits, 0, count($defaultArr));
        return $bits;
    };

    $statusesBits = $normBits($statusesPart, $defaultStatuses); // length 3
    $typesBits    = $normBits($typesPart, $defaultTypes);       // length 2
    $gamesBits    = $normBits($gamesPart, $defaultGames);       // length gameCount

    // اعمال اکشن‌ها
    if ($action === '+filter') {
        $filters++;
    } elseif ($action === '-filter') {
        $filters = max(0, $filters - 1);
        if ($filters < 2) $gamesPage = 0;
    } elseif ($action === 'clear_types') {
        $typesBits = array_fill(0, count($typesBits), 0);
    } elseif ($action === 'clear_games') {
        $gamesBits = array_fill(0, $gameCount, 0);
    } elseif ($action === 'toggle_status' && $subIndex !== null && isset($statusesBits[$subIndex])) {
        $statusesBits[$subIndex] = $statusesBits[$subIndex] ? 0 : 1;
    } elseif ($action === 'toggle_type' && $subIndex !== null && isset($typesBits[$subIndex])) {
        $typesBits[$subIndex] = $typesBits[$subIndex] ? 0 : 1;
    } elseif ($action === 'toggle_game' && $subIndex !== null && isset($gamesBits[$subIndex])) {
        $gamesBits[$subIndex] = $gamesBits[$subIndex] ? 0 : 1;
    }

    // آماده‌سازی انتخاب‌ها برای SQL
    $statusMap = ['active','archived','finished'];
    $typeMap   = ['tournament','custom'];

    $selectedStatuses = [];
    foreach ($statusesBits as $i => $b) if ($b && isset($statusMap[$i])) $selectedStatuses[] = $statusMap[$i];

    $selectedTypes = [];
    foreach ($typesBits as $i => $b) if ($b && isset($typeMap[$i])) $selectedTypes[] = $typeMap[$i];

    $selectedGames = [];
    foreach ($gamesBits as $i => $b) {
        if ($b && isset($allGames[$i])) $selectedGames[] = $allGames[$i]['name'];
    }

    // جستجو از callback یا ورودی تابع
    // اگر searchTerm در callback (بخش action ممکن است شامل متن باشد) شما از قبل نساختید، از پارامتر ورودی استفاده کن
    if ($searchTerm === null) $searchTerm = null;

    // ساخت شرط SQL با پارامترایز
    $where = [];
    $params = [];

    if (count($selectedStatuses) > 0) {
        $ph = implode(',', array_fill(0, count($selectedStatuses), '?'));
        $where[] = "status IN ($ph)";
        $params = array_merge($params, $selectedStatuses);
    }
    if (count($selectedTypes) > 0) {
        $ph = implode(',', array_fill(0, count($selectedTypes), '?'));
        $where[] = "type IN ($ph)";
        $params = array_merge($params, $selectedTypes);
    }
    if (count($selectedGames) > 0) {
        $ph = implode(',', array_fill(0, count($selectedGames), '?'));
        $where[] = "game IN ($ph)";
        $params = array_merge($params, $selectedGames);
    }
    if ($searchTerm && trim($searchTerm) !== '') {
        $like = "%$searchTerm%";
        $where[] = "(CAST(id AS CHAR) LIKE ? OR name LIKE ? OR game LIKE ?)";
        $params = array_merge($params, [$like, $like, $like]);
    }

    $sqlWhere = $where ? 'WHERE ' . implode(' AND ', $where) : '';
    $limit = 24;
    $offset = $page * $limit;

    // اجرای پرس‌وجو
    $sql = "SELECT SQL_CALC_FOUND_ROWS * FROM events $sqlWhere ORDER BY id DESC LIMIT $limit OFFSET $offset";
    $st = $pdo->prepare($sql);
    $st->execute($params);
    $rows = $st->fetchAll(PDO::FETCH_ASSOC);
    $cnt = (int)($pdo->query('SELECT FOUND_ROWS() as c')->fetch()['c'] ?? 0);
    $hasMore = ($offset + count($rows)) < $cnt;

    // تابع سازنده کال‌بک برای بازسازی کامل وضعیت‌ها
    $buildCb = function(array $statusesBits, array $typesBits, array $gamesBits, $page, $filters, $gamesPage, $action = '', $subIndex = '') {
        $s = implode('|', $statusesBits);
        $t = implode('|', $typesBits);
        $g = implode('|', $gamesBits);
        $act = $action ?? '';
        $sub = $subIndex === null ? '' : (string)$subIndex;
        return "admin_events:$s:$t:$g:$page:$filters:$gamesPage:$act:$sub";
    };

    // ساخت inline keyboard
    $ik = [];

    // Status buttons
    $statusLabels = ['🟢 جاری','📦 آرشیوشده','🔴 پایان یافته'];
    $row = [];
    for ($i = 0; $i < 3; $i++) {
        $label = ($statusesBits[$i] ? '✅ ' : '') . $statusLabels[$i];
        $row[] = ['text' => $label, 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page, $filters, $gamesPage, 'toggle_status', $i)];
    }
    $ik[] = $row;

    // Types (only when filters>=1)
    if ($filters >= 1) {
        $typeLabels = ['🏆 تورنومنت','🎯 کاستوم'];
        $row = [];
        for ($i = 0; $i < 2; $i++) {
            $label = ($typesBits[$i] ? '✅ ' : '') . $typeLabels[$i];
            $row[] = ['text' => $label, 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page, $filters, $gamesPage, 'toggle_type', $i)];
        }
        $ik[] = $row;
    }

    // Games with paging (only when filters>=1)
    if ($filters >= 2) {
        $perRow = 3;
        $perPageRows = 4;
        $perPage = $perRow * $perPageRows;
        $totalPages = max(1, (int)ceil($gameCount / $perPage));
        $gamesPage = min(max(0, $gamesPage), $totalPages - 1);
        $start = $gamesPage * $perPage;
        $slice = array_slice($allGames, $start, $perPage);

        $row = []; $col = 0;
        foreach ($slice as $idx => $g) {
            $globalIndex = $start + $idx;
            $label = ($gamesBits[$globalIndex] ? '✅ ' : '🎮 ') . $g['name'];
            $row[] = ['text' => $label, 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page, $filters, $gamesPage, 'toggle_game', $globalIndex)];
            $col++;
            if ($col === $perRow) { $ik[] = $row; $row = []; $col = 0; }
        }
        if ($row) $ik[] = $row;

        $gpRow = [];
        if ($gamesPage > 0) $gpRow[] = ['text' => '⬅️ قبلی', 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page, $filters, $gamesPage-1, '', '')];
        if ($gamesPage + 1 < $totalPages) $gpRow[] = ['text' => '➡️ بعدی', 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page, $filters, $gamesPage+1, '', '')];
        if ($gpRow) $ik[] = $gpRow;
    }

    $ik[] = [['text' => '──────────────────────────────', 'callback_data' => 'noop']];

    // Events list (2 per row)
    $rowBtns = [];
    foreach ($rows as $r) {
        $emoji = ($r['type'] ?? '') === 'tournament' ? '🏆 ' : '🎯 ';
        $rowBtns[] = ['text' => $emoji . ($r['name'] ?: 'بدون نام') . ' — ' . ($r['game'] ?? ''), 'callback_data' => 'admin_ev:' . $r['id']];
        if (count($rowBtns) === 2) { $ik[] = $rowBtns; $rowBtns = []; }
    }
    if ($rowBtns) $ik[] = $rowBtns;

    // Events pagination
    $navRow = [];
    if ($page > 0) $navRow[] = ['text' => '⬅️ قبلی', 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page-1, $filters, $gamesPage, '', '')];
    if ($hasMore) $navRow[] = ['text' => '➡️ بعدی', 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page+1, $filters, $gamesPage, '', '')];
    if ($navRow) $ik[] = $navRow;

    // Footer
    $endRow = [
        ['text' => '🔙 بازگشت', 'callback_data' => 'admin_panel'],
        ['text' => '📤 خروجی CSV', 'callback_data' => 'admin_ad_export'],
        ['text' => '+ فیلتر', 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page, $filters, $gamesPage, '+filter', '')]
    ];
    if ($filters > 0) $endRow[] = ['text' => '- فیلتر', 'callback_data' => $buildCb($statusesBits, $typesBits, $gamesBits, $page, $filters, $gamesPage, '-filter', '')];
    $ik[] = $endRow;

    // Title
    $statusLabelsMap = ['active'=>'جاری','archived'=>'آرشیوشده','finished'=>'پایان‌یافته'];
    $selectedStatusNames = [];
    foreach ($statusesBits as $i => $b) if ($b && isset($statusLabelsMap[$statusMap[$i] ?? ''])) {
        // استفاده از $statusMap که قبلاً ایجاد شده؛ اما اگر نبود fallback به نام‌های مشخص
        $mapNames = ['جاری','آرشیوشده','پایان‌یافته'];
        $selectedStatusNames[] = $mapNames[$i] ?? ('status'.$i);
    }
    $statusTitle = count($selectedStatusNames) ? implode('، ', $selectedStatusNames) : 'همه';

    $typeNamesMap = ['تورنومنت','کاستوم'];
    $selectedTypeNames = [];
    foreach ($typesBits as $i => $b) if ($b) $selectedTypeNames[] = $typeNamesMap[$i] ?? ('type'.$i);
    $typeTitle = count($selectedTypeNames) ? implode('، ', $selectedTypeNames) : 'همه';

    $selectedGameNames = [];
    foreach ($gamesBits as $i => $b) {
        if ($b && isset($allGames[$i])) $selectedGameNames[] = $allGames[$i]['name'];
    }
    $gamesTitle = count($selectedGameNames) ? implode('، ', $selectedGameNames) : 'همه';

    $titleParts = [
        'وضعیت: ' . $statusTitle,
        'نوع: ' . $typeTitle,
        'بازی: ' . $gamesTitle
    ];
    if ($searchTerm) $titleParts[] = 'جستجو: «' . htmlspecialchars($searchTerm) . '»';
    $title = "<blockquote>📅 مدیریت رویدادها</blockquote>\n\n<b>🔍 فیلترها:</b>\n• " . implode("\n• ", $titleParts);

    // نمایش پیام
    if (isset($cb['id'])) {
        editMessageText($chat_id, $mid, $title, ['inline_keyboard' => $ik]);
        answerCb($cb['id'], '');
    } else {
        sendMessage($chat_id, $title, ['inline_keyboard' => $ik]);
    }
}

if (str_starts_with($data, 'admin_ev:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ فقط ادمین‌ها دسترسی دارند', true);
        exit;
    }

    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);

    if (!$eid) {
        answerCb($cb['id'], '❌ شناسه نامعتبر', true);
        exit;
    }

    renderAdminEventInfo($pdo, $chat_id, $mid, $eid);
    answerCb($cb['id'], '');
    exit;
}



function renderAdminEventInfo(PDO $pdo, int $chat_id, int $mid, int $eid) {
    // مقداردهی اولیه
    $txt = '';

    // گرفتن اطلاعات ایونت
    $st = $pdo->prepare('SELECT * FROM events WHERE id=?');
    $st->execute([$eid]);
    $e = $st->fetch(PDO::FETCH_ASSOC);

    if (!$e) {
        editMessageText($chat_id, $mid, '❌ رویداد پیدا نشد');
        return;
    }

    // اطلاعات سازنده
    $creator_name = '';
    if (!empty($e['creator_id'])) {
        $st2 = $pdo->prepare('SELECT username, first_name FROM users WHERE id=?');
        $st2->execute([$e['creator_id']]);
        $creator = $st2->fetch(PDO::FETCH_ASSOC);
        if ($creator) {
            $creator_name = "👤 سازنده: " . $creator['first_name'] . " | @" . $creator['username'] . " | <code>" . $e['creator_id'] ."</code>";
        }
    }

    // تاریخ ایجاد جلالی
    $ts = strtotime($e['created_at']);
    $jalaliDate = $ts ? jdate("Y/m/d - H:i", $ts) : '';

    // تعداد پلیرهای ثبت‌نام‌شده
    $stPlayers = $pdo->prepare(
        "SELECT COUNT(*) FROM event_players WHERE ev_id = ? AND status = 'accepted'"
    );
    $stPlayers->execute([$eid]);
    $count = (int)$stPlayers->fetchColumn();

    // آیکون نوع ایونت
    $icon = ($e['type'] === 'tournament' ? '🏆' : '🎯');

    // خط اول: نام ایونت | #id | تاریخ ایجاد داخل بلوک
    $lineParts = [];
    if (!empty($e['name'])) $lineParts[] = $e['name'];
    if (!empty($e['id']))   $lineParts[] = "<code>#{$e['id']}</code>";
    if (!empty($jalaliDate)) $lineParts[] = $jalaliDate;
    if (!empty($e['status'])) $lineParts[] = "<b>{$e['status']}</b>";
    if (!empty($lineParts)) $txt .= "<blockquote>{$icon} " . implode(' | ', $lineParts) . "</blockquote>\n";

    // بلوک اطلاعات سازنده و info
    $info_lines = [];
    if (!empty($creator_name)) $info_lines[] = $creator_name;
    if (!empty($e['info'])) $info_lines[] = "🧭 توضیحات: " . $e['info'];
    if (!empty($e['rules'])) $info_lines[] = "📜 قوانین: " . $e['rules'];
    if (!empty($e['capacity'])) $info_lines[] = "👥 شرکت‌کننده: {$count} / {$e['capacity']}";

    if (!empty($e['private_channel'])) {
            $privateChannels = json_decode($e['private_channel'], true);
        if (is_array($privateChannels) && !empty($privateChannels)) {
            $privateChannelLinks = [];
            foreach ($privateChannels as $channel) {
                $invite = $channel['invite'] ?? null;
                if ($invite) {
                    $privateChannelLinks[] = "🔗 " . ($channel['title'] ?? 'کانال خصوصی') . ': ' . $invite;
                }
            }
        }
     }

    if (!empty($info_lines)) {
        $txt .= "<blockquote>" . implode("\n", $info_lines) . "</blockquote>\n";
        if (!empty($privateChannelLinks)) {
            $txt .= "<blockquote>🔒 کانال خصوصی:\n" . implode("\n", $privateChannelLinks)."</blockquote>\n\n";
            }
        } elseif (is_string($e['private_channel']) && trim($e['private_channel']) !== '') {
            $txt .= "<blockquote>🔒 کانال خصوصی: " . trim($e['private_channel']) . "</blockquote>\n\n";
        }

    // گیم
    if (!empty($e['game'])) $txt .= "<b>🎮 گیم:</b> {$e['game']}\n";

    // تاریخ شروع جلالی
    if (!empty($e['date_str'])) {
        $ts_start = strtotime($e['date_str']);
        $jalali_start = $ts_start ? jdate("Y/m/d - H:i", $ts_start) : $e['date_str'];
        $txt .= "<b>📅 تاریخ شروع:</b> {$jalali_start}\n";
    }

    // مهلت ثبت‌نام جلالی
    if (!empty($e['deadline'])) {
        $ts_deadline = strtotime($e['deadline']);
        $jalali_deadline = $ts_deadline ? jdate("Y/m/d - H:i", $ts_deadline) : $e['deadline'];
        $txt .= "<b>⏰ مهلت ثبت‌نام:</b> {$jalali_deadline}\n";
    }

    // Entry Fee
    if (!empty($e['entry_fee'])) $txt .= "<b>💰 هزینه شرکت:</b> <code>{$e['entry_fee']}</code> تومان\n";

    // جوایز
    if (!empty($e['prize'])) {
        $prizes = json_decode($e['prize'], true);
        if (is_array($prizes) && count($prizes) > 0) {
            $txt .= "🎁 جوایز:\n";
            foreach ($prizes as $pos => $amount) {
                $txt .= "$pos: <code>$amount</code>\n";
            }
        }
    }

        // ظرفیت اسکواد
        if (!empty($e['limit'])) $txt .= "<b>🛡 ظرفیت اسکواد:</b> {$e['limit']}\n";

        // ID / Pass
        if (!empty($e['id_pass'])) {
            $id_pass = jdec($e['id_pass']);
            $id_text = $id_pass['id'] ?? '-';
            $pass_text = $id_pass['pass'] ?? '-';
            $txt .= "<blockquote><b>🔖 آیدی: </b> <code>{$id_text}</code> | ";
            $txt .= "<b> رمز: </b><code>{$pass_text}</code>\n</blockquote>";
        }



        // کیبورد
    $status = $e['status'] ?? '';

    if ($status === 'active') {
        $ik = [
            [
                ['text' => '✏️ ویرایش ایونت', 'callback_data' => 'admin_edit:' . $eid],
                ['text' => '👥 شرکت‌کنندگان', 'callback_data' => 'admin_players:' . $eid],
            ],
            [
                ['text' => '🎯 مدیریت مراحل', 'callback_data' => 'admin_stages:' . $eid],
                ['text' => '📨 ساخت دعوتنامه', 'callback_data' => 'admin_invites:' . $eid],
            ],
            [
                ['text' => '🏁 انتخاب برنده', 'callback_data' => 'admin_finish:' . $eid],
                ['text' => '📦 آرشیو ایونت', 'callback_data' => 'admin_archive:' . $eid],
            ],
            [
                ['text' => '🎫 ارسال رمز و آیدی', 'callback_data' => 'admin_send_credentials:' . $eid],
            ],
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'admin_events:active:0'],
            ],
        ];
    } else {
        $ik = [
            [
                ['text' => '♻️ بازگردانی ایونت', 'callback_data' => 'admin_restore:' . $eid],
                ['text' => '📤 خروجی CSV', 'callback_data' => 'admin_export:' . $eid],
            ],
            [
                ['text' => '👥 مشاهده شرکت‌کنندگان', 'callback_data' => 'admin_players:' . $eid],
            ],
            [
                ['text' => '🔙 بازگشت', 'callback_data' => 'admin_events:active:0'],
            ],
        ];
    }


        // ارسال پیام با کیبورد
        editMessageText($chat_id, $mid, $txt, ['inline_keyboard' => $ik]);
}

function renderAdminEventInvites(PDO $pdo, int $chat_id, int $mid, int $eid): void
{
    $st = $pdo->prepare("
        SELECT *
        FROM event_registration_invites
        WHERE event_id = ?
        ORDER BY id DESC
    ");
    $st->execute([$eid]);

    $invites = $st->fetchAll(PDO::FETCH_ASSOC);

    $txt = "📨 <b>دعوتنامه‌های ایونت #{$eid}</b>\n\n";

    if (!$invites) {
        $txt .= "هنوز دعوتنامه‌ای ساخته نشده است.";
    } else {
        foreach ($invites as $invite) {
            $options = [];

            if ((int)$invite['skip_force_join'] === 1) {
                $options[] = '🚫 عضویت اجباری';
            }

            if ((int)$invite['skip_referral'] === 1) {
                $options[] = '🚫 رفرال';
            }

            if (!$options) {
                $options[] = 'بدون عبور از مراحل';
            }

            $status = (int)$invite['is_active'] === 1 ? '🟢 فعال' : '🔴 غیرفعال';

            $txt .= "🎫 <b>{$invite['title']}</b>\n";
            $txt .= "وضعیت: {$status}\n";
            $txt .= "تنظیمات: " . implode(' + ', $options) . "\n";
            $txt .= "استفاده: {$invite['used_count']}\n";
            $txt .= "کد: <code>{$invite['token']}</code>\n\n";
        }
    }

    $ik = [
        [
            [
                'text' => '➕ ساخت دعوتنامه جدید',
                'callback_data' => "admin_invite_create:{$eid}"
            ]
        ],
        [
            [
                'text' => '🔙 بازگشت',
                'callback_data' => "admin_event:{$eid}"
            ]
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        ['inline_keyboard' => $ik]
    );
}

function renderInviteCreateMenu(
    PDO $pdo,
    int $chat_id,
    ?int $mid,
    int $eid
): void {

    // دریافت temp کاربر
    global $uid;

    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$uid]);

    $tempRaw = $st->fetchColumn();

    $temp = json_decode(
        $tempRaw ?: '{}',
        true
    );

    if (!is_array($temp)) {
        $temp = [];
    }

    // دریافت Draft دعوتنامه
    $draft = $temp['invite'] ?? null;

    if (
        !is_array($draft) ||
        (int)($draft['eid'] ?? 0) !== $eid
    ) {

        if ($mid) {
            editMessageText(
                $chat_id,
                $mid,
                '❌ اطلاعات ساخت دعوتنامه پیدا نشد.'
            );
        } else {
            sendMessage(
                $chat_id,
                '❌ اطلاعات ساخت دعوتنامه پیدا نشد.'
            );
        }

        return;
    }

    // =========================
    // مقادیر فعلی
    // =========================

    $skipJoin = !empty(
        $draft['skip_force_join']
    );

    $skipReferral = !empty(
        $draft['skip_referral']
    );

    $title = trim(
        (string)($draft['title'] ?? '')
    );

    $usageLimit = $draft['usage_limit'] ?? null;


    // =========================
    // متن دکمه‌ها
    // =========================

    $joinText = $skipJoin
        ? '🟢 عضویت اجباری: رد شود'
        : '🔴 عضویت اجباری: الزامی';

    $refText = $skipReferral
        ? '🟢 رفرال: رد شود'
        : '🔴 رفرال: الزامی';


    // =========================
    // نمایش وضعیت
    // =========================

    $titleDisplay = $title !== ''
        ? htmlspecialchars(
            $title,
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        : '❌ تعیین نشده';

    $limitDisplay = (
        $usageLimit === null ||
        $usageLimit === 0 ||
        $usageLimit === '0'
    )
        ? '♾ نامحدود'
        : number_format(
            (int)$usageLimit
        );


    // =========================
    // متن منو
    // =========================

    $txt = "📨 <b>ساخت دعوتنامه جدید</b>\n\n";

    $txt .= "🎯 ایونت: <code>#{$eid}</code>\n\n";

    $txt .= "🏷 <b>نام دعوتنامه:</b> "
        . $titleDisplay
        . "\n";

    $txt .= "🔢 <b>محدودیت استفاده:</b> "
        . $limitDisplay
        . "\n\n";

    $txt .= "⚙️ <b>شرایط ثبت‌نام</b>\n";

    $txt .= $skipJoin
        ? "🔐 عضویت اجباری: ❌ رد می‌شود\n"
        : "🔐 عضویت اجباری: ✅ الزامی است\n";

    $txt .= $skipReferral
        ? "👥 رفرال: ❌ رد می‌شود\n"
        : "👥 رفرال: ✅ الزامی است\n\n";

    $txt .= "تنظیمات دعوتنامه را انتخاب کنید.";


    // =========================
    // کیبورد
    // =========================

    $ik = [
        [
            [
                'text' => $joinText,
                'callback_data' =>
                    "admin_invite_toggle_join:{$eid}"
            ]
        ],
        [
            [
                'text' => $refText,
                'callback_data' =>
                    "admin_invite_toggle_referral:{$eid}"
            ]
        ],
        [
            [
                'text' => '📝 تعیین نام دعوتنامه',
                'callback_data' =>
                    "admin_invite_name:{$eid}"
            ]
        ],
        [
            [
                'text' => '🔢 تعیین محدودیت استفاده',
                'callback_data' =>
                    "admin_invite_limit:{$eid}"
            ]
        ],
        [
            [
                'text' => '✅ ساخت دعوتنامه',
                'callback_data' =>
                    "admin_invite_save:{$eid}"
            ]
        ],
        [
            [
                'text' => '❌ لغو',
                'callback_data' =>
                    "admin_invites:{$eid}"
            ]
        ],
    ];


    // =========================
    // نمایش منو
    // =========================

    if (!$mid) {

        sendMessage(
            $chat_id,
            $txt,
            [
                'inline_keyboard' => $ik
            ]
        );

    } else {

        editMessageText(
            $chat_id,
            $mid,
            $txt,
            [
                'inline_keyboard' => $ik
            ]
        );
    }
}

function generateInviteToken(): string
{
    return bin2hex(random_bytes(8));
}

function renderAdminStages(PDO $pdo, int $chat_id, int $mid, int $eid): void
{
    $st = $pdo->prepare("
        SELECT
            id,
            name,
            type,
            stage_order,
            status,
            created_at
        FROM tournament_stages
        WHERE ev_id = ?
        ORDER BY stage_order ASC, id ASC
    ");

    $st->execute([$eid]);

    $stages = $st->fetchAll(PDO::FETCH_ASSOC);

    // اطلاعات ایونت
    $eventSt = $pdo->prepare("
        SELECT name
        FROM events
        WHERE id = ?
        LIMIT 1
    ");

    $eventSt->execute([$eid]);

    $event = $eventSt->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ رویداد پیدا نشد.'
        );
        return;
    }

    $txt = "🎯 <b>مدیریت مراحل</b>\n\n";

    $txt .= "🏆 <b>{$event['name']}</b> | <code>#{$eid}</code>\n\n";

    if (!$stages) {

        $txt .= "<blockquote>";
        $txt .= "📭 هنوز هیچ مرحله‌ای برای این ایونت ایجاد نشده.";
        $txt .= "</blockquote>\n\n";

    } else {

        foreach ($stages as $stage) {

            $typeMap = [
                'qualification' => '🎯 کوالیفای',
                'group'         => '👥 گروهی',
                'playoff'       => '🏆 حذفی',
            ];

            $statusMap = [
                'pending'   => '⏳ در انتظار',
                'active'    => '🟢 فعال',
                'completed' => '✅ تکمیل شده',
                'cancelled' => '❌ لغو شده',
            ];

            $type =
                $typeMap[$stage['type']]
                ?? $stage['type'];

            $status =
                $statusMap[$stage['status']]
                ?? $stage['status'];

            $txt .= "<blockquote>";
            $txt .= "<b>{$stage['stage_order']}. {$stage['name']}</b>\n";
            $txt .= "🆔 <code>#{$stage['id']}</code>\n";
            $txt .= "📌 نوع: {$type}\n";
            $txt .= "📊 وضعیت: {$status}";
            $txt .= "</blockquote>\n";
        }
    }

    $ik = [
        [
            [
                'text' => '➕ ایجاد مرحله',
                'callback_data' => 'admin_stage_create:' . $eid
            ],
        ],
    ];

    if ($stages) {
        foreach ($stages as $stage) {

            $ik[] = [
                [
                    'text' =>
                        '⚙️ ' .
                        $stage['stage_order'] .
                        '. ' .
                        $stage['name'],

                    'callback_data' =>
                        'admin_stage:' .
                        $stage['id']
                ],
            ];
        }
    }

    $ik[] = [
        [
            'text' => '🔙 بازگشت',
            'callback_data' => 'admin_event:' . $eid
        ],
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}

function renderAdminStageInfo(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $stageId
): void {
    $st = $pdo->prepare("
        SELECT
            ts.*,
            e.name AS event_name
        FROM tournament_stages ts
        INNER JOIN events e
            ON e.id = ts.ev_id
        WHERE ts.id = ?
        LIMIT 1
    ");

    $st->execute([$stageId]);

    $stage = $st->fetch(PDO::FETCH_ASSOC);

    if (!$stage) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ مرحله پیدا نشد.'
        );
        return;
    }

    $typeMap = [
        'qualification' => '🎯 Qualification',
        'group'         => '👥 Group',
        'playoff'       => '🏆 Playoff',
    ];

    $formatMap = [
        'elimination'  => '⚔️ Elimination',
        'battle_royale' => '🔥 Battle Royale',
    ];

    $statusMap = [
        'pending'   => '⏳ در انتظار',
        'active'    => '🟢 فعال',
        'completed' => '✅ تکمیل شده',
        'cancelled' => '❌ لغو شده',
    ];

    $type =
        $typeMap[$stage['type']]
        ?? $stage['type'];

    $format =
        $formatMap[$stage['format'] ?? 'elimination']
        ?? ($stage['format'] ?? 'elimination');

    $status =
        $statusMap[$stage['status']]
        ?? $stage['status'];

    $isBattleRoyale =
        ($stage['format'] ?? '') === 'battle_royale';

    /*
     * تعداد شرکت‌کنندگان
     */
    $stCount = $pdo->prepare("
        SELECT COUNT(*)
        FROM tournament_stage_participants tsp
        INNER JOIN tournament_participants tp
            ON tp.id = tsp.tournament_participant_id
        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id
        WHERE tsp.stage_id = ?
        AND tsp.status = 'active'
    ");

    $stCount->execute([
        $stageId
    ]);

    $participantCount =
        (int) $stCount->fetchColumn();

    /*
     * Bracket count
     */
    $bracketCount = 0;

    if (!$isBattleRoyale) {

        $stBracket = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_brackets
            WHERE stage_id = ?
        ");

        $stBracket->execute([
            $stageId
        ]);

        $bracketCount =
            (int) $stBracket->fetchColumn();
    }

    /*
     * Battle Royale statistics
     */
    $brRoomCount = 0;
    $brCompletedRooms = 0;
    $brActiveRooms = 0;

    if ($isBattleRoyale) {

        $stRooms = $pdo->prepare("
            SELECT
                COUNT(*) AS total_rooms,
                COALESCE(
                    SUM(
                        CASE
                            WHEN status = 'completed'
                            THEN 1
                            ELSE 0
                        END
                    ),
                    0
                ) AS completed_rooms,
                COALESCE(
                    SUM(
                        CASE
                            WHEN status = 'active'
                            THEN 1
                            ELSE 0
                        END
                    ),
                    0
                ) AS active_rooms
            FROM tournament_br_rooms
            WHERE stage_id = ?
        ");

        $stRooms->execute([
            $stageId
        ]);

        $roomStats =
            $stRooms->fetch(PDO::FETCH_ASSOC);

        if ($roomStats) {
            $brRoomCount =
                (int) $roomStats['total_rooms'];

            $brCompletedRooms =
                (int) $roomStats['completed_rooms'];

            $brActiveRooms =
                (int) $roomStats['active_rooms'];
        }
    }

    /*
     * متن اصلی
     */
    $txt = '';

    $txt .= "<blockquote>";
    $txt .= "🎯 <b>{$stage['name']}</b> | ";
    $txt .= "<code>#{$stage['id']}</code>\n";
    $txt .= "🏆 ایونت: <b>{$stage['event_name']}</b> | ";
    $txt .= "<code>#{$stage['ev_id']}</code>";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "📌 نوع: {$type}\n";
    $txt .= "🎮 فرمت: {$format}\n";
    $txt .= "📊 وضعیت: {$status}\n";
    $txt .= "🔢 ترتیب: <code>{$stage['stage_order']}</code>\n";
    $txt .= "👥 شرکت‌کنندگان: <code>{$participantCount}</code>\n";

    if ($isBattleRoyale) {

        $roomSize =
            (int) ($stage['match_size'] ?? 0);

        $matchesPerPlayer =
            (int) ($stage['matches_per_player'] ?? 0);

        $advancementType =
            (string) ($stage['advancement_type'] ?? '');

        $advancementCount =
            $stage['advancement_count'] ?? null;

        $scoringStrategy =
            (string) ($stage['scoring_strategy'] ?? '');

        $txt .=
            "🏠 Roomها: <code>{$brRoomCount}</code>\n";

        $txt .=
            "👤 ظرفیت هر Room: <code>{$roomSize}</code>\n";

        $txt .=
            "🎮 بازی هر بازیکن: <code>{$matchesPerPlayer}</code>\n";

        if ($advancementType !== '') {

            $advancementLabel = match (
                $advancementType
            ) {
                'top_n' =>
                    'Top ' .
                    (int) $advancementCount,

                'percentage' =>
                    ((float) $advancementCount) .
                    '%',

                'points' =>
                    'حداقل ' .
                    ((float) $advancementCount) .
                    ' امتیاز',

                default =>
                    $advancementType,
            };

            $txt .=
                "📈 صعود: <code>{$advancementLabel}</code>\n";
        }

        if ($scoringStrategy !== '') {

            $scoringLabel = match (
                $scoringStrategy
            ) {
                'placement_kills' =>
                    'Placement + Kills',

                'default' =>
                    'Score مستقیم',

                default =>
                    $scoringStrategy,
            };

            $txt .=
                "🧮 امتیازدهی: <code>{$scoringLabel}</code>\n";
        }

        if ($brRoomCount > 0) {
            $txt .=
                "🏁 Roomهای تکمیل‌شده: "
                . "<code>{$brCompletedRooms}/{$brRoomCount}</code>\n";
        }

    } else {

        $txt .=
            "🏟 Bracketها: <code>{$bracketCount}</code>\n";
    }

    $txt .= "</blockquote>";

    /*
     * Keyboard
     */
    $ik = [];

    /*
     * ============================
     * PENDING
     * ============================
     */
    if ($stage['status'] === 'pending') {

        if ($isBattleRoyale) {

            /*
             * هنوز Room ساخته نشده
             */
            if ($brRoomCount === 0) {

                $ik[] = [
                    [
                        'text' =>
                            '🔥 تولید Roomهای Battle Royale',
                        'callback_data' =>
                            'admin_br_generate:' .
                            $stageId
                    ]
                ];

            } else {

                /*
                 * Roomها قبلاً ساخته شده‌اند.
                 */
                $ik[] = [
                    [
                        'text' =>
                            '🏠 مدیریت Roomها',
                        'callback_data' =>
                            'admin_br_rooms:' .
                            $stageId
                    ]
                ];
            }

        } else {

            /*
             * Elimination
             */
            $ik[] = [
                [
                    'text' => '🏟 مدیریت Bracket',
                    'callback_data' =>
                        'admin_stage_brackets:' .
                        $stageId
                ]
            ];
        }

        $ik[] = [
            [
                'text' =>
                    '▶️ فعال‌سازی Stage',
                'callback_data' =>
                    'admin_stage_activate:' .
                    $stageId
            ]
        ];
    }

    /*
     * ============================
     * ACTIVE
     * ============================
     */
    elseif ($stage['status'] === 'active') {

        if ($isBattleRoyale) {

            $ik[] = [
                [
                    'text' =>
                        '🏠 مدیریت Roomها',
                    'callback_data' =>
                        'admin_br_rooms:' .
                        $stageId
                ]
            ];

        } else {

            $ik[] = [
                [
                    'text' =>
                        '🏟 مدیریت Bracket',
                    'callback_data' =>
                        'admin_stage_brackets:' .
                        $stageId
                ]
            ];
        }

        $ik[] = [
            [
                'text' =>
                    '⏹ پایان Stage',
                'callback_data' =>
                    'admin_stage_complete:' .
                    $stageId
            ]
        ];
    }

    /*
     * ============================
     * COMPLETED
     * ============================
     */
    elseif ($stage['status'] === 'completed') {

        if ($isBattleRoyale) {

            $ik[] = [
                [
                    'text' =>
                        '🏆 مشاهده Leaderboard',
                    'callback_data' =>
                        'admin_br_leaderboard:' .
                        $stageId
                ]
            ];

        } else {

            $ik[] = [
                [
                    'text' =>
                        '🏟 مشاهده Bracket',
                    'callback_data' =>
                        'admin_stage_brackets:' .
                        $stageId
                ]
            ];
        }
    }

    /*
     * بازگشت
     */
    $ik[] = [
        [
            'text' =>
                '🔙 بازگشت به مراحل',
            'callback_data' =>
                'admin_stages:' .
                $stage['ev_id']
        ],
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}

function renderAdminStageBrackets(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $stageId
): void {
    $st = $pdo->prepare("
        SELECT
            ts.id,
            ts.ev_id,
            ts.name,
            ts.type,
            ts.stage_order,
            ts.status,
            e.name AS event_name
        FROM tournament_stages ts
        INNER JOIN events e
            ON e.id = ts.ev_id
        WHERE ts.id = ?
        LIMIT 1
    ");

    $st->execute([$stageId]);

    $stage = $st->fetch(PDO::FETCH_ASSOC);

    if (!$stage) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Stage پیدا نشد.'
        );
        return;
    }

    $st = $pdo->prepare("
        SELECT
            id,
            name,
            type,
            status,
            participant_count,
            created_at,
            updated_at
        FROM tournament_brackets
        WHERE stage_id = ?
        ORDER BY id ASC
    ");

    $st->execute([$stageId]);

    $brackets = $st->fetchAll(PDO::FETCH_ASSOC);

    $txt = '';

    $txt .= "<blockquote>";
    $txt .= "🏟 <b>مدیریت Bracket</b>\n";
    $txt .= "🎯 Stage: <b>{$stage['name']}</b>\n";
    $txt .= "🏆 Event: <b>{$stage['event_name']}</b>";
    $txt .= "</blockquote>\n";

    if (!$brackets) {

        $txt .= "<blockquote>";
        $txt .= "📭 هنوز هیچ Bracketی برای این Stage ساخته نشده.";
        $txt .= "</blockquote>\n";

    } else {

        $txt .= "<blockquote>";

        foreach ($brackets as $index => $bracket) {

            $number = $index + 1;

            $statusMap = [
                'pending'   => '⏳',
                'active'    => '🟢',
                'completed' => '✅',
                'cancelled' => '❌',
            ];

            $statusIcon =
                $statusMap[$bracket['status']]
                ?? '❔';

            $txt .=
                "{$number}. 🏟 <b>{$bracket['name']}</b>\n";

            $txt .=
                "   {$statusIcon} {$bracket['status']}";

            if (
                isset($bracket['participant_count'])
            ) {
                $txt .=
                    " | 👥 {$bracket['participant_count']}";
            }

            $txt .=
                " | <code>#{$bracket['id']}</code>\n\n";
        }

        $txt .= "</blockquote>";
    }

    $ik = [];

    /*
     * ساخت Bracket فقط وقتی Stage
     * قابل مدیریت است.
     */
    if (
        in_array(
            $stage['status'],
            ['pending', 'active'],
            true
        )
    ) {
        $ik[] = [
            [
                'text' => '➕ ساخت Bracket',
                'callback_data' =>
                    'admin_bracket_create:' . $stageId
            ]
        ];
    }

    /*
     * اگر Bracket وجود داشته باشد،
     * دکمه ورود به هرکدام
     */
    foreach ($brackets as $bracket) {

        $ik[] = [
            [
                'text' =>
                    '🏟 ' .
                    $bracket['name'] .
                    ' #' .
                    $bracket['id'],

                'callback_data' =>
                    'admin_bracket:' .
                    $bracket['id']
            ]
        ];
    }

    $ik[] = [
        [
            'text' => '🔙 بازگشت',
            'callback_data' =>
                'admin_stage:' . $stageId
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}


function renderAdminBracketMatches(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $bracketId
): void {
    /*
     * Bracket
     */
    $st = $pdo->prepare("
        SELECT
            tb.id,
            tb.stage_id,
            tb.name,
            tb.type,
            tb.status,
            tb.participant_count,
            ts.name AS stage_name,
            e.name AS event_name
        FROM tournament_brackets tb
        INNER JOIN tournament_stages ts
            ON ts.id = tb.stage_id
        INNER JOIN events e
            ON e.id = ts.ev_id
        WHERE tb.id = ?
        LIMIT 1
    ");

    $st->execute([
        $bracketId
    ]);

    $bracket =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$bracket) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Bracket پیدا نشد.'
        );

        return;
    }

    /*
     * فقط Bracket فعال قابل مدیریت Match است.
     */
    if ($bracket['status'] !== 'active') {
        editMessageText(
            $chat_id,
            $mid,
            "❌ این Bracket در وضعیت <b>{$bracket['status']}</b> است "
            . "و هنوز قابل مدیریت Matchها نیست.",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 مدیریت Bracket',
                            'callback_data' =>
                                'admin_bracket:' . $bracketId
                        ]
                    ]
                ]
            ]
        );

        return;
    }

    /*
     * Matchها
     */
    $st = $pdo->prepare("
        SELECT
            id,
            round_number,
            match_number,
            status,
            is_bye,
            winner_participant_id
        FROM tournament_matches
        WHERE bracket_id = ?
        ORDER BY
            round_number ASC,
            match_number ASC
    ");

    $st->execute([
        $bracketId
    ]);

    $matches =
        $st->fetchAll(PDO::FETCH_ASSOC);

    $txt = '';

    $txt .= "<blockquote>";
    $txt .= "🎮 <b>مدیریت Matchها</b>\n";
    $txt .= "🏟 <b>{$bracket['name']}</b>\n";
    $txt .= "🎯 Stage: <b>{$bracket['stage_name']}</b>\n";
    $txt .= "🏆 Event: <b>{$bracket['event_name']}</b>";
    $txt .= "</blockquote>\n";

    if (!$matches) {
        $txt .= "<blockquote>";
        $txt .= "📭 هنوز هیچ Matchی برای این Bracket ساخته نشده.";
        $txt .= "</blockquote>";

        $ik = [
            [
                [
                    'text' => '🔙 مدیریت Bracket',
                    'callback_data' =>
                        'admin_bracket:' . $bracketId
                ]
            ]
        ];

        editMessageText(
            $chat_id,
            $mid,
            $txt,
            [
                'inline_keyboard' => $ik
            ]
        );

        return;
    }

    /*
     * گروه‌بندی بر اساس Round
     */
    $rounds = [];

    foreach ($matches as $match) {
        $round =
            (int) $match['round_number'];

        $rounds[$round][] =
            $match;
    }

    $statusMap = [
        'pending'   => '⏳',
        'ready'     => '🟡',
        'active'    => '🟢',
        'finished'  => '✅',
        'completed' => '✅',
        'cancelled' => '❌',
    ];

    foreach ($rounds as $roundNumber => $roundMatches) {

        $roundName = match ($roundNumber) {
            1 => '🥊 Round 1',
            2 => '⚔️ Round 2',
            default =>
                '🏆 Round ' . $roundNumber,
        };

        /*
         * اگر آخرین Round باشد،
         * Final نمایش داده شود.
         */
        $maxRound =
            max(
                array_keys($rounds)
            );

        if ($roundNumber === $maxRound) {
            $roundName = '🏆 Final';
        } elseif (
            $roundNumber === ($maxRound - 1)
        ) {
            $roundName = '🔥 Semi Final';
        }

        $txt .= "\n<b>{$roundName}</b>\n";

        foreach ($roundMatches as $match) {

            $statusIcon =
                $statusMap[$match['status']]
                ?? '❔';

            $byeText =
                ((int) $match['is_bye'] === 1)
                    ? ' | 🆓 BYE'
                    : '';

            $txt .=
                "<blockquote>"
                . "🎮 Match #{$match['match_number']}\n"
                . "{$statusIcon} {$match['status']}{$byeText}\n"
                . "🆔 <code>#{$match['id']}</code>"
                . "</blockquote>\n";
        }
    }

    /*
     * Keyboard
     */
    $ik = [];

    foreach ($matches as $match) {

        $statusIcon =
            $statusMap[$match['status']]
            ?? '❔';

        $text =
            $statusIcon
            . ' Match #'
            . $match['match_number'];

        if ((int) $match['is_bye'] === 1) {
            $text .= ' 🆓';
        }

        $ik[] = [
            [
                'text' => $text,
                'callback_data' =>
                    'admin_match:' .
                    $match['id']
            ]
        ];
    }

    $ik[] = [
        [
            'text' => '🔄 بروزرسانی',
            'callback_data' =>
                'admin_bracket_matches:' .
                $bracketId
        ]
    ];

    $ik[] = [
        [
            'text' => '🔙 مدیریت Bracket',
            'callback_data' =>
                'admin_bracket:' .
                $bracketId
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}


function renderAdminBracketInfo(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $bracketId
): void {
    $st = $pdo->prepare("
        SELECT
            tb.*,
            ts.name AS stage_name,
            ts.ev_id,
            e.name AS event_name
        FROM tournament_brackets tb
        INNER JOIN tournament_stages ts
            ON ts.id = tb.stage_id
        INNER JOIN events e
            ON e.id = ts.ev_id
        WHERE tb.id = ?
        LIMIT 1
    ");

    $st->execute([$bracketId]);

    $bracket = $st->fetch(PDO::FETCH_ASSOC);

    if (!$bracket) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Bracket پیدا نشد.'
        );

        return;
    }

    $participantCount =
        (int) ($bracket['participant_count'] ?? 0);

    /*
     * اندازه واقعی Bracket
     */
    $bracketSize = 1;

    while ($bracketSize < max(2, $participantCount)) {
        $bracketSize *= 2;
    }

    /*
     * تعداد Roundها
     */
    $rounds =
        (int) log($bracketSize, 2);

    /*
     * تعداد Matchها
     */
    $totalMatches =
        max(0, $bracketSize - 1);

    /*
     * اطلاعات Matchهای ساخته‌شده
     */
    $actualMatches = 0;
    $byeMatches = 0;

    $st = $pdo->prepare("
        SELECT
            COUNT(*) AS total_matches,
            COALESCE(
                SUM(
                    CASE
                        WHEN is_bye = 1 THEN 1
                        ELSE 0
                    END
                ),
                0
            ) AS bye_matches
        FROM tournament_matches
        WHERE bracket_id = ?
    ");

    $st->execute([$bracketId]);

    $matchStats =
        $st->fetch(PDO::FETCH_ASSOC);

    if ($matchStats) {
        $actualMatches =
            (int) $matchStats['total_matches'];

        $byeMatches =
            (int) $matchStats['bye_matches'];
    }

    /*
     * آیکون وضعیت
     */
    $statusIcons = [
        'pending'   => '⏳',
        'active'    => '🟢',
        'completed' => '✅',
        'cancelled' => '❌',
    ];

    $statusIcon =
        $statusIcons[$bracket['status']]
        ?? '❔';

    /*
     * متن
     */
    $txt = '';

    $txt .= "<blockquote>";
    $txt .= "🏟 <b>{$bracket['name']}</b>\n";
    $txt .= "🆔 Bracket: <code>#{$bracket['id']}</code>\n";
    $txt .= "🏆 Event: <b>{$bracket['event_name']}</b>\n";
    $txt .= "🎯 Stage: <b>{$bracket['stage_name']}</b>";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "📌 وضعیت: {$statusIcon} <b>{$bracket['status']}</b>\n";
    $txt .= "🏷 نوع: <code>{$bracket['type']}</code>\n";
    $txt .= "👥 شرکت‌کنندگان: <code>{$participantCount}</code>\n";
    $txt .= "📐 اندازه Bracket: <code>{$bracketSize}</code>\n";
    $txt .= "🔄 تعداد Round: <code>{$rounds}</code>\n";
    $txt .= "🎮 Match موردنیاز: <code>{$totalMatches}</code>\n";
    $txt .= "📦 Match ساخته‌شده: <code>{$actualMatches}</code>\n";
    $txt .= "🆓 BYE: <code>{$byeMatches}</code>";
    $txt .= "</blockquote>";

    /*
     * Keyboard
     */
    $ik = [];

    /*
     * فقط Bracket pending قابلیت Generate دارد.
     */
    if (
        $bracket['status'] === 'pending'
    ) {
        $ik[] = [
            [
                'text' => '⚙️ تولید Bracket',
                'callback_data' =>
                    'admin_bracket_generate:' .
                    $bracketId
            ]
        ];
    }

    /*
     * اگر فعال شده باشد،
     * مدیریت Matchها
     */
    if (
        $bracket['status'] === 'active'
    ) {
        $ik[] = [
            [
                'text' => '🎮 مدیریت Matchها',
                'callback_data' =>
                    'admin_bracket_matches:' .
                    $bracketId
            ]
        ];
    }

    /*
     * Bracket کامل شده
     */
    if (
        $bracket['status'] === 'completed'
    ) {
        $ik[] = [
            [
                'text' => '🏆 مشاهده نتیجه نهایی',
                'callback_data' =>
                    'admin_bracket_result:' .
                    $bracketId
            ]
        ];
    }

    $ik[] = [
        [
            'text' => '🔙 Bracketهای Stage',
            'callback_data' =>
                'admin_stage_brackets:' .
                $bracket['stage_id']
        ]
    ];

    $ik[] = [
        [
            'text' => '🔙 مدیریت Stage',
            'callback_data' =>
                'admin_stage:' .
                $bracket['stage_id']
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}

function renderAdminMatchInfo(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $matchId
): void {
    /*
     * Match + Bracket + Stage
     */
    $st = $pdo->prepare("
        SELECT
            tm.id,
            tm.bracket_id,
            tm.stage_id,
            tm.round_number,
            tm.match_number,
            tm.status,
            tm.is_bye,
            tm.winner_participant_id,
            tm.winner_next_match_id,
            tm.winner_next_slot,
            tb.name AS bracket_name,
            ts.name AS stage_name
        FROM tournament_matches tm
        INNER JOIN tournament_brackets tb
            ON tb.id = tm.bracket_id
        INNER JOIN tournament_stages ts
            ON ts.id = tm.stage_id
        WHERE tm.id = ?
        LIMIT 1
    ");

    $st->execute([
        $matchId
    ]);

    $match =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$match) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Match پیدا نشد.'
        );

        return;
    }

    /*
     * Participants
     */
    $st = $pdo->prepare("
        SELECT
            tmp.id,
            tmp.tournament_participant_id,
            tmp.slot,
            tmp.status,
            tp.event_player_id,
            ep.user_id,
            ep.ign
        FROM tournament_match_participants tmp
        INNER JOIN tournament_participants tp
            ON tp.id = tmp.tournament_participant_id
        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id
        WHERE tmp.match_id = ?
        ORDER BY tmp.slot ASC
    ");

    $st->execute([
        $matchId
    ]);

    $participants =
        $st->fetchAll(PDO::FETCH_ASSOC);

    $slotA = null;
    $slotB = null;

    foreach ($participants as $participant) {

        if ($participant['slot'] === 'a' || (int) $participant['slot'] === 1) {
            $slotA = $participant;
        }

        if ($participant['slot'] === 'b' || (int) $participant['slot'] === 2) {
            $slotB = $participant;
        }
    }

    /*
     * Status
     */
    $statusMap = [
        'pending'   => '⏳ در انتظار',
        'ready'     => '🟡 آماده',
        'active'    => '🟢 فعال',
        'finished'  => '✅ تمام شده',
        'completed' => '✅ تکمیل شده',
        'cancelled' => '❌ لغو شده',
    ];

    $status =
        $statusMap[$match['status']]
        ?? $match['status'];

    /*
     * Match type
     */
    $matchType =
        ((int) $match['is_bye'] === 1)
            ? '🆓 BYE'
            : '⚔️ Match معمولی';

    /*
     * Slot formatter
     */
    $formatParticipant =
        static function (?array $participant): string {

            if ($participant === null) {
                return '❓ TBD';
            }

            $ign =
                trim((string) ($participant['ign'] ?? ''));

            $eventPlayerId =
                (int) $participant['event_player_id'];

            if ($ign === '') {
                $ign = 'Player #' . $eventPlayerId;
            }

            return
                "<b>"
                . htmlspecialchars(
                    $ign,
                    ENT_QUOTES,
                    'UTF-8'
                )
                . "</b> "
                . "<code>#{$eventPlayerId}</code>";
        };

    /*
     * متن
     */
    $txt = '';

    $txt .= "<blockquote>";
    $txt .= "🎮 <b>Match #{$match['match_number']}</b>\n";
    $txt .= "🆔 Match ID: <code>#{$match['id']}</code>\n";
    $txt .= "🏟 Bracket: <b>{$match['bracket_name']}</b>\n";
    $txt .= "🎯 Stage: <b>{$match['stage_name']}</b>\n";
    $txt .= "🔄 Round: <code>{$match['round_number']}</code>";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "📌 وضعیت: {$status}\n";
    $txt .= "🎲 نوع: {$matchType}";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "🅰️ Slot A\n";
    $txt .= $formatParticipant($slotA);
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "🅱️ Slot B\n";
    $txt .= $formatParticipant($slotB);
    $txt .= "</blockquote>\n";

    if (!empty($match['winner_participant_id'])) {
        $txt .= "<blockquote>";
        $txt .= "🏆 Winner: <code>"
            . (int) $match['winner_participant_id']
            . "</code>";
        $txt .= "</blockquote>\n";
    }

    if (!empty($match['winner_next_match_id'])) {
        $txt .= "<blockquote>";
        $txt .= "➡️ Match بعدی: <code>#"
            . (int) $match['winner_next_match_id']
            . "</code>";

        if (!empty($match['winner_next_slot'])) {
            $txt .=
                " | Slot "
                . strtoupper(
                    (string) $match['winner_next_slot']
                );
        }

        $txt .= "</blockquote>\n";
    }

    /*
     * Keyboard
     */
    $ik = [];

    /*
     * Match pending/ready و هر دو بازیکن موجود باشند:
     * آماده ثبت نتیجه است.
     */
    if (
        in_array(
            $match['status'],
            ['pending', 'ready', 'active'],
            true
        )
        && $slotA !== null
        && $slotB !== null
        && (int) $match['is_bye'] === 0
    ) {
        $ik[] = [
            [
                'text' => '📝 ثبت نتیجه',
                'callback_data' =>
                    'admin_match_result:' .
                    $matchId
            ]
        ];
    }

    /*
     * BYE
     */
    $isByeReady =
        (int) $match['is_bye'] === 1
        && $match['status'] === 'ready'
        && (($slotA !== null) xor ($slotB !== null));

    if ($isByeReady) {
        $ik[] = [
            [
                'text' => '⚡ پردازش BYE',
                'callback_data' =>
                    'admin_match_bye:' . $matchId
            ]
        ];
    }

    $ik[] = [
        [
            'text' => '🔄 بروزرسانی',
            'callback_data' =>
                'admin_match:' .
                $matchId
        ]
    ];

    $ik[] = [
        [
            'text' => '🔙 مدیریت Matchها',
            'callback_data' =>
                'admin_bracket_matches:' .
                $match['bracket_id']
        ]
    ];

    $ik[] = [
        [
            'text' => '🏟 مدیریت Bracket',
            'callback_data' =>
                'admin_bracket:' .
                $match['bracket_id']
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}

function renderAdminMatchResult(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $matchId
): void {
    $st = $pdo->prepare("
        SELECT
            tm.id,
            tm.bracket_id,
            tm.round_number,
            tm.match_number,
            tm.status,
            tm.is_bye,
            tb.name AS bracket_name,
            ts.name AS stage_name
        FROM tournament_matches tm
        INNER JOIN tournament_brackets tb
            ON tb.id = tm.bracket_id
        INNER JOIN tournament_stages ts
            ON ts.id = tm.stage_id
        WHERE tm.id = ?
        LIMIT 1
    ");

    $st->execute([$matchId]);

    $match = $st->fetch(PDO::FETCH_ASSOC);

    if (!$match) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Match پیدا نشد.'
        );
        return;
    }

    if ((int) $match['is_bye'] === 1) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ برای BYE نیازی به ثبت نتیجه دستی نیست.',
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 بازگشت',
                            'callback_data' =>
                                'admin_match:' . $matchId
                        ]
                    ]
                ]
            ]
        );
        return;
    }

    if (!in_array(
        $match['status'],
        ['pending', 'ready', 'active'],
        true
    )) {
        editMessageText(
            $chat_id,
            $mid,
            "❌ این Match در وضعیت <b>{$match['status']}</b> "
            . "قابل ثبت نتیجه نیست.",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 بازگشت',
                            'callback_data' =>
                                'admin_match:' . $matchId
                        ]
                    ]
                ]
            ]
        );
        return;
    }

    $st = $pdo->prepare("
        SELECT
            tmp.tournament_participant_id,
            tmp.slot,
            ep.id AS event_player_id,
            ep.ign,
            ep.user_id
        FROM tournament_match_participants tmp
        INNER JOIN tournament_participants tp
            ON tp.id = tmp.tournament_participant_id
        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id
        WHERE tmp.match_id = ?
        ORDER BY tmp.slot ASC
    ");

    $st->execute([$matchId]);

    $participants =
        $st->fetchAll(PDO::FETCH_ASSOC);

    $slotA = null;
    $slotB = null;

    foreach ($participants as $participant) {
        if (
            $participant['slot'] === 'a'
            || (string) $participant['slot'] === '1'
        ) {
            $slotA = $participant;
        }

        if (
            $participant['slot'] === 'b'
            || (string) $participant['slot'] === '2'
        ) {
            $slotB = $participant;
        }
    }

    if ($slotA === null || $slotB === null) {
        editMessageText(
            $chat_id,
            $mid,
            "❌ هر دو بازیکن Match هنوز مشخص نشده‌اند.",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 بازگشت',
                            'callback_data' =>
                                'admin_match:' . $matchId
                        ]
                    ]
                ]
            ]
        );
        return;
    }

    $nameA = trim(
        (string) ($slotA['ign'] ?? '')
    );

    $nameB = trim(
        (string) ($slotB['ign'] ?? '')
    );

    if ($nameA === '') {
        $nameA =
            'Player #' .
            (int) $slotA['event_player_id'];
    }

    if ($nameB === '') {
        $nameB =
            'Player #' .
            (int) $slotB['event_player_id'];
    }

    $txt =
        "📝 <b>ثبت نتیجه Match #{$match['match_number']}</b>\n\n"
        . "🏟 <b>{$match['bracket_name']}</b>\n"
        . "🎯 {$match['stage_name']}\n"
        . "🔄 Round: <code>{$match['round_number']}</code>\n\n"
        . "🅰️ <b>"
        . htmlspecialchars(
            $nameA,
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n"
        . "🅱️ <b>"
        . htmlspecialchars(
            $nameB,
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n\n"
        . "🏆 برنده را انتخاب کنید:";

    $ik = [
        [
            [
                'text' =>
                    '🏆 ' .
                    $nameA,
                'callback_data' =>
                    'admin_match_winner:' .
                    $matchId .
                    ':a'
            ]
        ],
        [
            [
                'text' =>
                    '🏆 ' .
                    $nameB,
                'callback_data' =>
                    'admin_match_winner:' .
                    $matchId .
                    ':b'
            ]
        ],
        [
            [
                'text' => '🔙 بازگشت',
                'callback_data' =>
                    'admin_match:' .
                    $matchId
            ]
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}

function renderAdminBracketResult(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $bracketId
): void {
    /*
     * Bracket
     */
    $st = $pdo->prepare("
        SELECT
            tb.id,
            tb.name,
            tb.status,
            tb.participant_count,
            tb.stage_id,
            ts.name AS stage_name,
            ts.ev_id,
            e.name AS event_name
        FROM tournament_brackets tb
        INNER JOIN tournament_stages ts
            ON ts.id = tb.stage_id
        INNER JOIN events e
            ON e.id = ts.ev_id
        WHERE tb.id = ?
        LIMIT 1
    ");

    $st->execute([
        $bracketId
    ]);

    $bracket =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$bracket) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Bracket پیدا نشد.'
        );
        return;
    }

    /*
     * آخرین Match = Final
     */
    $st = $pdo->prepare("
        SELECT
            tm.id,
            tm.match_number,
            tm.status,
            tm.winner_participant_id
        FROM tournament_matches tm
        WHERE tm.bracket_id = ?
        ORDER BY
            tm.round_number DESC,
            tm.match_number DESC
        LIMIT 1
    ");

    $st->execute([
        $bracketId
    ]);

    $final =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$final) {
        editMessageText(
            $chat_id,
            $mid,
            "❌ هنوز هیچ Matchی برای این Bracket وجود ندارد.",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 مدیریت Bracket',
                            'callback_data' =>
                                'admin_bracket:' . $bracketId
                        ]
                    ]
                ]
            ]
        );

        return;
    }

    /*
     * Champion
     */
    $champion = null;

    if (!empty($final['winner_participant_id'])) {

        $st = $pdo->prepare("
            SELECT
                tp.id AS participant_id,
                tp.event_player_id,
                ep.user_id,
                ep.ign
            FROM tournament_participants tp
            INNER JOIN event_players ep
                ON ep.id = tp.event_player_id
            WHERE tp.id = ?
            LIMIT 1
        ");

        $st->execute([
            (int) $final['winner_participant_id']
        ]);

        $champion =
            $st->fetch(PDO::FETCH_ASSOC);
    }

    /*
     * وضعیت Matchها
     */
    $st = $pdo->prepare("
        SELECT
            COUNT(*) AS total_matches,
            COALESCE(
                SUM(
                    CASE
                        WHEN status IN ('finished', 'completed')
                        THEN 1
                        ELSE 0
                    END
                ),
                0
            ) AS completed_matches
        FROM tournament_matches
        WHERE bracket_id = ?
    ");

    $st->execute([
        $bracketId
    ]);

    $stats =
        $st->fetch(PDO::FETCH_ASSOC);

    $totalMatches =
        (int) ($stats['total_matches'] ?? 0);

    $completedMatches =
        (int) ($stats['completed_matches'] ?? 0);

    /*
     * متن
     */
    $txt = '';

    $txt .= "<blockquote>";
    $txt .= "🏆 <b>نتیجه نهایی Bracket</b>\n";
    $txt .= "🏟 <b>"
        . htmlspecialchars(
            (string) $bracket['name'],
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n";
    $txt .= "🎯 Stage: <b>"
        . htmlspecialchars(
            (string) $bracket['stage_name'],
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n";
    $txt .= "🏆 Event: <b>"
        . htmlspecialchars(
            (string) $bracket['event_name'],
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "🎮 Matchها: <code>{$completedMatches}/{$totalMatches}</code>\n";
    $txt .= "📊 وضعیت Bracket: <b>{$bracket['status']}</b>";
    $txt .= "</blockquote>\n";

    if ($champion) {

        $championName =
            trim(
                (string) ($champion['ign'] ?? '')
            );

        if ($championName === '') {
            $championName =
                'Player #' .
                (int) $champion['event_player_id'];
        }

        $txt .= "<blockquote>";
        $txt .= "👑 <b>قهرمان</b>\n";
        $txt .= "🏆 <b>"
            . htmlspecialchars(
                $championName,
                ENT_QUOTES,
                'UTF-8'
            )
            . "</b>\n";
        $txt .= "🆔 شرکت‌کننده: <code>#"
            . (int) $champion['participant_id']
            . "</code>";
        $txt .= "</blockquote>\n";

    } else {

        $txt .= "<blockquote>";
        $txt .= "⏳ هنوز قهرمان مشخص نشده است.";
        $txt .= "</blockquote>\n";
    }

    /*
     * Keyboard
     */
    $ik = [
        [
            [
                'text' => '🎮 مدیریت Matchها',
                'callback_data' =>
                    'admin_bracket_matches:' .
                    $bracketId
            ]
        ],
        [
            [
                'text' => '🔄 بروزرسانی',
                'callback_data' =>
                    'admin_bracket_result:' .
                    $bracketId
            ]
        ],
        [
            [
                'text' => '🔙 مدیریت Bracket',
                'callback_data' =>
                    'admin_bracket:' .
                    $bracketId
            ]
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}


function renderAdminBRRooms(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $stageId,
    bool $sendNew = false
): void {
    /*
     * Stage
     */
    $st = $pdo->prepare("
        SELECT
            ts.id,
            ts.ev_id,
            ts.name,
            ts.type,
            ts.format,
            ts.status,
            ts.match_size,
            ts.matches_per_player,
            e.name AS event_name
        FROM tournament_stages ts
        INNER JOIN events e
            ON e.id = ts.ev_id
        WHERE ts.id = ?
        LIMIT 1
    ");

    $st->execute([
        $stageId
    ]);

    $stage = $st->fetch(
        PDO::FETCH_ASSOC
    );

    if (!$stage) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Stage پیدا نشد.'
        );
        return;
    }

    if ($stage['format'] !== 'battle_royale') {
        editMessageText(
            $chat_id,
            $mid,
            '❌ این Stage از نوع Battle Royale نیست.',
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 بازگشت',
                            'callback_data' =>
                                'admin_stage:' . $stageId
                        ]
                    ]
                ]
            ]
        );
        return;
    }

    /*
     * Rooms
     */
    $st = $pdo->prepare("
        SELECT
            id,
            round_number,
            room_number,
            capacity,
            participant_count,
            status
        FROM tournament_br_rooms
        WHERE stage_id = ?
        ORDER BY
            round_number ASC,
            room_number ASC
    ");

    $st->execute([
        $stageId
    ]);

    $rooms = $st->fetchAll(
        PDO::FETCH_ASSOC
    );

    /*
     * Statistics
     */
    $totalRooms = count($rooms);
    $completedRooms = 0;
    $activeRooms = 0;
    $readyRooms = 0;
    $pendingRooms = 0;

    foreach ($rooms as $room) {

        switch ($room['status']) {
            case 'completed':
                $completedRooms++;
                break;

            case 'active':
                $activeRooms++;
                break;

            case 'ready':
                $readyRooms++;
                break;

            case 'pending':
                $pendingRooms++;
                break;
        }
    }

    /*
     * Text
     */
    $txt = '';

    $txt .= "<blockquote>";
    $txt .= "🏠 <b>مدیریت Roomهای Battle Royale</b>\n";
    $txt .= "🎯 Stage: <b>"
        . htmlspecialchars(
            (string) $stage['name'],
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n";
    $txt .= "🏆 Event: <b>"
        . htmlspecialchars(
            (string) $stage['event_name'],
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>";
    $txt .= "</blockquote>\n";

    $txt .= "<blockquote>";
    $txt .= "👥 ظرفیت Room: <code>"
        . (int) $stage['match_size']
        . "</code>\n";
    $txt .= "🎮 بازی هر بازیکن: <code>"
        . (int) $stage['matches_per_player']
        . "</code>\n";
    $txt .= "📦 کل Roomها: <code>{$totalRooms}</code>\n";
    $txt .= "✅ تکمیل‌شده: <code>{$completedRooms}</code>\n";
    $txt .= "🟢 فعال: <code>{$activeRooms}</code>\n";
    $txt .= "🟡 آماده: <code>{$readyRooms}</code>\n";
    $txt .= "⏳ در انتظار: <code>{$pendingRooms}</code>";
    $txt .= "</blockquote>\n";

    /*
     * اگر Room نداریم
     */
    if ($totalRooms === 0) {

        $txt .= "<blockquote>";
        $txt .= "📭 هنوز هیچ Roomای برای این Stage ساخته نشده.";
        $txt .= "</blockquote>";

        $ik = [
            [
                [
                    'text' => '🔥 تولید Roomها',
                    'callback_data' =>
                        'admin_br_generate:' . $stageId
                ]
            ],
            [
                [
                    'text' => '🔙 مدیریت Stage',
                    'callback_data' =>
                        'admin_stage:' . $stageId
                ]
            ]
        ];

        editMessageText(
            $chat_id,
            $mid,
            $txt,
            [
                'inline_keyboard' => $ik
            ]
        );

        return;
    }

    /*
     * Group rooms by round
     */
    $rounds = [];

    foreach ($rooms as $room) {
        $round =
            (int) $room['round_number'];

        $rounds[$round][] =
            $room;
    }

    $statusMap = [
        'pending' =>
            '⏳ در انتظار',

        'ready' =>
            '🟡 آماده',

        'active' =>
            '🟢 فعال',

        'completed' =>
            '✅ تکمیل شده',

        'cancelled' =>
            '❌ لغو شده',
    ];

    foreach (
        $rounds as $roundNumber => $roundRooms
    ) {
        $txt .= "\n";
        $txt .= "<b>🔥 Round {$roundNumber}</b>\n";

        foreach ($roundRooms as $room) {

            $status =
                $statusMap[$room['status']]
                ?? $room['status'];

            $txt .= "<blockquote>";
            $txt .= "🏠 <b>Room #{$room['room_number']}</b>\n";
            $txt .= "👥 "
                . "<code>"
                . (int) $room['participant_count']
                . "</code>/"
                . "<code>"
                . (int) $room['capacity']
                . "</code>\n";
            $txt .= "📌 {$status}\n";
            $txt .= "🆔 <code>#{$room['id']}</code>";
            $txt .= "</blockquote>\n";
        }
    }

    /*
     * Keyboard
     */
    $ik = [];

    foreach ($rooms as $room) {

        $statusIcon = match (
            $room['status']
        ) {
            'pending' =>
                '⏳',

            'ready' =>
                '🟡',

            'active' =>
                '🟢',

            'completed' =>
                '✅',

            'cancelled' =>
                '❌',

            default =>
                '❔',
        };

        $buttonText =
            $statusIcon
            . ' R'
            . $room['round_number']
            . ' - Room '
            . $room['room_number']
            . ' ('
            . $room['participant_count']
            . ')';

        $ik[] = [
            [
                'text' =>
                    $buttonText,

                'callback_data' =>
                    'admin_br_room:' .
                    $room['id']
            ]
        ];
    }

    $ik[] = [
        [
            'text' =>
                '📢 اعلام زمان برگزاری به بازیکنان',
            'callback_data' =>
                'admin_br_broadcast_schedule:' .
                $stageId
        ]
    ];

    $ik[] = [
        [
            'text' => '🔄 بروزرسانی',
            'callback_data' =>
                'admin_br_rooms:' .
                $stageId
        ]
    ];

    $ik[] = [
        [
            'text' => '🔙 مدیریت Stage',
            'callback_data' =>
                'admin_stage:' .
                $stageId
        ]
    ];

    if ($sendNew) {

        sendMessage(
            $chat_id,
            $txt,
            [
                'inline_keyboard' => $ik
            ]
        );

    } else {

        editMessageText(
            $chat_id,
            $mid,
            $txt,
            [
                'inline_keyboard' => $ik
            ]
        );
    }
}

function renderAdminBRRoomInfo(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $roomId
): void {
    /*
     * Room + Stage
     */
    $st = $pdo->prepare("
        SELECT
            r.id,
            r.stage_id,
            r.round_number,
            r.room_number,
            r.room_game_id,
            r.room_password,
            r.scheduled_at,
            r.capacity,
            r.participant_count,
            r.status,

            s.name AS stage_name,
            s.ev_id,

            e.name AS event_name

        FROM tournament_br_rooms r

        INNER JOIN tournament_stages s
            ON s.id = r.stage_id

        INNER JOIN events e
            ON e.id = s.ev_id

        WHERE r.id = ?

        LIMIT 1
    ");

    $st->execute([
        $roomId
    ]);

    $room =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$room) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Room پیدا نشد.'
        );

        return;
    }

    /*
     * Participants
     */
    $st = $pdo->prepare("
        SELECT
            rp.id,
            rp.slot_number,
            rp.status AS room_participant_status,

            tp.id AS participant_id,
            tp.event_player_id,

            ep.user_id,
            ep.ign

        FROM tournament_br_room_participants rp

        INNER JOIN tournament_participants tp
            ON tp.id = rp.tournament_participant_id

        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id

        WHERE rp.room_id = ?

        ORDER BY
            rp.slot_number ASC
    ");

    $st->execute([
        $roomId
    ]);

    $participants =
        $st->fetchAll(
            PDO::FETCH_ASSOC
        );

    $statusMap = [
        'pending' =>
            '⏳ در انتظار',

        'ready' =>
            '🟡 آماده',

        'active' =>
            '🟢 فعال',

        'completed' =>
            '✅ تکمیل شده',

        'cancelled' =>
            '❌ لغو شده',
    ];

    $roomStatus =
        $statusMap[$room['status']]
        ?? $room['status'];

    /*
     * متن
     */
    $txt = '';

    $txt .= "<blockquote>";
    $txt .=
        "🏠 <b>Room #{$room['room_number']}</b>\n";

    $txt .=
        "🔥 Round: <code>"
        . (int) $room['round_number']
        . "</code>\n";

    $txt .=
        "🆔 Room ID: <code>#"
        . (int) $room['id']
        . "</code>\n";

    $txt .=
        "🎯 Stage: <b>"
        . htmlspecialchars(
            (string) $room['stage_name'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        . "</b>\n";

    $txt .=
        "🏆 Event: <b>"
        . htmlspecialchars(
            (string) $room['event_name'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        . "</b>";

    $txt .= "</blockquote>\n";

    /*
     * وضعیت Room
     */
    $txt .= "<blockquote>";

    $txt .=
        "📌 وضعیت: {$roomStatus}\n";

    $txt .=
        "👥 بازیکنان: <code>"
        . count($participants)
        . "</code>/"
        . "<code>"
        . (int) $room['capacity']
        . "</code>";

    $txt .= "</blockquote>\n";

    /*
     * Credential
     */
    $txt .= "<blockquote>";

    $txt .=
        "🎫 <b>اطلاعات Custom Room</b>\n";

    if (
        !empty($room['room_game_id'])
        && !empty($room['room_password'])
    ) {
        $txt .=
            "🆔 ID: <code>"
            . htmlspecialchars(
                (string) $room['room_game_id'],
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>\n";

        $txt .=
            "🔐 Password: <code>"
            . htmlspecialchars(
                (string) $room['room_password'],
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>";

    } else {

        $txt .=
            "⚠️ <b>Credential هنوز تنظیم نشده است.</b>";
    }

    $txt .= "</blockquote>\n";

    /*
    * زمان برگزاری Custom Room
    */
    $txt .= "<blockquote>";

    $txt .=
        "🕒 <b>زمان برگزاری Custom Room</b>\n";

    if (!empty($room['scheduled_at'])) {

        $scheduledAt =
            (string) $room['scheduled_at'];

        try {

            $scheduledDate =
                new DateTime(
                    $scheduledAt,
                    new DateTimeZone('Asia/Tehran')
                );

        $jalaliDate =
            jdate(
                'Y/m/d H:i',
                strtotime(
                    $room['scheduled_at']
                )
            );

            $txt .=
                "📅 "
                . htmlspecialchars(
                    $jalaliDate,
                    ENT_QUOTES | ENT_SUBSTITUTE,
                    'UTF-8'
                );

        } catch (Throwable) {

            $txt .=
                "⚠️ زمان ذخیره‌شده نامعتبر است.";
        }

    } else {

        $txt .=
            "⚠️ هنوز تاریخ و ساعت تنظیم نشده است.";
    }

    $txt .= "</blockquote>\n";

    /*
     * لیست بازیکنان
     */
    $txt .= "<b>👥 لیست بازیکنان</b>\n\n";

    if (!$participants) {

        $txt .= "<blockquote>";
        $txt .=
            "📭 هیچ بازیکنی در این Room نیست.";
        $txt .= "</blockquote>\n";

    } else {

        foreach (
            $participants as $participant
        ) {
            $slot =
                (int) $participant['slot_number'];

            $ign =
                trim(
                    (string) (
                        $participant['ign'] ?? ''
                    )
                );

            if ($ign === '') {
                $ign =
                    'Player #' .
                    (int) $participant['event_player_id'];
            }

            $txt .=
                "<blockquote>"
                . "<b>"
                . $slot
                . ". "
                . htmlspecialchars(
                    $ign,
                    ENT_QUOTES | ENT_SUBSTITUTE,
                    'UTF-8'
                )
                . "</b>\n"
                . "🆔 Participant: <code>#"
                . (int) $participant['participant_id']
                . "</code>\n"
                . "📌 "
                . (
                    $participant[
                        'room_participant_status'
                    ]
                    ?? 'pending'
                )
                . "</blockquote>\n";
        }
    }

    /*
     * Keyboard
     */
    $ik = [];

    $ik[] = [
        [
            'text' =>
                !empty($room['scheduled_at'])
                    ? '🕒 تغییر تاریخ و ساعت'
                    : '🕒 تنظیم تاریخ و ساعت',
            'callback_data' =>
                'admin_br_room_schedule:' .
                $roomId
        ]
    ];

    /*
     * تنظیم Credential
     */
    $ik[] = [
        [
            'text' =>
                '🎫 تنظیم ID و Password',
            'callback_data' =>
                'admin_br_room_credentials:' .
                $roomId
        ]
    ];

    /*
     * ارسال Credential
     *
     * فقط وقتی Credential وجود دارد.
     */
    if (
        !empty($room['room_game_id'])
        && !empty($room['room_password'])
        && !empty($participants)
    ) {
        $ik[] = [
            [
                'text' =>
                    '📤 ارسال اطلاعات به بازیکنان',
                'callback_data' =>
                    'admin_br_room_send_credentials:' .
                    $roomId
            ]
        ];
    }
    

    /*
     * شروع Room
     */
    if ($room['status'] === 'ready') {

        $ik[] = [
            [
                'text' =>
                    '▶️ شروع Room',
                'callback_data' =>
                    'admin_br_room_start:' .
                    $roomId
            ]
        ];
    }

    /*
     * Room فعال
     */
    if ($room['status'] === 'active') {

        $ik[] = [
            [
                'text' =>
                    '📋 ثبت نتایج',
                'callback_data' =>
                    'admin_br_room_results:' .
                    $roomId
            ]
        ];

        $ik[] = [
            [
                'text' =>
                    '✅ پایان Room',
                'callback_data' =>
                    'admin_br_room_complete:' .
                    $roomId
            ]
        ];
    }

    /*
     * Room تکمیل‌شده
     */
    if ($room['status'] === 'completed') {

        $ik[] = [
            [
                'text' =>
                    '📊 مشاهده نتایج',
                'callback_data' =>
                    'admin_br_room_results:' .
                    $roomId
            ]
        ];
    }

    /*
     * بروزرسانی
     */
    $ik[] = [
        [
            'text' =>
                '🔄 بروزرسانی',
            'callback_data' =>
                'admin_br_room:' .
                $roomId
        ]
    ];

    /*
     * بازگشت
     */
    $ik[] = [
        [
            'text' =>
                '🔙 Roomهای Stage',
            'callback_data' =>
                'admin_br_rooms:' .
                $room['stage_id']
        ]
    ];

    $ik[] = [
        [
            'text' =>
                '🎯 مدیریت Stage',
            'callback_data' =>
                'admin_stage:' .
                $room['stage_id']
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' =>
                $ik
        ]
    );
}

function sendBRRoomCredentials(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $roomId
): void {
    ignore_user_abort(true);
    set_time_limit(0);

    error_log(
        "BR ROOM CREDENTIALS STARTED | room_id={$roomId}"
    );

    /*
     * Room + Stage + Event
     */
    $st = $pdo->prepare("
        SELECT
            r.id,
            r.stage_id,
            r.round_number,
            r.room_number,
            r.room_game_id,
            r.room_password,
            r.status,

            s.name AS stage_name,
            e.name AS event_name

        FROM tournament_br_rooms r

        INNER JOIN tournament_stages s
            ON s.id = r.stage_id

        INNER JOIN events e
            ON e.id = s.ev_id

        WHERE r.id = ?

        LIMIT 1
    ");

    $st->execute([
        $roomId
    ]);

    $room =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$room) {
        sendMessage(
            $chat_id,
            '❌ Room پیدا نشد.'
        );

        return;
    }

    /*
     * Credential باید وجود داشته باشد.
     */
    if (
        empty($room['room_game_id'])
        || empty($room['room_password'])
    ) {
        sendMessage(
            $chat_id,
            '❌ ابتدا ID و Password این Room را تنظیم کنید.'
        );

        return;
    }

    /*
     * فقط بازیکنان همان Room
     */
    $st = $pdo->prepare("
        SELECT
            u.id AS chat_id,
            ep.ign,
            ep.ig_id

        FROM tournament_br_room_participants rp

        INNER JOIN tournament_participants tp
            ON tp.id = rp.tournament_participant_id

        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id

        INNER JOIN users u
            ON u.id = ep.user_id

        WHERE rp.room_id = ?

        ORDER BY
            rp.slot_number ASC
    ");

    $st->execute([
        $roomId
    ]);

    $players =
        $st->fetchAll(
            PDO::FETCH_ASSOC
        );

    if (!$players) {
        sendMessage(
            $chat_id,
            '⚠️ هیچ بازیکنی در این Room پیدا نشد.'
        );

        return;
    }

    $total =
        count($players);

    $success = 0;
    $failed = 0;

    /*
     * Keyboard
     */
    $keyboard = [
        [
            [
                'text' => 'کپی Password',
                'copy_text' => [
                    'text' => (string) $room['room_password'],
                ],
                'style' => 'danger',
            ],
            [
                'text' => 'کپی ID',
                'copy_text' => [
                    'text' => (string) $room['room_game_id'],
                ],
                'style' => 'primary',
            ],
        ],
    ];

    /*
     * Escape
     */
    $eventName =
        htmlspecialchars(
            (string) $room['event_name'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        );

    $stageName =
        htmlspecialchars(
            (string) $room['stage_name'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        );

    $safeRoomId =
        htmlspecialchars(
            (string) $room['room_game_id'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        );

    $safePassword =
        htmlspecialchars(
            (string) $room['room_password'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        );

    error_log(
        "BR ROOM BULK SEND | room_id={$roomId} | total={$total}"
    );

    foreach (
        $players as $index => $player
    ) {
        $playerChatId =
            (int) (
                $player['chat_id'] ?? 0
            );

        if ($playerChatId <= 0) {
            $failed++;

            continue;
        }

        $ign =
            htmlspecialchars(
                (string) (
                    $player['ign'] ?? '-'
                ),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            );

        $igId =
            htmlspecialchars(
                (string) (
                    $player['ig_id'] ?? '-'
                ),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            );

        $roomNumber =
            (int) $room['room_number'];

        $roundNumber =
            (int) $room['round_number'];

        $message =
            "<blockquote>"
            . "🎫 <b>اطلاعات Custom Room</b>"
            . "</blockquote>\n"

            . "🏆 Event: <b>{$eventName}</b>\n"
            . "🎯 Stage: <b>{$stageName}</b>\n"
            . "🔥 Round: <code>{$roundNumber}</code>\n"
            . "🏠 Room: <code>#{$roomNumber}</code>\n\n"

            . "<blockquote>🆔 Room ID: <code>{$safeRoomId}</code></blockquote>\n"
            . "<blockquote>🔐 Password: <code>{$safePassword}</code></blockquote>\n\n"

            . "<blockquote>"
            . "🔖 <b>اطلاعات شما</b>"
            . "</blockquote>\n"

            . "🎮 NickName: <code>{$ign}</code>\n"
            . "🆔 Game ID: <code>{$igId}</code>\n\n"

            . "<i>⚠️ عدم حضور شما تا ۵ دقیقه آینده در لابی، به منزله انصراف بوده و منجر به حذف از ایونت خواهد شد.</i>";

        $response =
            sendMessage(
                $playerChatId,
                $message,
                [
                    'inline_keyboard' =>
                        $keyboard,
                ]
            );

        if (
            is_array($response)
            && ($response['ok'] ?? false) === true
        ) {
            $success++;

        } else {

            $errorCode =
                is_array($response)
                    ? (int) (
                        $response['error_code']
                        ?? 0
                    )
                    : 0;

            $retryAfter =
                is_array($response)
                    ? (int) (
                        $response['parameters']['retry_after']
                        ?? 0
                    )
                    : 0;

            /*
             * Flood Limit
             */
            if (
                $errorCode === 429
                && $retryAfter > 0
            ) {
                sleep(
                    $retryAfter + 1
                );

                $retryResponse =
                    sendMessage(
                        $playerChatId,
                        $message,
                        [
                            'inline_keyboard' =>
                                $keyboard,
                        ]
                    );

                if (
                    is_array($retryResponse)
                    && (
                        $retryResponse['ok']
                        ?? false
                    ) === true
                ) {
                    $success++;

                } else {
                    $failed++;
                }

            } else {
                $failed++;
            }
        }

        /*
         * حدود 16 پیام در ثانیه
         */
        usleep(60000);
    }

    error_log(
        "BR ROOM CREDENTIALS COMPLETED | "
        . "room_id={$roomId} | "
        . "total={$total} | "
        . "success={$success} | "
        . "failed={$failed}"
    );

    sendMessage(
        $chat_id,
        "📤 <b>اطلاعات Room ارسال شد</b>\n\n"
        . "🏠 Room #<code>"
        . (int) $room['room_number']
        . "</code>\n"
        . "👥 Total: <code>{$total}</code>\n"
        . "✔️ Sent: <code>{$success}</code>\n"
        . "❌ Failed: <code>{$failed}</code>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' =>
                            '🏠 مشاهده Room',
                        'callback_data' =>
                            'admin_br_room:' .
                            $roomId
                    ]
                ]
            ]
        ]
    );
}

function renderAdminBRRoomResults(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $roomId,
    int $page = 1
): void {
    /*
     * Room
     */
    $st = $pdo->prepare("
        SELECT
            r.id,
            r.stage_id,
            r.round_number,
            r.room_number,
            r.capacity,
            r.participant_count,
            r.status,
            s.name AS stage_name,
            s.scoring_strategy
        FROM tournament_br_rooms r
        INNER JOIN tournament_stages s
            ON s.id = r.stage_id
        WHERE r.id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomId
    ]);

    $room = $st->fetch(PDO::FETCH_ASSOC);

    if (!$room) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Room پیدا نشد.'
        );
        return;
    }

    /*
     * فقط Room فعال یا تکمیل‌شده
     */
    if (!in_array(
        $room['status'],
        ['active', 'completed'],
        true
    )) {
        editMessageText(
            $chat_id,
            $mid,
            "❌ این Room هنوز قابل ثبت نتیجه نیست.\n\n"
            . "📌 وضعیت: <b>{$room['status']}</b>",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 Room',
                            'callback_data' =>
                                'admin_br_room:' . $roomId
                        ]
                    ]
                ]
            ]
        );

        return;
    }

    /*
     * تمام Participants + Results
     */
    $st = $pdo->prepare("
        SELECT
            rp.id AS room_participant_id,
            rp.slot_number,
            rp.status AS room_participant_status,

            tp.id AS tournament_participant_id,

            ep.id AS event_player_id,
            ep.user_id,
            ep.ign,

            tbr.id AS result_id,
            tbr.placement,
            tbr.kills,
            tbr.score,
            tbr.status AS result_status

        FROM tournament_br_room_participants rp

        INNER JOIN tournament_participants tp
            ON tp.id = rp.tournament_participant_id

        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id

        LEFT JOIN tournament_br_results tbr
            ON tbr.room_id = rp.room_id
            AND tbr.room_participant_id = rp.id

        WHERE rp.room_id = ?

        ORDER BY
            rp.slot_number ASC
    ");

    $st->execute([
        $roomId
    ]);

    $participants =
        $st->fetchAll(PDO::FETCH_ASSOC);

    $totalParticipants =
        count($participants);

    /*
     * Pagination
     *
     * 16 buttons per page
     */
    $perPage = 16;

    $totalPages =
        max(
            1,
            (int) ceil(
                $totalParticipants / $perPage
            )
        );

    $page =
        min(
            max(1, $page),
            $totalPages
        );

    $offset =
        ($page - 1) * $perPage;

    $pageParticipants =
        array_slice(
            $participants,
            $offset,
            $perPage
        );

    /*
     * آمار نتایج کل Room
     */
    $completedResults = 0;

    foreach ($participants as $participant) {

        if (
            $participant['result_id'] !== null
            && $participant['result_status'] === 'confirmed'
        ) {
            $completedResults++;
        }
    }

    /*
     * متن
     */
    $txt =
        "📋 <b>ثبت نتایج Room</b>\n\n"
        . "🏠 Room #{$room['room_number']}\n"
        . "🔥 Round {$room['round_number']}\n"
        . "👥 بازیکنان: <code>{$totalParticipants}</code>/"
        . "<code>{$room['capacity']}</code>\n"
        . "✅ نتایج ثبت‌شده: <code>{$completedResults}/{$totalParticipants}</code>\n"
        . "📄 صفحه: <code>{$page}/{$totalPages}</code>\n\n"
        . "💡 بازیکن را برای ثبت یا ویرایش نتیجه انتخاب کنید.";

    /*
     * Keyboard
     */
    $ik = [];

    /*
     * حداکثر 16 بازیکن
     * 2 دکمه در هر ردیف
     */
    $row = [];

    foreach ($pageParticipants as $participant) {

        $name =
            trim(
                (string) ($participant['ign'] ?? '')
            );

        if ($name === '') {
            $name =
                'Player #' .
                (int) $participant['event_player_id'];
        }

        $roomParticipantId =
            (int) $participant['room_participant_id'];

        $hasResult =
            $participant['result_id'] !== null
            && $participant['result_status'] === 'confirmed';

        if ($hasResult) {

            $score =
                rtrim(
                    rtrim(
                        number_format(
                            (float) $participant['score'],
                            2,
                            '.',
                            ''
                        ),
                        '0'
                    ),
                    '.'
                );

            $button = [
                'text' =>
                    '✅ '
                    . $participant['slot_number']
                    . '. '
                    . $name
                    . ' | '
                    . $score,

                'style' =>
                    'success',

                'callback_data' =>
                    'admin_br_result_player:' .
                    $roomId .
                    ':' .
                    $roomParticipantId
            ];

        } else {

            $button = [
                'text' =>
                    '📝 '
                    . $participant['slot_number']
                    . '. '
                    . $name,

                'callback_data' =>
                    'admin_br_result_player:' .
                    $roomId .
                    ':' .
                    $roomParticipantId
            ];
        }

        $row[] = $button;

        /*
         * هر ردیف 2 دکمه
         */
        if (count($row) === 2) {
            $ik[] = $row;
            $row = [];
        }
    }

    /*
     * اگر یک دکمه باقی مانده باشد
     */
    if ($row) {
        $ik[] = $row;
    }

    /*
     * Pagination
     */
    if ($totalPages > 1) {

        $paginationRow = [];

        if ($page > 1) {
            $paginationRow[] = [
                'text' => '⬅️ قبلی',
                'callback_data' =>
                    'admin_br_room_results:' .
                    $roomId .
                    ':' .
                    ($page - 1)
            ];
        }

        $paginationRow[] = [
            'text' =>
                "📄 {$page}/{$totalPages}",
            'callback_data' =>
                'admin_br_room_results:' .
                $roomId .
                ':' .
                $page
        ];

        if ($page < $totalPages) {
            $paginationRow[] = [
                'text' => 'بعدی ➡️',
                'callback_data' =>
                    'admin_br_room_results:' .
                    $roomId .
                    ':' .
                    ($page + 1)
            ];
        }

        $ik[] = $paginationRow;
    }

    /*
     * تکمیل Room
     */
    if ($room['status'] === 'active') {

        $ik[] = [
            [
                'text' => '✅ تکمیل نتایج Room',
                'callback_data' =>
                    'admin_br_room_complete:' .
                    $roomId
            ]
        ];
    }

    /*
     * بروزرسانی
     */
    $ik[] = [
        [
            'text' => '🔄 بروزرسانی',
            'callback_data' =>
                'admin_br_room_results:' .
                $roomId .
                ':' .
                $page
        ]
    ];

    $ik[] = [
        [
            'text' => '🔎 جستجوی بازیکن',
            'callback_data' =>
                'admin_br_result_search:' . $roomId
        ]
    ];

    /*
     * بازگشت
     */
    $ik[] = [
        [
            'text' => '🔙 Room',
            'callback_data' =>
                'admin_br_room:' .
                $roomId
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );
}

function renderAdminBRResultPlayer(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $uid,
    int $roomId,
    int $roomParticipantId
): void {
    $st = $pdo->prepare("
        SELECT
            rp.id AS room_participant_id,
            rp.room_id,
            rp.slot_number,
            rp.status AS room_participant_status,

            tp.id AS tournament_participant_id,
            ep.id AS event_player_id,
            ep.user_id,
            ep.ign,

            r.round_number,
            r.room_number,
            r.status AS room_status,
            r.stage_id

        FROM tournament_br_room_participants rp

        INNER JOIN tournament_br_rooms r
            ON r.id = rp.room_id

        INNER JOIN tournament_participants tp
            ON tp.id = rp.tournament_participant_id

        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id

        WHERE rp.id = ?
          AND rp.room_id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomParticipantId,
        $roomId
    ]);

    $player =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$player) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ بازیکن این Room پیدا نشد.'
        );
        return;
    }

    if (
        !in_array(
            $player['room_status'],
            ['active', 'completed'],
            true
        )
    ) {
        editMessageText(
            $chat_id,
            $mid,
            "❌ این Room هنوز قابل ثبت نتیجه نیست.\n\n"
            . "📌 وضعیت Room: <b>{$player['room_status']}</b>",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🔙 بازگشت',
                            'callback_data' =>
                                'admin_br_room_results:' .
                                $roomId
                        ]
                    ]
                ]
            ]
        );

        return;
    }

    /*
     * اگر نتیجه قبلاً وجود دارد، آن را بخوان.
     */
    $st = $pdo->prepare("
        SELECT
            id,
            placement,
            kills,
            score,
            status
        FROM tournament_br_results
        WHERE room_id = ?
          AND room_participant_id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomId,
        $roomParticipantId
    ]);

    $result =
        $st->fetch(PDO::FETCH_ASSOC);

    $name =
        trim(
            (string) ($player['ign'] ?? '')
        );

    if ($name === '') {
        $name =
            'Player #' .
            (int) $player['event_player_id'];
    }

    $txt =
        "📝 <b>ثبت نتیجه بازیکن</b>\n\n"
        . "👤 <b>"
        . htmlspecialchars(
            $name,
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n"
        . "🏠 Room #"
        . (int) $player['room_number']
        . "\n"
        . "🔥 Round "
        . (int) $player['round_number']
        . "\n"
        . "🎯 Slot: <code>"
        . (int) $player['slot_number']
        . "</code>\n\n";

    if ($result) {
        $txt .=
            "🏅 Placement: <code>"
            . (int) $result['placement']
            . "</code>\n"
            . "🔫 Kills: <code>"
            . (int) $result['kills']
            . "</code>\n"
            . "🧮 Score: <code>"
            . $result['score']
            . "</code>\n"
            . "📌 وضعیت: <b>"
            . $result['status']
            . "</b>\n\n";
    }

    $txt .=
        "ابتدا Placement را وارد کنید.";

    setState(
        $pdo,
        $uid,
        'admin_br_result:placement:' .
        $roomId .
        ':' .
        $roomParticipantId
    );

    sendMessage(
        $chat_id,
        $txt,
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '🔙 بازگشت',
                        'callback_data' =>
                            'admin_br_room_results:' .
                            $roomId
                    ]
                ]
            ]
        ]
    );
}

function renderAdminBRLeaderboard(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $stageId,
    int $page = 1
): void {
    $st = $pdo->prepare("
        SELECT
            l.rank_position,
            l.total_score,
            l.total_kills,
            l.games_played,
            l.best_placement,
            l.qualified,

            ep.ign,
            ep.user_id

        FROM tournament_br_leaderboards l

        INNER JOIN tournament_participants tp
            ON tp.id =
                l.tournament_participant_id

        INNER JOIN event_players ep
            ON ep.id =
                tp.event_player_id

        WHERE l.stage_id = ?

        ORDER BY
            l.rank_position ASC
    ");

    $st->execute([
        $stageId
    ]);

    $players =
        $st->fetchAll(
            PDO::FETCH_ASSOC
        );

    if (!$players) {
        editMessageText(
            $chat_id,
            $mid,
            '📭 هنوز Leaderboard ساخته نشده.'
        );

        return;
    }

    $perPage = 20;

    $total =
        count($players);

    $totalPages =
        max(
            1,
            (int) ceil(
                $total / $perPage
            )
        );

    $page =
        min(
            max(1, $page),
            $totalPages
        );

    $offset =
        ($page - 1) * $perPage;

    $pagePlayers =
        array_slice(
            $players,
            $offset,
            $perPage
        );

    $txt =
        "🏆 <b>Leaderboard Stage</b>\n\n"
        . "🎯 Stage: <code>#{$stageId}</code>\n"
        . "👥 Players: <code>{$total}</code>\n"
        . "📄 صفحه: <code>{$page}/{$totalPages}</code>\n\n";

    $rankIcons = [
        1 => '🥇',
        2 => '🥈',
        3 => '🥉',
    ];

    foreach (
        $pagePlayers as $player
    ) {
        $rank =
            (int) $player['rank_position'];

        $icon =
            $rankIcons[$rank]
            ?? '▫️';

        $name =
            trim(
                (string) (
                    $player['ign']
                    ?? ''
                )
            );

        if ($name === '') {
            $name =
                'Player #' .
                (int) $player['user_id'];
        }

        $qualified =
            (int) $player['qualified'] === 1;

        $txt .=
            "<blockquote>"
            . "{$icon} <b>#{$rank} "
            . htmlspecialchars(
                $name,
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</b>\n"
            . "🧮 Score: <code>"
            . $player['total_score']
            . "</code>\n"
            . "🔫 Kills: <code>"
            . (int) $player['total_kills']
            . "</code>\n"
            . "🎮 Games: <code>"
            . (int) $player['games_played']
            . "</code>\n";

        if ($player['best_placement'] !== null) {
            $txt .=
                "🏅 Best Placement: <code>"
                . (int) $player['best_placement']
                . "</code>\n";
        }

        $txt .=
            $qualified
                ? "✅ <b>صعود</b>"
                : "❌ حذف";

        $txt .= "</blockquote>\n";
    }

    $ik = [];

    if ($totalPages > 1) {

        $row = [];

        if ($page > 1) {
            $row[] = [
                'text' =>
                    '⬅️ قبلی',

                'callback_data' =>
                    'admin_br_leaderboard_page:' .
                    $stageId .
                    ':' .
                    ($page - 1)
            ];
        }

        $row[] = [
            'text' =>
                "{$page}/{$totalPages}",

            'callback_data' =>
                'admin_br_leaderboard_page:' .
                $stageId .
                ':' .
                $page
        ];

        if ($page < $totalPages) {
            $row[] = [
                'text' =>
                    'بعدی ➡️',

                'callback_data' =>
                    'admin_br_leaderboard_page:' .
                    $stageId .
                    ':' .
                    ($page + 1)
            ];
        }

        $ik[] = $row;
    }

    $ik[] = [
        [
            'text' =>
                '🔄 بروزرسانی',
            'callback_data' =>
                'admin_br_leaderboard:' .
                $stageId
        ]
    ];

    $ik[] = [
        [
            'text' =>
                '📨 ارسال نتیجه Stage به بازیکنان',

            'callback_data' =>
                'admin_br_broadcast_results:' .
                $stageId,

            'style' =>
                'primary'
        ]
    ];

    $ik[] = [
        [
            'text' =>
                '🔙 مدیریت Stage',
            'callback_data' =>
                'admin_stage:' .
                $stageId
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' =>
                $ik
        ]
    );
}


function renderAdminBRSearchResults(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $uid,
    int $roomId,
    string $query,
    int $page = 1,
    bool $editMessage = true
): void {
    $query = trim($query);

    if ($query === '') {
        if ($editMessage) {
            editMessageText(
                $chat_id,
                $mid,
                '❌ عبارت جستجو خالی است.'
            );
        } else {
            sendMessage(
                $chat_id,
                '❌ عبارت جستجو خالی است.'
            );
        }

        return;
    }

    /*
     * نرمال‌سازی Search
     *
     * Meti Drax
     * metidrax
     * meti-drax
     * meti_drax
     *
     * همه → metidrax
     */
    $normalizedQuery = mb_strtolower(
        preg_replace(
            '/[\s_\-]+/u',
            '',
            $query
        ),
        'UTF-8'
    );

    /*
     * Search معمولی
     */
    $normalLike =
        '%' .
        mb_strtolower(
            $query,
            'UTF-8'
        ) .
        '%';

    /*
     * Search نرمال‌شده
     */
    $normalizedLike =
        '%' .
        $normalizedQuery .
        '%';

    /*
     * UID
     */
    $uidSearch =
        ctype_digit($query)
            ? $query
            : '__NO_UID__';

    /*
     * Search
     */
    $st = $pdo->prepare("
        SELECT
            rp.id AS room_participant_id,
            rp.slot_number,
            rp.status AS room_participant_status,

            tp.id AS tournament_participant_id,

            ep.id AS event_player_id,
            ep.user_id,
            ep.ign,

            tbr.id AS result_id,
            tbr.placement,
            tbr.kills,
            tbr.score,
            tbr.status AS result_status

        FROM tournament_br_room_participants rp

        INNER JOIN tournament_participants tp
            ON tp.id = rp.tournament_participant_id

        INNER JOIN event_players ep
            ON ep.id = tp.event_player_id

        LEFT JOIN tournament_br_results tbr
            ON tbr.room_id = rp.room_id
            AND tbr.room_participant_id = rp.id

        WHERE rp.room_id = :room_id

          AND (
                CAST(ep.user_id AS CHAR) = :uid_search

                OR LOWER(
                    REPLACE(
                        REPLACE(
                            REPLACE(
                                TRIM(
                                    COALESCE(
                                        ep.ign,
                                        ''
                                    )
                                ),
                                ' ',
                        ''
                    ),
                    '_',
                    ''
                ),
                '-',
                ''
            )
        ) LIKE :normalized_like

        OR LOWER(
            COALESCE(
                ep.ign,
                ''
            )
        ) LIKE :normal_like
    )

    ORDER BY
        rp.slot_number ASC
    ");

    $st->execute([
        ':room_id' =>
            $roomId,

        ':uid_search' =>
            $uidSearch,

        ':normalized_like' =>
            $normalizedLike,

        ':normal_like' =>
            $normalLike,
    ]);

    $players =
        $st->fetchAll(
            PDO::FETCH_ASSOC
        );

    /*
     * چیزی پیدا نشد
     */
    if (!$players) {

        $message =
            "🔎 بازیکنی با عبارت "
            . "<code>"
            . htmlspecialchars(
                $query,
                ENT_QUOTES,
                'UTF-8'
            )
            . "</code>"
            . " در این Room پیدا نشد.";

        $keyboard = [
            [
                [
                    'text' =>
                        '🔎 جستجوی دوباره',

                    'callback_data' =>
                        'admin_br_result_search:' .
                        $roomId
                ]
            ],
            [
                [
                    'text' =>
                        '🔙 ثبت نتایج',

                    'callback_data' =>
                        'admin_br_room_results:' .
                        $roomId
                ]
            ]
        ];

        if ($editMessage) {
            editMessageText(
                $chat_id,
                $mid,
                $message,
                [
                    'inline_keyboard' =>
                        $keyboard
                ]
            );
        } else {
            sendMessage(
                $chat_id,
                $message,
                [
                    'inline_keyboard' =>
                        $keyboard
                ]
            );
        }

        return;
    }

    /*
     * Pagination
     */
    $perPage = 16;

    $totalResults =
        count($players);

    $totalPages =
        max(
            1,
            (int) ceil(
                $totalResults / $perPage
            )
        );

    $page =
        min(
            max(1, $page),
            $totalPages
        );

    $offset =
        ($page - 1) * $perPage;

    $pagePlayers =
        array_slice(
            $players,
            $offset,
            $perPage
        );

    /*
     * متن
     */
    $txt =
        "🔎 <b>نتایج جستجو</b>\n\n"
        . "🏠 Room: <code>#{$roomId}</code>\n"
        . "🔍 عبارت: <code>"
        . htmlspecialchars(
            $query,
            ENT_QUOTES,
            'UTF-8'
        )
        . "</code>\n"
        . "👥 نتایج: <code>{$totalResults}</code>\n"
        . "📄 صفحه: <code>{$page}/{$totalPages}</code>\n\n";

    $ik = [];

    /*
     * دو دکمه در هر ردیف
     */
    $row = [];

    foreach ($pagePlayers as $player) {

        $name =
            trim(
                (string) ($player['ign'] ?? '')
            );

        if ($name === '') {
            $name =
                'Player #' .
                (int) $player['event_player_id'];
        }

        $hasResult =
            $player['result_id'] !== null
            && $player['result_status'] === 'confirmed';

        if ($hasResult) {

            $score =
                rtrim(
                    rtrim(
                        number_format(
                            (float) $player['score'],
                            2,
                            '.',
                            ''
                        ),
                        '0'
                    ),
                    '.'
                );

            $button = [
                'text' =>
                    '✅ '
                    . $name
                    . ' | '
                    . $score,

                'style' =>
                    'success',

                'callback_data' =>
                    'admin_br_result_player:' .
                    $roomId .
                    ':' .
                    (int) $player['room_participant_id']
            ];

        } else {

            $button = [
                'text' =>
                    '📝 '
                    . $name,

                'callback_data' =>
                    'admin_br_result_player:' .
                    $roomId .
                    ':' .
                    (int) $player['room_participant_id']
            ];
        }

        $row[] = $button;

        if (count($row) === 2) {
            $ik[] = $row;
            $row = [];
        }
    }

    if ($row) {
        $ik[] = $row;
    }

    /*
     * Pagination
     */
    if ($totalPages > 1) {

        $paginationRow = [];

        if ($page > 1) {
            $paginationRow[] = [
                'text' =>
                    '⬅️ قبلی',

                'callback_data' =>
                    'admin_br_result_search_page:' .
                    $roomId .
                    ':' .
                    ($page - 1)
            ];
        }

        $paginationRow[] = [
            'text' =>
                "📄 {$page}/{$totalPages}",

            'callback_data' =>
                'admin_br_result_search_page:' .
                $roomId .
                ':' .
                $page
        ];

        if ($page < $totalPages) {
            $paginationRow[] = [
                'text' =>
                    'بعدی ➡️',

                'callback_data' =>
                    'admin_br_result_search_page:' .
                    $roomId .
                    ':' .
                    ($page + 1)
            ];
        }

        $ik[] =
            $paginationRow;
    }

    /*
     * پایین صفحه
     */
    $ik[] = [
        [
            'text' =>
                '🔎 جستجوی دوباره',

            'callback_data' =>
                'admin_br_result_search:' .
                $roomId
        ]
    ];

    $ik[] = [
        [
            'text' =>
                '🔙 همه بازیکنان',

            'callback_data' =>
                'admin_br_room_results:' .
                $roomId
        ]
    ];

    /*
     * Send یا Edit
     */
    if ($editMessage) {

        editMessageText(
            $chat_id,
            $mid,
            $txt,
            [
                'inline_keyboard' =>
                    $ik
            ]
        );

    } else {

        sendMessage(
            $chat_id,
            $txt,
            [
                'inline_keyboard' =>
                    $ik
            ]
        );
    }
}


function sendEventCredentials(
    PDO $pdo,
    int $chat_id,
    int $mid,
    int $eid
): void {
    ignore_user_abort(true);
    set_time_limit(0);

    error_log(
        "EVENT CREDENTIALS SEND STARTED | eid={$eid}"
    );

    // =========================
    // دریافت اطلاعات ایونت
    // =========================

    $st = $pdo->prepare("
        SELECT
            name,
            id_pass
        FROM events
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([$eid]);

    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        error_log(
            "EVENT NOT FOUND | eid={$eid}"
        );

        sendMessage(
            $chat_id,
            "❌ ایونت پیدا نشد"
        );

        return;
    }

    // =========================
    // Room ID و Password
    // =========================

    $idPass = jdec(
        $event['id_pass'] ?: '{}'
    );

    if (!is_array($idPass)) {
        $idPass = [];
    }

    $eventId = $idPass['id'] ?? '-';

    $eventPass = $idPass['pass'] ?? '-';

    // =========================
    // دریافت بازیکنان
    // =========================

    $st = $pdo->prepare("
        SELECT
            u.id AS chat_id,
            ep.ign,
            ep.ig_id
        FROM event_players ep
        INNER JOIN users u
            ON u.id = ep.user_id
        WHERE ep.ev_id = ?
          AND ep.status = 'accepted'
    ");

    $st->execute([$eid]);

    $players = $st->fetchAll(
        PDO::FETCH_ASSOC
    );

    if (!$players) {
        sendMessage(
            $chat_id,
            "⚠️ هیچ بازیکنی برای این ایونت پیدا نشد."
        );

        return;
    }

    // =========================
    // مقادیر اولیه
    // =========================

    $total = count($players);

    $success = 0;
    $failed = 0;

    // =========================
    // کیبورد مشترک
    // =========================

    $keyboard = [
        [
            [
                'text'          => 'ایونت شروع شد!',
                'callback_data' => 'noop',
                'style'         => 'success',
            ],
        ],
    ];

    // =========================
    // Escape اطلاعات ایونت
    // =========================

    $eventName = htmlspecialchars(
        (string) $event['name'],
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    );

    $safeEventId = htmlspecialchars(
        (string) $eventId,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    );

    $safeEventPass = htmlspecialchars(
        (string) $eventPass,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    );

    error_log(
        "BULK SEND STARTED | eid={$eid} | total={$total}"
    );

    // =========================
    // ارسال به بازیکنان
    // =========================

    foreach ($players as $index => $player) {

        $playerChatId = (int) (
            $player['chat_id'] ?? 0
        );

        if ($playerChatId <= 0) {
            $failed++;

            error_log(
                "INVALID CHAT ID | eid={$eid} | index={$index}"
            );

            continue;
        }

        // -------------------------
        // Escape اطلاعات کاربر
        // -------------------------

        $ign = htmlspecialchars(
            (string) (
                $player['ign'] ?? '-'
            ),
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        );

        $igId = htmlspecialchars(
            (string) (
                $player['ig_id'] ?? '-'
            ),
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        );

        // -------------------------
        // ساخت پیام
        // -------------------------

        $message =
            "<blockquote>🎫 <b>اطلاعات ایونت {$eventName}</b></blockquote>\n\n" .
            "🆔 Room ID: <code>{$safeEventId}</code>\n" .
            "🔐 Password: <code>{$safeEventPass}</code>\n\n" .
            "<blockquote>🔖 اطلاعات شما</blockquote>\n" .
            "🎮 NickName: <code>{$ign}</code>\n" .
            "🆔 Game ID: <code>{$igId}</code>\n\n" .
            "⚠️ عدم حضور شما تا ۵ دقیقه آینده در لابی، به منزله انصراف بوده و منجر به حذف از ایونت خواهد شد.";

        // -------------------------
        // ارسال پیام
        // -------------------------

        $response = sendMessage(
            $playerChatId,
            $message,
            [
                'inline_keyboard' => $keyboard,
            ]
        );

        // =========================
        // بررسی موفقیت
        // =========================

        if (
            is_array($response)
            && ($response['ok'] ?? false) === true
        ) {
            $success++;

        } else {

            $errorCode = is_array($response)
                ? (int) (
                    $response['error_code'] ?? 0
                )
                : 0;

            $retryAfter = is_array($response)
                ? (int) (
                    $response['parameters']['retry_after']
                    ?? 0
                )
                : 0;

            // =====================
            // مدیریت Flood Limit
            // =====================

            if (
                $errorCode === 429
                && $retryAfter > 0
            ) {
                error_log(
                    "FLOOD LIMIT | " .
                    "eid={$eid} | " .
                    "chat_id={$playerChatId} | " .
                    "retry_after={$retryAfter}"
                );

                // صبر بر اساس دستور تلگرام
                sleep(
                    $retryAfter + 1
                );

                // تلاش مجدد
                $retryResponse = sendMessage(
                    $playerChatId,
                    $message,
                    [
                        'inline_keyboard' => $keyboard,
                    ]
                );

                if (
                    is_array($retryResponse)
                    && ($retryResponse['ok'] ?? false) === true
                ) {
                    $success++;
                } else {
                    $failed++;

                    error_log(
                        "RETRY FAILED | " .
                        "eid={$eid} | " .
                        "chat_id={$playerChatId} | " .
                        "response=" .
                        json_encode(
                            $retryResponse,
                            JSON_UNESCAPED_UNICODE
                        )
                    );
                }

            } else {
                $failed++;

                error_log(
                    "SEND FAILED | " .
                    "eid={$eid} | " .
                    "chat_id={$playerChatId} | " .
                    "response=" .
                    json_encode(
                        $response,
                        JSON_UNESCAPED_UNICODE
                    )
                );
            }
        }

        // =========================
        // گزارش هر 100 پیام
        // =========================

        $processed = $index + 1;

        if ($processed % 100 === 0) {
            error_log(
                "BULK SEND PROGRESS | " .
                "eid={$eid} | " .
                "processed={$processed}/{$total} | " .
                "success={$success} | " .
                "failed={$failed}"
            );
        }

        // =========================
        // سرعت ارسال
        // حدود 16 پیام در ثانیه
        // =========================

        usleep(60000);
    }

    // =========================
    // پایان ارسال
    // =========================

    error_log(
        "BULK SEND COMPLETED | " .
        "eid={$eid} | " .
        "total={$total} | " .
        "success={$success} | " .
        "failed={$failed}"
    );

    // =========================
    // گزارش نهایی ادمین
    // =========================

    sendMessage(
        $chat_id,
        "📤 <b>ارسال اطلاعات ایونت انجام شد</b>\n\n" .
        "👥 Total: <code>{$total}</code>\n" .
        "✔️ Sent: <code>{$success}</code>\n" .
        "❌ Failed: <code>{$failed}</code>"
    );
}

if (str_starts_with($data, 'admin_send_credentials:')) {

    $eid = (int) substr($data, strlen('admin_send_credentials:'));

    error_log("RAW = " . $data);
    error_log("PARSED EID = " . $eid);

    if ($eid <= 0) {
        error_log("INVALID EID DETECTED");
        return;
    }

    sendEventCredentials($pdo, $chat_id, $mid, $eid);
    exit;
}


if (str_starts_with($data, 'admin_archive:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️', true);
        exit;
    }

    $eid = (int)substr($data, 14);
    if (archiveEvent($pdo, $uid, $eid)) {
        answerCb($cb['id'], '📦 آرشیو شد ✅');
        renderAdminEventInfo($pdo, $chat_id, $mid, $eid); // پیام با وضعیت جدید ویرایش میشه
    } else {
        answerCb($cb['id'], '❌ آرشیو نشد');
    }
    exit;
}


if (str_starts_with($data, 'admin_restore:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️', true);
        exit;
    }

    $eid = (int)substr($data, 14);
    if (restoreEvent($pdo, $eid)) {
        answerCb($cb['id'], '♻️ بازگردانده شد ✅');
        renderAdminEventInfo($pdo, $chat_id, $mid, $eid); // پیام با وضعیت جدید ویرایش میشه
    } else {
        answerCb($cb['id'], '❌ امکان بازگردانی وجود ندارد');
    }
    exit;
}



    if (str_starts_with($data,'admin_export:')){ if(!isAdmin($uid)){ answerCb($cb['id'],'⛔️',true); exit; } $eid=(int)substr($data,13); $file = exportEventCSV($pdo,$eid); if(!$file){ answerCb($cb['id'],'خطا',true); exit; } sendDocument($chat_id,$file,'CSV شرکت‌کنندگان'); answerCb($cb['id'],'ارسال شد'); exit; }

//--------------edit events-------------------------

if (str_starts_with($data, 'admin_edit:')) {
    $eid = (int)substr($data, 11);

    // بررسی ایونت
    $st = $pdo->prepare("SELECT * FROM events WHERE id=?");
    $st->execute([$eid]);
    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        answerCb($cb['id'], '❌ ایونت پیدا نشد');
        exit;
    }

    // ذخیره استیت
    setState($pdo, $uid, "edit_event_menu:$eid");

    // ساخت منو
  $kb = [
    [
        ['text'=>'🎮 بازی','callback_data'=>"edit_event_field:game:$eid"],
        ['text'=>'📝 توضیحات','callback_data'=>"edit_event_field:info:$eid"]
    ],
    [
        ['text'=>'📛 نام','callback_data'=>"edit_event_field:name:$eid"],
        ['text'=>'📅 تاریخ','callback_data'=>"edit_event_field:date_str:$eid"]
    ],
    [
        ['text'=>'🔑 رمز/آیدی','callback_data'=>"edit_event_field:credentials:$eid"],
        ['text'=>'⭐ امتیاز','callback_data'=>"edit_event_field:points_for_winner:$eid"]
    ],
    [
        ['text'=>'🔒 کانال خصوصی','callback_data'=>"edit_event_field:private_channel:$eid"],
        ['text'=>'⚙️ الزامات','callback_data'=>"edit_event_requirements:$eid"]
    ],
    [
        ['text'=>'🔙 بازگشت','callback_data'=>"admin_ev:$eid"],
    ]
];



    editMessageText($chat_id, $mid, "✏️ چه چیزی رو میخوای ویرایش کنی؟", [
        'inline_keyboard' => $kb
    ]);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'edit_event_requirements:')) {
    $eid = (int)substr($data, strlen('edit_event_requirements:'));
    $stmt = $pdo->prepare("SELECT require_ign, require_game_id, require_referral, require_private_channel FROM events WHERE id = ?");
    $stmt->execute([$eid]);
    $req = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];

    $kb = [
        'inline_keyboard' => [
            [
                ['text' => ((int)($req['require_ign'] ?? 0) ? '✅' : '❌') . ' IGN اجباری', 'callback_data' => "toggle_event_requirement:require_ign:$eid"],
                ['text' => ((int)($req['require_game_id'] ?? 0) ? '✅' : '❌') . ' Game ID اجباری', 'callback_data' => "toggle_event_requirement:require_game_id:$eid"]
            ],
            [
                ['text' => ((int)($req['require_referral'] ?? 0) ? '✅' : '❌') . ' Referral اجباری', 'callback_data' => "toggle_event_requirement:require_referral:$eid"],
                ['text' => ((int)($req['require_private_channel'] ?? 0) ? '✅' : '❌') . ' Private Channel اجباری', 'callback_data' => "toggle_event_requirement:require_private_channel:$eid"]
            ],
            [['text' => '🔙 بازگشت', 'callback_data' => "admin_edit:". $eid]]
        ]
    ];

    editMessageText($chat_id, $mid, "⚙️ وضعیت الزامات ایونت را تنظیم کنید:", $kb);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'toggle_event_requirement:')) {
    [, $field, $eid] = explode(':', $data, 3);
    $allowed = ['require_ign', 'require_game_id', 'require_referral', 'require_private_channel'];
    if (!in_array($field, $allowed, true)) {
        answerCb($cb['id'], '❌ فیلد نامعتبر', true);
        exit;
    }

    $stmt = $pdo->prepare("SELECT `$field` FROM events WHERE id = ?");
    $stmt->execute([$eid]);
    $current = (int)$stmt->fetchColumn();
    $next = $current ? 0 : 1;
    $pdo->prepare("UPDATE events SET `$field` = ? WHERE id = ?")->execute([$next, $eid]);

    $data = 'edit_event_requirements:' . $eid;
    $cb['data'] = $data;
    $cb['id'] = $cb['id'];
    $_SERVER['__event_req_refresh'] = true;
    if (isset($cb['id'])) {
        answerCb($cb['id'], '');
    }
    $data = 'edit_event_requirements:' . $eid;
    if (str_starts_with($data, 'edit_event_requirements:')) {
        $eid2 = (int)substr($data, strlen('edit_event_requirements:'));
        $stmt = $pdo->prepare("SELECT require_ign, require_game_id, require_referral, require_private_channel FROM events WHERE id = ?");
        $stmt->execute([$eid2]);
        $req = $stmt->fetch(PDO::FETCH_ASSOC) ?: [];

        $kb = [
            'inline_keyboard' => [
                [
                    ['text' => ((int)($req['require_ign'] ?? 0) ? '✅' : '❌') . ' IGN اجباری', 'callback_data' => "toggle_event_requirement:require_ign:$eid2"],
                    ['text' => ((int)($req['require_game_id'] ?? 0) ? '✅' : '❌') . ' Game ID اجباری', 'callback_data' => "toggle_event_requirement:require_game_id:$eid2"]
                ],
                [
                    ['text' => ((int)($req['require_referral'] ?? 0) ? '✅' : '❌') . ' Referral اجباری', 'callback_data' => "toggle_event_requirement:require_referral:$eid2"],
                    ['text' => ((int)($req['require_private_channel'] ?? 0) ? '✅' : '❌') . ' Private Channel اجباری', 'callback_data' => "toggle_event_requirement:require_private_channel:$eid2"]
                ],
                [['text' => '🔙 بازگشت', 'callback_data' => "admin_edit:$eid2"]]
            ]
        ];

        editMessageText($chat_id, $mid, "⚙️ وضعیت الزامات ایونت را تنظیم کنید:", $kb);
    }
    exit;
}

if (str_starts_with($data,'edit_event_field:')) {
    [, $field, $eid] = explode(':',$data,3);

    if ($field === 'credentials') {
        // گرفتن اطلاعات قبلی از دیتابیس
        $stmt = $pdo->prepare("SELECT id_pass FROM events WHERE id = ?");
        $stmt->execute([$eid]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        $current_id = $current_pass = '';
        if ($row && $row['id_pass']) {
            $saved = json_decode($row['id_pass'], true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $current_id = htmlspecialchars($saved['id'] ?? '', ENT_QUOTES, 'UTF-8');
                $current_pass = htmlspecialchars($saved['pass'] ?? '', ENT_QUOTES, 'UTF-8');
            }
        }

        // ساخت پیام با فرمت مونو و quouted
        $msg = <<<HTML
📌 آیدی فعلی: <code>$current_id</code>

🔑 رمز فعلی: <code>$current_pass</code>

<blockquote>✍️ لطفا اطلاعات جدید رو به شکل زیر ارسال کنید:
خط اول: ID
خط دوم: Password</blockquote>
HTML;

        setState($pdo,$uid,"edit_credentials:$eid");

        editMessageText($chat_id,$mid,$msg,[
            'parse_mode'=>'HTML',
            'inline_keyboard'=>[
                [['text'=>'🔙 بازگشت','callback_data'=>"admin_edit:$eid"]]
            ]
        ]);
        exit;
    }

    if ($field === 'private_channel') {
        $stmt = $pdo->prepare("SELECT private_channel FROM events WHERE id = ?");
        $stmt->execute([$eid]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);

        $current = htmlspecialchars($row['private_channel'] ?? '', ENT_QUOTES, 'UTF-8');
        $msg = <<<HTML
🔒 کانال‌های اجباری فعلی:

<blockquote>{$current}</blockquote>

✍️ لطفاً اطلاعات کانال‌ها را به یکی از این دو شکل ارسال کنید:

۱) JSON:
<code>[{"title":"کانال اول","chat_id":-1002958275866,"invite":"https://t.me/+DH_EZZffNTk1YjVk"}]</code>

۲) یا متن چندخطی:
<code>کانال اول
-1002958275866
https://t.me/+DH_EZZffNTk1YjVk

کانال دوم
-1001575068270
https://t.me/HoradOfficial</code>
HTML;

        setState($pdo, $uid, "edit_private_channel:$eid");

        editMessageText($chat_id, $mid, $msg, [
            'parse_mode' => 'HTML',
            'inline_keyboard' => [
                [['text' => '🔙 بازگشت', 'callback_data' => "admin_edit:$eid"]]
            ]
        ]);
        exit;
    }

    $fieldMap = [
        'name' => 'name',
        'info' => 'info',
        'game' => 'game',
        'date_str' => 'date_str',
        'points_for_winner' => 'points_for_winner',
    ];

    if (isset($fieldMap[$field])) {
        $prompt = match ($field) {
            'name' => '📛 نام رویداد را ارسال کنید یا عبور کنید',
            'info' => '📝 توضیحات رویداد را ارسال کنید یا عبور کنید',
            'game' => '🎮 نام بازی را ارسال کنید یا عبور کنید',
            'date_str' => '📅 تاریخ و ساعت را به فرم yyyy/mm/dd - hh:mm:ss ارسال کنید یا عبور کنید',
            'points_for_winner' => '⭐ امتیاز برنده را ارسال کنید یا عبور کنید',
            default => '✏️ مقدار جدید را ارسال کنید یا عبور کنید'
        };

        $kb = [
            'inline_keyboard' => [
                [['text' => '🔙 بازگشت', 'callback_data' => "admin_edit:". $eid]]
            ]
        ];

        setState($pdo, $uid, "edit_{$field}:$eid");
        editMessageText($chat_id, $mid, $prompt, $kb);
        exit;
    }
}

 



if (str_starts_with($state, 'edit_private_channel:') && isAdmin($uid)) {
    $parts = explode(':', $state, 2);
    $eid = (int)($parts[1] ?? 0);
    $val = trim($text);
    $skip = mb_strtolower($val) === 'عبور';

    if (!$skip) {
        $channels = normalizeMandatoryJoinChannels($val);
        $json = json_encode($channels, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        $requireJoin = !empty($channels) ? 1 : 0;
        $pdo->prepare('UPDATE events SET private_channel=?, require_private_channel=? WHERE id=?')->execute([$json ?: '[]', $requireJoin, $eid]);
    } else {
        $pdo->prepare('UPDATE events SET private_channel=?, require_private_channel=? WHERE id=?')->execute(['[]', 0, $eid]);
    }

    setState($pdo, $uid, '');
    sendMessage($chat_id, "✅ اطلاعات کانال‌های اجباری ذخیره شد.");
    exit;
}

if (str_starts_with($data,'confirm_credentials:')) {
    [, $eid] = explode(':',$data,2);

    // پاک کردن پیام پیش‌نمایش
    $cb_msg_id = $update['callback_query']['message']['message_id'];
    deleteMessage($chat_id, $cb_msg_id);

    setState($pdo,$uid,"");
    sendMessage($chat_id,"✅ اطلاعات آیدی/رمز ذخیره شد.");
    exit;
}

if (str_starts_with($data,'cancel_credentials:')) {
    [, $eid] = explode(':',$data,2);

    $stmt = $pdo->prepare("UPDATE events SET id_pass = NULL WHERE id = ?");
    $stmt->execute([$eid]);

    // پاک کردن پیام پیش‌نمایش
    $cb_msg_id = $update['callback_query']['message']['message_id'];
    deleteMessage($chat_id, $cb_msg_id);

    setState($pdo,$uid,"");
    sendMessage($chat_id,"❌ اطلاعات آیدی/رمز حذف شد.");
    exit;
}



//-----------------------show player list------------------------

  if (str_starts_with($data, 'admin_players:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️', true);
        exit;
    }

    setUserStep($uid, null);

    $parts = explode(':', $data);
    $eid   = (int)($parts[1] ?? 0);

    $st = $pdo->prepare('SELECT * FROM events WHERE id=?');
    $st->execute([$eid]);
    $e = $st->fetch();

    if (!$e) {
        answerCb($cb['id'], 'رویداد پیدا نشد');
        exit;
    }

    $stPlayers = $pdo->prepare(
        'SELECT ep.user_id, ep.ign, u.username, u.first_name
         FROM event_players ep
         LEFT JOIN users u ON u.id = ep.user_id
         WHERE ep.ev_id = ? AND ep.status = ?'
    );
    $stPlayers->execute([$eid, 'accepted']);
    $players = $stPlayers->fetchAll(PDO::FETCH_ASSOC);

    if (!$players) {
        editMessageText($chat_id, $mid, "👥 هیچ پلیری ثبت‌نام نکرده.", ['inline_keyboard'=>[
            [['text'=>'🔙 بازگشت','callback_data'=>'admin_ev:'.$eid]]
        ]]);
        exit;
    }

    // ساخت دکمه‌ها (دو تا در هر ردیف)
    $ik = [];
    $row = [];
    foreach ($players as $p) {
        $displayName = !empty($p['ign']) ? $p['ign'] : ($p['first_name'] ?? 'کاربر');
        $btnText = $displayName . " (" . $p['user_id'] . ")";
        $row[] = [
            'text' => $btnText,
            'callback_data' => 'admin_player_info:'.$eid.':'.$p['user_id']
        ];
        if (count($row) == 2) {
            $ik[] = $row;
            $row = [];
        }
    }

    if ($row) $ik[] = $row;

    $ik[] = [
    ['text' => '🔍 جستجو', 'callback_data' => 'admin_search_player:'.$eid],
    ['text' => '🔙 بازگشت', 'callback_data' => 'admin_ev:'.$eid]
    ];



  editMessageText($chat_id, $mid, "👥 لیست پلیرها یا جستجو:", [
    'inline_keyboard' => $ik
]);

answerCb($cb['id'], '');
exit;
}

//=======================admin_invite=============================


if (str_starts_with($data, 'admin_invites:')) {

    $parts = explode(':', $data);

    $eid = (int)($parts[1] ?? 0);

    if ($eid <= 0) {
        answerCb($cb['id'], '❌ ایونت نامعتبر است.', true);
        return;
    }

    answerCb($cb['id']);

    renderAdminEventInvites(
        $pdo,
        $chat_id,
        $mid,
        $eid
    );

    exit;
}

if (str_starts_with($data, 'admin_invite_create:')) {

    $eid = (int)substr(
        $data,
        strlen('admin_invite_create:')
    );

    if ($eid <= 0) {
        answerCb($cb['id'], '❌ ایونت نامعتبر است.', true);
        return;
    }

    $st = $pdo->prepare("
        SELECT id, name
        FROM events
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$eid]);

    $event = $st->fetch(PDO::FETCH_ASSOC);

    if (!$event) {
        answerCb($cb['id'], '❌ ایونت پیدا نشد.', true);
        return;
    }

    // مقدار temp فعلی
    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$uid]);

    $temp = json_decode($st->fetchColumn() ?: '{}', true);

    if (!is_array($temp)) {
        $temp = [];
    }

    // Draft دعوتنامه
    $temp['invite'] = [
        'eid' => $eid,
        'title' => null,
        'skip_force_join' => 0,
        'skip_referral' => 0,
        'usage_limit' => null
    ];

    $st = $pdo->prepare("
        UPDATE users
        SET temp = ?
        WHERE id = ?
    ");

    $st->execute([
        json_encode(
            $temp,
            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
        ),
        $uid
    ]);

    // state فقط برای مشخص کردن مرحله
    setState(
        $pdo,
        $uid,
        'admin_invite_create:' . $eid
    );

    answerCb($cb['id']);

    // نمایش منو
    $joinText = '🚫 رد عضویت اجباری ❌';
    $refText  = '🚫 رد رفرال ❌';

    $ik = [
        [
            [
                'text' => $joinText,
                'callback_data' => "admin_invite_toggle_join:{$eid}"
            ]
        ],
        [
            [
                'text' => $refText,
                'callback_data' => "admin_invite_toggle_referral:{$eid}"
            ]
        ],
        [
            [
                'text' => '📝 تعیین نام دعوتنامه',
                'callback_data' => "admin_invite_name:{$eid}"
            ]
        ],
        [
            [
                'text' => '🔢 تعیین محدودیت استفاده',
                'callback_data' => "admin_invite_limit:{$eid}"
            ]
        ],
        [
            [
                'text' => '✅ ساخت دعوتنامه',
                'callback_data' => "admin_invite_save:{$eid}"
            ]
        ],
        [
            [
                'text' => '❌ لغو',
                'callback_data' => "admin_invites:{$eid}"
            ]
        ],
    ];

    editMessageText(
        $chat_id,
        $mid,
        "📨 <b>ساخت دعوتنامه جدید</b>\n\n"
        . "🎯 ایونت: <b>" . htmlspecialchars($event['name']) . "</b>\n\n"
        . "⚙️ تنظیمات را انتخاب کنید.",
        [
            'inline_keyboard' => $ik
        ]
    );

    exit;
}

if (str_starts_with($data, 'admin_invite_toggle_join:')) {

    $eid = (int)substr(
        $data,
        strlen('admin_invite_toggle_join:')
    );

    if ($eid <= 0) {
        answerCb($cb['id'], '❌ ایونت نامعتبر است.', true);
        return;
    }

    // بررسی state
    $state = getState($pdo, $uid);

    if (
        !$state ||
        !str_starts_with($state, 'admin_invite_create:')
    ) {
        answerCb(
            $cb['id'],
            '❌ فرآیند ساخت دعوتنامه منقضی شده است.',
            true
        );
        return;
    }

    $stateEid = (int)substr(
        $state,
        strlen('admin_invite_create:')
    );

    if ($stateEid !== $eid) {
        answerCb(
            $cb['id'],
            '❌ فرآیند ساخت دعوتنامه منقضی شده است.',
            true
        );
        return;
    }

    // گرفتن temp فعلی
    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$uid]);

    $tempRaw = $st->fetchColumn();

    $temp = json_decode(
        $tempRaw ?: '{}',
        true
    );

    if (!is_array($temp)) {
        $temp = [];
    }

    // بررسی Draft
    if (
        !isset($temp['invite']) ||
        (int)($temp['invite']['eid'] ?? 0) !== $eid
    ) {
        answerCb(
            $cb['id'],
            '❌ اطلاعات دعوتنامه پیدا نشد.',
            true
        );
        return;
    }

    // فقط همین فیلد را تغییر بده
    $temp['invite']['skip_force_join'] =
        empty($temp['invite']['skip_force_join']) ? 1 : 0;

    // ذخیره کل temp
    $st = $pdo->prepare("
        UPDATE users
        SET temp = ?
        WHERE id = ?
    ");

    $st->execute([
        json_encode(
            $temp,
            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
        ),
        $uid
    ]);

    answerCb(
        $cb['id'],
        $temp['invite']['skip_force_join']
            ? '✅ عضویت اجباری رد خواهد شد.'
            : '❌ عضویت اجباری الزامی شد.'
    );

    // منو را دوباره نمایش بده
    $invite = $temp['invite'];

    $joinText = !empty($invite['skip_force_join'])
        ? '🚫 رد عضویت اجباری ✅'
        : '🚫 رد عضویت اجباری ❌';

    $refText = !empty($invite['skip_referral'])
        ? '👥 رد رفرال ✅'
        : '👥 رد رفرال ❌';

    $titleText = !empty($invite['title'])
        ? $invite['title']
        : 'تعیین نشده';

    $limitDisplay = $invite['usage_limit'] === null
        ? '♾ نامحدود'
        : number_format((int)$invite['usage_limit']);

    $txt  = "📨 <b>ساخت دعوتنامه جدید</b>\n\n";
    $txt .= "🆔 ایونت: <code>{$eid}</code>\n\n";
    $txt .= "⚙️ <b>تنظیمات دعوتنامه</b>\n";
    $txt .= "🏷 نام: <b>" . htmlspecialchars(
        $titleText,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    ) . "</b>\n";

    $txt .= "🔐 عضویت اجباری: "
        . (!empty($invite['skip_force_join'])
            ? '❌ رد می‌شود'
            : '✅ الزامی')
        . "\n";

    $txt .= "👥 رفرال: "
        . (!empty($invite['skip_referral'])
            ? '❌ رد می‌شود'
            : '✅ الزامی')
        . "\n";

    $txt .= "🔢 محدودیت استفاده: <b>{$limitDisplay}</b>\n\n";
    $txt .= "تنظیمات موردنظر را انتخاب کنید.";

    $ik = [
        [
            [
                'text' => $joinText,
                'callback_data' => "admin_invite_toggle_join:{$eid}"
            ]
        ],
        [
            [
                'text' => $refText,
                'callback_data' => "admin_invite_toggle_referral:{$eid}"
            ]
        ],
        [
            [
                'text' => '📝 تعیین نام دعوتنامه',
                'callback_data' => "admin_invite_name:{$eid}"
            ]
        ],
        [
            [
                'text' => '🔢 تعیین محدودیت استفاده',
                'callback_data' => "admin_invite_limit:{$eid}"
            ]
        ],
        [
            [
                'text' => '✅ ساخت دعوتنامه',
                'callback_data' => "admin_invite_save:{$eid}"
            ]
        ],
        [
            [
                'text' => '❌ لغو',
                'callback_data' => "admin_invites:{$eid}"
            ]
        ],
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );

    exit;
}

if (str_starts_with($data, 'admin_invite_toggle_referral:')) {

    $eid = (int)substr(
        $data,
        strlen('admin_invite_toggle_referral:')
    );

    if ($eid <= 0) {
        answerCb($cb['id'], '❌ ایونت نامعتبر است.', true);
        return;
    }

    // بررسی state
    $state = getState($pdo, $uid);

    if (
        !$state ||
        !str_starts_with(
            $state,
            'admin_invite_create:'
        )
    ) {
        answerCb(
            $cb['id'],
            '❌ فرآیند ساخت دعوتنامه منقضی شده است.',
            true
        );
        return;
    }

    $stateEid = (int)substr(
        $state,
        strlen('admin_invite_create:')
    );

    if ($stateEid !== $eid) {
        answerCb(
            $cb['id'],
            '❌ ایونت با فرآیند فعلی مطابقت ندارد.',
            true
        );
        return;
    }

    // دریافت temp فعلی
    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$uid]);

    $tempRaw = $st->fetchColumn();

    $temp = json_decode(
        $tempRaw ?: '{}',
        true
    );

    if (!is_array($temp)) {
        $temp = [];
    }

    // بررسی Draft دعوتنامه
    if (
        !isset($temp['invite']) ||
        (int)($temp['invite']['eid'] ?? 0) !== $eid
    ) {
        answerCb(
            $cb['id'],
            '❌ اطلاعات دعوتنامه پیدا نشد.',
            true
        );
        return;
    }

    // Toggle فقط referral
    $temp['invite']['skip_referral'] =
        empty($temp['invite']['skip_referral']) ? 1 : 0;

    // ذخیره کل temp بدون حذف اطلاعات قبلی
    $st = $pdo->prepare("
        UPDATE users
        SET temp = ?
        WHERE id = ?
    ");

    $st->execute([
        json_encode(
            $temp,
            JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
        ),
        $uid
    ]);

    $skipReferral = (int)$temp['invite']['skip_referral'];

    answerCb(
        $cb['id'],
        $skipReferral
            ? '✅ رفرال رد خواهد شد.'
            : '❌ رفرال الزامی شد.'
    );

    // State همچنان فقط مرحله فعلی را مشخص می‌کند
    setState(
        $pdo,
        $uid,
        'admin_invite_create:' . $eid
    );

    // نمایش مجدد منو
    $invite = $temp['invite'];

    $joinText = !empty($invite['skip_force_join'])
        ? '🚫 رد عضویت اجباری ✅'
        : '🚫 رد عضویت اجباری ❌';

    $refText = !empty($invite['skip_referral'])
        ? '👥 رد رفرال ✅'
        : '👥 رد رفرال ❌';

    $titleText = !empty($invite['title'])
        ? $invite['title']
        : 'تعیین نشده';

    $limitDisplay = $invite['usage_limit'] === null
        ? '♾ نامحدود'
        : number_format((int)$invite['usage_limit']);

    $txt  = "📨 <b>ساخت دعوتنامه جدید</b>\n\n";
    $txt .= "🆔 ایونت: <code>{$eid}</code>\n\n";

    $txt .= "⚙️ <b>تنظیمات دعوتنامه</b>\n";
    $txt .= "🏷 نام: <b>" . htmlspecialchars(
        $titleText,
        ENT_QUOTES | ENT_SUBSTITUTE,
        'UTF-8'
    ) . "</b>\n";

    $txt .= "🔐 عضویت اجباری: "
        . (!empty($invite['skip_force_join'])
            ? '❌ رد می‌شود'
            : '✅ الزامی')
        . "\n";

    $txt .= "👥 رفرال: "
        . (!empty($invite['skip_referral'])
            ? '❌ رد می‌شود'
            : '✅ الزامی')
        . "\n";

    $txt .= "🔢 محدودیت استفاده: <b>{$limitDisplay}</b>\n\n";

    $txt .= "تنظیمات موردنظر را انتخاب کنید.";

    $ik = [
        [
            [
                'text' => $joinText,
                'callback_data' => "admin_invite_toggle_join:{$eid}"
            ]
        ],
        [
            [
                'text' => $refText,
                'callback_data' => "admin_invite_toggle_referral:{$eid}"
            ]
        ],
        [
            [
                'text' => '📝 تعیین نام دعوتنامه',
                'callback_data' => "admin_invite_name:{$eid}"
            ]
        ],
        [
            [
                'text' => '🔢 تعیین محدودیت استفاده',
                'callback_data' => "admin_invite_limit:{$eid}"
            ]
        ],
        [
            [
                'text' => '✅ ساخت دعوتنامه',
                'callback_data' => "admin_invite_save:{$eid}"
            ]
        ],
        [
            [
                'text' => '❌ لغو',
                'callback_data' => "admin_invites:{$eid}"
            ]
        ],
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );

    exit;
}

if (str_starts_with($data, 'admin_invite_name:')) {

    $eid = (int)substr(
        $data,
        strlen('admin_invite_name:')
    );

    if ($eid <= 0) {
        answerCb($cb['id'], '❌ ایونت نامعتبر است.', true);
        return;
    }

    // دریافت state فعلی
    $state = getState($pdo, $uid);

    if (
        !$state ||
        !str_starts_with(
            $state,
            'admin_invite_create:'
        )
    ) {
        answerCb(
            $cb['id'],
            '❌ فرآیند ساخت دعوتنامه منقضی شده است.',
            true
        );
        return;
    }

    // بررسی ایونت موجود در state
    $stateEid = (int)substr(
        $state,
        strlen('admin_invite_create:')
    );

    if ($stateEid !== $eid) {
        answerCb(
            $cb['id'],
            '❌ ایونت با فرآیند فعلی مطابقت ندارد.',
            true
        );
        return;
    }

    // بررسی وجود Draft در temp
    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");
    $st->execute([$uid]);

    $temp = json_decode(
        $st->fetchColumn() ?: '{}',
        true
    );

    if (
        !is_array($temp) ||
        !isset($temp['invite']) ||
        (int)($temp['invite']['eid'] ?? 0) !== $eid
    ) {
        answerCb(
            $cb['id'],
            '❌ اطلاعات دعوتنامه پیدا نشد.',
            true
        );
        return;
    }

    // فقط تغییر مرحله
    setState(
        $pdo,
        $uid,
        'admin_invite_name:' . $eid
    );

    answerCb($cb['id']);

    editMessageText(
        $chat_id,
        $mid,
        "📝 <b>نام دعوتنامه را ارسال کنید.</b>\n\n"
        . "مثلاً:\n"
        . "<code>دعوت گیلد X</code>\n\n"
        . "حداکثر ۱۰۰ کاراکتر."
    );

    exit;
}

if (str_starts_with($data, 'admin_invite_limit:')) {

    $eid = (int)substr(
        $data,
        strlen('admin_invite_limit:')
    );

    $state = getState($pdo, $uid);

    if (
        !$state ||
        !str_starts_with(
            $state,
            'admin_invite_create:'
        )
    ) {
        answerCb(
            $cb['id'],
            '❌ فرآیند ساخت دعوتنامه منقضی شده است.',
            true
        );
        return;
    }

    $stateEid = (int)substr(
        $state,
        strlen('admin_invite_create:')
    );

    if ($stateEid !== $eid) {
        answerCb(
            $cb['id'],
            '❌ فرآیند ساخت دعوتنامه منقضی شده است.',
            true
        );
        return;
    }

    setState(
        $pdo,
        $uid,
        'admin_invite_limit:' . $eid
    );

    answerCb($cb['id']);

    editMessageText(
        $chat_id,
        $mid,
        "🔢 <b>محدودیت استفاده را ارسال کنید.</b>\n\n"
        . "مثال:\n"
        . "<code>100</code>\n\n"
        . "برای نامحدود بودن بنویسید:\n"
        . "<code>0</code>"
    );

    exit;
}

if (str_starts_with($data, 'admin_invite_save:')) {

    $eid = (int)substr(
        $data,
        strlen('admin_invite_save:')
    );

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ ایونت نامعتبر است.',
            true
        );
        return;
    }

    // =========================
    // بررسی state
    // =========================

    $state = getState($pdo, $uid);

    if (
        !$state ||
        !str_starts_with(
            $state,
            'admin_invite_create:'
        )
    ) {
        answerCb(
            $cb['id'],
            '❌ فرآیند ساخت دعوتنامه منقضی شده است.',
            true
        );
        return;
    }

    $stateEid = (int)substr(
        $state,
        strlen('admin_invite_create:')
    );

    if ($stateEid !== $eid) {
        answerCb(
            $cb['id'],
            '❌ ایونت با فرآیند فعلی مطابقت ندارد.',
            true
        );
        return;
    }

    // =========================
    // دریافت temp
    // =========================

    $st = $pdo->prepare("
        SELECT temp
        FROM users
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([$uid]);

    $tempRaw = $st->fetchColumn();

    $temp = json_decode(
        $tempRaw ?: '{}',
        true
    );

    if (!is_array($temp)) {
        $temp = [];
    }

    // =========================
    // دریافت Draft
    // =========================

    if (
        !isset($temp['invite']) ||
        !is_array($temp['invite']) ||
        (int)($temp['invite']['eid'] ?? 0) !== $eid
    ) {
        answerCb(
            $cb['id'],
            '❌ اطلاعات دعوتنامه پیدا نشد.',
            true
        );
        return;
    }

    $invite = $temp['invite'];

    // =========================
    // نام دعوتنامه
    // =========================

    $title = trim(
        (string)($invite['title'] ?? '')
    );

    if ($title === '') {
        answerCb(
            $cb['id'],
            '❌ ابتدا نام دعوتنامه را تعیین کنید.',
            true
        );
        return;
    }

    if (mb_strlen($title, 'UTF-8') > 100) {
        answerCb(
            $cb['id'],
            '❌ نام دعوتنامه حداکثر ۱۰۰ کاراکتر است.',
            true
        );
        return;
    }

    // =========================
    // محدودیت
    // =========================

    $usageLimit = $invite['usage_limit'] ?? null;

    if ($usageLimit !== null) {
        $usageLimit = (int)$usageLimit;

        if ($usageLimit < 0) {
            answerCb(
                $cb['id'],
                '❌ محدودیت استفاده نامعتبر است.',
                true
            );
            return;
        }

        if ($usageLimit === 0) {
            $usageLimit = null;
        }
    }

    // =========================
    // تنظیمات
    // =========================

    $skipForceJoin = !empty(
        $invite['skip_force_join']
    ) ? 1 : 0;

    $skipReferral = !empty(
        $invite['skip_referral']
    ) ? 1 : 0;


    // =========================
    // ساخت Token
    // =========================

    try {

        $token = bin2hex(
            random_bytes(16)
        );

    } catch (Throwable $ex) {

        answerCb(
            $cb['id'],
            '❌ خطا در ساخت دعوتنامه.',
            true
        );

        return;
    }


    // =========================
    // ذخیره
    // =========================

    try {

        $pdo->beginTransaction();

        $st = $pdo->prepare("
            INSERT INTO event_registration_invites
            (
                event_id,
                token,
                title,
                skip_force_join,
                skip_referral,
                usage_limit,
                used_count,
                is_active,
                created_by,
                created_at
            )
            VALUES
            (
                ?,
                ?,
                ?,
                ?,
                ?,
                ?,
                0,
                1,
                ?,
                NOW()
            )
        ");

        $st->execute([
            $eid,
            $token,
            $title,
            $skipForceJoin,
            $skipReferral,
            $usageLimit,
            $uid
        ]);

        $inviteId = (int)$pdo->lastInsertId();

        // =========================
        // حذف فقط Draft دعوتنامه
        // =========================

        unset($temp['invite']);

        $st = $pdo->prepare("
            UPDATE users
            SET temp = ?
            WHERE id = ?
        ");

        $st->execute([
            json_encode(
                $temp,
                JSON_UNESCAPED_UNICODE |
                JSON_UNESCAPED_SLASHES
            ),
            $uid
        ]);

        $pdo->commit();

    } catch (Throwable $e) {

        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        error_log(
            'INVITE SAVE ERROR | '
            . $e->getMessage()
        );

        answerCb(
            $cb['id'],
            '❌ خطا در ساخت دعوتنامه.',
            true
        );

        return;
    }


    // =========================
    // پاک کردن state
    // =========================

    setState(
        $pdo,
        $uid,
        ''
    );


    // =========================
    // لینک دعوتنامه
    // =========================

    global $bot_username;

    $inviteLink =
        'https://t.me/'
        . $bot_username
        . '?start=event_invite_'
        . $token;


    answerCb(
        $cb['id'],
        '✅ دعوتنامه با موفقیت ساخته شد.'
    );


    // =========================
    // نمایش نتیجه
    // =========================

    $txt  = "🎫 <b>دعوتنامه ساخته شد</b>\n\n";

    $txt .= "🏷 نام: <b>"
        . htmlspecialchars(
            $title,
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        . "</b>\n";

    $txt .= "🎯 ایونت: <code>#{$eid}</code>\n";

    $txt .= "🔐 عضویت اجباری: "
        . ($skipForceJoin
            ? '❌ رد می‌شود'
            : '✅ الزامی')
        . "\n";

    $txt .= "👥 رفرال: "
        . ($skipReferral
            ? '❌ رد می‌شود'
            : '✅ الزامی')
        . "\n";

    $txt .= "🔢 محدودیت استفاده: "
        . (
            $usageLimit === null
                ? '♾ نامحدود'
                : '<code>' . number_format($usageLimit) . '</code>'
        )
        . "\n\n";

    $txt .= "🔗 <b>لینک دعوتنامه:</b>\n";
    $txt .= "<code>{$inviteLink}</code>";


    $ik = [
        [
            [
                'text' => '📋 کپی لینک',
                'copy_text' => [
                    'text' => $inviteLink
                ]
            ]
        ],
        [
            [
                'text' => '🔙 بازگشت به دعوتنامه‌ها',
                'callback_data' => "admin_invites:{$eid}"
            ]
        ],
        [
            [
                'text' => '🔙 مدیریت ایونت',
                'callback_data' => "admin_event_info:{$eid}"
            ]
        ]
    ];


    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );

    exit;
}

//=======================admin_stages=============================

if (str_starts_with($data, 'admin_stages:')) {
    $eid = (int) substr($data, strlen('admin_stages:'));

    if ($eid <= 0) {
        answerCb($cb['id'], '❌ شناسه ایونت نامعتبر است.');
        return;
    }

    answerCb($cb['id'], '');

    renderAdminStages(
        $pdo,
        $chat_id,
        $mid,
        $eid
    );

    return;
}

if (str_starts_with($data, 'admin_stage:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_stage:')
    );

    if ($stageId <= 0) {
        answerCb($cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

        answerCb($cb['id'],'');

    renderAdminStageInfo(
        $pdo,
        $chat_id,
        $mid,
        $stageId
    );

    return;
}

if (str_starts_with($data, 'admin_stage_activate:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_stage_activate:')
    );

    if ($stageId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال فعال‌سازی Stage...'
    );

    try {

        /*
         * Stage را قفل و بررسی می‌کنیم.
         */
        $st = $pdo->prepare("
            SELECT
                id,
                ev_id,
                name,
                type,
                status,
                stage_order
            FROM tournament_stages
            WHERE id = ?
            LIMIT 1
            FOR UPDATE
        ");

        /*
         * اگر Transaction از قبل باز نیست،
         * خودمان باز می‌کنیم.
         */
        $ownsTransaction =
            !$pdo->inTransaction();

        if ($ownsTransaction) {
            $pdo->beginTransaction();
        }

        $st->execute([
            $stageId
        ]);

        $stage =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$stage) {
            throw new RuntimeException(
                'Stage not found.'
            );
        }

        if ($stage['status'] !== 'pending') {
            throw new RuntimeException(
                'فقط Stageهای pending قابل فعال‌سازی هستند.'
            );
        }

        /*
         * جلوگیری از فعال بودن همزمان چند Stage
         * در یک Event.
         */
        $st = $pdo->prepare("
            SELECT id
            FROM tournament_stages
            WHERE ev_id = ?
              AND status = 'active'
              AND id <> ?
            LIMIT 1
            FOR UPDATE
        ");

        $st->execute([
            (int) $stage['ev_id'],
            $stageId
        ]);

        $activeStage =
            $st->fetch(PDO::FETCH_ASSOC);

        if ($activeStage) {
            throw new RuntimeException(
                'یک Stage دیگر از این Event در حال حاضر فعال است.'
            );
        }

        /*
         * Stage را فعال کن.
         */
        $st = $pdo->prepare("
            UPDATE tournament_stages
            SET
                status = 'active',
                updated_at = NOW()
            WHERE id = ?
              AND status = 'pending'
        ");

        $st->execute([
            $stageId
        ]);

        if ($st->rowCount() !== 1) {
            throw new RuntimeException(
                'فعال‌سازی Stage انجام نشد.'
            );
        }

        if ($ownsTransaction) {
            $pdo->commit();
        }

        /*
         * اطلاعات تازه Stage را نمایش بده.
         */
        renderAdminStageInfo(
            $pdo,
            $chat_id,
            $mid,
            $stageId
        );

    } catch (Throwable $e) {

        if (
            isset($ownsTransaction)
            && $ownsTransaction
            && $pdo->inTransaction()
        ) {
            $pdo->rollBack();
        }

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>فعال‌سازی Stage انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_stage_complete:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_stage_complete:')
    );

    if ($stageId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال بررسی Stage...'
    );

    try {

        /*
         * ==========================================
         * Stage
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                id,
                ev_id,
                name,
                type,
                format,
                stage_order,
                status
            FROM tournament_stages
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([
            $stageId
        ]);

        $stage =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$stage) {
            throw new RuntimeException(
                'Stage پیدا نشد.'
            );
        }

        if (
            $stage['status']
            !== 'active'
        ) {
            throw new RuntimeException(
                'فقط Stage فعال قابل پایان است.'
            );
        }

        /*
         * ==========================================
         * Battle Royale
         * ==========================================
         */
        if (
            $stage['format']
            === 'battle_royale'
        ) {

            /*
             * ======================================
             * تعداد Roomها
             * ======================================
             */
            $st = $pdo->prepare("
                SELECT
                    COUNT(*) AS total_rooms,

                    COALESCE(
                        SUM(
                            CASE
                                WHEN status = 'completed'
                                THEN 1
                                ELSE 0
                            END
                        ),
                        0
                    ) AS completed_rooms

                FROM tournament_br_rooms

                WHERE stage_id = ?
            ");

            $st->execute([
                $stageId
            ]);

            $stats =
                $st->fetch(PDO::FETCH_ASSOC);

            $totalRooms =
                (int) (
                    $stats['total_rooms']
                    ?? 0
                );

            $completedRooms =
                (int) (
                    $stats['completed_rooms']
                    ?? 0
                );

            if ($totalRooms === 0) {
                throw new RuntimeException(
                    'این Stage هیچ Roomای ندارد.'
                );
            }

            if (
                $completedRooms
                !==
                $totalRooms
            ) {
                throw new RuntimeException(
                    "همه Roomهای Stage هنوز تکمیل نشده‌اند. "
                    . "("
                    . $completedRooms
                    . "/"
                    . $totalRooms
                    . ")"
                );
            }

            /*
             * ======================================
             * Final
             * ======================================
             *
             * Final Advancement ندارد.
             *
             * FinalStageService:
             *
             * - Resultها را بررسی می‌کند
             * - Leaderboard نهایی را می‌سازد
             * - Champion را مشخص می‌کند
             * - Stage را completed می‌کند
             */
            if (
                strtolower(
                    trim(
                        (string) (
                            $stage['type']
                            ?? ''
                        )
                    )
                ) === 'final'
            ) {

                $finalService =
                    new \Tournament\Stage\FinalStageService(
                        $pdo
                    );

                $finalResult =
                    $finalService->finalize(
                        $stageId
                    );

                $winner =
                    $finalResult['winner'];

                $leaderboard =
                    $finalResult['leaderboard'];

                /*
                 * نام Champion
                 */
                $winnerIgn =
                    htmlspecialchars(
                        (string) (
                            $winner['ign']
                            ?? 'Unknown'
                        ),
                        ENT_QUOTES
                        | ENT_SUBSTITUTE,
                        'UTF-8'
                    );

                /*
                 * Score
                 */
                $winnerScore =
                    number_format(
                        (float) (
                            $winner['score']
                            ?? 0
                        ),
                        2,
                        '.',
                        ''
                    );

                $winnerScore =
                    rtrim(
                        rtrim(
                            $winnerScore,
                            '0'
                        ),
                        '.'
                    );

                if ($winnerScore === '') {
                    $winnerScore = '0';
                }

                /*
                 * پیام Final
                 */
                $message =
                    "🏆 <b>تورنمنت با موفقیت به پایان رسید.</b>\n\n"

                    . "🎯 Stage: <b>"
                    . htmlspecialchars(
                        (string) $stage['name'],
                        ENT_QUOTES
                        | ENT_SUBSTITUTE,
                        'UTF-8'
                    )
                    . "</b>\n\n"

                    . "🥇 <b>Champion</b>\n"
                    . "👤 <b>"
                    . $winnerIgn
                    . "</b>\n"
                    . "🆔 User ID: <code>"
                    . (int) (
                        $winner['user_id']
                        ?? 0
                    )
                    . "</code>\n"
                    . "🧮 Score: <code>"
                    . $winnerScore
                    . "</code>\n"
                    . "🔫 Kills: <code>"
                    . (int) (
                        $winner['kills']
                        ?? 0
                    )
                    . "</code>\n\n"

                    . "👥 Finalists: <code>"
                    . count($leaderboard)
                    . "</code>\n"
                    . "🏠 Roomها: <code>"
                    . $completedRooms
                    . "/"
                    . $totalRooms
                    . "</code>";

                /*
                 * Keyboard
                 */
                $ik = [
                    [
                        [
                            'text' =>
                                '🏆 مشاهده Leaderboard',

                            'callback_data' =>
                                'admin_br_leaderboard:' .
                                $stageId
                        ]
                    ],
                    [
                        [
                            'text' =>
                                '🎯 مدیریت Stage',

                            'callback_data' =>
                                'admin_stage:' .
                                $stageId
                        ]
                    ]
                ];

                editMessageText(
                    $chat_id,
                    $mid,
                    $message,
                    [
                        'inline_keyboard' =>
                            $ik
                    ]
                );

                return;
            }

            /*
             * ======================================
             * BR معمولی
             * ======================================
             */
            $leaderboardService =
                new \Tournament\Stage\BattleRoyaleLeaderboard(
                    $pdo
                );

            $leaderboardResult =
                $leaderboardService->generate(
                    $stageId
                );

            /*
             * ======================================
             * Advancement
             * ======================================
             */
            $advancementService =
                new \Tournament\Stage\BattleRoyaleAdvancement(
                    $pdo
                );

            $advancementResult =
                $advancementService->process(
                    $stageId
                );

            $qualifiedCount =
                (int) (
                    $advancementResult['qualified']
                    ?? 0
                );

            $participantCount =
                (int) (
                    $leaderboardResult['participants']
                    ?? 0
                );

            /*
             * ======================================
             * پایان Stage
             * ======================================
             */
            $st = $pdo->prepare("
                UPDATE tournament_stages
                SET
                    status = 'completed',
                    updated_at = NOW()
                WHERE id = ?
                  AND status = 'active'
            ");

            $st->execute([
                $stageId
            ]);

            if (
                $st->rowCount() !== 1
            ) {
                throw new RuntimeException(
                    'وضعیت Stage تغییر نکرد.'
                );
            }

            /*
             * ======================================
             * Stage بعدی
             * ======================================
             *
             * فقط برای اطلاعات/نمایش.
             * انتقال Participant توسط
             * prepareForStage() انجام می‌شود.
             */
            $st = $pdo->prepare("
                SELECT
                    id,
                    name,
                    format,
                    type,
                    stage_order,
                    status
                FROM tournament_stages
                WHERE ev_id = ?
                  AND stage_order > ?
                ORDER BY stage_order ASC
                LIMIT 1
            ");

            $st->execute([
                (int) $stage['ev_id'],
                (int) (
                    $stage['stage_order']
                    ?? 0
                )
            ]);

            $nextStage =
                $st->fetch(PDO::FETCH_ASSOC);

            /*
             * ======================================
             * نمایش
             * ======================================
             */
            $message =
                "✅ <b>Stage با موفقیت به پایان رسید.</b>\n\n"

                . "🎯 <b>"
                . htmlspecialchars(
                    (string) $stage['name'],
                    ENT_QUOTES
                    | ENT_SUBSTITUTE,
                    'UTF-8'
                )
                . "</b>\n"

                . "🏠 Roomها: <code>"
                . $completedRooms
                . "/"
                . $totalRooms
                . "</code>\n"

                . "👥 بازیکنان: <code>"
                . $participantCount
                . "</code>\n"

                . "⬆️ صعودکنندگان: <code>"
                . $qualifiedCount
                . "</code>";

            $ik = [];

            /*
             * Leaderboard
             */
            $ik[] = [
                [
                    'text' =>
                        '🏆 مشاهده Leaderboard',

                    'callback_data' =>
                        'admin_br_leaderboard:' .
                        $stageId
                ]
            ];

            /*
             * Stage بعدی
             */
            if ($nextStage) {

                $ik[] = [
                    [
                        'text' =>
                            '🎯 مدیریت Stage بعدی',

                        'callback_data' =>
                            'admin_stage:' .
                            (int) $nextStage['id']
                    ]
                ];
            }

            /*
             * مدیریت Stage فعلی
             */
            $ik[] = [
                [
                    'text' =>
                        '🎯 مدیریت Stage',

                    'callback_data' =>
                        'admin_stage:' .
                        $stageId
                ]
            ];

            editMessageText(
                $chat_id,
                $mid,
                $message,
                [
                    'inline_keyboard' =>
                        $ik
                ]
            );

            return;
        }

        /*
         * ==========================================
         * Elimination / Bracket
         * ==========================================
         */
        if (
            in_array(
                $stage['format'],
                [
                    'elimination',
                    'bracket'
                ],
                true
            )
        ) {

            /*
             * اینجا منطق Bracket خودت را نگه دار.
             */
            throw new RuntimeException(
                'منطق پایان Bracket باید در Handler بخش Elimination اجرا شود.'
            );
        }

        throw new RuntimeException(
            'فرمت Stage پشتیبانی نمی‌شود.'
        );

    } catch (Throwable $e) {

        error_log(
            '[STAGE COMPLETE ERROR] '
            . $e->getMessage()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>پایان Stage انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES
                | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_stage_brackets:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_stage_brackets:')
    );

    if ($stageId <= 0) {
        answerCb($cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'],'');

    renderAdminStageBrackets(
        $pdo,
        $chat_id,
        $mid,
        $stageId
    );

    return;
}

if (str_starts_with($data, 'admin_bracket_result:')) {

    $bracketId = (int) substr(
        $data,
        strlen('admin_bracket_result:')
    );

    if ($bracketId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Bracket نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    renderAdminBracketResult(
        $pdo,
        $chat_id,
        $mid,
        $bracketId
    );

    return;
}

if (str_starts_with($data, 'admin_bracket_create:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_bracket_create:')
    );

    if ($stageId <= 0) {
        answerCb($cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'],'');

    setState($pdo, $uid,
        'admin_bracket_create:name:' . $stageId
    );

    editMessageText(
        $chat_id,
        $mid,
        "➕ <b>ساخت Bracket جدید</b>\n\n"
        . "نام Bracket را ارسال کنید.\n\n"
        . "مثال:\n"
        . "<code>Playoff Main Bracket</code>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' =>
                            'admin_stage_brackets:' . $stageId
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_stage_create:')) {
    $eid = (int) substr($data, strlen('admin_stage_create:'));

    if ($eid <= 0) {
        answerCb($cb['id'], '❌ شناسه ایونت نامعتبر است.');
        return;
    }

    answerCb($cb['id'], '');

    // ورود به حالت ایجاد Stage
    setState($pdo, $uid, 'admin_stage_create:name:' . $eid);

    editMessageText(
        $chat_id,
        $mid,
        "➕ <b>ایجاد مرحله جدید</b>\n\n"
        . "لطفاً نام مرحله را ارسال کنید.\n\n"
        . "مثال:\n"
        . "<code>مرحله مقدماتی</code>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' => 'admin_stages:' . $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_br_rooms:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_br_rooms:')
    );

    if ($stageId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    renderAdminBRRooms(
        $pdo,
        $chat_id,
        $mid,
        $stageId
    );

    return;
}

if (str_starts_with($data, 'admin_br_room:')) {

    $roomId = (int) substr(
        $data,
        strlen('admin_br_room:')
    );

    if ($roomId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    renderAdminBRRoomInfo(
        $pdo,
        $chat_id,
        $mid,
        $roomId
    );

    return;
}

if (str_starts_with($data, 'admin_br_room_credentials:')) {

    $roomId = (int) substr(
        $data,
        strlen('admin_br_room_credentials:')
    );

    if ($roomId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    /*
     * وضعیت Room
     */
    $st = $pdo->prepare("
        SELECT
            id,
            stage_id,
            room_number,
            room_game_id,
            room_password
        FROM tournament_br_rooms
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomId
    ]);

    $room =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$room) {
        sendMessage(
            $chat_id,
            '❌ Room پیدا نشد.'
        );
        return;
    }

    setState(
        $pdo,
        $uid,
        'admin_br_room_credentials_id:' .
        $roomId
    );

    sendMessage(
        $chat_id,
        "🎫 <b>تنظیم اطلاعات Custom Room</b>\n\n"
        . "🏠 Room #"
        . (int) $room['room_number']
        . "\n\n"
        . "🆔 <b>Room ID</b> را ارسال کنید."
    );

    return;
}

if (str_starts_with($data, 'admin_br_room_start:')) {

    $roomId = (int) substr(
        $data,
        strlen('admin_br_room_start:')
    );

    if ($roomId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال شروع Room...'
    );

    try {

        $ownsTransaction =
            !$pdo->inTransaction();

        if ($ownsTransaction) {
            $pdo->beginTransaction();
        }

        /*
         * Room را قفل و وضعیت فعلی را بررسی کن.
         */
        $st = $pdo->prepare("
            SELECT
                id,
                stage_id,
                round_number,
                room_number,
                capacity,
                participant_count,
                status
            FROM tournament_br_rooms
            WHERE id = ?
            LIMIT 1
            FOR UPDATE
        ");

        $st->execute([
            $roomId
        ]);

        $room =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$room) {
            throw new RuntimeException(
                'Room not found.'
            );
        }

        if ($room['status'] !== 'ready') {
            throw new RuntimeException(
                'فقط Roomهای آماده قابل شروع هستند.'
            );
        }

        $participantCount =
            (int) $room['participant_count'];

        if ($participantCount < 2) {
            throw new RuntimeException(
                'حداقل 2 بازیکن برای شروع Room لازم است.'
            );
        }

        /*
         * بررسی تعداد واقعی Participantها.
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_room_participants
            WHERE room_id = ?
        ");

        $st->execute([
            $roomId
        ]);

        $actualParticipants =
            (int) $st->fetchColumn();

        if ($actualParticipants !== $participantCount) {
            throw new RuntimeException(
                'تعداد بازیکنان Room با اطلاعات ذخیره‌شده مطابقت ندارد.'
            );
        }

        /*
         * همه Participantها باید ready باشند.
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_room_participants
            WHERE room_id = ?
              AND status = 'ready'
        ");

        $st->execute([
            $roomId
        ]);

        $readyParticipants =
            (int) $st->fetchColumn();

        if ($readyParticipants !== $actualParticipants) {
            throw new RuntimeException(
                'همه بازیکنان Room هنوز آماده نیستند.'
            );
        }

        /*
         * Room را فعال کن.
         */
        $st = $pdo->prepare("
            UPDATE tournament_br_rooms
            SET
                status = 'active',
                updated_at = NOW()
            WHERE id = ?
              AND status = 'ready'
        ");

        $st->execute([
            $roomId
        ]);

        if ($st->rowCount() !== 1) {
            throw new RuntimeException(
                'فعال‌سازی Room انجام نشد.'
            );
        }

        /*
         * وضعیت Participantها → playing
         */
        $st = $pdo->prepare("
            UPDATE tournament_br_room_participants
            SET status = 'playing'
            WHERE room_id = ?
              AND status = 'ready'
        ");

        $st->execute([
            $roomId
        ]);

        if ($ownsTransaction) {
            $pdo->commit();
        }

        /*
         * نمایش مجدد Room
         */
        renderAdminBRRoomInfo(
            $pdo,
            $chat_id,
            $mid,
            $roomId
        );

    } catch (Throwable $e) {

        if (
            isset($ownsTransaction)
            && $ownsTransaction
            && $pdo->inTransaction()
        ) {
            $pdo->rollBack();
        }

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>شروع Room انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_br_room_results:')) {

    $parts = explode(':', $data, 3);

    $roomId = (int) ($parts[1] ?? 0);
    $page   = max(1, (int) ($parts[2] ?? 1));

    if ($roomId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    renderAdminBRRoomResults(
        $pdo,
        $chat_id,
        $mid,
        $roomId,
        $page
    );

    return;
}

if (str_starts_with($data, 'admin_br_result_player:')) {

    $parts = explode(':', $data, 3);

    $roomId =
        (int) ($parts[1] ?? 0);

    $roomParticipantId =
        (int) ($parts[2] ?? 0);

    if (
        $roomId <= 0
        || $roomParticipantId <= 0
    ) {
        answerCb(
            $cb['id'],
            '❌ اطلاعات بازیکن نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    renderAdminBRResultPlayer(
        $pdo,
        $chat_id,
        $mid,
        $uid,
        $roomId,
        $roomParticipantId
    );

    return;
}

if (str_starts_with($data, 'admin_br_result_search_page:')) {

    $parts = explode(':', $data, 3);

    $roomId = (int) ($parts[1] ?? 0);
    $page   = max(1, (int) ($parts[2] ?? 1));

    if ($roomId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    /*
     * Search state
     *
     * admin_br_result_search_query:
     * {roomId}:{query}
     */
    $state = getState(
        $pdo,
        $uid
    );

    if (
        !str_starts_with(
            $state,
            'admin_br_result_search_query:'
        )
    ) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ نشست جستجو منقضی شده است.',
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' =>
                                '🔎 جستجوی دوباره',
                            'callback_data' =>
                                'admin_br_result_search:' .
                                $roomId
                        ]
                    ],
                    [
                        [
                            'text' =>
                                '🔙 ثبت نتایج',
                            'callback_data' =>
                                'admin_br_room_results:' .
                                $roomId
                        ]
                    ]
                ]
            ]
        );

        return;
    }

    /*
     * چون query ممکن است شامل ":" باشد،
     * فقط اولین دو بخش را جدا می‌کنیم.
     */
    $statePrefix =
        'admin_br_result_search_query:';

    $searchState =
        substr(
            $state,
            strlen($statePrefix)
        );

    /*
     * اولین : جداکننده Room ID و Query است.
     */
    $separatorPos =
        strpos(
            $searchState,
            ':'
        );

    if ($separatorPos === false) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ اطلاعات جستجو نامعتبر است.'
        );

        return;
    }

    $stateRoomId =
        (int) substr(
            $searchState,
            0,
            $separatorPos
        );

    $query =
        substr(
            $searchState,
            $separatorPos + 1
        );

    $query =
        trim($query);

    if (
        $stateRoomId !== $roomId
        || $query === ''
    ) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ اطلاعات جستجو نامعتبر است.'
        );

        return;
    }

    renderAdminBRSearchResults(
        $pdo,
        $chat_id,
        $mid,
        $uid,
        $roomId,
        $query,
        $page
    );

    return;
}


if (str_starts_with($data, 'admin_stage_format:')) {

    $parts = explode(':', $data, 3);

    $format = $parts[1] ?? '';
    $eid = (int) ($parts[2] ?? 0);

    $allowedFormats = [
        'elimination',
        'battle_royale',
    ];

    if (!in_array($format, $allowedFormats, true)) {
        answerCb(
            $cb['id'],
            '❌ فرمت مرحله نامعتبر است.'
        );
        return;
    }

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه ایونت نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    $state = getState(
        $pdo,
        $uid
    );

    if (
        !str_starts_with(
            $state,
            'admin_stage_create:format:'
        )
    ) {
        sendMessage(
            $chat_id,
            '❌ نشست ایجاد مرحله منقضی شده است.'
        );
        return;
    }

    $parts = explode(
        ':',
        $state,
        5
    );

    $encodedName =
        $parts[3] ?? '';

    $type =
        $parts[4] ?? '';

    $name = base64_decode(
        $encodedName,
        true
    );

    if (
        $name === false
        || $name === ''
    ) {
        sendMessage(
            $chat_id,
            '❌ نام مرحله قابل بازیابی نیست.'
        );
        return;
    }

    /*
     * Battle Royale
     */
    if ($format === 'battle_royale') {

        setState(
            $pdo,
            $uid,
            'admin_stage_create:br_match_size:' .
            $eid .
            ':' .
            base64_encode($name) .
            ':' .
            $type
        );

        sendMessage(
            $chat_id,
            "🔥 <b>تنظیم Battle Royale</b>\n\n"
            . "👥 تعداد بازیکن در هر Custom Room را وارد کنید.\n\n"
            . "برای Free Fire Solo:\n"
            . "<code>48</code>"
        );

        return;
    }

    /*
     * Elimination
     */
    setState(
        $pdo,
        $uid,
        'admin_stage_create:elimination:' .
        $eid .
        ':' .
        base64_encode($name) .
        ':' .
        $type
    );

    sendMessage(
        $chat_id,
        "⚔️ <b>تنظیم Elimination</b>\n\n"
        . "نوع حذفی را انتخاب کنید:",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '1️⃣ Single Elimination',
                        'callback_data' =>
                            'admin_stage_elimination:single:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' => '2️⃣ Double Elimination',
                        'callback_data' =>
                            'admin_stage_elimination:double:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' =>
                            'admin_stages:' . $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_stage_type:')) {

    $parts = explode(':', $data, 3);

    $type = $parts[1] ?? '';
    $eid  = (int) ($parts[2] ?? 0);

    $allowedTypes = [
        'qualification',
        'group',
        'playoff',
        'final'

    ];

    if (!in_array($type, $allowedTypes, true)) {
        answerCb(
            $cb['id'],
            '❌ نوع مرحله نامعتبر است.'
        );
        return;
    }

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه ایونت نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    /*
     * نام مرحله از state قبلی
     */
    $state = getState(
        $pdo,
        $uid
    );

    if (
        !str_starts_with(
            $state,
            'admin_stage_create:type:'
        )
    ) {
        sendMessage(
            $chat_id,
            '❌ نشست ایجاد مرحله منقضی شده است.'
        );
        return;
    }

    $stateParts =
        explode(
            ':',
            $state,
            4
        );

    $stateEid =
        (int) ($stateParts[2] ?? 0);

    $encodedName =
        $stateParts[3] ?? '';

    /*
     * اطمینان از یکسان بودن Event
     */
    if ($stateEid !== $eid) {
        sendMessage(
            $chat_id,
            '❌ اطلاعات Event با نشست فعلی مطابقت ندارد.'
        );
        return;
    }

    $name = base64_decode(
        $encodedName,
        true
    );

    if (
        $name === false
        || $name === ''
    ) {
        sendMessage(
            $chat_id,
            '❌ نام مرحله قابل بازیابی نیست.'
        );
        return;
    }

    /*
     * ذخیره اطلاعات فعلی و رفتن به انتخاب Format
     */
    setState(
        $pdo,
        $uid,
        'admin_stage_create:format:' .
        $eid .
        ':' .
        base64_encode($name) .
        ':' .
        $type
    );

    sendMessage(
        $chat_id,
        "🎮 <b>فرمت مرحله را انتخاب کنید:</b>\n\n"
        . "⚔️ <b>Elimination</b>\n"
        . "برای Single / Double Elimination\n\n"
        . "🔥 <b>Battle Royale</b>\n"
        . "برای مسابقات Free Fire با Custom Room",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '⚔️ Elimination',
                        'callback_data' =>
                            'admin_stage_format:elimination:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' => '🔥 Battle Royale',
                        'callback_data' =>
                            'admin_stage_format:battle_royale:' .
                            $eid
                    ]
                ],
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' =>
                            'admin_stages:' .
                            $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_bracket:')) {

    $bracketId = (int) substr(
        $data,
        strlen('admin_bracket:')
    );

    if ($bracketId <= 0) {
        answerCb($cb['id'],
            '❌ شناسه Bracket نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'],'');

    renderAdminBracketInfo(
        $pdo,
        $chat_id,
        $mid,
        $bracketId
    );

    return;
}

if (str_starts_with($data, 'admin_bracket_generate:')) {

    $bracketId = (int) substr(
        $data,
        strlen('admin_bracket_generate:')
    );

    if ($bracketId <= 0) {
        answerCb($cb['id'],
            '❌ شناسه Bracket نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'],'');

    $st = $pdo->prepare("
        SELECT
            tb.id,
            tb.stage_id,
            tb.name,
            tb.type,
            tb.status,
            tb.participant_count,
            ts.name AS stage_name,
            ts.status AS stage_status,
            ts.ev_id
        FROM tournament_brackets tb
        INNER JOIN tournament_stages ts
            ON ts.id = tb.stage_id
        WHERE tb.id = ?
        LIMIT 1
    ");

    $st->execute([$bracketId]);

    $bracket = $st->fetch(PDO::FETCH_ASSOC);
    

    if (!$bracket) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Bracket پیدا نشد.'
        );
        return;
    }

    if ($bracket['status'] !== 'pending') {
        editMessageText(
            $chat_id,
            $mid,
            '❌ این Bracket قبلاً تولید شده یا دیگر قابل تولید نیست.'
        );
        return;
    }

    if ($bracket['type'] !== 'single_elimination') {
        editMessageText(
            $chat_id,
            $mid,
            '❌ نوع Bracket پشتیبانی نمی‌شود.'
        );
        return;
    }

    /*
     * تعداد شرکت‌کنندگان واقعی Stage
     */
    $st = $pdo->prepare("
        SELECT COUNT(*)
        FROM event_players
        WHERE ev_id = ?
          AND status = 'accepted'
    ");

    $st->execute([
        $bracket['ev_id']
    ]);

    $playerCount =
        (int) $st->fetchColumn();

    if ($playerCount < 2) {
        editMessageText(
            $chat_id,
            $mid,
            "❌ حداقل 2 شرکت‌کننده برای تولید Bracket لازم است.\n\n"
            . "👥 شرکت‌کنندگان فعلی: <code>{$playerCount}</code>"
        );
        return;
    }

    $requiredCount =
        (int) $bracket['participant_count'];

    if (
        $requiredCount > 0
        && $playerCount < $requiredCount
    ) {
        editMessageText(
            $chat_id,
            $mid,
            "❌ تعداد شرکت‌کنندگان کافی نیست.\n\n"
            . "👥 موردنیاز: <code>{$requiredCount}</code>\n"
            . "👤 موجود: <code>{$playerCount}</code>"
        );
        return;
    }

    /*
     * تعداد واقعی مورد استفاده
     */
    $useCount =
        $requiredCount > 0
            ? min($requiredCount, $playerCount)
            : $playerCount;

    /*
     * دریافت بازیکنان
     */
    $st = $pdo->prepare("
        SELECT
            id,
            user_id,
            ign,
            squad_id
        FROM event_players
        WHERE ev_id = ?
          AND status = 'accepted'
        ORDER BY id ASC
        LIMIT {$useCount}
    ");

    $st->execute([
        $bracket['ev_id']
    ]);

    $players =
        $st->fetchAll(PDO::FETCH_ASSOC);

    if (count($players) !== $useCount) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ هنگام دریافت شرکت‌کنندگان خطایی رخ داد.'
        );
        return;
    }

    /*
     * محاسبه اندازه Bracket
     */
    $bracketSize = 1;

    while ($bracketSize < $useCount) {
        $bracketSize *= 2;
    }

    $byeCount =
        $bracketSize - $useCount;

    $rounds =
        (int) log($bracketSize, 2);

    $matches =
        $bracketSize - 1;

    /*
     * نمایش تأیید نهایی
     */
    $txt =
        "⚙️ <b>تولید Bracket</b>\n\n"
        . "🏟 Bracket: <b>{$bracket['name']}</b>\n"
        . "🎯 Stage: <b>{$bracket['stage_name']}</b>\n\n"
        . "👥 شرکت‌کنندگان: <code>{$useCount}</code>\n"
        . "📐 اندازه Bracket: <code>{$bracketSize}</code>\n"
        . "🔄 Roundها: <code>{$rounds}</code>\n"
        . "🎮 Matchها: <code>{$matches}</code>\n"
        . "🆓 BYE: <code>{$byeCount}</code>\n\n"
        . "⚠️ بعد از تولید، ساختار Bracket ایجاد می‌شود.";

    $ik = [
        [
            [
                'text' => '✅ تأیید و تولید',
                'callback_data' =>
                    'admin_bracket_generate_confirm:' .
                    $bracketId
            ]
        ],
        [
            [
                'text' => '❌ انصراف',
                'callback_data' =>
                    'admin_bracket:' . $bracketId
            ]
        ]
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' => $ik
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_bracket_generate_confirm:')) {

    $bracketId = (int) substr(
        $data,
        strlen('admin_bracket_generate_confirm:')
    );

    if ($bracketId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Bracket نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال تولید Bracket...'
    );

    /*
     * دریافت Bracket + Stage
     */
    $st = $pdo->prepare("
        SELECT
            tb.id,
            tb.stage_id,
            tb.name,
            tb.type,
            tb.status,
            tb.participant_count,
            ts.name AS stage_name,
            ts.status AS stage_status,
            ts.ev_id
        FROM tournament_brackets tb
        INNER JOIN tournament_stages ts
            ON ts.id = tb.stage_id
        WHERE tb.id = ?
        LIMIT 1
    ");

    $st->execute([
        $bracketId
    ]);

    $bracket = $st->fetch(
        PDO::FETCH_ASSOC
    );

    if (!$bracket) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Bracket پیدا نشد.'
        );
        return;
    }

    /*
     * Bracket باید pending باشد.
     */
    if ($bracket['status'] !== 'pending') {
        editMessageText(
            $chat_id,
            $mid,
            '❌ این Bracket قبلاً تولید شده یا قابل تولید نیست.'
        );
        return;
    }

    /*
     * فقط Single Elimination
     */
    if ($bracket['type'] !== 'single_elimination') {
        editMessageText(
            $chat_id,
            $mid,
            '❌ این نوع Bracket فعلاً پشتیبانی نمی‌شود.'
        );
        return;
    }

    /*
     * Stage باید قابل اجرا باشد.
     */
    if (
        !in_array(
            $bracket['stage_status'],
            ['pending', 'active'],
            true
        )
    ) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Stage در وضعیت فعلی قابل اجرای Bracket نیست.'
        );
        return;
    }

    try {

    error_log(
    '[BRACKET DEBUG] PDO transaction before service: ' .
    (
        $pdo->inTransaction()
            ? 'YES'
            : 'NO'
    )
);

        /*
         * 1. آماده‌سازی شرکت‌کنندگان Stage
         */
        $participantService =
            new \Tournament\Stage\StageParticipantService(
                $pdo
            );

        $participantIds =
            $participantService->prepareParticipants(
                (int) $bracket['stage_id'],
                (int) $bracket['participant_count']
            );

            error_log(
    '[BRACKET DEBUG] PDO transaction after participant service: ' .
    (
        $pdo->inTransaction()
            ? 'YES'
            : 'NO'
    )
);

        if (count($participantIds) < 2) {
            throw new RuntimeException(
                'At least 2 participants are required.'
            );
        }

        /*
         * 2. ساخت ByeHandler
         */
        $progression =
            new \Tournament\Bracket\BracketProgression(
                $pdo
            );

        $byeHandler =
            new \Tournament\Bracket\ByeHandler(
                $pdo,
                $progression
            );

        /*
         * 3. ساخت Validator
         */
        $validator =
            new \Tournament\Bracket\BracketValidator(
                $pdo
            );

        /*
         * 4. ساخت Generator
         */
        $generator =
            new \Tournament\Bracket\TournamentBracketGenerator(
                $pdo,
                $byeHandler
            );


        error_log(
            '[BRACKET DEBUG] Generator file: ' .
            (
                new ReflectionClass(
                    \Tournament\Bracket\TournamentBracketGenerator::class
                )
            )->getFileName()
        );

        error_log(
            '[BRACKET DEBUG] PDO transaction before generate: ' .
            (
                $pdo->inTransaction()
                    ? 'YES'
                    : 'NO'
            )
        );

        /*
         * 5. Generate
         *
         * نکته:
         * Generator فعلی خودش participants را
         * از DB می‌خواند؛ بنابراین فقط کافی است
         * participantهای Stage آماده باشند.
         */
        $result =
            $generator->generate(
                (int) $bracket['id'],
                (int) $bracket['stage_id']
            );

        /*
         * 6. نمایش نتیجه
         */
        $txt =
            "✅ <b>Bracket با موفقیت تولید شد.</b>\n\n"
            . "🏟 <b>{$bracket['name']}</b>\n"
            . "🎯 Stage: <b>{$bracket['stage_name']}</b>\n\n"
            . "👥 شرکت‌کنندگان: "
            . "<code>{$result['participant_count']}</code>\n"
            . "📐 اندازه Bracket: "
            . "<code>{$result['bracket_size']}</code>\n"
            . "🔄 Roundها: "
            . "<code>{$result['rounds']}</code>\n"
            . "🎮 Matchها: "
            . "<code>{$result['matches']}</code>\n"
            . "🆓 BYE: "
            . "<code>{$result['bye_count']}</code>\n"
            . "⚡ BYE پردازش‌شده: "
            . "<code>{$result['bye_processed']}</code>\n"
            . "➡️ صعود از BYE: "
            . "<code>{$result['participants_advanced_by_bye']}</code>";

        editMessageText(
            $chat_id,
            $mid,
            $txt,
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' => '🏟 مشاهده Bracket',
                            'callback_data' =>
                                'admin_bracket:' .
                                $bracketId
                        ]
                    ],
                    [
                        [
                            'text' => '🎯 مدیریت Stage',
                            'callback_data' =>
                                'admin_stage:' .
                                $bracket['stage_id']
                        ]
                    ],
                    [
                        [
                            'text' => '🔙 Bracketهای Stage',
                            'callback_data' =>
                                'admin_stage_brackets:' .
                                $bracket['stage_id']
                        ]
                    ]
                ]
            ]
        );

    } catch (Throwable $e) {

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>تولید Bracket انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES,
                'UTF-8'
            )
            . "</code>\n\n"
            . "Bracket همچنان در وضعیت <b>pending</b> باقی می‌ماند."
        );
    }

    return;
}

if (str_starts_with($data, 'admin_bracket_matches:')) {

    $bracketId = (int) substr(
        $data,
        strlen('admin_bracket_matches:')
    );

    if ($bracketId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Bracket نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    renderAdminBracketMatches(
        $pdo,
        $chat_id,
        $mid,
        $bracketId
    );

    return;
}


if (str_starts_with($data, 'admin_match:')) {

    $matchId = (int) substr(
        $data,
        strlen('admin_match:')
    );

    if ($matchId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Match نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    renderAdminMatchInfo(
        $pdo,
        $chat_id,
        $mid,
        $matchId
    );

    return;
}

if (str_starts_with($data, 'admin_match_winner:')) {

    $parts = explode(':', $data, 3);

    $matchId = (int) ($parts[1] ?? 0);
    $slot = $parts[2] ?? '';

    if (
        $matchId <= 0
        || !in_array(
            $slot,
            ['a', 'b'],
            true
        )
    ) {
        answerCb(
            $cb['id'],
            '❌ اطلاعات نتیجه نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال ثبت نتیجه...'
    );

    /*
     * پیدا کردن participant بر اساس slot
     */
    $st = $pdo->prepare("
        SELECT
            tournament_participant_id
        FROM tournament_match_participants
        WHERE match_id = ?
          AND (
              slot = ?
              OR (
                  ? = 'a'
                  AND slot = 1
              )
              OR (
                  ? = 'b'
                  AND slot = 2
              )
          )
        LIMIT 1
    ");

    $st->execute([
        $matchId,
        $slot,
        $slot,
        $slot,
    ]);

    $winnerParticipantId =
        $st->fetchColumn();

    if ($winnerParticipantId === false) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ بازیکن انتخاب‌شده در این Match پیدا نشد.'
        );
        return;
    }

    try {
        $pdo->beginTransaction();

        /*
        * Match را قفل و وضعیت فعلی را بررسی کن.
        */
        $st = $pdo->prepare("
            SELECT
                id,
                bracket_id,
                status,
                is_bye
            FROM tournament_matches
            WHERE id = ?
            FOR UPDATE
        ");

        $st->execute([
            $matchId
        ]);

        $match = $st->fetch(
            PDO::FETCH_ASSOC
        );

        if (!$match) {
            throw new RuntimeException(
                'Match not found.'
            );
        }

        if (
            !in_array(
                $match['status'],
                ['pending', 'ready', 'active'],
                true
            )
        ) {
            throw new RuntimeException(
                'Match is not available for result submission.'
            );
        }

        if ((int) $match['is_bye'] === 1) {
            throw new RuntimeException(
                'BYE match cannot receive a manual result.'
            );
        }

        /*
        * بررسی کن Winner واقعاً یکی از
        * شرکت‌کنندگان همین Match باشد.
        */
        $st = $pdo->prepare("
            SELECT
                tournament_participant_id
            FROM tournament_match_participants
            WHERE match_id = ?
            AND tournament_participant_id = ?
            LIMIT 1
        ");

        $st->execute([
            $matchId,
            (int) $winnerParticipantId
        ]);

        if ($st->fetchColumn() === false) {
            throw new RuntimeException(
                'Selected winner is not a participant of this match.'
            );
        }

        /*
        * Match را تمام کن.
        */
        $st = $pdo->prepare("
            UPDATE tournament_matches
            SET
                status = 'finished',
                winner_participant_id = ?,
                finished_at = NOW()
            WHERE id = ?
            AND status IN ('pending', 'ready', 'active')
        ");

        $st->execute([
            (int) $winnerParticipantId,
            $matchId
        ]);

        if ($st->rowCount() !== 1) {
            throw new RuntimeException(
                'Failed to finish match.'
            );
        }

        /*
        * وضعیت شرکت‌کنندگان Match
        */
        $st = $pdo->prepare("
            UPDATE tournament_match_participants
            SET status = 'finished'
            WHERE match_id = ?
        ");

        $st->execute([
            $matchId
        ]);

        /*
        * حالا Progression می‌تواند Winner را
        * به Match بعدی منتقل کند.
        */
        $progression =
            new \Tournament\Bracket\BracketProgression(
                $pdo
            );

        $progression->advanceWinner(
            matchId: $matchId,
            winnerParticipantId:
                (int) $winnerParticipantId
        );

        $pdo->commit();

        renderAdminMatchInfo(
            $pdo,
            $chat_id,
            $mid,
            $matchId
        );

    } catch (Throwable $e) {

        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>ثبت نتیجه انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_match_result:')) {

    $matchId = (int) substr(
        $data,
        strlen('admin_match_result:')
    );

    if ($matchId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Match نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    renderAdminMatchResult(
        $pdo,
        $chat_id,
        $mid,
        $matchId
    );

    return;
}

if (str_starts_with($data, 'admin_stage_advancement:')) {

    $parts = explode(':', $data, 3);

    $advancementType = $parts[1] ?? '';
    $eid = (int) ($parts[2] ?? 0);

    $allowedTypes = [
        'top_n',
        'percentage',
        'points',
    ];

    if (!in_array($advancementType, $allowedTypes, true)) {
        answerCb(
            $cb['id'],
            '❌ قانون صعود نامعتبر است.'
        );
        return;
    }

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه ایونت نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    $state = getState(
        $pdo,
        $uid
    );

    if (
        !str_starts_with(
            $state,
            'admin_stage_create:br_advancement:'
        )
    ) {
        sendMessage(
            $chat_id,
            '❌ نشست ایجاد Stage منقضی شده است.'
        );
        return;
    }

    $stateParts = explode(
        ':',
        $state,
        7
    );

    $stateEid =
        (int) ($stateParts[2] ?? 0);

    $encodedName =
        $stateParts[3] ?? '';

    $type =
        $stateParts[4] ?? '';

    $matchSize =
        (int) ($stateParts[5] ?? 0);

    $matchesPerPlayer =
        (int) ($stateParts[6] ?? 0);

    if ($stateEid !== $eid) {
        sendMessage(
            $chat_id,
            '❌ اطلاعات Event با نشست فعلی مطابقت ندارد.'
        );
        return;
    }

    $name = base64_decode(
        $encodedName,
        true
    );

    if (
        $name === false
        || $name === ''
        || $type === ''
        || $matchSize < 2
        || $matchesPerPlayer < 1
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات تنظیمات Battle Royale نامعتبر است.'
        );
        return;
    }

    /*
     * Top N
     */
    if ($advancementType === 'top_n') {

        setState(
            $pdo,
            $uid,
            'admin_stage_create:br_advancement_count:' .
            $eid .
            ':' .
            base64_encode($name) .
            ':' .
            $type .
            ':' .
            $matchSize .
            ':' .
            $matchesPerPlayer .
            ':top_n'
        );

        sendMessage(
            $chat_id,
            "🏅 <b>تعداد صعودی‌ها را وارد کنید:</b>\n\n"
            . "مثلاً اگر از هر Stage قرار است 48 نفر صعود کنند:\n"
            . "<code>48</code>"
        );

        return;
    }

    /*
     * Percentage
     */
    if ($advancementType === 'percentage') {

        setState(
            $pdo,
            $uid,
            'admin_stage_create:br_advancement_count:' .
            $eid .
            ':' .
            base64_encode($name) .
            ':' .
            $type .
            ':' .
            $matchSize .
            ':' .
            $matchesPerPlayer .
            ':percentage'
        );

        sendMessage(
            $chat_id,
            "📊 <b>درصد صعودی‌ها را وارد کنید:</b>\n\n"
            . "عددی بین <code>1</code> تا <code>100</code> وارد کنید.\n\n"
            . "مثال:\n"
            . "<code>20</code>"
        );

        return;
    }

    /*
     * Points
     */
    if ($advancementType === 'points') {

        setState(
            $pdo,
            $uid,
            'admin_stage_create:br_advancement_count:' .
            $eid .
            ':' .
            base64_encode($name) .
            ':' .
            $type .
            ':' .
            $matchSize .
            ':' .
            $matchesPerPlayer .
            ':points'
        );

        sendMessage(
            $chat_id,
            "🎯 <b>حداقل امتیاز صعود را وارد کنید:</b>\n\n"
            . "مثال:\n"
            . "<code>20</code>"
        );

        return;
    }

    return;
}

if (str_starts_with($data, 'admin_stage_scoring:')) {

    $parts = explode(':', $data, 3);

    $scoringStrategy = $parts[1] ?? '';
    $eid = (int) ($parts[2] ?? 0);

    $allowedStrategies = [
        'placement_kills',
        'default',
    ];

    if (
        !in_array(
            $scoringStrategy,
            $allowedStrategies,
            true
        )
    ) {
        answerCb(
            $cb['id'],
            '❌ سیستم امتیازدهی نامعتبر است.'
        );
        return;
    }

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه ایونت نامعتبر است.'
        );
        return;
    }

    answerCb($cb['id'], '');

    $state = getState(
        $pdo,
        $uid
    );

    if (
        !str_starts_with(
            $state,
            'admin_stage_create:br_scoring:'
        )
    ) {
        sendMessage(
            $chat_id,
            '❌ نشست ایجاد Stage منقضی شده است.'
        );
        return;
    }

    $stateParts = explode(
        ':',
        $state,
        9
    );

    $stateEid =
        (int) ($stateParts[2] ?? 0);

    $encodedName =
        $stateParts[3] ?? '';

    $type =
        $stateParts[4] ?? '';

    $matchSize =
        (int) ($stateParts[5] ?? 0);

    $matchesPerPlayer =
        (int) ($stateParts[6] ?? 0);

    $advancementType =
        $stateParts[7] ?? '';

    $advancementValue =
        $stateParts[8] ?? '';

    if ($stateEid !== $eid) {
        sendMessage(
            $chat_id,
            '❌ اطلاعات Event با نشست فعلی مطابقت ندارد.'
        );
        return;
    }

    $name = base64_decode(
        $encodedName,
        true
    );

    if (
        $name === false
        || $name === ''
        || $type === ''
        || $matchSize < 2
        || $matchesPerPlayer < 1
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات تنظیمات Stage نامعتبر است.'
        );
        return;
    }

    if (
        $type === 'final'
    ) {

        if (
            $advancementType !== 'champion'
            || (string) $advancementValue !== '0'
        ) {
            setState(
                $pdo,
                $uid,
                ''
            );

            sendMessage(
                $chat_id,
                '❌ تنظیمات صعود Final نامعتبر است.'
            );

            return;
        }

    } else {

        if (
            !in_array(
                $advancementType,
                [
                    'top_n',
                    'percentage',
                    'points',
                ],
                true
            )
        ) {
            setState(
                $pdo,
                $uid,
                ''
            );

            sendMessage(
                $chat_id,
                '❌ قانون صعود نامعتبر است.'
            );

            return;
        }
    }

    /*
     * ذخیره اطلاعات کامل تا مرحله تأیید نهایی.
     */
    setState(
        $pdo,
        $uid,
        'admin_stage_create:confirm:' .
        $eid .
        ':' .
        base64_encode($name) .
        ':' .
        $type .
        ':battle_royale' .
        ':' .
        $matchSize .
        ':' .
        $matchesPerPlayer .
        ':' .
        $advancementType .
        ':' .
        $advancementValue .
        ':' .
        $scoringStrategy
    );

    $advancementLabel = match ($advancementType) {
        'top_n' =>
            '🏅 Top ' . $advancementValue,

        'percentage' =>
            '📊 ' . $advancementValue . '%',

        'points' =>
            '🎯 حداقل ' . $advancementValue . ' امتیاز',

        'champion' =>
            '🏆 Champion',

        default =>
            $advancementType,
    };

    $scoringLabel = match ($scoringStrategy) {
        'placement_kills' =>
            '🏆 Placement + Kills',

        'default' =>
            '🎯 Score مستقیم',

        default =>
            $scoringStrategy,
    };

    sendMessage(
        $chat_id,
        "✅ <b>تنظیمات Stage آماده است</b>\n\n"
        . "🎯 نام: <b>"
        . htmlspecialchars(
            $name,
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n"
        . "📌 نوع: <code>{$type}</code>\n"
        . "🔥 فرمت: <code>battle_royale</code>\n"
        . "👥 Room Size: <code>{$matchSize}</code>\n"
        . "🎮 بازی برای هر بازیکن: <code>{$matchesPerPlayer}</code>\n"
        . "📈 صعود: <b>{$advancementLabel}</b>\n"
        . "🧮 امتیازدهی: <b>{$scoringLabel}</b>\n\n"
        . "آیا Stage ساخته شود؟",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '✅ ساخت Stage',
                        'callback_data' =>
                            'admin_stage_create_confirm:' . $eid
                    ]
                ],
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' =>
                            'admin_stages:' . $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_br_generate:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_br_generate:')
    );

    if ($stageId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال آماده‌سازی Roomها...'
    );

    /*
     * Stage
     */
    $st = $pdo->prepare("
        SELECT
            id,
            name,
            type,
            format,
            stage_order,
            match_size,
            matches_per_player,
            advancement_type,
            advancement_count,
            scoring_strategy,
            status,
            ev_id
        FROM tournament_stages
        WHERE id = ?
        LIMIT 1
    ");

    $st->execute([
        $stageId
    ]);

    $stage =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$stage) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ Stage پیدا نشد.'
        );
        return;
    }

    /*
     * فقط Battle Royale
     */
    if ($stage['format'] !== 'battle_royale') {
        editMessageText(
            $chat_id,
            $mid,
            '❌ این Stage از نوع Battle Royale نیست.'
        );
        return;
    }

    /*
     * فقط pending
     */
    if ($stage['status'] !== 'pending') {
        editMessageText(
            $chat_id,
            $mid,
            '❌ فقط Stageهای pending قابل تولید Room هستند.'
        );
        return;
    }

    $matchSize =
        (int) $stage['match_size'];

    $matchesPerPlayer =
        (int) $stage['matches_per_player'];

    /*
     * ==========================================
     * تعداد Participantهای همین Stage
     * ==========================================
     *
     * Stage اول:
     * ممکن است هنوز participant نداشته باشد
     *
     * Stageهای بعدی:
     * باید Participantهای Qualified شده را
     * از Stage قبلی داشته باشند.
     */
    $st = $pdo->prepare("
        SELECT COUNT(*)
        FROM tournament_stage_participants
        WHERE stage_id = ?
          AND status = 'active'
    ");

    $st->execute([
        $stageId
    ]);

    $participantCount =
        (int) $st->fetchColumn();

    /*
     * ==========================================
     * اگر Stage اول است و هنوز Participant
     * ساخته نشده، تعداد accepted Event Players
     * را فقط برای Preview نشان بده.
     * ==========================================
     */
    if (
        $participantCount === 0
        && (int) $stage['stage_order'] === 1
    ) {
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM event_players
            WHERE ev_id = ?
              AND status = 'accepted'
        ");

        $st->execute([
            (int) $stage['ev_id']
        ]);

        $participantCount =
            (int) $st->fetchColumn();
    }


    /*
    * ==========================================
    * اگر Stage بعدی است و هنوز Participant
    * برای آن ساخته نشده، Qualifiedهای Stage
    * قبلی را فقط برای Preview بشمار.
    * ==========================================
    */
    if (
        $participantCount === 0
        && (int) $stage['stage_order'] > 1
    ) {
        $st = $pdo->prepare("
            SELECT
                COUNT(*)
            FROM tournament_stage_advancements sa
            INNER JOIN tournament_stages ps
                ON ps.id = sa.from_stage_id
            WHERE ps.ev_id = ?
            AND ps.stage_order = (
                SELECT
                    stage_order - 1
                FROM tournament_stages
                WHERE id = ?
            )
            AND sa.status = 'qualified'
        ");

        $st->execute([
            (int) $stage['ev_id'],
            $stageId
        ]);

        $participantCount =
            (int) $st->fetchColumn();
    }

    if ($participantCount < 2) {
        editMessageText(
            $chat_id,
            $mid,
            '❌ حداقل 2 شرکت‌کننده برای تولید Room لازم است.'
        );
        return;
    }

    /*
     * محاسبات Preview
     */
    $roomsPerRound =
        (int) ceil(
            $participantCount /
            max(1, $matchSize)
        );

    $totalRooms =
        $roomsPerRound *
        max(
            1,
            $matchesPerPlayer
        );

    /*
     * متن
     */
    $txt =
        "🔥 <b>تولید Roomهای Battle Royale</b>\n\n"
        . "🎯 Stage: <b>"
        . htmlspecialchars(
            (string) $stage['name'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        . "</b>\n"
        . "👥 شرکت‌کنندگان: <code>"
        . $participantCount
        . "</code>\n"
        . "🎮 بازیکن در هر Room: <code>"
        . $matchSize
        . "</code>\n"
        . "🔄 بازی برای هر بازیکن: <code>"
        . $matchesPerPlayer
        . "</code>\n"
        . "🏠 Room در هر Round: <code>"
        . $roomsPerRound
        . "</code>\n"
        . "📦 مجموع Roomها: <code>"
        . $totalRooms
        . "</code>\n\n"
        . "⚠️ بعد از تأیید، Participantهای این Stage "
        . "مشخص و Roomها ساخته می‌شوند.";

    /*
     * Keyboard
     */
    $ik = [
        [
            [
                'text' =>
                    '✅ تأیید و تولید Roomها',

                'callback_data' =>
                    'admin_br_generate_confirm:' .
                    $stageId
            ]
        ],
        [
            [
                'text' =>
                    '❌ انصراف',

                'callback_data' =>
                    'admin_stage:' .
                    $stageId
            ]
        ],
    ];

    editMessageText(
        $chat_id,
        $mid,
        $txt,
        [
            'inline_keyboard' =>
                $ik
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_br_generate_confirm:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_br_generate_confirm:')
    );

    if ($stageId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال آماده‌سازی شرکت‌کنندگان و تولید Roomها...'
    );

    try {

        /*
         * ==========================================
         * دریافت اطلاعات Stage
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                id,
                ev_id,
                name,
                type,
                format,
                stage_order,
                status
            FROM tournament_stages
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([
            $stageId
        ]);

        $stage =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$stage) {
            throw new RuntimeException(
                'Stage پیدا نشد.'
            );
        }

        /*
         * فقط Battle Royale
         */
        if ($stage['format'] !== 'battle_royale') {
            throw new RuntimeException(
                'این Stage از نوع Battle Royale نیست.'
            );
        }

        /*
         * ==========================================
         * آماده‌سازی Participantهای Stage
         *
         * Stage اول:
         * accepted event_players
         *
         * Stage دوم به بعد:
         * Qualifiedهای Stage قبلی
         * ==========================================
         */
        $participantService =
            new \Tournament\Stage\StageParticipantService(
                $pdo
            );

        $participantIds =
            $participantService->prepareForStage(
                $stageId
            );

        $participantCount =
            count($participantIds);

        if ($participantCount < 2) {
            throw new RuntimeException(
                'حداقل 2 شرکت‌کننده برای این Stage لازم است.'
            );
        }

        /*
         * ==========================================
         * جلوگیری از Generate مجدد
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_rooms
            WHERE stage_id = ?
        ");

        $st->execute([
            $stageId
        ]);

        $existingRooms =
            (int) $st->fetchColumn();

        if ($existingRooms > 0) {
            throw new RuntimeException(
                'Roomهای این Stage قبلاً تولید شده‌اند.'
            );
        }

        /*
         * ==========================================
         * تولید Roomهای Battle Royale
         * ==========================================
         */
        $generator =
            new \Tournament\Stage\BattleRoyaleStageGenerator(
                $pdo
            );

        $result =
            $generator->generate(
                $stageId
            );

        /*
         * ==========================================
         * پیام موفقیت
         * ==========================================
         */
        $roomCount =
            (int) (
                $result['total_rooms']
                ?? 0
            );

        $roundCount =
            (int) (
                $result['rounds']
                ?? 0
            );

        editMessageText(
            $chat_id,
            $mid,
            "✅ <b>Roomهای Battle Royale با موفقیت تولید شدند.</b>\n\n"
            . "🎯 Stage: <b>"
            . htmlspecialchars(
                (string) $stage['name'],
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</b>\n"
            . "👥 شرکت‌کنندگان: <code>"
            . $participantCount
            . "</code>\n"
            . "🔥 Roundها: <code>"
            . $roundCount
            . "</code>\n"
            . "🏠 Roomها: <code>"
            . $roomCount
            . "</code>",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' =>
                                '🏠 مدیریت Roomها',
                            'callback_data' =>
                                'admin_br_rooms:' .
                                $stageId
                        ]
                    ],
                    [
                        [
                            'text' =>
                                '🎯 مشاهده Stage',
                            'callback_data' =>
                                'admin_stage:' .
                                $stageId
                        ]
                    ]
                ]
            ]
        );

    } catch (Throwable $e) {

        error_log(
            '[BR GENERATE ERROR] '
            . 'stage_id='
            . $stageId
            . ' | '
            . $e->getMessage()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>تولید Roomها انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_br_result_search:')) {

    $roomId = (int) substr(
        $data,
        strlen('admin_br_result_search:')
    );

    if ($roomId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    /*
     * منتظر دریافت متن جستجو
     */
    setState(
        $pdo,
        $uid,
        'admin_br_result_search:' . $roomId
    );

    sendMessage(
        $chat_id,
        "🔎 <b>جستجوی بازیکن</b>\n\n"
        . "UID یا نام بازیکن را ارسال کنید.\n\n"
        . "مثال:\n"
        . "<code>123456789</code>\n"
        . "<code>TestPlayer_123</code>\n"
        . "<code>metidrax</code>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '❌ انصراف',
                        'callback_data' =>
                            'admin_br_room_results:' .
                            $roomId
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_stage_create_confirm:')) {

    $eid = (int) substr(
        $data,
        strlen('admin_stage_create_confirm:')
    );

    if ($eid <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه ایونت نامعتبر است.'
        );
        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال ساخت Stage...'
    );

    $state = getState(
        $pdo,
        $uid
    );

    if (
        !str_starts_with(
            $state,
            'admin_stage_create:confirm:'
        )
    ) {
        sendMessage(
            $chat_id,
            '❌ نشست ایجاد Stage منقضی شده است.'
        );
        return;
    }

    $parts = explode(
        ':',
        $state,
        11
    );

    $stateEid =
        (int) ($parts[2] ?? 0);

    $encodedName =
        $parts[3] ?? '';

    $type =
        $parts[4] ?? '';

    $format =
        $parts[5] ?? '';

    $matchSize =
        (int) ($parts[6] ?? 0);

    $matchesPerPlayer =
        (int) ($parts[7] ?? 0);

    $advancementType =
        $parts[8] ?? '';

    $advancementValue =
        $parts[9] ?? '';

    $scoringStrategy =
        $parts[10] ?? '';

    if ($stateEid !== $eid) {
        sendMessage(
            $chat_id,
            '❌ اطلاعات Event با نشست فعلی مطابقت ندارد.'
        );
        return;
    }

    $name = base64_decode(
        $encodedName,
        true
    );

    if (
        $name === false
        || $name === ''
        || $format !== 'battle_royale'
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ اطلاعات Stage نامعتبر است.'
        );
        return;
    }

    if (
        $matchSize < 2
        || $matchSize > 48
        || $matchesPerPlayer < 1
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ تنظیمات Battle Royale نامعتبر است.'
        );

        return;
    }

    /*
    * اعتبارسنجی نوع Stage
    */
    if (
        !in_array(
            $type,
            [
                'qualification',
                'group',
                'playoff',
                'final'
            ],
            true
        )
    ) {
        setState(
            $pdo,
            $uid,
            ''
        );

        sendMessage(
            $chat_id,
            '❌ نوع Stage نامعتبر است.'
        );

        return;
    }

    /*
    * اعتبارسنجی قانون صعود
    */
    if (
        $type === 'final'
    ) {

        /*
        * Final صعودکننده ندارد.
        */
        if (
            $advancementType !== 'champion'
            || (string) $advancementValue !== '0'
        ) {
            setState(
                $pdo,
                $uid,
                ''
            );

            sendMessage(
                $chat_id,
                '❌ تنظیمات صعود Final نامعتبر است.'
            );

            return;
        }

    } else {

        /*
        * Group / Playoff باید
        * قانون صعود معتبر داشته باشند.
        */
        if (
            !in_array(
                $advancementType,
                [
                    'top_n',
                    'percentage',
                    'points',
                ],
                true
            )
        ) {
            setState(
                $pdo,
                $uid,
                ''
            );

            sendMessage(
                $chat_id,
                '❌ قانون صعود نامعتبر است.'
            );

            return;
        }
    }

    /*
     * محاسبه ترتیب Stage
     */
    $st = $pdo->prepare("
        SELECT COALESCE(
            MAX(stage_order),
            0
        )
        FROM tournament_stages
        WHERE ev_id = ?
    ");

    $st->execute([
        $eid
    ]);

    $nextOrder =
        ((int) $st->fetchColumn()) + 1;

    /*
     * ایجاد Stage
     */
    $st = $pdo->prepare("
        INSERT INTO tournament_stages (
            ev_id,
            name,
            type,
            format,
            match_size,
            matches_per_player,
            advancement_type,
            advancement_count,
            scoring_strategy,
            stage_order,
            status
        )
        VALUES (
            ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending'
        )
    ");

    $st->execute([
        $eid,
        $name,
        $type,
        $format,
        $matchSize,
        $matchesPerPlayer,
        $advancementType,
        $advancementType === 'top_n'
            ? (int) $advancementValue
            : (
                $advancementType === 'none'
                    ? 0
                    : $advancementValue
            ),
        $scoringStrategy,
        $nextOrder,
    ]);

    $stageId =
        (int) $pdo->lastInsertId();

    setState(
        $pdo,
        $uid,
        ''
    );

    $advancementLabel = match ($advancementType) {
        'top_n' =>
            'Top ' . $advancementValue,

        'percentage' =>
            $advancementValue . '%',

        'points' =>
            'حداقل ' . $advancementValue . ' امتیاز',

        'champion' =>
            '🏆 Champion',

        default =>
            $advancementType,
    };

    $scoringLabel = match ($scoringStrategy) {
        'placement_kills' =>
            'Placement + Kills',

        'default' =>
            'Score مستقیم',

        default =>
            $scoringStrategy,
    };

    sendMessage(
        $chat_id,
        "✅ <b>Stage با موفقیت ساخته شد.</b>\n\n"
        . "🎯 نام: <b>"
        . htmlspecialchars(
            $name,
            ENT_QUOTES,
            'UTF-8'
        )
        . "</b>\n"
        . "📌 نوع: <code>{$type}</code>\n"
        . "🔥 فرمت: <code>{$format}</code>\n"
        . "👥 Room Size: <code>{$matchSize}</code>\n"
        . "🎮 بازی هر بازیکن: <code>{$matchesPerPlayer}</code>\n"
        . "📈 صعود: <b>{$advancementLabel}</b>\n"
        . "🧮 امتیازدهی: <b>{$scoringLabel}</b>\n"
        . "🔢 ترتیب: <code>{$nextOrder}</code>\n"
        . "🆔 شناسه: <code>#{$stageId}</code>",
        [
            'inline_keyboard' => [
                [
                    [
                        'text' => '🧩 مدیریت Stage',
                        'callback_data' =>
                            'admin_stage:' . $stageId
                    ]
                ],
                [
                    [
                        'text' => '🔙 مدیریت مراحل',
                        'callback_data' =>
                            'admin_stages:' . $eid
                    ]
                ]
            ]
        ]
    );

    return;
}

if (str_starts_with($data, 'admin_br_room_send_credentials:')) {
    $roomId = (int) substr(
        $data,
        strlen(
            'admin_br_room_send_credentials:'
        )
    );

    if ($roomId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال ارسال اطلاعات Room...'
    );

    try {

        sendBRRoomCredentials(
            $pdo,
            $chat_id,
            $mid,
            $roomId
        );

    } catch (Throwable $e) {

        error_log(
            '[BR ROOM CREDENTIAL ERROR] ' .
            $e->getMessage()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>ارسال اطلاعات Room انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_br_stage_finalize:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_br_stage_finalize:')
    );

    if ($stageId <= 0) {

        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال نهایی‌سازی Stage...'
    );

    try {

        /*
         * ==========================================
         * Stage
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                id,
                name,
                status
            FROM tournament_stages
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([
            $stageId
        ]);

        $stage =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$stage) {

            throw new RuntimeException(
                'Stage پیدا نشد.'
            );
        }

        if (
            $stage['status'] !== 'active'
        ) {

            throw new RuntimeException(
                'این Stage قبلاً نهایی شده یا فعال نیست.'
            );
        }

        /*
         * ==========================================
         * حتماً تمام Roomها باید Complete باشند
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                COUNT(*) AS total_rooms,

                COALESCE(
                    SUM(status = 'completed'),
                    0
                ) AS completed_rooms

            FROM tournament_br_rooms
            WHERE stage_id = ?
        ");

        $st->execute([
            $stageId
        ]);

        $roomStats =
            $st->fetch(PDO::FETCH_ASSOC);

        $totalRooms =
            (int) (
                $roomStats['total_rooms']
                ?? 0
            );

        $completedRooms =
            (int) (
                $roomStats['completed_rooms']
                ?? 0
            );

        if (
            $totalRooms <= 0
        ) {

            throw new RuntimeException(
                'برای این Stage هیچ Roomای وجود ندارد.'
            );
        }

        if (
            $completedRooms !==
            $totalRooms
        ) {

            throw new RuntimeException(
                "هنوز تمام Roomهای Stage تکمیل نشده‌اند. "
                . "({$completedRooms}/{$totalRooms})"
            );
        }

        /*
         * ==========================================
         * Stage Progression
         * ==========================================
         *
         * اینجا تنها جایی است که Stage واقعاً
         * نهایی و رتبه‌بندی می‌شود.
         */
        $progressionService =
            new \Tournament\Stage\StageProgressionService(
                $pdo
            );

        $progressionResult =
            $progressionService->progress(
                $stageId
            );

        /*
         * ==========================================
         * آمار
         * ==========================================
         */
        $qualifiedCount =
            (int) (
                $progressionResult[
                    'qualified_count'
                ]
                ?? 0
            );

        $nextStageId =
            $progressionResult[
                'next_stage_id'
            ]
            ?? null;

        $nextStageGenerated =
            (bool) (
                $progressionResult[
                    'next_stage_generated'
                ]
                ?? false
            );

        /*
         * ==========================================
         * Leaderboard Count
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_leaderboards
            WHERE stage_id = ?
        ");

        $st->execute([
            $stageId
        ]);

        $leaderboardParticipantCount =
            (int) $st->fetchColumn();

        /*
         * ==========================================
         * Admin Message
         * ==========================================
         */
        $message =
            "✅ <b>Stage با موفقیت نهایی شد.</b>\n\n"

            . "🏆 Stage: <code>#"
            . $stageId
            . "</code>\n"

            . "🏠 Roomها: <code>"
            . $completedRooms
            . "/"
            . $totalRooms
            . "</code>\n"

            . "📊 Leaderboard: <code>"
            . $leaderboardParticipantCount
            . "</code> بازیکن\n"

            . "⬆️ صعودکنندگان: <code>"
            . $qualifiedCount
            . "</code>";

        if (
            $nextStageId !== null
        ) {

            $message .=
                "\n\n"
                . "➡️ Stage بعدی: <code>#"
                . (int) $nextStageId
                . "</code>";

            if (
                $nextStageGenerated
            ) {

                $message .=
                    "\n✅ ساختار Stage بعدی ایجاد شد.";
            }
        }

        editMessageText(
            $chat_id,
            $mid,
            $message,
            [
                'inline_keyboard' => [

                    [
                        [
                            'text' =>
                                '🏆 مشاهده Leaderboard',

                            'callback_data' =>
                                'admin_br_leaderboard:'
                                . $stageId
                        ]
                    ],

                    [
                        [
                            'text' =>
                                '🎯 مدیریت Stage',

                            'callback_data' =>
                                'admin_stage:'
                                . $stageId
                        ]
                    ]
                ]
            ]
        );

    } catch (Throwable $e) {

        error_log(
            '[BR STAGE FINALIZE ERROR] '
            . $e->getMessage()
            . "\n"
            . $e->getTraceAsString()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>نهایی‌سازی Stage انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_br_room_complete:')) {

    $roomId = (int) substr(
        $data,
        strlen('admin_br_room_complete:')
    );

    if ($roomId <= 0) {

        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال بررسی نتایج Room...'
    );

    $stageId = 0;

    $groupFinalizeResult = null;

    $stageReadyToFinalize = false;

    $totalStageRooms = 0;

    $completedStageRooms = 0;

    try {

        /*
         * ==========================================
         * Transaction
         * ==========================================
         */
        $ownsTransaction =
            !$pdo->inTransaction();

        if ($ownsTransaction) {
            $pdo->beginTransaction();
        }

        /*
         * ==========================================
         * Room
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                id,
                stage_id,
                round_number,
                room_number,
                capacity,
                participant_count,
                status
            FROM tournament_br_rooms
            WHERE id = ?
            LIMIT 1
            FOR UPDATE
        ");

        $st->execute([
            $roomId
        ]);

        $room =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$room) {

            throw new RuntimeException(
                'Room پیدا نشد.'
            );
        }

        $stageId =
            (int) $room['stage_id'];

        $groupNumber =
            (int) $room['room_number'];

        $roundNumber =
            (int) $room['round_number'];

        /*
         * ==========================================
         * فقط Room فعال
         * ==========================================
         */
        if (
            $room['status'] !== 'active'
        ) {

            throw new RuntimeException(
                'فقط Room فعال قابل تکمیل است.'
            );
        }

        /*
         * ==========================================
         * Stage
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                id,
                name,
                advancement_type,
                advancement_count,
                scoring_strategy,
                status
            FROM tournament_stages
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([
            $stageId
        ]);

        $stageConfig =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$stageConfig) {

            throw new RuntimeException(
                'تنظیمات Stage پیدا نشد.'
            );
        }

        if (
            $stageConfig['status'] !== 'active'
        ) {

            throw new RuntimeException(
                'این Stage فعال نیست.'
            );
        }

        /*
         * ==========================================
         * Participant Count
         * ==========================================
         */
        $participantCount =
            (int) $room['participant_count'];

        if (
            $participantCount < 2
        ) {

            throw new RuntimeException(
                'Room حداقل به 2 بازیکن نیاز دارد.'
            );
        }

        /*
         * ==========================================
         * تعداد واقعی Participantها
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_room_participants
            WHERE room_id = ?
        ");

        $st->execute([
            $roomId
        ]);

        $actualParticipants =
            (int) $st->fetchColumn();

        if (
            $actualParticipants !==
            $participantCount
        ) {

            throw new RuntimeException(
                'تعداد بازیکنان Room با اطلاعات ذخیره‌شده مطابقت ندارد.'
            );
        }

        /*
         * ==========================================
         * Confirmed Results
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_results
            WHERE room_id = ?
              AND status = 'confirmed'
        ");

        $st->execute([
            $roomId
        ]);

        $confirmedResults =
            (int) $st->fetchColumn();

        if (
            $confirmedResults !==
            $participantCount
        ) {

            throw new RuntimeException(
                "هنوز نتیجه همه بازیکنان ثبت نشده است. "
                . "({$confirmedResults}/{$participantCount})"
            );
        }

        /*
         * ==========================================
         * Validate Results
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                COUNT(*) AS total_results,

                COUNT(
                    DISTINCT tournament_participant_id
                ) AS unique_players,

                COUNT(
                    DISTINCT CASE
                        WHEN placement > 0
                        THEN placement
                        ELSE NULL
                    END
                ) AS unique_valid_placements,

                SUM(
                    CASE
                        WHEN placement = 0
                        THEN 1
                        ELSE 0
                    END
                ) AS disqualified_players

            FROM tournament_br_results

            WHERE room_id = ?
              AND status = 'confirmed'
        ");

        $st->execute([
            $roomId
        ]);

        $resultStats =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!is_array($resultStats)) {

            throw new RuntimeException(
                'امکان دریافت آمار Resultهای Room وجود ندارد.'
            );
        }

        $totalResults =
            (int) (
                $resultStats['total_results']
                ?? 0
            );

        $uniquePlayers =
            (int) (
                $resultStats['unique_players']
                ?? 0
            );

        $uniqueValidPlacements =
            (int) (
                $resultStats['unique_valid_placements']
                ?? 0
            );

        $disqualifiedPlayers =
            (int) (
                $resultStats['disqualified_players']
                ?? 0
            );

        /*
         * ==========================================
         * تعداد Result
         * ==========================================
         */
        if (
            $totalResults !==
            $participantCount
        ) {

            throw new RuntimeException(
                'تعداد Resultهای ثبت‌شده صحیح نیست.'
            );
        }

        /*
         * ==========================================
         * هر Participant فقط یک Result
         * ==========================================
         */
        if (
            $uniquePlayers !==
            $participantCount
        ) {

            throw new RuntimeException(
                'برای بعضی بازیکنان Result معتبر ثبت نشده است.'
            );
        }

        /*
         * ==========================================
         * تعداد Placementهای مثبت
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_results
            WHERE room_id = ?
              AND status = 'confirmed'
              AND placement > 0
        ");

        $st->execute([
            $roomId
        ]);

        $validPlacementPlayerCount =
            (int) $st->fetchColumn();

        /*
         * ==========================================
         * Placement تکراری
         * ==========================================
         *
         * placement = 0 آزاد است و می‌تواند
         * برای چند بازیکن تکرار شود.
         */
        if (
            $uniqueValidPlacements !==
            $validPlacementPlayerCount
        ) {

            throw new RuntimeException(
                'Placement تکراری وجود دارد.'
            );
        }

        /*
         * ==========================================
         * حداقل یک Placement معتبر
         * ==========================================
         *
         * اگر همه DQ باشند، از نظر Placement
         * مشکلی نداریم.
         */
        if (
            $validPlacementPlayerCount === 0
            &&
            $disqualifiedPlayers !==
            $participantCount
        ) {

            throw new RuntimeException(
                'هیچ Placement معتبری برای بازیکنان ثبت نشده است.'
            );
        }

        /*
         * ==========================================
         * Placementهای معتبر
         * ==========================================
         *
         * مثال صحیح:
         *
         * 1,2,3,4,5,0,0,0
         *
         * مثال غلط:
         *
         * 1,2,3,5,6,0,0
         *
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT placement
            FROM tournament_br_results
            WHERE room_id = ?
              AND status = 'confirmed'
              AND placement > 0
            ORDER BY placement ASC
        ");

        $st->execute([
            $roomId
        ]);

        $validPlacements =
            $st->fetchAll(PDO::FETCH_COLUMN);

        foreach (
            $validPlacements as $index => $placement
        ) {

            $placement =
                (int) $placement;

            $expected =
                $index + 1;

            if (
                $placement !==
                $expected
            ) {

                throw new RuntimeException(
                    "Placementها صحیح نیستند. "
                    . "انتظار رتبه {$expected} بود، "
                    . "اما {$placement} ثبت شده است."
                );
            }
        }

        /*
         * ==========================================
         * Complete Room
         * ==========================================
         */
        $st = $pdo->prepare("
            UPDATE tournament_br_rooms
            SET
                status = 'completed',
                updated_at = NOW()
            WHERE id = ?
              AND status = 'active'
        ");

        $st->execute([
            $roomId
        ]);

        if (
            $st->rowCount() !== 1
        ) {

            throw new RuntimeException(
                'تکمیل Room انجام نشد.'
            );
        }

        /*
         * ==========================================
         * Room Participants → finished
         * ==========================================
         */
        $st = $pdo->prepare("
            UPDATE tournament_br_room_participants
            SET
                status = 'finished'
            WHERE room_id = ?
              AND status IN ('playing', 'ready')
        ");

        $st->execute([
            $roomId
        ]);

        /*
         * ==========================================
         * Commit Room
         * ==========================================
         */
        if (
            $ownsTransaction
            &&
            $pdo->inTransaction()
        ) {

            $pdo->commit();
        }

        /*
         * ==========================================
         * Finalize Group
         * ==========================================
         *
         * فقط اگر تمام Roundهای همین Group
         * کامل شده باشند.
         *
         * این تابع نباید Stage را ببندد.
         */
        $groupFinalizeResult =
            finalizeBRGroupIfComplete(
                $pdo,
                $roomId
            );

        if (
            $groupFinalizeResult !== null
        ) {

            error_log(
                '[BR GROUP FINALIZE] '
                . json_encode(
                    $groupFinalizeResult,
                    JSON_UNESCAPED_UNICODE |
                    JSON_UNESCAPED_SLASHES
                )
            );
        }

        /*
         * ==========================================
         * وضعیت کل Stage
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                COUNT(*) AS total_rooms,

                COALESCE(
                    SUM(
                        status = 'completed'
                    ),
                    0
                ) AS completed_rooms

            FROM tournament_br_rooms

            WHERE stage_id = ?
        ");

        $st->execute([
            $stageId
        ]);

        $stageRoomStats =
            $st->fetch(PDO::FETCH_ASSOC);

        $totalStageRooms =
            (int) (
                $stageRoomStats['total_rooms']
                ?? 0
            );

        $completedStageRooms =
            (int) (
                $stageRoomStats['completed_rooms']
                ?? 0
            );

        /*
         * ==========================================
         * آیا Stage آماده Finalize است؟
         * ==========================================
         *
         * اینجا Stage را نمی‌بندیم.
         *
         * فقط متوجه می‌شویم که تمام Roomها
         * کامل شده‌اند.
         */
        $stageReadyToFinalize =
            (
                $totalStageRooms > 0
                &&
                $completedStageRooms ===
                $totalStageRooms
            );


    /*
    * ==========================================
    * تعداد واقعی صعودکنندگان
    * ==========================================
    */

    $st = $pdo->prepare("
        SELECT
            br.room_number AS group_number,
            COUNT(DISTINCT CASE
                WHEN NOT EXISTS (
                    SELECT 1
                    FROM tournament_br_rooms br2
                    INNER JOIN tournament_br_room_participants rp2
                        ON rp2.room_id = br2.id
                    INNER JOIN tournament_br_results r2
                        ON r2.room_participant_id = rp2.id
                    AND r2.tournament_participant_id = rp2.tournament_participant_id
                    WHERE br2.stage_id = br.stage_id
                    AND br2.room_number = br.room_number
                    AND rp2.tournament_participant_id = rp.tournament_participant_id
                    AND r2.status = 'confirmed'
                    AND r2.placement = 0
                )
                THEN rp.tournament_participant_id
                ELSE NULL
            END) AS eligible_count
        FROM tournament_br_rooms br
        INNER JOIN tournament_br_room_participants rp
            ON rp.room_id = br.id
        WHERE br.stage_id = ?
        GROUP BY br.room_number
        ORDER BY br.room_number ASC
    ");

    $st->execute([$stageId]);

    $groupEligibleCounts = [];

    while ($row = $st->fetch(PDO::FETCH_ASSOC)) {
        $groupEligibleCounts[(int)$row['group_number']] =
            (int)$row['eligible_count'];
    }

    /*
    * محاسبه سهم واقعی هر Group
    *
    * بدون انتقال ظرفیت خالی بین Groupها
    */
    $calculator = new \Tournament\Stage\BattleRoyaleAdvancementCalculator();

    $groupQuotas =
        $calculator->calculateGroupQuotas(
            $groupEligibleCounts,
            (string) $stageConfig['advancement_type'],
            (int) $stageConfig['advancement_count']
        );

    $realAdvancementCount =
        array_sum($groupQuotas);

    /*
    * ==========================================
    * Admin Message
    * ==========================================
    */

    
    if ($stageReadyToFinalize) {

        $message =
            "⚠️ <b>تمام Roomهای Stage تکمیل شدند.</b>\n\n"

            . "🏆 Stage: <code>#"
            . $stageId
            . "</code>\n"

            . "🏠 Group: <code>"
            . $groupNumber
            . "</code>\n"

            . "🔥 Round: <code>"
            . $roundNumber
            . "</code>\n\n"

            . "📊 Roomهای Stage: <code>"
            . $completedStageRooms
            . "/"
            . $totalStageRooms
            . "</code>\n\n"

            . "🏆 تعداد صعودکنندگان: <b>"
            . $realAdvancementCount
            . "</b> نفر\n\n"

            . "⚠️ با نهایی‌سازی Stage، "
            . "رتبه‌بندی نهایی انجام می‌شود، "
            . "بازیکنان DQ مشخص می‌شوند و "
            . "صعودکنندگان محاسبه خواهند شد.\n\n"

            . "<b>آیا می‌خواهید Stage را نهایی کنید؟</b>";

        editMessageText(
            $chat_id,
            $mid,
            $message,
            [
                'inline_keyboard' => [

                    [
                        [
                            'text' =>
                                '✅ بله، نهایی‌سازی Stage',

                            'callback_data' =>
                                'admin_br_stage_finalize:'
                                . $stageId
                        ]
                    ],

                    [
                        [
                            'text' =>
                                '❌ فعلاً نه',

                            'callback_data' =>
                                'admin_stage:'
                                . $stageId
                        ]
                    ]
                ]
            ]
        );


        } else {

            /*
             * ======================================
             * Stage هنوز ادامه دارد
             * ======================================
             */

            if (
                $groupFinalizeResult !== null
                &&
                !(
                    $groupFinalizeResult[
                        'already_finalized'
                    ]
                    ?? false
                )
            ) {

                $groupNumber =
                    (int) (
                        $groupFinalizeResult[
                            'group_number'
                        ]
                        ?? $groupNumber
                    );

                $groupUsers =
                    (int) (
                        $groupFinalizeResult[
                            'total_users'
                        ]
                        ?? 0
                    );

                renderAdminBRRoomInfo(
                    $pdo,
                    $chat_id,
                    $mid,
                    $roomId
                );

                sendMessage(
                    $chat_id,
                    "✅ <b>Room تکمیل شد.</b>\n\n"
                    . "🏆 <b>Group {$groupNumber} نیز نهایی شد.</b>\n"
                    . "📨 پیام نتیجه "
                    . "<code>{$groupUsers}</code> "
                    . "بازیکن وارد صف ارسال شد."
                );

            } else {

                /*
                 * Room تمام شد ولی Group یا Stage
                 * هنوز کامل نشده است.
                 */
                renderAdminBRRoomInfo(
                    $pdo,
                    $chat_id,
                    $mid,
                    $roomId
                );
            }
        }

    } catch (Throwable $e) {

        /*
         * ==========================================
         * Rollback
         * ==========================================
         */
        if (
            isset($ownsTransaction)
            &&
            $ownsTransaction
            &&
            $pdo->inTransaction()
        ) {

            $pdo->rollBack();
        }

        error_log(
            '[BR ROOM COMPLETE ERROR] '
            . $e->getMessage()
            . "\n"
            . $e->getTraceAsString()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>تکمیل Room انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_br_leaderboard:')
) {
    $stageId = (int) substr(
        $data,
        strlen(
            'admin_br_leaderboard:'
        )
    );

    if ($stageId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    try {

        $leaderboard =
            new \Tournament\Stage\BattleRoyaleLeaderboard(
                $pdo
            );

        /*
         * تولید / بروزرسانی Leaderboard
         */
        $leaderboard->generate(
            $stageId
        );

        renderAdminBRLeaderboard(
            $pdo,
            $chat_id,
            $mid,
            $stageId,
            1
        );

    } catch (Throwable $e) {

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>Leaderboard ساخته نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_br_broadcast_results:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_br_broadcast_results:')
    );

    if ($stageId <= 0) {

        answerCb(
            $cb['id'],
            '❌ Stage نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال آماده‌سازی...'
    );

    try {

        /*
         * ==========================================
         * Stage
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                id,
                name,
                status
            FROM tournament_stages
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([
            $stageId
        ]);

        $stage =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$stage) {

            throw new RuntimeException(
                'Stage پیدا نشد.'
            );
        }

        /*
         * ==========================================
         * Top 15 Global Ranking
         * ==========================================
         *
         * global_rank =
         * رتبه واقعی کل Stage
         *
         * DQ ها چون global_rank = NULL هستند
         * در این لیست قرار نمی‌گیرند.
         */
        $st = $pdo->prepare("
            SELECT
                l.tournament_participant_id,

                l.global_rank,
                l.rank_position,
                l.total_score,
                l.total_kills,
                l.games_played,
                l.best_placement,

                CASE
                    WHEN a.participant_id IS NOT NULL
                        THEN 1
                    ELSE 0
                END AS is_qualified,

                ep.ign,
                ep.user_id

            FROM tournament_br_leaderboards l

            INNER JOIN tournament_participants tp
                ON tp.id = l.tournament_participant_id

            INNER JOIN event_players ep
                ON ep.id = tp.event_player_id

            LEFT JOIN tournament_stage_advancements a
                ON a.from_stage_id = l.stage_id
            AND a.participant_id = l.tournament_participant_id
            AND a.status = 'qualified'

            WHERE l.stage_id = ?
            AND l.global_rank IS NOT NULL

            ORDER BY
                l.global_rank ASC

            LIMIT 15
        ");

        $st->execute([
            $stageId
        ]);

        $topPlayers =
            $st->fetchAll(PDO::FETCH_ASSOC);

        if (!$topPlayers) {

            throw new RuntimeException(
                'Global Ranking این Stage وجود ندارد.'
            );
        }

        /*
         * ==========================================
         * تعداد کل بازیکنان
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_leaderboards
            WHERE stage_id = ?
        ");

        $st->execute([
            $stageId
        ]);

        $totalPlayers =
            (int) $st->fetchColumn();

        /*
         * ==========================================
         * تعداد Eligible
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_leaderboards
            WHERE stage_id = ?
              AND global_rank IS NOT NULL
        ");

        $st->execute([
            $stageId
        ]);

        $eligiblePlayers =
            (int) $st->fetchColumn();

        /*
         * ==========================================
         * Preview
         * ==========================================
         */
        $text =
            "📨 <b>ارسال نتیجه Stage</b>\n\n"

            . "🏆 Stage: <code>#"
            . $stageId
            . "</code>\n"

            . "👥 کل بازیکنان: <b>"
            . $totalPlayers
            . "</b>\n"

            . "✅ بازیکنان واجد شرایط Ranking: <b>"
            . $eligiblePlayers
            . "</b>\n\n"

            . "🏅 <b>15 نفر اول Global Ranking</b>\n\n";

        $rankIcons = [
            1 => '🥇',
            2 => '🥈',
            3 => '🥉',
        ];

        foreach (
            $topPlayers as $player
        ) {

            /*
             * ======================================
             * Global Rank
             * ======================================
             */
            $rank =
                (int) (
                    $player['global_rank']
                    ?? 0
                );

            $icon =
                $rankIcons[$rank]
                ?? '▫️';

            /*
             * ======================================
             * IGN
             * ======================================
             */
            $name =
                trim(
                    (string) (
                        $player['ign']
                        ?? ''
                    )
                );

            if ($name === '') {

                $name =
                    'Player #' .
                    (int) $player['user_id'];
            }

            /*
             * ======================================
             * Stats
             * ======================================
             */
            $score =
                (float) (
                    $player['total_score']
                    ?? 0
                );

            $kills =
                (int) (
                    $player['total_kills']
                    ?? 0
                );

            $games =
                (int) (
                    $player['games_played']
                    ?? 0
                );

            $bestPlacement =
                $player['best_placement'] !== null
                    ? (int) $player['best_placement']
                    : null;

            $qualified =
                (int) (
                    $player['is_qualified']
                    ?? 0
                ) === 1;

            /*
             * ======================================
             * Player Preview
             * ======================================
             */
            $text .=
                "<blockquote>"

                . "{$icon} "
                . "<b>#{$rank} "
                . htmlspecialchars(
                    $name,
                    ENT_QUOTES | ENT_SUBSTITUTE,
                    'UTF-8'
                )
                . "</b>\n"

                . "🧮 Score: <code>"
                . $score
                . "</code>\n"

                . "🔫 Kills: <code>"
                . $kills
                . "</code>\n"

                . "🎮 Games: <code>"
                . $games
                . "</code>\n";

            if (
                $bestPlacement !== null
            ) {

                $text .=
                    "🏅 Best Placement: <code>"
                    . $bestPlacement
                    . "</code>\n";
            }

            $text .=
                $qualified
                    ? "✅ Qualified"
                    : "❌ Eliminated";

            $text .=
                "</blockquote>\n";
        }

        /*
         * ==========================================
         * Confirmation
         * ==========================================
         */
        $text .=
            "\n⚠️ <b>آیا می‌خواهید نتیجه Stage "
            . "برای همه بازیکنان ارسال شود؟</b>\n\n"

            . "📨 تعداد پیام‌ها: <b>"
            . $totalPlayers
            . "</b>";

        editMessageText(
            $chat_id,
            $mid,
            $text,
            [
                'inline_keyboard' => [

                    [
                        [
                            'text' =>
                                '✅ بله، ارسال شود',

                            'callback_data' =>
                                'admin_br_broadcast_results_confirm:'
                                . $stageId
                        ]
                    ],

                    [
                        [
                            'text' =>
                                '❌ لغو',

                            'callback_data' =>
                                'admin_br_leaderboard:'
                                . $stageId
                        ]
                    ]

                ]
            ]
        );

    } catch (Throwable $e) {

        error_log(
            '[BR BROADCAST PREVIEW ERROR] '
            . $e->getMessage()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>آماده‌سازی ارسال انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES | ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (str_starts_with($data, 'admin_br_broadcast_results_confirm:')) {

    $stageId = (int) substr(
        $data,
        strlen('admin_br_broadcast_results_confirm:')
    );

    if ($stageId <= 0) {

        answerCb(
            $cb['id'],
            '❌ Stage نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال ساخت صف ارسال...'
    );

    $ownsTransaction =
        !$pdo->inTransaction();

    try {

        /*
         * ==========================================
         * Transaction
         * ==========================================
         */
        if ($ownsTransaction) {
            $pdo->beginTransaction();
        }

        /*
         * ==========================================
         * Stage
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT
                id,
                name,
                status
            FROM tournament_stages
            WHERE id = ?
            LIMIT 1
        ");

        $st->execute([
            $stageId
        ]);

        $stage =
            $st->fetch(PDO::FETCH_ASSOC);

        if (!$stage) {

            throw new RuntimeException(
                'Stage پیدا نشد.'
            );
        }

        /*
         * ==========================================
         * Leaderboard باید وجود داشته باشد
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_leaderboards
            WHERE stage_id = ?
        ");

        $st->execute([
            $stageId
        ]);

        $totalPlayers =
            (int) $st->fetchColumn();

        if ($totalPlayers <= 0) {

            throw new RuntimeException(
                'Leaderboard این Stage وجود ندارد.'
            );
        }

        /*
         * ==========================================
         * جلوگیری از Broadcast تکراری
         * ==========================================
         *
         * اگر قبلاً برای این Stage یک Broadcast
         * نتیجه ساخته شده باشد، دوباره Queue
         * ایجاد نمی‌کنیم.
         */
        $st = $pdo->prepare("
            SELECT
                id,
                status,
                total_users
            FROM tournament_br_broadcasts
            WHERE stage_id = ?
              AND type = 'stage_results'
            ORDER BY id DESC
            LIMIT 1
        ");

        $st->execute([
            $stageId
        ]);

        $existingBroadcast =
            $st->fetch(PDO::FETCH_ASSOC);

        if ($existingBroadcast) {

            throw new RuntimeException(
                'برای این Stage قبلاً Broadcast نتیجه ساخته شده است.'
                . ' Broadcast #'
                . (int) $existingBroadcast['id']
            );
        }

        /*
         * ==========================================
         * دریافت بازیکنان
         * ==========================================
         *
         * global_rank:
         * رتبه واقعی کل Stage
         *
         * Qualified:
         * وجود رکورد در stage_advancements
         *
         * Group:
         * از room_number
         */
        $st = $pdo->prepare("
            SELECT
                l.tournament_participant_id,

                l.global_rank,

                l.total_score,
                l.total_kills,
                l.games_played,
                l.best_placement,

                ep.user_id,
                ep.ign,

                gm.group_number,

                CASE
                    WHEN a.participant_id IS NOT NULL
                        THEN 1
                    ELSE 0
                END AS is_qualified

            FROM tournament_br_leaderboards l

            INNER JOIN tournament_participants tp
                ON tp.id =
                    l.tournament_participant_id

            INNER JOIN event_players ep
                ON ep.id =
                    tp.event_player_id

            /*
             * Group ثابت Participant
             */
            INNER JOIN (
                SELECT
                    rp.tournament_participant_id,

                    MIN(br.room_number)
                        AS group_number

                FROM tournament_br_room_participants rp

                INNER JOIN tournament_br_rooms br
                    ON br.id = rp.room_id

                WHERE br.stage_id = ?

                GROUP BY
                    rp.tournament_participant_id

                HAVING COUNT(
                    DISTINCT br.room_number
                ) = 1

            ) gm
                ON gm.tournament_participant_id =
                    l.tournament_participant_id

            /*
             * Qualified واقعی
             */
            LEFT JOIN tournament_stage_advancements a
                ON a.from_stage_id = l.stage_id
               AND a.participant_id =
                   l.tournament_participant_id
               AND a.status = 'qualified'

            WHERE l.stage_id = ?

            ORDER BY
                ep.user_id ASC
        ");

        $st->execute([
            $stageId,
            $stageId
        ]);

        $players =
            $st->fetchAll(PDO::FETCH_ASSOC);

        if (!$players) {

            throw new RuntimeException(
                'هیچ بازیکنی برای ارسال نتیجه پیدا نشد.'
            );
        }

        /*
         * ==========================================
         * ساخت Broadcast
         * ==========================================
         */
        $st = $pdo->prepare("
            INSERT INTO tournament_br_broadcasts (
                stage_id,
                type,
                status,
                total_users,
                created_at
            )
            VALUES (
                ?,
                'stage_results',
                'queued',
                ?,
                NOW()
            )
        ");

        $st->execute([
            $stageId,
            count($players)
        ]);

        $broadcastId =
            (int) $pdo->lastInsertId();

        if ($broadcastId <= 0) {

            throw new RuntimeException(
                'ساخت Broadcast انجام نشد.'
            );
        }

        /*
         * ==========================================
         * Queue Insert
         * ==========================================
         */
        $insertQueue = $pdo->prepare("
            INSERT INTO tournament_br_broadcast_queue (
                broadcast_id,
                stage_id,
                group_number,
                user_id,
                message_text
            )
            VALUES (
                ?,
                ?,
                ?,
                ?,
                ?
            )
        ");

        $queuedCount = 0;

        foreach (
            $players as $player
        ) {

            $participantId =
                (int) (
                    $player[
                        'tournament_participant_id'
                    ]
                    ?? 0
                );

            $userId =
                (int) (
                    $player[
                        'user_id'
                    ]
                    ?? 0
                );

            if (
                $participantId <= 0
                ||
                $userId <= 0
            ) {
                continue;
            }

            $ign =
                trim(
                    (string) (
                        $player['ign']
                        ?? ''
                    )
                );

            if ($ign === '') {
                $ign =
                    'Player #' . $userId;
            }

            $groupNumber =
                (int) (
                    $player[
                        'group_number'
                    ]
                    ?? 0
                );

            $globalRank =
                $player['global_rank'] !== null
                    ? (int) $player['global_rank']
                    : null;

            $score =
                (float) (
                    $player['total_score']
                    ?? 0
                );

            $kills =
                (int) (
                    $player['total_kills']
                    ?? 0
                );

            $games =
                (int) (
                    $player['games_played']
                    ?? 0
                );

            $bestPlacement =
                $player['best_placement'] !== null
                    ? (int) (
                        $player['best_placement']
                    )
                    : null;

            $isQualified =
                (int) (
                    $player['is_qualified']
                    ?? 0
                ) === 1;

            /*
             * ======================================
             * متن پیام
             * ======================================
             */
            $message =
                "🏆 <b>نتیجه Stage #{$stageId}</b>\n\n"

                . "👤 <b>"
                . htmlspecialchars(
                    $ign,
                    ENT_QUOTES |
                    ENT_SUBSTITUTE,
                    'UTF-8'
                )
                . "</b>\n\n";

            /*
             * DQ
             */
            if (
                $globalRank === null
            ) {

                $message .=
                    "❌ <b>وضعیت: Disqualified</b>\n"
                    . "📌 در تمام راندهای Stage "
                    . "Placement معتبر ثبت نشده است.\n\n";

            } else {

                /*
                 * Global Rank
                 */
                $message .=
                    "📊 رتبه کل Stage: <b>#"
                    . $globalRank
                    . "</b>\n"

                    . "🏠 Group: <b>"
                    . $groupNumber
                    . "</b>\n"

                    . "🧮 Score: <b>"
                    . $score
                    . "</b>\n"

                    . "🔫 Kills: <b>"
                    . $kills
                    . "</b>\n"

                    . "🎮 Games: <b>"
                    . $games
                    . "</b>\n";

                if (
                    $bestPlacement !== null
                ) {

                    $message .=
                        "🏅 Best Placement: <b>"
                        . $bestPlacement
                        . "</b>\n";
                }

                $message .=
                    "\n"
                    . (
                        $isQualified
                            ? "✅ <b>صعود کردی</b>"
                            : "❌ <b>صعود نکردی</b>"
                    )
                    . "\n";
            }

            /*
             * ======================================
             * Queue
             * ======================================
             */
            $insertQueue->execute([
                $broadcastId,
                $stageId,
                $groupNumber,
                $userId,
                $message
            ]);

            $queuedCount++;
        }

        /*
         * ==========================================
         * بررسی Queue
         * ==========================================
         */
        if (
            $queuedCount <= 0
        ) {

            throw new RuntimeException(
                'هیچ پیام قابل ارسالی وارد صف نشد.'
            );
        }

        /*
         * ==========================================
         * تعداد واقعی Queue
         * ==========================================
         */
        $st = $pdo->prepare("
            SELECT COUNT(*)
            FROM tournament_br_broadcast_queue
            WHERE broadcast_id = ?
        ");

        $st->execute([
            $broadcastId
        ]);

        $actualQueued =
            (int) $st->fetchColumn();

        /*
         * تعداد Broadcast را با Queue واقعی
         * هماهنگ می‌کنیم.
         */
        $st = $pdo->prepare("
            UPDATE tournament_br_broadcasts
            SET
                total_users = ?
            WHERE id = ?
        ");

        $st->execute([
            $actualQueued,
            $broadcastId
        ]);

        /*
         * ==========================================
         * Commit
         * ==========================================
         */
        if (
            $ownsTransaction
            &&
            $pdo->inTransaction()
        ) {

            $pdo->commit();
        }

        /*
         * ==========================================
         * Admin Response
         * ==========================================
         */
        editMessageText(
            $chat_id,
            $mid,
            "✅ <b>صف ارسال نتیجه Stage ساخته شد.</b>\n\n"

            . "🏆 Stage: <code>#"
            . $stageId
            . "</code>\n"

            . "📨 Broadcast: <code>#"
            . $broadcastId
            . "</code>\n"

            . "👥 تعداد پیام‌ها: <b>"
            . $actualQueued
            . "</b>\n\n"

            . "⏳ پیام‌ها وارد صف Cron شدند و "
            . "به‌صورت تدریجی ارسال خواهند شد.",
            [
                'inline_keyboard' => [
                    [
                        [
                            'text' =>
                                '🔙 مدیریت Leaderboard',

                            'callback_data' =>
                                'admin_br_leaderboard:'
                                . $stageId
                        ]
                    ]
                ]
            ]
        );

    } catch (Throwable $e) {

        /*
         * ==========================================
         * Rollback
         * ==========================================
         */
        if (
            $ownsTransaction
            &&
            $pdo->inTransaction()
        ) {

            $pdo->rollBack();
        }

        error_log(
            '[BR BROADCAST CONFIRM ERROR] '
            . $e->getMessage()
            . "\n"
            . $e->getTraceAsString()
        );

        editMessageText(
            $chat_id,
            $mid,
            "❌ <b>ساخت صف ارسال انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

if (
    str_starts_with(
        $data,
        'admin_br_leaderboard_page:'
    )
) {
    $parts =
        explode(
            ':',
            $data,
            3
        );

    $stageId =
        (int) ($parts[1] ?? 0);

    $page =
        max(
            1,
            (int) ($parts[2] ?? 1)
        );

    if ($stageId <= 0) {
        answerCb(
            $cb['id'],
            '❌ شناسه Stage نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        ''
    );

    renderAdminBRLeaderboard(
        $pdo,
        $chat_id,
        $mid,
        $stageId,
        $page
    );

    return;
}

if (
    str_starts_with(
        $data,
        'admin_br_room_schedule:'
    )
) {

    $roomId =
        (int) substr(
            $data,
            strlen(
                'admin_br_room_schedule:'
            )
        );

    if ($roomId <= 0) {

        answerCb(
            $cb['id'],
            '❌ شناسه Room نامعتبر است.'
        );

        return;
    }

    /*
     * بررسی Room
     */
    $st = $pdo->prepare("
        SELECT
            r.id,
            r.room_number,
            r.round_number,
            s.name AS stage_name
        FROM tournament_br_rooms r
        INNER JOIN tournament_stages s
            ON s.id = r.stage_id
        WHERE r.id = ?
        LIMIT 1
    ");

    $st->execute([
        $roomId
    ]);

    $room =
        $st->fetch(PDO::FETCH_ASSOC);

    if (!$room) {

        answerCb(
            $cb['id'],
            '❌ Room پیدا نشد.'
        );

        return;
    }

    setState(
        $pdo,
        $uid,
        'admin_br_room_schedule:' .
        $roomId
    );

    answerCb(
        $cb['id']
    );

    sendMessage(
        $chat_id,
        "🕒 <b>تنظیم تاریخ و ساعت Custom Room</b>\n\n"
        . "🏠 Room #"
        . (int) $room['room_number']
        . "\n"
        . "🔥 Round "
        . (int) $room['round_number']
        . "\n"
        . "🎯 "
        . htmlspecialchars(
            (string) $room['stage_name'],
            ENT_QUOTES | ENT_SUBSTITUTE,
            'UTF-8'
        )
        . "\n\n"
        . "تاریخ و ساعت برگزاری را به صورت جلالی وارد کنید:\n\n"
        . "<code>1405/06/15 18:30</code>\n\n"
        . "فرمت:\n"
        . "<code>YYYY/MM/DD HH:MM</code>\n\n"
        . "مثال:\n"
        . "<code>1405/06/15 21:45</code>"
    );

    return;
}

if (
    str_starts_with(
        $data,
        'admin_br_broadcast_schedule:'
    )
) {

    $stageId =
        (int) substr(
            $data,
            strlen(
                'admin_br_broadcast_schedule:'
            )
        );

    if ($stageId <= 0) {

        answerCb(
            $cb['id'],
            '❌ Stage نامعتبر است.'
        );

        return;
    }

    answerCb(
        $cb['id'],
        '⏳ در حال ساخت صف ارسال...'
    );

    try {

        $result =
            createBRScheduleBroadcast(
                $pdo,
                $stageId,
                null,
                $uid
            );

        $summary =
            "✅ <b>صف ارسال زمان‌بندی ساخته شد.</b>\n\n"

            . "🆔 Broadcast: <code>#"
            . $result['broadcast_id']
            . "</code>\n"

            . "👥 Groupها: <code>"
            . $result['groups']
            . "</code>\n"

            . "📨 کاربران در صف: <code>"
            . $result['users']
            . "</code>\n\n"

            . "⏳ ارسال پیام‌ها توسط Cron انجام می‌شود.";

        sendMessage(
            $chat_id,
            $summary
        );

    } catch (Throwable $e) {

        error_log(
            '[BR SCHEDULE BROADCAST CREATE ERROR] '
            . $e->getMessage()
        );

        sendMessage(
            $chat_id,
            "❌ <b>ساخت صف ارسال انجام نشد.</b>\n\n"
            . "<code>"
            . htmlspecialchars(
                $e->getMessage(),
                ENT_QUOTES |
                ENT_SUBSTITUTE,
                'UTF-8'
            )
            . "</code>"
        );
    }

    return;
}

//----------------advance search in list----------------------------

 if ($data) {
    if (str_starts_with($data, 'admin_search_player:')) {
        if (!isAdmin($uid)) {
            answerCb($cb['id'], '⛔️', true);
            exit;
        }

        $parts = explode(':', $data);
        $eid   = (int)($parts[1] ?? 0);

        // کیبورد با دکمه بازگشت
        $kb = [
            'inline_keyboard' => [
                [
                    [
                        'text'          => '🔙 بازگشت',
                        'callback_data' => 'admin_players:'.$eid
                        
                    ]
                ]
            ]
        ];

        // ویرایش پیام با متن جستجو و دکمه بازگشت
        editMessageText(
            $chat_id,
            $mid,
            "🔍 لطفا متن جستجو را وارد کنید:",
            $kb
        );

        // ذخیره وضعیت برای دریافت متن بعدی
        setUserStep($uid, "waiting_for_search_query:$eid");

        // پاسخ به callback تا لودینگ ناپدید شود
        answerCb($cb['id'], '');

        exit;
    }
}



$step = getUserStep($uid);
if ($step && str_starts_with($step, 'waiting_for_search_query:')) {
    $parts = explode(':', $step);
    $eid   = (int)($parts[1] ?? 0); // گرفتن id رویداد
    $query = trim($text);

    setUserStep($uid, null); // ریست
    showSearchResults($chat_id, $eid, $query);
    exit;
}



if (strpos($data, 'search_player_page:') === 0) {
    $parts = explode(':', $data, 4);
    $eid   = (int)($parts[1] ?? 0);
    $page  = (int)($parts[2] ?? 1);
    $query = urldecode($parts[3] ?? '');

    showSearchResults($chat_id, $eid, $query, $page);
    exit;
}




//------------------------------------------------------------------
if (str_starts_with($data, 'admin_player_info:')) {
    $parts = explode(':', $data);
    $eid   = (int)($parts[1] ?? 0);
    $uid   = $parts[2] ?? '';

    $st = $pdo->prepare('SELECT * FROM events WHERE id=?');
    $st->execute([$eid]);
    $e = $st->fetch();

    if (!$e) {
        answerCb($cb['id'], 'ایونت پیدا نشد');
        exit;
    }

    $stPlayer = $pdo->prepare(
        'SELECT * FROM event_players WHERE ev_id = ? AND user_id = ? AND status = ? LIMIT 1'
    );
    $stPlayer->execute([$eid, $uid, 'accepted']);
    $player = $stPlayer->fetch(PDO::FETCH_ASSOC);

    if (!$player) {
        answerCb($cb['id'], 'پلیر پیدا نشد');
        exit;
    }

    // ساخت متن شیک
    $txt  = "━━━━━━━━━━━━━━\n";
    $txt .= "👤 <b>" . htmlspecialchars($player['ign'] ?? 'نامشخص') . "</b>\n";
    $txt .= "🆔 <code>" . htmlspecialchars((string)$player['user_id']) . "</code>\n";
    $txt .= "━━━━━━━━━━━━━━\n";

    // تاریخ ورود
    $txt .= "📅 <b>تاریخ ورود:</b>\n" . toJalali($player['joined_at'] ?? '') . "\n\n";

    // پرداخت
    $txt .= "💰 <b>پرداخت:</b> " . (!empty($player['paid']) ? '✅ انجام شده' : '❌ نشده') . "\n";

    if (!empty($player['pay_method'])) {
        $txt .= "💳 <b>روش پرداخت:</b> " . htmlspecialchars($player['pay_method']) . "\n";
    }

    if (!empty($player['pay_time'])) {
        $txt .= "⏰ <b>زمان پرداخت:</b>\n" . toJalali($player['pay_time']) . "\n";
    }

    if (!empty($player['pay_meta'])) {
        $txt .= "ℹ️ <b>جزئیات پرداخت:</b>\n" . htmlspecialchars($player['pay_meta']) . "\n";
    }

$txt .= "━━━━━━━━━━━━━━";

$ik = [
    [
        ['text' => '❌ حذف ثبت‌نام', 'callback_data' => 'admin_player_remove:' . $eid . ':' . $player['user_id']],
        ['text' => '📩 پیام به پلیر', 'callback_data' => 'admin_player_msg:' . $eid . ':' . $player['user_id']]
    ],
    [
        ['text' => '🔄 تغییر وضعیت', 'callback_data' => 'admin_player_status:' . $eid . ':' . $player['user_id']]
    ],
    [['text' => '🔙 بازگشت به پلیرها', 'callback_data' => 'admin_players:' . $eid]]
];

    editMessageText($chat_id, $mid, $txt, ['inline_keyboard'=>$ik, 'parse_mode'=>'HTML']);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'admin_player_remove:')) {
    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);
    $targetUid = (int)($parts[2] ?? 0);

    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    $st = $pdo->prepare('UPDATE event_players SET status = ? WHERE ev_id = ? AND user_id = ? AND status = ?');
    $st->execute(['rejected', $eid, $targetUid, 'accepted']);

    $message = $st->rowCount()
        ? "✅ ثبت‌نام کاربر <code>$targetUid</code> در ایونت #$eid لغو شد."
        : "⚠️ این کاربر یا ثبت‌نام نکرده یا قبلاً لغو شده است.";

    if ($st->rowCount()) {
        sendMessage($targetUid, "❌ ثبت‌نام شما در ایونت #$eid توسط ادمین لغو شد.");
    }

    answerCb($cb['id'], $message, true);
    exit;
}

if (str_starts_with($data, 'admin_player_msg:')) {
    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);
    $targetUid = (int)($parts[2] ?? 0);

    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    setUserStep($uid, "admin_player_msg:$eid:$targetUid");

    editMessageText($chat_id, $mid, "✉️ لطفاً متن پیام را برای کاربر <code>$targetUid</code> وارد کنید:", [
        'inline_keyboard' => [[['text' => '🔙 انصراف', 'callback_data' => 'admin_players:' . $eid]]]
    ]);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'admin_player_status:')) {
    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);
    $targetUid = (int)($parts[2] ?? 0);

    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    editMessageText($chat_id, $mid, "🔄 انتخاب وضعیت جدید برای کاربر <code>$targetUid</code>:", [
        'inline_keyboard' => [
            [['text' => '✅ قبول', 'callback_data' => 'admin_player_status_set:' . $eid . ':' . $targetUid . ':accepted']],
            [['text' => '❌ رد', 'callback_data' => 'admin_player_status_set:' . $eid . ':' . $targetUid . ':rejected']],
            [['text' => '🚫 لغو', 'callback_data' => 'admin_player_status_set:' . $eid . ':' . $targetUid . ':canceled']],
            [['text' => '🔙 بازگشت', 'callback_data' => 'admin_player_info:' . $eid . ':' . $targetUid]]
        ]
    ]);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'admin_player_status_set:')) {
    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);
    $targetUid = (int)($parts[2] ?? 0);
    $newStatus = $parts[3] ?? 'accepted';

    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    $allowed = ['accepted', 'rejected', 'canceled'];
    if (!in_array($newStatus, $allowed, true)) {
        answerCb($cb['id'], '❌ وضعیت نامعتبر', true);
        exit;
    }

    $st = $pdo->prepare('UPDATE event_players SET status = ? WHERE ev_id = ? AND user_id = ?');
    $st->execute([$newStatus, $eid, $targetUid]);

    if ($st->rowCount()) {
        sendMessage($targetUid, "🔄 وضعیت ثبت‌نام شما در ایونت #$eid اکنون به <b>$newStatus</b> تغییر یافت.");
        answerCb($cb['id'], '✅ وضعیت با موفقیت تغییر کرد.', true);
    } else {
        answerCb($cb['id'], '⚠️ رکوردی برای تغییر وضعیت یافت نشد.', true);
    }
}

//----------------advance export----------------------
    

     if ($data === 'admin_ad_export') {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    // آپدیت منو برای انتخاب نوع ایونت
    $kb = ['inline_keyboard'=>[
        [['text'=>'🟢 جاری','callback_data'=>'export_events:active'],['text'=>'📦 آرشیو','callback_data'=>'export_events:archived'],['text'=>'🔴 پایان یافته','callback_data'=>'export_events:finished']],
        [['text'=>'🌐 تمام ایونت‌ها','callback_data'=>'export_events:all'],['text'=>'🔙 بازگشت','callback_data'=>'admin_panel']], // دکمه جدید
    ]];

    editMessageText($chat_id, $mid, '📤 لطفاً نوع ایونت برای خروجی CSV را انتخاب کنید:', $kb);
    answerCb($cb['id'], '');
    exit;
}
     
if (str_starts_with($data, 'export_events:')) {
    if (!isAdmin($uid)) {
        answerCb($cb['id'], '⛔️ دسترسی ندارید', true);
        exit;
    }

    $parts = explode(':', $data);
    $status = $parts[1] ?? '';
    $statusMap = ['active'=>'active','finished'=>'finished','archived'=>'archive','all'=>'all'];

    if (!isset($statusMap[$status])) {
        answerCb($cb['id'], '❌ وضعیت نامعتبر', true);
        exit;
    }

    // واکشی ایونت‌ها
    if ($status === 'all') {
        $st = $pdo->prepare("SELECT id FROM events ORDER BY id DESC");
        $st->execute();
    } else {
        $st = $pdo->prepare("SELECT id FROM events WHERE status=? ORDER BY id DESC");
        $st->execute([$statusMap[$status]]);
    }

    $rows = $st->fetchAll(PDO::FETCH_ASSOC);

    if (!$rows) {
        answerCb($cb['id'], '❌ ایونتی یافت نشد', true);
        exit;
    }

    // خروجی CSV
    $file = exportMultipleEventsCSV($pdo, array_column($rows,'id'));

    if (!$file) {
        answerCb($cb['id'], '❌ خطا در خروجی CSV', true);
        exit;
    }

    sendDocument($chat_id, $file, 'CSV شرکت‌کنندگان');
    answerCb($cb['id'], '✅ ارسال شد');
    exit;
}


//------------------announcement system-----------------------

if ($data === 'admin_announcements') {
    $kb = ['inline_keyboard' => [
        [['text'=>'📨 پیام همگانی','callback_data'=>'ann_send:broadcast'], ['text'=>'👤 پیام شخصی','callback_data'=>'ann_send:private']],
        [['text'=>'📊 گزارش ارسال','callback_data'=>'ann_report'], ['text'=>'🔍 جستجو','callback_data'=>'ann_search']],
        [['text'=>'🔙 بازگشت','callback_data'=>'admin_panel']]
    ]];

    editMessageText($chat_id,$mid,'📢 منوی ارسال اعلان', $kb);
    answerCb($cb['id'],'');
    exit;
}

if (str_starts_with($data, 'ann_send:')) {
    [, $mode] = explode(':', $data);

    if ($mode === 'private') {
        // اول آیدی مخاطب رو بگیره
        setState($pdo, $uid, "ann_private_getid");
        editMessageText($chat_id, $mid, "👤 لطفاً آیدی عددی کاربر مقصد رو وارد کن:", [
            'inline_keyboard' => [
                [['text'=>'🔙 بازگشت','callback_data'=>'admin_announcements']]
            ]
        ]);
    } else {
        // روال قبلی
        setState($pdo, $uid, "ann_input:$mode");
        editMessageText($chat_id, $mid, "✍️ متن اعلان برای <b>$mode</b> رو ارسال کن.\nبعد از ارسال، پیش‌نمایش نمایش داده میشه.", [
            'inline_keyboard' => [
                [['text'=>'🔙 بازگشت','callback_data'=>'admin_announcements']]
            ]
        ]);
    }
    answerCb($cb['id'],'');
    exit;
}




if (str_starts_with($data, 'ann_confirm:')) {
    $parts = explode(':', $data);
    $mode = $parts[1];
    $target_id = $parts[2] ?? null;


    // گرفتن state
    $state_parts = explode(':', getState($pdo, $uid));

    // پیام نهایی
    if ($mode === 'private') {
        // state = ann_preview:private:123456789:ENCODED
        $encoded = $state_parts[3] ?? '';
    } else {
        // state = ann_preview:all:ENCODED
        $encoded = $state_parts[2] ?? '';
    }
    $msg = base64_decode($encoded);

    // تولید شناسه یکتا
    $announcement_id = 'ann_' . bin2hex(random_bytes(8));
    $type = $mode === 'private' ? 'private' : $mode;
    $save_target_id = $mode === 'private' ? $target_id : null;

    // ذخیره در جدول announcements
    $st = $pdo->prepare("
        INSERT INTO announcements (admin_id, message, type, target_id, sent_at, unique_id) 
        VALUES (?,?,?,?,?,?)
    ");
    $st->execute([$uid, $msg, $type, $save_target_id, date('Y-m-d H:i:s'), $announcement_id]);

    if ($mode === 'private') {
        // 🔹 فقط ارسال برای یک کاربر
        $ok = sendMessage($target_id, $msg);
        clearState($pdo, $uid);

        $report = "📢 <b>اعلان شخصی ارسال شد!</b>\n\n";
        $report .= "👤 گیرنده: <code>$target_id</code>\n";
        $report .= "🧑‍💻 ارسال‌کننده: <code>$uid</code>\n";
        $report .= "🕒 زمان: " . jdate("Y/m/d - H:i") . "\n";
        $report .= "📄 متن: <i>" . mb_substr($msg,0,100) . "</i>";
        $report .= $ok ? "\n✅ با موفقیت ارسال شد." : "\n❌ ارسال ناموفق بود.";

        sendMessage($uid, $report, [
            'inline_keyboard' => [
                [['text'=>'🔙 بازگشت','callback_data'=>'admin_announcements']]
            ]
        ]);

        answerCb($cb['id'], $ok ? "✅ ارسال شد" : "❌ خطا در ارسال");
    } else {
        // 🔹 ارسال همگانی
        $st = $pdo->query("SELECT id, last_announcement_id FROM users");
        $users = $st->fetchAll();

        $sent_count = 0;
        foreach ($users as $u) {
            if ($u['last_announcement_id'] === $announcement_id) continue;
            if (sendMessage($u['id'], $msg)) {
                $sent_count++;
                $st2 = $pdo->prepare("UPDATE users SET last_announcement_id=? WHERE id=?");
                $st2->execute([$announcement_id, $u['id']]);
            }
        }

        clearState($pdo, $uid);

        // گزارش
        $preview = mb_substr($msg, 0, 100) . (mb_strlen($msg) > 100 ? '...' : '');
        $success_rate = $sent_count > 0 ? round(($sent_count / count($users)) * 100, 1) : 0;
        $failed_count = count($users) - $sent_count;

        $report = "📢 <b>اعلان ارسال شد!</b>\n\n";
        $report .= "🆔 شناسه: <code>$announcement_id</code>\n";
        $report .= "🧑‍💻 ارسال‌کننده: <code>$uid</code>\n";
        $report .= "🕒 زمان: " . jdate("Y/m/d - H:i") . "\n";
        $report .= "📄 متن: <i>$preview</i>\n";
        $report .= "📊 کاربران هدف: <b>" . count($users) . "</b>\n";
        $report .= "✅ موفق: <b>$sent_count</b>\n";
        $report .= "❌ ناموفق: <b>$failed_count</b>\n";
        $report .= "📈 نرخ موفقیت: <b>$success_rate٪</b>";
        if ($failed_count > 0) $report .= "\n⚠️ <i>برخی کاربران پیام را دریافت نکردند.</i>";

        $kb = ['inline_keyboard' => [
            [['text'=>'📄 مشاهده اعلان','callback_data'=>"ann_view:$announcement_id"]],
            [['text'=>'🔁 ارسال مجدد','callback_data'=>"ann_resend:$announcement_id"], ['text'=>'🗑 حذف اعلان','callback_data'=>"ann_delete:$announcement_id"]],
            [['text'=>'📊 آمار اعلان','callback_data'=>"ann_stats:$announcement_id"], ['text'=>'✏️ ویرایش','callback_data'=>"ann_edit:$announcement_id"]],
            [['text'=>'🔙 بازگشت','callback_data'=>'admin_announcements']]
        ]];

        sendMessage($uid, $report, $kb);
        answerCb($cb['id'], "✅ اعلان ارسال شد به $sent_count کاربر");
    }
    exit;
}




if (str_starts_with($data, 'ann_resend:')) {
    [, $ann_id] = explode(':', $data);

    $st = $pdo->prepare("SELECT message FROM announcements WHERE unique_id=?");
    $st->execute([$ann_id]);
    $msg = $st->fetchColumn();

    if (!$msg) {
        answerCb($cb['id'], '❌ اعلان پیدا نشد');
        exit;
    }

    $st = $pdo->query("SELECT id, last_announcement_id FROM users");
    $users = $st->fetchAll();

    $sent_count = 0;
    foreach ($users as $u) {
        if ($u['last_announcement_id'] === $ann_id) continue;

        sendMessage($u['id'], $msg);
        $sent_count++;

        $st2 = $pdo->prepare("UPDATE users SET last_announcement_id=? WHERE id=?");
        $st2->execute([$ann_id, $u['id']]);
    }

    editMessageText($chat_id,$mid, "✅ ارسال مجدد انجام شد برای <b>$sent_count</b> کاربر", [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>"ann_back:$ann_id"]]
        ]
    ]);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'ann_delete:')) {
    [, $ann_id] = explode(':', $data);

    $st = $pdo->prepare("DELETE FROM announcements WHERE unique_id=?");
    $st->execute([$ann_id]);

    editMessageText($chat_id,$mid, "🗑 اعلان با شناسه <code>$ann_id</code> حذف شد", [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>"ann_back:$ann_id"]]
        ]
    ]);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'ann_stats:')) {
    [, $ann_id] = explode(':', $data);

    $st = $pdo->query("SELECT COUNT(*) FROM users");
    $total = $st->fetchColumn();

    $st = $pdo->prepare("SELECT COUNT(*) FROM users WHERE last_announcement_id=?");
    $st->execute([$ann_id]);
    $sent = $st->fetchColumn();

    $failed = $total - $sent;
    $rate = $sent > 0 ? round(($sent / $total) * 100, 1) : 0;

    $txt = "📊 آمار اعلان <code>$ann_id</code>\n\n";
    $txt .= "👥 کاربران کل: <b>$total</b>\n";
    $txt .= "✅ ارسال موفق: <b>$sent</b>\n";
    $txt .= "❌ ارسال نشده: <b>$failed</b>\n";
    $txt .= "📈 نرخ موفقیت: <b>$rate٪</b>";

    editMessageText($chat_id,$mid, $txt, [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>"ann_back:$ann_id"]]
        ]
    ]);
    exit;
}

if (str_starts_with($data, 'ann_edit:')) {
    [, $ann_id] = explode(':', $data);

    setState($pdo, $uid, "edit_announcement:$ann_id");

    sendMessage($uid, "✏️ متن جدید برای اعلان <code>$ann_id</code> رو ارسال کن:", [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>"ann_back:$ann_id"]]
        ]
    ]);
    answerCb($cb['id'], '');
    exit;
}

// دریافت متن جدید
//if (str_starts_with($state, 'edit_announcement:')) {
   // [, $ann_id] = explode(':', $state);

  //  $st = $pdo->prepare("UPDATE announcements SET message=? WHERE unique_id=?");
   // $st->execute([$text, $ann_id]);

   // clearState($pdo, $uid);
   // sendMessage($uid, "✅ متن اعلان <code>$ann_id</code> با موفقیت ویرایش شد.");
//exit;
//}



if ($data === 'ann_report') {
    $st = $pdo->query("SELECT COUNT(*) as total, SUM(views) as views FROM announcements");
    $r = $st->fetch();

    $txt = "📊 گزارش کلی:\n";
    $txt .= "تعداد اعلان‌ها: <b>{$r['total']}</b>\n";
    $txt .= "مجموع بازدیدها: <b>{$r['views']}</b>";

    editMessageText($chat_id, $mid, $txt, [
        'inline_keyboard' => [
            [['text'=>'🔙 بازگشت','callback_data'=>"admin_announcements"]]
        ]
    ]);
    answerCb($cb['id'],'');
    exit;
}

if (str_starts_with($data, 'ann_back:')) {
    [, $ann_id] = explode(':', $data);

    // دریافت اطلاعات اعلان
    $st = $pdo->prepare("SELECT admin_id, message, sent_at FROM announcements WHERE unique_id=?");
    $st->execute([$ann_id]);
    $e = $st->fetch();

    if (!$e) {
        answerCb($cb['id'], '❌ اعلان پیدا نشد');
        exit;
    }

    $st = $pdo->query("SELECT COUNT(*) FROM users");
    $total = $st->fetchColumn();

    $st = $pdo->prepare("SELECT COUNT(*) FROM users WHERE last_announcement_id=?");
    $st->execute([$ann_id]);
    $sent = $st->fetchColumn();

    $failed = $total - $sent;
    $rate = $sent > 0 ? round(($sent / $total) * 100, 1) : 0;
    $preview = mb_substr($e['message'], 0, 100) . (mb_strlen($e['message']) > 100 ? '...' : '');

    $txt = "📢 <b>اعلان ارسال شده</b>\n\n";
    $txt .= "🆔 شناسه: <code>$ann_id</code>\n";
    $txt .= "🧑‍💻 ارسال‌کننده: <code>{$e['admin_id']}</code>\n";
    $txt .= "🕒 زمان: " . jdate("Y/m/d - H:i", strtotime($e['sent_at'])) . "\n";
    $txt .= "📄 متن: <i>$preview</i>\n";
    $txt .= "📊 کاربران هدف: <b>$total</b>\n";
    $txt .= "✅ موفق: <b>$sent</b>\n";
    $txt .= "❌ ناموفق: <b>$failed</b>\n";
    $txt .= "📈 نرخ موفقیت: <b>$rate٪</b>";

    $kb = ['inline_keyboard' => [
        [['text'=>'📄 مشاهده اعلان','callback_data'=>"ann_view:$ann_id"]],
        [['text'=>'🔁 ارسال مجدد','callback_data'=>"ann_resend:$ann_id"], ['text'=>'🗑 حذف اعلان','callback_data'=>"ann_delete:$ann_id"]],
        [['text'=>'📊 آمار اعلان','callback_data'=>"ann_stats:$ann_id"], ['text'=>'✏️ ویرایش','callback_data'=>"ann_edit:$ann_id"]],
        [['text'=>'🔙 بازگشت','callback_data'=>"admin_announcements"]]
    ]];

    editMessageText($chat_id, $mid, $txt, $kb);
    answerCb($cb['id'], '');
    exit;
}

if (str_starts_with($data, 'admin_finish:')) {
 if (!isAdmin($uid)) { answerCb($cb['id'], '⛔️', true); exit; }
    $parts = explode(':', $data);
    $eid = (int)($parts[1] ?? 0);
    $players = getEventPlayers($pdo, $eid);
    if ($players === null) { answerCb($cb['id'], 'پیدا نشد'); exit; }

    saveSelectionSession($pdo, $eid, $uid, [], 'open', null);
    renderAdminSelectionMenu(
        $pdo,
        $chat_id,
        $mid,
        $eid,
        $players,
        [],
        "انتخاب برنده — رویداد #{$eid}\nبرای انتخاب چند برنده، روی نام‌ها بزنید تا تیک بخورد.",
        $players
    );
    answerCb($cb['id'], '');
    exit;
}


http_response_code(200);
exit;
?>
