<?php

declare(strict_types=1);

use Bot\Domain\Service\AdminService;
use Bot\Domain\Service\AnalyticsService;
use Bot\Domain\Service\LogService;
use Bot\Domain\Service\MediaService;
use Bot\Domain\Service\UserService;
use Bot\Domain\Service\AdsService;
use Bot\Domain\ValueObject\MediaType;
use SergiX44\Nutgram\Nutgram;

/**
 * هندلرهای دستورات متنی
 */
function registerCommandHandlers(
    Nutgram $bot,
    UserService $userService,
    AdminService $adminService,
    MediaService $mediaService,
    AnalyticsService $analyticsService,
    AdsService $adsService,
    ?int $ownerTelegramId,
    LogService $logService,
): void {
    // دستور /broadcast برای ارسال/فوروارد گروهی مدیا
    $bot->onCommand('broadcast', function (Nutgram $bot) use (
        $adminService,
        $mediaService,
        $userService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // بررسی دسترسی ادمین
        $isAdmin = ($ownerTelegramId !== null && $telegramId === $ownerTelegramId) 
            || $adminService->getByTelegramId($telegramId) !== null;
        
        if (!$isAdmin) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 3);

        if (count($parts) < 2) {
            $bot->sendMessage(
                "استفاده: /broadcast <media_id> [all|users|channel_id]" . PHP_EOL .
                "مثال: /broadcast 1 all" . PHP_EOL .
                "مثال: /broadcast 1 -1001234567890"
            );
            return;
        }

        $mediaId = (int) ($parts[1] ?? 0);
        $target = $parts[2] ?? 'all';

        $media = $mediaService->findById($mediaId);
        if ($media === null) {
            $bot->sendMessage("مدیا با شناسه {$mediaId} یافت نشد.");
            return;
        }

        $sentCount = 0;
        $failedCount = 0;

        if ($target === 'all' || $target === 'users') {
            // ارسال به همه کاربران
            $users = $userService->getAll();
            $bot->sendMessage("شروع ارسال به " . count($users) . " کاربر...");

            foreach ($users as $user) {
                try {
                    $caption = $media->getCaption();
                    switch ($media->getType()) {
                        case MediaType::PHOTO->value:
                            $bot->sendPhoto($media->getTelegramFileId(), chat_id: $user->getTelegramId(), caption: $caption);
                            break;
                        case MediaType::VIDEO->value:
                            $bot->sendVideo($media->getTelegramFileId(), chat_id: $user->getTelegramId(), caption: $caption);
                            break;
                        case MediaType::DOCUMENT->value:
                        default:
                            $bot->sendDocument($media->getTelegramFileId(), chat_id: $user->getTelegramId(), caption: $caption);
                            break;
                    }
                    $sentCount++;
                    // تأخیر برای رعایت محدودیت‌های API تلگرام
                    usleep(50000); // 50ms
                } catch (Throwable $e) {
                    $failedCount++;
                }
            }
        } else {
            // ارسال به کانال/گروه خاص
            $chatId = $target;
            try {
                $caption = $media->getCaption();
                        switch ($media->getType()) {
                            case MediaType::PHOTO->value:
                                $bot->sendPhoto($media->getTelegramFileId(), chat_id: $chatId, caption: $caption);
                                break;
                            case MediaType::VIDEO->value:
                                $bot->sendVideo($media->getTelegramFileId(), chat_id: $chatId, caption: $caption);
                                break;
                            case MediaType::DOCUMENT->value:
                            default:
                                $bot->sendDocument($media->getTelegramFileId(), chat_id: $chatId, caption: $caption);
                                break;
                        }
                $sentCount = 1;
            } catch (Throwable $e) {
                $failedCount = 1;
                $bot->sendMessage("خطا در ارسال به {$chatId}: " . $e->getMessage());
                return;
            }
        }

        $bot->sendMessage(
            "ارسال انجام شد! ✅" . PHP_EOL .
            "موفق: {$sentCount}" . PHP_EOL .
            "ناموفق: {$failedCount}"
        );
    });

    // دستور /forward برای فوروارد گروهی مدیا
    $bot->onCommand('forward', function (Nutgram $bot) use (
        $adminService,
        $userService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط ادمین‌ها می‌توانند forward کنند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 3);

        if (count($parts) < 3) {
            $bot->sendMessage(
                "استفاده: /forward <message_id> <target_chat_id>" . PHP_EOL .
                "مثال: /forward 123 -1001234567890" . PHP_EOL .
                "یا: /forward 123 all (برای فوروارد به همه کاربران)"
            );
            return;
        }

        $messageId = (int) ($parts[1] ?? 0);
        $target = $parts[2] ?? '';

        $fromChatId = $bot->chatId();
        if ($fromChatId === null) {
            $bot->sendMessage("خطا: شناسه چت یافت نشد.");
            return;
        }

        $sentCount = 0;
        $failedCount = 0;

        if ($target === 'all') {
            // فوروارد به همه کاربران
            $users = $userService->getAll();
            $bot->sendMessage("شروع فوروارد به " . count($users) . " کاربر...");

            foreach ($users as $user) {
                try {
                    $bot->forwardMessage(
                        chat_id: $user->getTelegramId(),
                        from_chat_id: $fromChatId,
                        message_id: $messageId,
                    );
                    $sentCount++;
                    // تأخیر برای رعایت محدودیت‌های API تلگرام
                    usleep(50000); // 50ms
                } catch (Throwable $e) {
                    $failedCount++;
                }
            }
        } else {
            // فوروارد به کانال/گروه خاص
            try {
                $bot->forwardMessage(
                    chat_id: $target,
                    from_chat_id: $fromChatId,
                    message_id: $messageId,
                );
                $sentCount = 1;
            } catch (Throwable $e) {
                $failedCount = 1;
                $bot->sendMessage("خطا در فوروارد به {$target}: " . $e->getMessage());
                return;
            }
        }

        $bot->sendMessage(
            "فوروارد انجام شد! ✅" . PHP_EOL .
            "موفق: {$sentCount}" . PHP_EOL .
            "ناموفق: {$failedCount}"
        );
    });

    // دستور /stats - هدایت به منوی آمار
    $bot->onCommand('stats', function (Nutgram $bot) use (
        $userService,
        $adminService,
        $analyticsService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $isAdmin = ($ownerTelegramId !== null && $telegramId === $ownerTelegramId) 
            || $adminService->getByTelegramId($telegramId) !== null;

        if ($isAdmin) {
            $bot->sendMessage(
                '📊 آمار و گزارشات',
                reply_markup: buildAdminStatsMenu()
            );
        } else {
            $user = $userService->getOrCreateByTelegramId($telegramId);
            $downloads = $analyticsService->getDownloadCountForUser($user->getId());
            $clicks = $analyticsService->getClickCountForUser($user->getId());
            $payments = $analyticsService->getPaymentCountForUser($user->getId());
            
            $text = "📊 آمار شخصی" . PHP_EOL . PHP_EOL;
            $text .= "📥 دانلودها: {$downloads}" . PHP_EOL;
            $text .= "👆 کلیک‌ها: {$clicks}" . PHP_EOL;
            $text .= "💳 پرداخت‌ها: {$payments}" . PHP_EOL . PHP_EOL;
            $text .= "وضعیت: " . ($user->getMode() === 'premium' ? '⭐ پریمیوم' : '🆓 رایگان');
            
            $bot->sendMessage(
                $text,
                reply_markup: buildUserStatsMenu()
            );
        }
    });

    // دستور /admins - هدایت به منوی مدیریت ادمین‌ها
    $bot->onCommand('admins', function (Nutgram $bot) use (
        $adminService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند لیست ادمین‌ها را ببیند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        $bot->sendMessage(
            '👥 مدیریت ادمین‌ها',
            reply_markup: buildAdminsMenu()
        );
    });

    // دستور /addadmin برای افزودن ادمین
    $bot->onCommand('addadmin', function (Nutgram $bot) use (
        $adminService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند ادمین اضافه کند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage(
                "استفاده: /addadmin <telegram_id>" . PHP_EOL . PHP_EOL .
                "یا از منوی مدیریت ادمین‌ها استفاده کنید:",
                reply_markup: buildAdminsMenu()
            );
            return;
        }

        $newAdminId = (int) ($parts[1] ?? 0);
        if ($newAdminId === 0) {
            $bot->sendMessage("شناسه تلگرام معتبر نیست.");
            return;
        }

        $admin = $adminService->addAdmin($newAdminId);
        $bot->sendMessage("ادمین با شناسه {$newAdminId} اضافه شد. ✅");
    });

    // دستور /removeadmin برای حذف ادمین
    $bot->onCommand('removeadmin', function (Nutgram $bot) use (
        $adminService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند ادمین حذف کند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /removeadmin <telegram_id>");
            return;
        }

        $adminIdToRemove = (int) ($parts[1] ?? 0);
        if ($adminIdToRemove === 0) {
            $bot->sendMessage("شناسه تلگرام معتبر نیست.");
            return;
        }

        $removed = $adminService->removeAdmin($adminIdToRemove);
        if ($removed) {
            $bot->sendMessage("ادمین با شناسه {$adminIdToRemove} حذف شد. ✅");
        } else {
            $bot->sendMessage("ادمین یافت نشد یا نمی‌توان owner را حذف کرد.");
        }
    });

    // دستور /ads - هدایت به منوی مدیریت تبلیغات
    $bot->onCommand('ads', function (Nutgram $bot) use (
        $adminService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $isAdmin = ($ownerTelegramId !== null && $telegramId === $ownerTelegramId) 
            || $adminService->getByTelegramId($telegramId) !== null;

        if (!$isAdmin) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $bot->sendMessage(
            '📢 مدیریت تبلیغات',
            reply_markup: buildAdsMenu()
        );
    });

    // دستور /addad برای افزودن تبلیغ
    $bot->onCommand('addad', function (Nutgram $bot) use (
        $adminService,
        $adsService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /addad <متن تبلیغ>");
            return;
        }

        $adText = $parts[1] ?? '';
        $ad = $adsService->createAd($admin->getId(), $adText);

        $bot->sendMessage("تبلیغ با شناسه #{$ad->getId()} اضافه شد. ✅");
    });

    // دستور /togglead برای فعال/غیرفعال کردن تبلیغ
    $bot->onCommand('togglead', function (Nutgram $bot) use (
        $adminService,
        $adsService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /togglead <ad_id>");
            return;
        }

        $adId = (int) ($parts[1] ?? 0);
        $ad = $adsService->findById($adId);

        if ($ad === null || $ad->getOwnerAdminId() !== $admin->getId()) {
            $bot->sendMessage("تبلیغ یافت نشد یا شما دسترسی ندارید.");
            return;
        }

        $ad->toggle(!$ad->isEnabled());
        $adsService->updateAd($ad);

        $status = $ad->isEnabled() ? "فعال" : "غیرفعال";
        $bot->sendMessage("تبلیغ #{$adId} {$status} شد. ✅");
    });

    // دستور /deletead برای حذف تبلیغ
    $bot->onCommand('deletead', function (Nutgram $bot) use (
        $adminService,
        $adsService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /deletead <ad_id>");
            return;
        }

        $adId = (int) ($parts[1] ?? 0);
        $ad = $adsService->findById($adId);

        if ($ad === null || $ad->getOwnerAdminId() !== $admin->getId()) {
            $bot->sendMessage("تبلیغ یافت نشد یا شما دسترسی ندارید.");
            return;
        }

        $adsService->deleteAd($adId);
        $bot->sendMessage("تبلیغ #{$adId} حذف شد. ✅");
    });

    // دستور /mediainfo برای نمایش اطلاعات مدیا
    $bot->onCommand('mediainfo', function (Nutgram $bot) use (
        $adminService,
        $mediaService,
        $analyticsService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /mediainfo <media_id>");
            return;
        }

        $mediaId = (int) ($parts[1] ?? 0);
        $media = $mediaService->findById($mediaId);

        if ($media === null || $media->getOwnerAdminId() !== $admin->getId()) {
            $bot->sendMessage("مدیا یافت نشد یا شما دسترسی ندارید.");
            return;
        }

        $downloads = $analyticsService->getDownloadCount($mediaId);
        $clicks = $analyticsService->getClickCount($mediaId);

        $info = "📊 اطلاعات مدیا #{$mediaId}\n\n";
        $info .= "نوع: {$media->getType()}\n";
        $info .= "پوشه: #{$media->getFolderId()}\n";
        $info .= "Thumbnail: " . ($media->isThumbnailEnabled() ? "✅ فعال" : "❌ غیرفعال") . "\n";
        $info .= "لینک در کپشن: " . ($media->isLinkInCaptionEnabled() ? "✅ فعال" : "❌ غیرفعال") . "\n";
        if ($media->getAutoDeleteSeconds() !== null) {
            $info .= "Auto-delete: {$media->getAutoDeleteSeconds()} ثانیه\n";
        } else {
            $info .= "Auto-delete: ❌ غیرفعال\n";
        }
        $info .= "دانلود: {$downloads}\n";
        $info .= "کلیک: {$clicks}\n";
        if ($media->getCaption() !== null) {
            $info .= "کپشن: " . mb_substr($media->getCaption(), 0, 100) . "...\n";
        }

        $bot->sendMessage($info);
    });

    // دستور /toggletumbnail برای فعال/غیرفعال کردن Thumbnail
    $bot->onCommand('toggletumbnail', function (Nutgram $bot) use (
        $adminService,
        $mediaService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /toggletumbnail <media_id>");
            return;
        }

        $mediaId = (int) ($parts[1] ?? 0);
        $media = $mediaService->findById($mediaId);

        if ($media === null || $media->getOwnerAdminId() !== $admin->getId()) {
            $bot->sendMessage("مدیا یافت نشد یا شما دسترسی ندارید.");
            return;
        }

        $media->toggleThumbnail(!$media->isThumbnailEnabled());
        $mediaService->updateMedia($media);

        $status = $media->isThumbnailEnabled() ? "فعال" : "غیرفعال";
        $bot->sendMessage("Thumbnail مدیا #{$mediaId} {$status} شد. ✅");
    });

    // دستور /togglelinkcaption برای فعال/غیرفعال کردن لینک در کپشن
    $bot->onCommand('togglelinkcaption', function (Nutgram $bot) use (
        $adminService,
        $mediaService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /togglelinkcaption <media_id>");
            return;
        }

        $mediaId = (int) ($parts[1] ?? 0);
        $media = $mediaService->findById($mediaId);

        if ($media === null || $media->getOwnerAdminId() !== $admin->getId()) {
            $bot->sendMessage("مدیا یافت نشد یا شما دسترسی ندارید.");
            return;
        }

        $media->toggleLinkInCaption(!$media->isLinkInCaptionEnabled());
        $mediaService->updateMedia($media);

        $status = $media->isLinkInCaptionEnabled() ? "فعال" : "غیرفعال";
        $bot->sendMessage("لینک در کپشن مدیا #{$mediaId} {$status} شد. ✅");
    });

    // دستور /setautodelete برای تنظیم Auto-delete timer
    $bot->onCommand('setautodelete', function (Nutgram $bot) use (
        $adminService,
        $mediaService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 3);

        if (count($parts) < 3) {
            $bot->sendMessage("استفاده: /setautodelete <media_id> <seconds> (0 برای غیرفعال کردن)");
            return;
        }

        $mediaId = (int) ($parts[1] ?? 0);
        $seconds = (int) ($parts[2] ?? 0);
        $media = $mediaService->findById($mediaId);

        if ($media === null || $media->getOwnerAdminId() !== $admin->getId()) {
            $bot->sendMessage("مدیا یافت نشد یا شما دسترسی ندارید.");
            return;
        }

        $media->setAutoDeleteSeconds($seconds > 0 ? $seconds : null);
        $mediaService->updateMedia($media);

        if ($seconds > 0) {
            $bot->sendMessage("Auto-delete timer برای مدیا #{$mediaId} روی {$seconds} ثانیه تنظیم شد. ✅");
        } else {
            $bot->sendMessage("Auto-delete timer برای مدیا #{$mediaId} غیرفعال شد. ✅");
        }
    });

    // ذخیره‌سازی پیام‌های Forced-Seen
    /** @var array<string,bool> keyed by "chat_id:message_id" */
    static $forcedSeenMessages = [];

    // هندلر برای Reactions
    $bot->onMessageReaction(function (Nutgram $bot) use (&$forcedSeenMessages) {
        $messageReaction = $bot->messageReaction();
        if ($messageReaction === null) {
            return;
        }

        $chatId = $bot->chatId();
        $messageId = $bot->messageId();
        if ($chatId === null || $messageId === null) {
            return;
        }

        $key = "{$chatId}:{$messageId}";
        if (isset($forcedSeenMessages[$key])) {
            // کاربر reaction داده است، پیام دیده شده است
            $forcedSeenMessages[$key] = true;
        }
    });

    // دستور /forceseen برای ارسال پیام با Forced-Seen
    $bot->onCommand('forceseen', function (Nutgram $bot) use (
        &$forcedSeenMessages,
        $adminService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 2);

        if (count($parts) < 2) {
            $bot->sendMessage("استفاده: /forceseen <متن پیام>");
            return;
        }

        $messageText = $parts[1] ?? '';
        $sentMessage = $bot->sendMessage($messageText);

        if ($sentMessage !== null) {
            $chatId = $sentMessage->chat->id;
            $messageId = $sentMessage->message_id;
            $key = "{$chatId}:{$messageId}";
            $forcedSeenMessages[$key] = false; // منتظر reaction هستیم

            // درخواست reaction
            try {
                $bot->setMessageReaction($chatId, $messageId, ['👍']);
            } catch (Throwable) {
                // اگر reaction پشتیبانی نشد، نادیده می‌گیریم
            }
        }
    });

    // دستور /checkforceseen برای بررسی وضعیت Forced-Seen
    $bot->onCommand('checkforceseen', function (Nutgram $bot) use (
        &$forcedSeenMessages,
        $adminService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;
        $admin = getOrCreateAdmin($adminService, $telegramId, $ownerTelegramId);

        if ($admin === null) {
            $bot->sendMessage("فقط ادمین‌ها می‌توانند از این دستور استفاده کنند.");
            return;
        }

        $message = $bot->message();
        $text = $message?->text ?? '';
        $parts = explode(' ', $text, 3);

        if (count($parts) < 3) {
            $bot->sendMessage("استفاده: /checkforceseen <chat_id> <message_id>");
            return;
        }

        $chatId = $parts[1] ?? '';
        $messageId = (int) ($parts[2] ?? 0);
        $key = "{$chatId}:{$messageId}";

        if (isset($forcedSeenMessages[$key])) {
            $status = $forcedSeenMessages[$key] ? "✅ دیده شده" : "⏳ منتظر reaction";
            $bot->sendMessage("وضعیت پیام: {$status}");
        } else {
            $bot->sendMessage("پیام یافت نشد یا Forced-Seen فعال نیست.");
        }
    });
    
    // دستور /crdb برای ایجاد دیتابیس و جداول
    $bot->onCommand('crdb', function (Nutgram $bot) use (
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند دیتابیس را ایجاد کند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("❌ فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        // بررسی تنظیمات دیتابیس
        $dbHost = $_ENV['DB_HOST'] ?? 'localhost';
        $dbPort = isset($_ENV['DB_PORT']) ? (int) $_ENV['DB_PORT'] : 3306;
        $dbName = $_ENV['DB_DATABASE'] ?? $_ENV['DB_NAME'] ?? '';
        $dbUser = $_ENV['DB_USERNAME'] ?? $_ENV['DB_USER'] ?? '';
        $dbPass = $_ENV['DB_PASSWORD'] ?? '';
        
        if (empty($dbName) || empty($dbUser)) {
            $bot->sendMessage(
                "❌ لطفاً ابتدا تنظیمات دیتابیس را در فایل .env وارد کنید!" . PHP_EOL . PHP_EOL .
                "مثال:" . PHP_EOL .
                "DB_HOST=127.0.0.1" . PHP_EOL .
                "DB_PORT=3306" . PHP_EOL .
                "DB_DATABASE=your_database" . PHP_EOL .
                "DB_USERNAME=your_username" . PHP_EOL .
                "DB_PASSWORD=your_password"
            );
            return;
        }

        $bot->sendMessage("🔄 در حال نصب دیتابیس... لطفاً صبر کنید.");

        // اجرای نصب دیتابیس
        try {
            // بررسی وجود extension PDO
            if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) {
                throw new RuntimeException('Extension PDO یا PDO_MySQL نصب نشده است!');
            }
            
            $schemaFile = __DIR__ . '/../../../database/schema.sql';
            if (!file_exists($schemaFile)) {
                throw new RuntimeException('فایل schema.sql یافت نشد! مسیر: ' . $schemaFile);
            }
            
            $schema = file_get_contents($schemaFile);
            if ($schema === false) {
                throw new RuntimeException('خطا در خواندن فایل schema.sql!');
            }
            
            // اتصال به دیتابیس
            $dsn = "mysql:host={$dbHost};port={$dbPort};charset=utf8mb4";
            $pdo = new PDO($dsn, $dbUser, $dbPass, [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
            ]);
            
            // ایجاد دیتابیس اگر وجود نداشته باشد
            $pdo->exec("CREATE DATABASE IF NOT EXISTS `{$dbName}` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci");
            $pdo->exec("USE `{$dbName}`");
            
            // بررسی جداول موجود
            $existingTables = [];
            try {
                $stmt = $pdo->query("SHOW TABLES");
                while ($row = $stmt->fetch(PDO::FETCH_NUM)) {
                    $existingTables[] = $row[0];
                }
            } catch (PDOException $e) {
                // اگر خطا رخ داد، ادامه می‌دهیم
            }
            
            // حذف کامنت‌ها از schema
            $schema = preg_replace('/--.*$/m', '', $schema); // حذف کامنت‌های خطی
            $schema = preg_replace('/\/\*.*?\*\//s', '', $schema); // حذف کامنت‌های چندخطی
            
            // تقسیم schema به دستورات جداگانه
            $statements = [];
            $currentStatement = '';
            $lines = explode("\n", $schema);
            
            foreach ($lines as $line) {
                $line = trim($line);
                if (empty($line)) {
                    continue;
                }
                
                $currentStatement .= $line . "\n";
                
                // اگر خط با ; تمام شده باشد، دستور کامل است
                if (substr(rtrim($line), -1) === ';') {
                    $stmt = trim($currentStatement);
                    if (!empty($stmt) && strlen($stmt) > 5) {
                        $statements[] = $stmt;
                    }
                    $currentStatement = '';
                }
            }
            
            // اگر دستور ناقص باقی مانده باشد
            if (!empty(trim($currentStatement))) {
                $stmt = trim($currentStatement);
                if (!empty($stmt) && strlen($stmt) > 5) {
                    $statements[] = $stmt;
                }
            }
            
            if (empty($statements)) {
                throw new RuntimeException('هیچ دستور SQL معتبری در فایل schema.sql یافت نشد!');
            }
            
            // استخراج نام جداول از دستورات CREATE TABLE
            $requiredTables = [];
            $tableStatements = [];
            
            foreach ($statements as $statement) {
                // استخراج نام جدول از CREATE TABLE
                if (preg_match('/CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?`?(\w+)`?/i', $statement, $matches)) {
                    $tableName = $matches[1];
                    $requiredTables[] = $tableName;
                    $tableStatements[$tableName] = $statement;
                }
            }
            
            // جداول موجود نیست
            $missingTables = array_diff($requiredTables, $existingTables);
            
            // اگر همه جداول موجود هستند
            if (empty($missingTables)) {
                $bot->sendMessage(
                    "✅ همه جداول از قبل موجود هستند!" . PHP_EOL . PHP_EOL .
                    "📊 جداول موجود: " . implode(', ', $requiredTables) . PHP_EOL . PHP_EOL .
                    "هیچ کاری انجام نشد."
                );
                return;
            }
            
            // اجرای فقط جداول موجود نیست
            $createdTables = [];
            $errors = [];
            
            foreach ($missingTables as $tableName) {
                if (!isset($tableStatements[$tableName])) {
                    continue;
                }
                
                try {
                    $statement = trim($tableStatements[$tableName]);
                    if (empty($statement)) {
                        continue;
                    }
                    
                    // تبدیل به CREATE TABLE IF NOT EXISTS برای اطمینان
                    $statement = preg_replace(
                        '/CREATE\s+TABLE\s+(?!IF\s+NOT\s+EXISTS)/i',
                        'CREATE TABLE IF NOT EXISTS ',
                        $statement
                    );
                    
                    // حذف ; از انتها اگر وجود دارد
                    $statement = rtrim($statement, ';');
                    if (empty($statement)) {
                        continue;
                    }
                    
                    $pdo->exec($statement);
                    $createdTables[] = $tableName;
                } catch (PDOException $e) {
                    // اگر خطا مربوط به "table already exists" باشد، نادیده می‌گیریم
                    if (str_contains($e->getMessage(), 'already exists') || 
                        str_contains($e->getMessage(), 'Duplicate table')) {
                        $createdTables[] = $tableName; // به عنوان موجود در نظر می‌گیریم
                        continue;
                    }
                    $errors[] = "خطا در ایجاد جدول {$tableName}: " . $e->getMessage();
                }
            }
            
            // ایجاد فایل flag برای نشان دادن نصب موفق
            if (!empty($createdTables)) {
                $databaseConfigFile = __DIR__ . '/../../../.database_installed';
                file_put_contents($databaseConfigFile, date('Y-m-d H:i:s'));
            }
            
            // پیام نتیجه
            $message = "📊 نتیجه بررسی و نصب جداول:" . PHP_EOL . PHP_EOL;
            
            if (!empty($createdTables)) {
                $message .= "✅ جداول ایجاد شده: " . implode(', ', $createdTables) . PHP_EOL;
            }
            
            $existingRequiredTables = array_intersect($requiredTables, $existingTables);
            if (!empty($existingRequiredTables)) {
                $message .= "✅ جداول موجود (بدون تغییر): " . implode(', ', $existingRequiredTables) . PHP_EOL;
            }
            
            if (!empty($errors)) {
                $message .= PHP_EOL . "❌ خطاها:" . PHP_EOL;
                $message .= implode(PHP_EOL, array_slice($errors, 0, 5));
                if (count($errors) > 5) {
                    $message .= PHP_EOL . "... و " . (count($errors) - 5) . " خطای دیگر";
                }
            }
            
            if (empty($errors) && !empty($createdTables)) {
                $message .= PHP_EOL . PHP_EOL . "✅ نصب با موفقیت انجام شد!";
            } elseif (empty($errors) && empty($createdTables)) {
                $message .= PHP_EOL . PHP_EOL . "✅ همه جداول موجود بودند!";
            }
            
            $bot->sendMessage($message);
            
        } catch (PDOException $e) {
            $bot->sendMessage(
                "❌ خطا در نصب دیتابیس!" . PHP_EOL . PHP_EOL .
                "خطا: " . $e->getMessage() . PHP_EOL .
                "کد خطا: " . $e->getCode()
            );
        } catch (Throwable $e) {
            $bot->sendMessage(
                "❌ خطا در نصب دیتابیس!" . PHP_EOL . PHP_EOL .
                "خطا: " . $e->getMessage() . PHP_EOL .
                "نوع خطا: " . get_class($e)
            );
        }
    });
    
    // دستور /restart برای restart کردن ربات
    $bot->onCommand('restart', function (Nutgram $bot) use (
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند ربات را restart کند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("❌ فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        $bot->sendMessage("🔄 در حال restart کردن ربات... لطفاً صبر کنید.");

        // پیدا کردن مسیر فایل restart.sh
        $restartScript = __DIR__ . '/../../../restart.sh';
        
        if (!file_exists($restartScript)) {
            $bot->sendMessage(
                "❌ فایل restart.sh یافت نشد!" . PHP_EOL .
                "مسیر: {$restartScript}" . PHP_EOL . PHP_EOL .
                "لطفاً به صورت دستی ربات را restart کنید."
            );
            return;
        }

        // بررسی اینکه آیا فایل executable است
        if (!is_executable($restartScript)) {
            // تلاش برای chmod
            chmod($restartScript, 0755);
        }

        // بررسی اینکه آیا restart در حال انجام است
        $restartFlag = __DIR__ . '/../../../.restart_in_progress';
        if (file_exists($restartFlag)) {
            // اگر restart در حال انجام است، فقط پیام بده
            $bot->sendMessage(
                "⚠️ ربات در حال restart شدن است..." . PHP_EOL .
                "لطفاً چند ثانیه صبر کنید."
            );
            return;
        }
        
        // اجرای script restart
        try {
            // ایجاد flag برای جلوگیری از restart مکرر
            file_put_contents($restartFlag, date('Y-m-d H:i:s'));
            
            // ارسال پیام قبل از restart
            $bot->sendMessage(
                "🔄 در حال restart کردن ربات..." . PHP_EOL . PHP_EOL .
                "لطفاً چند ثانیه صبر کنید."
            );
            
            // تاخیر کوتاه برای اطمینان از ارسال پیام
            usleep(500000); // 0.5 ثانیه
            
            // پیدا کردن PID فعلی ربات
            // مسیر PID file داخل پوشه bot (نه پوشه اصلی)
            $pidFile = __DIR__ . '/../../bot.pid';
            $currentPid = null;
            if (file_exists($pidFile)) {
                $currentPid = (int) trim(file_get_contents($pidFile));
            }
            
            // اجرای restart.sh در background
            // استفاده از nohup و تغییر مسیر برای اطمینان از اجرا
            $botDir = __DIR__ . '/../../..';
            $command = sprintf(
                'cd %s && nohup bash %s > /dev/null 2>&1 &',
                escapeshellarg($botDir),
                escapeshellarg($restartScript)
            );
            
            exec($command);
            
            // تاخیر کوتاه برای اطمینان از اجرای دستور
            usleep(200000); // 0.2 ثانیه
            
            // خروج از ربات
            // ربات توسط restart.sh restart می‌شود
            exit(0);
            
        } catch (Throwable $e) {
            // حذف flag در صورت خطا
            if (file_exists($restartFlag)) {
                unlink($restartFlag);
            }
            
            $bot->sendMessage(
                "❌ خطا در restart کردن ربات!" . PHP_EOL . PHP_EOL .
                "خطا: " . $e->getMessage() . PHP_EOL . PHP_EOL .
                "لطفاً به صورت دستی ربات را restart کنید:" . PHP_EOL .
                "./restart.sh"
            );
        }
    });
    
    // دستور /dbstatus برای بررسی وضعیت Repository ها
    $bot->onCommand('dbstatus', function (Nutgram $bot) use (
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند وضعیت را بررسی کند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("❌ فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        // بارگذاری helper
        require_once __DIR__ . '/../database-repositories.php';
        
        $statusText = "📊 وضعیت Repository ها" . PHP_EOL . PHP_EOL;
        
        // بررسی فایل flag
        $databaseConfigFile = __DIR__ . '/../../../.database_installed';
        $isInstalled = file_exists($databaseConfigFile);
        
        $statusText .= "🔍 فایل .database_installed: " . ($isInstalled ? "✅ موجود" : "❌ موجود نیست") . PHP_EOL;
        
        if ($isInstalled) {
            $installedDate = file_get_contents($databaseConfigFile);
            $statusText .= "📅 تاریخ نصب: {$installedDate}" . PHP_EOL;
        }
        
        $statusText .= PHP_EOL;
        
        // بررسی اتصال به دیتابیس
        $pdo = createDatabaseConnection();
        if ($pdo === null) {
            $statusText .= "❌ اتصال به دیتابیس: ناموفق" . PHP_EOL;
            $statusText .= "⚠️ از InMemory Repository ها استفاده می‌شود." . PHP_EOL;
        } else {
            $statusText .= "✅ اتصال به دیتابیس: موفق" . PHP_EOL;
            
            // بررسی Repository های استفاده شده
            if ($isInstalled && $pdo !== null) {
                $statusText .= PHP_EOL . "📦 Repository های فعال:" . PHP_EOL;
                $statusText .= "✅ User: Database" . PHP_EOL;
                $statusText .= "✅ Admin: Database" . PHP_EOL;
                $statusText .= "⚠️ Media: InMemory" . PHP_EOL;
                $statusText .= "⚠️ Analytics: InMemory" . PHP_EOL;
                $statusText .= "⚠️ Payment: InMemory" . PHP_EOL;
                $statusText .= "⚠️ Ads: InMemory" . PHP_EOL;
                
                // شمارش رکوردها
                try {
                    $userCount = $pdo->query('SELECT COUNT(*) as count FROM users')->fetch()['count'];
                    $adminCount = $pdo->query('SELECT COUNT(*) as count FROM admins')->fetch()['count'];
                    
                    $statusText .= PHP_EOL . "📊 تعداد رکوردها:" . PHP_EOL;
                    $statusText .= "👥 کاربران: {$userCount}" . PHP_EOL;
                    $statusText .= "👨‍💼 ادمین‌ها: {$adminCount}" . PHP_EOL;
                } catch (PDOException $e) {
                    $statusText .= PHP_EOL . "❌ خطا در شمارش رکوردها: " . $e->getMessage();
                }
            } else {
                $statusText .= PHP_EOL . "⚠️ از InMemory Repository ها استفاده می‌شود." . PHP_EOL;
            }
        }
        
        $bot->sendMessage($statusText);
    });
    
    // دستور /killall برای متوقف کردن همه instance های ربات
    $bot->onCommand('killall', function (Nutgram $bot) use (
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند از این دستور استفاده کند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("❌ فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        $bot->sendMessage("🛑 در حال متوقف کردن همه instance های ربات...");
        
        try {
            // پیدا کردن مسیر stop.sh
            $stopScript = __DIR__ . '/../../../stop.sh';
            
            if (!file_exists($stopScript)) {
                throw new RuntimeException('فایل stop.sh یافت نشد!');
            }
            
            // اجرای stop.sh در background
            $command = "bash " . escapeshellarg($stopScript) . " 2>&1";
            $output = [];
            $returnVar = 0;
            exec($command, $output, $returnVar);
            
            $result = implode(PHP_EOL, $output);
            
            // بررسی process های باقی‌مانده
            $remainingProcesses = [];
            exec("ps aux | grep -E '[p]hp.*public/index\\.php' | awk '{print \$2}'", $remainingProcesses);
            
            if (empty($remainingProcesses)) {
                $bot->sendMessage(
                    "✅ همه instance های ربات با موفقیت متوقف شدند!" . PHP_EOL . PHP_EOL .
                    "📝 خروجی:" . PHP_EOL . $result
                );
            } else {
                $pids = implode(', ', $remainingProcesses);
                $bot->sendMessage(
                    "⚠️ برخی process ها هنوز در حال اجرا هستند!" . PHP_EOL . PHP_EOL .
                    "🔍 PID های باقی‌مانده: {$pids}" . PHP_EOL . PHP_EOL .
                    "📝 خروجی:" . PHP_EOL . $result . PHP_EOL . PHP_EOL .
                    "💡 برای متوقف کردن دستی:" . PHP_EOL .
                    "kill -9 {$pids}"
                );
            }
            
            // خروج از ربات فعلی
            exit(0);
            
        } catch (Throwable $e) {
            $bot->sendMessage(
                "❌ خطا در متوقف کردن ربات!" . PHP_EOL . PHP_EOL .
                "خطا: " . $e->getMessage() . PHP_EOL . PHP_EOL .
                "💡 برای متوقف کردن دستی:" . PHP_EOL .
                "ps aux | grep 'php.*public/index.php' | awk '{print \$2}' | xargs kill -9"
            );
        }
    });

    // دستور /migrate برای اجرای migration های دیتابیس
    $bot->onCommand('migrate', function (Nutgram $bot) use (
        $adminService,
        $ownerTelegramId,
    ) {
        $from = $bot->user();
        if ($from === null) {
            return;
        }

        $telegramId = (int) $from->id;

        // فقط owner می‌تواند از این دستور استفاده کند
        if ($ownerTelegramId === null || $telegramId !== $ownerTelegramId) {
            $bot->sendMessage("❌ فقط مالک ربات می‌تواند از این دستور استفاده کند.");
            return;
        }

        $bot->sendMessage("🔄 در حال اجرای migration های دیتابیس... لطفاً صبر کنید.");

        try {
            require_once __DIR__ . '/../helpers.php';
            require_once __DIR__ . '/../database-repositories.php';
            
            $pdo = createDatabaseConnection();
            if ($pdo === null) {
                $bot->sendMessage(
                    "❌ اتصال به دیتابیس برقرار نشد!" . PHP_EOL . PHP_EOL .
                    "لطفاً تنظیمات دیتابیس را در فایل .env بررسی کنید."
                );
                return;
            }

            $result = runAllMigrations($pdo);

            $message = "📊 نتیجه اجرای Migration ها:" . PHP_EOL . PHP_EOL;
            $message .= "📁 کل فایل‌ها: {$result['total']}" . PHP_EOL;
            $message .= "✅ اجرا شده: {$result['executed']}" . PHP_EOL;
            $message .= "❌ ناموفق: {$result['failed']}" . PHP_EOL . PHP_EOL;

            if (!empty($result['messages'])) {
                $message .= "📝 جزئیات:" . PHP_EOL;
                foreach ($result['messages'] as $msg) {
                    $message .= $msg . PHP_EOL;
                }
            }

            if ($result['success']) {
                $message .= PHP_EOL . "✅ همه migration ها با موفقیت اجرا شدند!";
            } else {
                $message .= PHP_EOL . "⚠️ برخی migration ها ناموفق بودند. لطفاً لاگ‌ها را بررسی کنید.";
            }

            $bot->sendMessage($message);
        } catch (Throwable $e) {
            $bot->sendMessage(
                "❌ خطا در اجرای migration ها!" . PHP_EOL . PHP_EOL .
                "خطا: " . $e->getMessage()
            );
        }
    });
}

