function sendMessage($chat_id,string $text,$reply_to=null,$kb=null,$protect=false){
    global $BOT_USERNAME;
    $L = $GLOBALS['_LANG'] ?? 'fa';
    $defaultKb=['inline_keyboard'=>[[['text'=>t('add_to_group',$L),'url'=>"https://t.me/{$BOT_USERNAME}?startgroup=start"]]]];
    $data=[
        'chat_id'=>$chat_id,
        'text'=>$text,
        'parse_mode'=>'HTML',
        'disable_web_page_preview'=>true,
        'reply_markup'=>json_encode($kb??$defaultKb, JSON_UNESCAPED_UNICODE),
        'protect_content'=>$protect?true:false,
    ];
    if($reply_to) $data['reply_to_message_id']=$reply_to;
    tgApi('sendMessage',$data);
}
function editMessageText($chat_id,$message_id,string $text,$kb=null){
    $data=['chat_id'=>$chat_id,'message_id'=>$message_id,'text'=>$text,'parse_mode'=>'HTML','disable_web_page_preview'=>true];
    if($kb) $data['reply_markup']=json_encode($kb, JSON_UNESCAPED_UNICODE);
    tgApi('editMessageText',$data);
}
function answerCb($cb_id,$text=null,$alert=false){
    $d=['callback_query_id'=>$cb_id];
    if($text!==null){ $d['text']=$text; $d['show_alert']=$alert?true:false; }
    tgApi('answerCallbackQuery',$d);
}

/* ================== BOT HELPERS ================== */
function getBotMe(): array {
    static $me = null;
    if ($me !== null) return $me;
    $res = tgApi('getMe', []);
    $me = (is_array($res) && !empty($res['ok']) && is_array($res['result'])) ? $res['result'] : [];
    return $me;
}
function getBotId(): int {
    global $BOT_TOKEN;
    // A bot token is "<bot_id>:<secret>", so the id is free — no getMe() call.
    if (preg_match('/^(\d+):/', (string)$BOT_TOKEN, $m)) return (int)$m[1];
    $me = getBotMe();
    return (int)($me['id'] ?? 0);
}

/**
 * Whether the bot is an admin in $chat_id.
 *
 * Cached because it used to cost a getChatMember round-trip on EVERY group
 * message -- twice, since the tracking helper and the group gate each asked.
function buildAdminPremiumText(): string {
    if (!function_exists('premiumEmojiMap')) {
        return "⚠️ ماژول ایموجی پریمیوم لود نشده است.";
    }

    $all = premiumEmojiMap(false);
    $valid = premiumEmojiMap(true);

    $lines = [];
    $lines[] = "💎 <b>پنل ایموجی پریمیوم</b>";
    $lines[] = "";
    $lines[] = "از لیست پایین انتخاب کن کدام ایموجی معمولی ربات به پریمیوم تبدیل شود، بعد خود <b>Custom Emoji</b> را برای ربات بفرست.";
    $lines[] = "";
    $lines[] = "تعداد قابل مدیریت: <b>" . count($all) . "</b>";
    $lines[] = "تعداد ثبت‌شده: <b>" . count($valid) . "</b>";
    $lines[] = "";
    $lines[] = "<b>راهنما:</b>";
    $lines[] = "✅ یعنی برای آن ایموجی پریمیوم ثبت شده.";
    $lines[] = "▫️ یعنی هنوز پریمیوم نشده.";
    $lines[] = "";
    $lines[] = "برای شروع، روی خود ایموجی از دکمه‌های پایین بزن.";
    $lines[] = "لغو عملیات: /cancel";

    if ($valid) {
        $lines[] = "";
        $lines[] = "<b>ثبت‌شده‌های فعلی:</b>";
        foreach ($valid as $emoji => $id) {
            $safeEmoji = htmlspecialchars((string)$emoji, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
            $safeId = htmlspecialchars((string)$id, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
            $lines[] = "• {$safeEmoji} → <code>{$safeId}</code>";
        }
    }

    return implode("\n", $lines);
}
function buildAdminPremiumChooseText(): string {
    return "💎 <b>انتخاب ایموجی</b>\n\nاز دکمه‌های پایین انتخاب کن کدام ایموجی معمولی داخل متن‌ها و دکمه‌های ربات باید با Premium Custom Emoji جایگزین شود.\n\nبعد از انتخاب، ربات ازت می‌خواهد ایموجی پریمیوم را بفرستی.";
}
function buildAdminPremiumSelectedText(string $target): string {
    $safeTarget = htmlspecialchars($target, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    return "💎 <b>ثبت ایموجی پریمیوم برای {$safeTarget}</b>\n\nحالا فقط خود <b>Premium/Custom Emoji</b> را به صورت پیام متنی بفرست.\n\nربات فقط <code>custom_emoji_id</code> را برمی‌دارد و برای ایموجی {$safeTarget} ذخیره می‌کند.\n\nلغو: /cancel";
