# script was programmed by:  Kodo
# For any inquiries:         @DevKodo
# Data source and operation: @SourceKodo

import asyncio
import aiohttp
import logging

from aiogram import Router, F, Bot
from aiogram.types import (
    Message, CallbackQuery,
    InlineKeyboardMarkup, InlineKeyboardButton,
)
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from sqlalchemy import select, delete

import sys, os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from config import DEVELOPER_IDS, FACTORY_TOKEN
from information.database import (
    get_session, get_settings, update_settings,
    get_all_buttons, get_button, update_button,
    get_statistics, get_broadcast_settings,
    update_broadcast_settings, get_all_bot_groups,
    get_all_active_users, get_all_users_for_open_msg,
    get_mandatory_channels, get_funded_channels,
    get_payment_packages, get_payment_package,
    update_payment_package, add_payment_package, delete_payment_package,
    get_payment_settings, update_bot_price,
    is_bot_paid as _is_paid_bot_dev,
    get_user_paid_bots, get_user_unpaid_bots,
    get_bot_subscription, expire_bot_subscription,
    create_bot_subscription, make_bot_paid, adjust_bot_subscription,
    get_bot_by_id, get_help_text, update_help_text,
    add_user_balance, get_user_balance,
)
from sqlalchemy import select, delete, func
from information.models import (
    User, Bot as BotModel, FactorySettings, ButtonSetting,
    MandatoryChannel, FundedChannel, FundedSubscription,
    CobotMandatoryChannel, CobotFundedChannel,
    BotGroup, BroadcastSettings, CobotUser,
    ChannelDisplayType, PaymentPackage, PaymentSettings,
)


logger = logging.getLogger(__name__)
dev_router = Router()

BROADCAST_DELAY = 2
BROADCAST_BATCH = 5

BOT_TYPE_KEYS = [
    "communication", "download", "decor",
    "buttons", "factory", "transcoding", "translation", "ai", "translation", "ai"
]

BOT_TYPE_LABELS = {
    "communication": "بوت تواصل",
    "download":      "بوت تحميل",
    "decor":         "بوت زخرفة",
    
    "buttons":       "بوت ازرار",
    "factory":       "مصنع بوتات",
    "transcoding":   "بوت تحويل صيغ",
}

ALL_EDITABLE_BUTTONS = [
    "create", "mybots", "help", "terms",
    "bots_channel", "source_channel", "developer", "back",
] + BOT_TYPE_KEYS


def is_pure_dev(user_id: int) -> bool:
    return user_id in DEVELOPER_IDS


async def is_dev_or_admin_db(user_id: int) -> bool:
    if user_id in DEVELOPER_IDS:
        return True
    async with get_session() as session:
        result = await session.execute(select(User).where(User.id == user_id))
        user = result.scalar_one_or_none()
        return user is not None and (user.is_dev or user.is_admin)


async def notify_devs(bot: Bot, text: str):
    async with get_session() as session:
        result = await session.execute(select(User).where(User.is_dev == True))
        devs = result.scalars().all()
    all_dev_ids = set(DEVELOPER_IDS) | {d.id for d in devs}
    for dev_id in all_dev_ids:
        try:
            await bot.send_message(dev_id, text, parse_mode="HTML", disable_web_page_preview=True)
        except Exception:
            pass


def btn_label(btn: ButtonSetting) -> str:
    emoji = f"{btn.emoji} " if btn.emoji else ""
    return f"{emoji}{btn.label}"

def make_inline_button(text: str, callback_data: str = None, url: str = None,
                        style: str = None, emoji_id: str = None) -> InlineKeyboardButton:
    kwargs = {"text": text}
    if url:
        kwargs["url"] = url
    elif callback_data:
        kwargs["callback_data"] = callback_data
    if style and style != "default":
        style_map = {"green": "success", "blue": "primary", "red": "danger"}
        telegram_style = style_map.get(style)
        if telegram_style:
            kwargs["style"] = telegram_style
    if emoji_id:
        kwargs["icon_custom_emoji_id"] = emoji_id
    return InlineKeyboardButton(**kwargs)

class DevStates(StatesGroup):
    waiting_broadcast_msg    = State()
    waiting_broadcast_fwd    = State()
    waiting_cobot_broadcast  = State()
    waiting_cobot_bcast_fwd  = State()
    waiting_add_admin        = State()
    waiting_ban_user         = State()
    waiting_new_btn_label    = State()
    waiting_new_btn_emoji    = State()
    waiting_close_msg        = State()
    waiting_open_msg         = State()
    waiting_max_bots         = State()
    waiting_start_template   = State()
    waiting_token_template   = State()
    waiting_mandatory_type   = State()
    waiting_mandatory_fwd    = State()
    waiting_funded_type      = State()
    waiting_funded_count     = State()
    waiting_funded_fwd       = State()
    waiting_cobot_mand_type  = State()
    waiting_cobot_mand_fwd   = State()
    waiting_cobot_fund_type  = State()
    waiting_cobot_fund_count = State()
    waiting_cobot_fund_fwd   = State()
    waiting_new_btn_url          = State()
    waiting_openbot_label        = State()
    waiting_openbot_username     = State()
    waiting_edit_pkg_value       = State()
    waiting_add_pkg_value        = State()
    waiting_bot_price_value      = State()
    waiting_extend_days          = State()
    waiting_reduce_days          = State()
    waiting_transfer_bot_user    = State()
    waiting_help_text            = State()
    waiting_transfer_user_id     = State()
    waiting_transfer_amount      = State()

async def kb_dev_panel() -> InlineKeyboardMarkup:
    settings = await get_settings()
    status   = "مفتوح 🟢" if settings.is_open else "مقفول 🔴"
    notify_u = "✅" if settings.notify_new_users else "✖️"
    notify_b = "✅" if settings.notify_blocked    else "✖️"
    notify_s = "✅" if settings.notify_funded_sub  else "✖️"

    return InlineKeyboardMarkup(inline_keyboard=[
        [InlineKeyboardButton(text=f"حالة البوت {status}",          callback_data="dev:noop", style="success")],
        [
            InlineKeyboardButton(text=f"اشعار الدخول {notify_u}",  callback_data="dev:toggle_notify_users", style="success"),
            InlineKeyboardButton(text=f"اشعار الحظر {notify_b}",   callback_data="dev:toggle_notify_ban", style="success"),
        ],
        [InlineKeyboardButton(text=f"اشعارات الاشتراك {notify_s}", callback_data="dev:toggle_notify_sub", style="success")],
        [InlineKeyboardButton(text="قسم الاحصائيات",                callback_data="dev:stats", style="success")],
        [InlineKeyboardButton(text="قسم المدفوعات",               callback_data="dev:payments", style="primary"),   InlineKeyboardButton(text="البوتات المدفوعة",              callback_data="dev:paid_bots:1", style="primary")],
        [InlineKeyboardButton(text="💸 تحويل مبلغ",                   callback_data="dev:transfer_balance", style="primary")],
        [InlineKeyboardButton(text="البوتات المصنوعة",              callback_data="dev:all_bots:1", style="primary"), InlineKeyboardButton(text="قسم المشتركين",                callback_data="dev:subscribers", style="primary")],
        [
            InlineKeyboardButton(text="قسم الاذاعة",                callback_data="dev:broadcast", style="primary"),
            InlineKeyboardButton(text="قسم الادمنية",               callback_data="dev:admins", style="primary"),
        ],
        [
            InlineKeyboardButton(text="قسم المحظورين",              callback_data="dev:banned", style="danger"),
            InlineKeyboardButton(text="قسم التعديل",                callback_data="dev:edit_buttons", style="danger"),
        ],
        [InlineKeyboardButton(text="قسم الاشتراك الاجباري",         callback_data="dev:mandatory", style="danger")],
        [InlineKeyboardButton(text="قسم الاشتراك الاجباري الثانوي", callback_data="dev:funded", style="danger")],
        [InlineKeyboardButton(text="قسم البوتات المصنوعة",       callback_data="dev:cobots", style="danger")],
        [InlineKeyboardButton(text="اعدادات المصنع",                callback_data="dev:factory_settings", style="danger")],
    ])


async def send_dev_panel(target: Message | CallbackQuery, state: FSMContext = None):
    if state:
        await state.clear()
    keyboard = await kb_dev_panel()
    text = (
        "» <b>هذه هي لوحة التحكم وادارة مصنع البوتات الخاص بك</b>.\n\n» <b>لوحة تحكم متكاملة تتيح لك الإشراف على صلاحيات البوت، متابعة الإحصائيات وإدارة الاشتراكات وكل شيء من مكان واحد</b>.\n\n» <b>قم بأختيار الاجراء المطلوب من القائمة ادناه</b>:"
    )
    if isinstance(target, CallbackQuery):
        await target.message.edit_text(text, parse_mode="HTML", reply_markup=keyboard)
        await target.answer()
    else:
        await target.answer(text, parse_mode="HTML", reply_markup=keyboard)


@dev_router.callback_query(F.data == "dev:panel")
async def cb_dev_panel(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح لك!", show_alert=True)
        return
    await send_dev_panel(callback, state)


@dev_router.callback_query(F.data == "dev:noop")
async def cb_noop(callback: CallbackQuery):
    await callback.answer()

@dev_router.callback_query(F.data == "dev:toggle_notify_users")
async def cb_toggle_notify_users(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    settings = await get_settings()
    await update_settings(notify_new_users=not settings.notify_new_users)
    await send_dev_panel(callback)


@dev_router.callback_query(F.data == "dev:toggle_notify_ban")
async def cb_toggle_notify_ban(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    settings = await get_settings()
    await update_settings(notify_blocked=not settings.notify_blocked)
    await send_dev_panel(callback)


@dev_router.callback_query(F.data == "dev:toggle_notify_sub")
async def cb_toggle_notify_sub(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    settings = await get_settings()
    await update_settings(notify_funded_sub=not settings.notify_funded_sub)
    await send_dev_panel(callback)

@dev_router.callback_query(F.data == "dev:stats")
async def cb_stats(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    stats = await get_statistics()
    text = (
        "📊 <b>إحصائيات المستخدمين:</b>\n"
        f"[+] عدد مستخدمين المصنع: <b>{stats['total_users']}</b> مستخدم\n"
        f"[+] النشطين آخر 24 ساعة: <b>{stats['active_24h']}</b> مستخدم\n"
        f"[+] المستخدمين المحظورين: <b>{stats['banned_users']}</b> مستخدم\n"
        f"[+] قام بحظر المصنع: <b>{stats['blocked_bot']}</b> مستخدم\n\n"
        "🏭 <b>إحصائيات المصنع الأساسي:</b>\n"
        f"[+] عدد البوتات المصنوعة: <b>{stats['total_bots']}</b> بوت\n"
        f"[+] عدد البوتات المصنوعة اليوم: <b>{stats['bots_today']}</b> بوت\n"
        f"[+] عدد البوتات المصنوعة هذا الشهر: <b>{stats['bots_month']}</b> بوت\n\n"
        "🤖 <b>إحصائيات البوتات المصنوعة:</b>\n"
        f"[+] عدد مستخدمي البوتات المصنوعة ككل: <b>{stats['cobot_users_total']}</b> مستخدم\n"
        f"[+] النشطين آخر 24 ساعة: <b>{stats['cobot_users_24h']}</b> مستخدم\n\n"
        "⚙️ <b>إحصائيات عامة للمصنع:</b>\n"
        f"[+] عدد المطورين: <b>{stats['total_devs']}</b> مطور\n"
        f"[+] عدد الأدمنية: <b>{stats['total_admins']}</b> أدمن\n"
        f"[+] عدد الاشتراك الإجباري: <b>{stats['mandatory_count']}</b> قناة\n"
        f"[+] قنوات جاري تمويلها: <b>{stats['funded_count']}</b> قناة"
    )
    await callback.message.edit_text(
        text, parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:panel", style="primary")]
        ])
    )
    await callback.answer()


async def kb_broadcast() -> InlineKeyboardMarkup:
    bs  = await get_broadcast_settings()
    pin = "✅" if bs.pin_broadcast else "✖️"
    grp = "✅" if bs.to_groups    else "✖️"
    ch  = "✅" if bs.to_channels  else "✖️"
    usr = "✅" if bs.to_users     else "✖️"
    return InlineKeyboardMarkup(inline_keyboard=[
        [InlineKeyboardButton(text=f"تثبيت الاذاعة {pin}",    callback_data="bcast:toggle_pin", style="primary")],
        [InlineKeyboardButton(text=f"اذاعة بالمجموعات {grp}", callback_data="bcast:toggle_groups", style="primary")],
        [InlineKeyboardButton(text=f"اذاعة بالقنوات {ch}",    callback_data="bcast:toggle_channels", style="primary")],
        [InlineKeyboardButton(text=f"اذاعة للمستخدمين {usr}", callback_data="bcast:toggle_users", style="primary")],
        [
            InlineKeyboardButton(text="اذاعة نصية",           callback_data="bcast:text", style="success"),
            InlineKeyboardButton(text="اذاعة موجهة",          callback_data="bcast:forward", style="success"),
        ],
        [InlineKeyboardButton(text="رجوع",                     callback_data="dev:panel", style="primary")],
    ])


@dev_router.callback_query(F.data == "dev:broadcast")
async def cb_broadcast_menu(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()
    await callback.message.edit_text(
        "» <b>قسم الاذاعة لمستخدمي المصنع</b>.\n» <b>في هذا القسم تستطيع ان تقوم بعمل اذاعة من المصنع الى المستخدمين</b>.\n\n» <b>حدد نوع الاذاعة سواء رسالة موجهة او نصية</b>:", parse_mode="HTML",
        reply_markup=await kb_broadcast()
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("bcast:toggle_"))
async def cb_bcast_toggle(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    key = callback.data.split("bcast:toggle_")[1]
    mapping = {"pin": "pin_broadcast", "groups": "to_groups", "channels": "to_channels", "users": "to_users"}
    if key in mapping:
        bs = await get_broadcast_settings()
        await update_broadcast_settings(**{mapping[key]: not getattr(bs, mapping[key])})
    await callback.message.edit_reply_markup(reply_markup=await kb_broadcast())
    await callback.answer()


@dev_router.callback_query(F.data == "bcast:text")
async def cb_bcast_text(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.set_state(DevStates.waiting_broadcast_msg)
    await callback.message.edit_text(
        "» <b>أرسل رسالة الإذاعة المطلوبة الآن</b>.\n» <b>يمكن أن تكون: نصية / صورة / فيديو / ملف / بصمة صوتية</b>", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:broadcast", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "bcast:forward")
async def cb_bcast_forward(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.set_state(DevStates.waiting_broadcast_fwd)
    await callback.message.edit_text(
        "» <b>قم بتوجيه الرسالة المطلوب إذاعتها الآن:</b>",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:broadcast", style="primary")]
        ])
    )
    await callback.answer()


async def _do_broadcast(bot: Bot, message: Message, forward: bool = False):
    bs     = await get_broadcast_settings()
    users  = await get_all_active_users()
    groups = await get_all_bot_groups()
    sent = failed = 0

    if bs.to_users:
        for i, user in enumerate(users):
            try:
                if forward:
                    await message.forward(user.id)
                else:
                    await message.copy_to(user.id)
                sent += 1
            except Exception:
                failed += 1
            if (i + 1) % BROADCAST_BATCH == 0:
                await asyncio.sleep(BROADCAST_DELAY)

    for group in groups:
        if group.chat_type == "channel" and not bs.to_channels:
            continue
        if group.chat_type in ("group", "supergroup") and not bs.to_groups:
            continue
        try:
            if forward:
                msg = await message.forward(group.chat_id)
            else:
                msg = await message.copy_to(group.chat_id)
            if bs.pin_broadcast:
                try:
                    await bot.pin_chat_message(group.chat_id, msg.message_id)
                except Exception:
                    pass
            sent += 1
        except Exception:
            failed += 1

    return sent, failed


@dev_router.message(DevStates.waiting_broadcast_msg)
async def process_broadcast_msg(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    await state.clear()
    wait = await message.answer("⏳ جاري إرسال الإذاعة...")
    sent, failed = await _do_broadcast(bot, message, forward=False)
    await wait.edit_text(
        f"» <b>تم ارسال الاذاعة الى كافة مستخدمين المصنع</b>.\n\n» <b>نجـح الارسال إلى: {sent} مستخدم</b>\n» <b>فشل الارسال إلى: {failed} مستخدم</b>",
        parse_mode="HTML", disable_web_page_preview=True)


@dev_router.message(DevStates.waiting_broadcast_fwd)
async def process_broadcast_fwd(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    await state.clear()
    wait = await message.answer("⏳ جاري إرسال الإذاعة...")
    sent, failed = await _do_broadcast(bot, message, forward=True)
    await wait.edit_text(
        f"» <b>تم ارسال الاذاعة الى كافة مستخدمين المصنع</b>.\n\n» <b>نجـح الارسال إلى: {sent} مستخدم</b>\n» <b>فشل الارسال إلى: {failed} مستخدم</b>",
        parse_mode="HTML", disable_web_page_preview=True)

@dev_router.callback_query(F.data == "dev:admins")
async def cb_admins(callback: CallbackQuery, state: FSMContext):
    if not is_pure_dev(callback.from_user.id):
        await callback.answer("⛔ هذا القسم مخصص للمطورين فقط!", show_alert=True)
        return
    await state.clear()
    await callback.message.edit_text(
        "» <b>عزيزي المطور هذا هو قسم التحكم بالادمنية</b>.\n» <b>يمكن اضافة وحذف وعرض الادمنية بالمصنع من الازرار</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="مسح جميع الأدمنية",  callback_data="admins:clear_all", style="danger")],
            [
                InlineKeyboardButton(text="الأدمنية المضافة", callback_data="admins:list", style="success"),
                InlineKeyboardButton(text="إضافة أدمن",       callback_data="admins:add", style="success"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="dev:panel", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "admins:list")
async def cb_admins_list(callback: CallbackQuery):
    async with get_session() as session:
        result = await session.execute(select(User).where(User.is_admin == True))
        admins = result.scalars().all()

    if not admins:
        await callback.answer("لا يوجد أدمنية مضافون.", show_alert=True)
        return

    buttons = []
    for admin in admins:
        name = f"@{admin.username}" if admin.username else admin.first_name
        buttons.append([
            InlineKeyboardButton(text=name, url=f"tg://user?id={admin.id}", style="success"),
            InlineKeyboardButton(text="🗑️", callback_data=f"admins:remove:{admin.id}", style="danger"),
        ])
    buttons.append([InlineKeyboardButton(text="رجوع", callback_data="dev:admins", style="primary")])
    await callback.message.edit_text(
        "» <b>هذه هي قائمة الأدمنية المضافون مسبقاً:</b>", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("admins:remove:"))
async def cb_admin_remove(callback: CallbackQuery):
    admin_id = int(callback.data.split(":")[2])
    async with get_session() as session:
        result = await session.execute(select(User).where(User.id == admin_id))
        user = result.scalar_one_or_none()
        if user:
            user.is_admin = False
    await callback.answer("✅ تم حذف الأدمن.", show_alert=True)
    await cb_admins_list(callback)


@dev_router.callback_query(F.data == "admins:clear_all")
async def cb_admins_clear_all(callback: CallbackQuery):
    await callback.message.edit_text(
        "» <b>عزيزي المطور هل أنت متأكد من حذف جميع الادمنية</b>؟", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="حذف",  callback_data="admins:clear_confirm", style="danger")],
            [InlineKeyboardButton(text="رجوع", callback_data="dev:admins", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "admins:clear_confirm")
async def cb_admins_clear_confirm(callback: CallbackQuery):
    async with get_session() as session:
        result = await session.execute(select(User).where(User.is_admin == True))
        for admin in result.scalars().all():
            admin.is_admin = False
    await callback.answer("✅ تم مسح جميع الأدمنية.", show_alert=True)
    await cb_admins(callback)


@dev_router.callback_query(F.data == "admins:add")
async def cb_admin_add(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_add_admin)
    await callback.message.edit_text(
        "» <b>قم بإرسال ايدي المستخدم المطلوب اضافته ادمن بالمصنع</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:admins", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_add_admin)
async def process_add_admin(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        admin_id = int(message.text.strip())
    except (ValueError, AttributeError):
        await message.answer("⚠️ أرسل ID رقمي صحيح!")
        return

    async with get_session() as session:
        result = await session.execute(select(User).where(User.id == admin_id))
        user = result.scalar_one_or_none()

    if not user:
        await message.answer("⚠️ هذا المستخدم غير مسجّل في المصنع!")
        await state.clear()
        return

    async with get_session() as session:
        result = await session.execute(select(User).where(User.id == admin_id))
        u = result.scalar_one()
        u.is_admin = True

    name = f"@{user.username}" if user.username else user.first_name
    await state.clear()
    await message.answer(
        f"✅ تم إضافة <b>{name}</b> كأدمن بالمصنع.",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="قسم الأدمنية", callback_data="dev:admins", style="primary")]
        ])
    )


@dev_router.callback_query(F.data == "dev:banned")
async def cb_banned_menu(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()
    await callback.message.edit_text(
        "» <b>قسم ادارة المستخدمين</b> 👤.\n\n» <b>في هذا القسم تستطيع عرض وحظر والغاء حظر المستخدمين بالمصنع</b>.\n» <b>استخدم الاجراء المطلوب بالضغط على احد الازرار</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="مسح جميع المحظورين", callback_data="banned:clear_all", style="danger")],
            [
                InlineKeyboardButton(text="المحظورون",        callback_data="banned:list", style="danger"),
                InlineKeyboardButton(text="حظر مستخدم",      callback_data="banned:add", style="danger"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="dev:panel", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "banned:list")
async def cb_banned_list(callback: CallbackQuery):
    async with get_session() as session:
        result = await session.execute(select(User).where(User.is_banned == True))
        banned = result.scalars().all()

    if not banned:
        await callback.answer("لا يوجد مستخدمون محظورون.", show_alert=True)
        return

    buttons = []
    for user in banned:
        name = f"@{user.username}" if user.username else user.first_name
        buttons.append([
            InlineKeyboardButton(text=name, url=f"tg://user?id={user.id}", style="success"),
            InlineKeyboardButton(text="🗑️", callback_data=f"banned:unban:{user.id}", style="danger"),
        ])
    buttons.append([InlineKeyboardButton(text="رجوع", callback_data="dev:banned", style="primary")])
    await callback.message.edit_text(
        "» <b>هذه هي قائمة المحظورين من استخدام المصنع</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("banned:unban:"))
async def cb_unban(callback: CallbackQuery, bot: Bot):
    user_id = int(callback.data.split(":")[2])
    async with get_session() as session:
        result = await session.execute(select(User).where(User.id == user_id))
        user = result.scalar_one_or_none()
        if user:
            user.is_banned = False
    try:
        await bot.send_message(user_id, "✅ تم رفع الحظر عنك، يمكنك استخدام البوت مجدداً.")
    except Exception:
        pass
    await callback.answer("✅ تم رفع الحظر.", show_alert=True)
    await cb_banned_list(callback)


@dev_router.callback_query(F.data == "banned:clear_all")
async def cb_banned_clear_all(callback: CallbackQuery, bot: Bot):
    async with get_session() as session:
        result = await session.execute(select(User).where(User.is_banned == True))
        banned = result.scalars().all()
        for user in banned:
            user.is_banned = False
            try:
                await bot.send_message(user.id, "✅ تم رفع الحظر عنك.")
            except Exception:
                pass
    await callback.answer("✅ تم مسح جميع المحظورين.", show_alert=True)
    await cb_banned_menu(callback)


@dev_router.callback_query(F.data == "banned:add")
async def cb_ban_add(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_ban_user)
    await callback.message.edit_text(
        "» <b>قم بإرسال ايدي المستخدم المطلوب حظره الآن</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:banned", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_ban_user)
async def process_ban_user(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        ban_id = int(message.text.strip())
    except (ValueError, AttributeError):
        await message.answer("⚠️ أرسل ID رقمي صحيح!")
        return

    if ban_id in DEVELOPER_IDS:
        await message.answer("⚠️ لا يمكن حظر مطور!")
        await state.clear()
        return

    async with get_session() as session:
        result = await session.execute(select(User).where(User.id == ban_id))
        user = result.scalar_one_or_none()

    if not user:
        await message.answer("⚠️ هذا المستخدم غير موجود في قاعدة البيانات!")
        await state.clear()
        return

    async with get_session() as session:
        result = await session.execute(select(User).where(User.id == ban_id))
        u = result.scalar_one()
        u.is_banned = True

    try:
        await bot.send_message(ban_id, "⛔ تم حظرك من استخدام هذا البوت.")
    except Exception:
        pass

    name = f"@{user.username}" if user.username else user.first_name
    await state.clear()
    await message.answer(
        f"✅ تم حظر <b>{name}</b>.",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="قسم المحظورين", callback_data="dev:banned", style="primary")]
        ])
    )


BUTTON_DISPLAY_NAMES = {
    "create":         "إنشاء بوت",
    "mybots":         "بوتاتي",
    "help":           "التعليمات",
    "terms":          "الشروط",
    "bots_channel":   "قناة البوتات",
    "source_channel": "قناة السورس",
    "developer":      "المطور",
    "back":           "رجوع",
    "communication":  "بوت تواصل",
    "download":       "بوت تحميل",
    "decor":          "بوت زخرفة",
    "translation":    "بوت ترجمه",
    "ai":            "بوت تحدث مع ذكاء اصطناعي",
    "buttons":        "بوت ازرار",
    "factory":        "مصنع بوتات",
    "transcoding":    "بوت تحويل صيغ",
    "bot_delete":     "حذف البوت",
    "paid_create":    "إنشاء بوت مدفوع 💎",
    "subscription":   "اشتراك 🌟",
    "pay_topup":      "إضافة رصيد",
    "pay_subscribe":  "اشتراك مدفوع",
    "pay_paid_bots":  "البوتات المدفوعة",
    "owner_self":     "أنا",
    "owner_other":    "شخص آخر",
    "bot_transfer":   "نقل البوت",
    "bot_edit_photo": "تغيير الصورة",
    "bot_edit_name":  "تغيير الاسم",
    "bot_change_type":"تغيير نوع البوت",
    "transfer_accept":"موافقة",
    "transfer_reject":"رفض",
    "transfer_confirm":"تأكيد",
}

PAGE1_BUTTONS = [
    "create", "mybots", "help", "paid_create", "subscription",
    "bots_channel", "source_channel", "developer", "back",
    "communication", "download", "decor",
    "buttons", "factory", "transcoding", "translation", "ai",
]

PAGE2_BUTTONS = [
    "open_bot_url", "back_to_main", "confirm_token",
    "bot_url", "bot_delete", "bot_manage",
    "check_sub", "sub_channel_url",
    "pay_topup", "pay_subscribe", "pay_paid_bots",
    "owner_self", "owner_other",
    "bot_transfer", "bot_edit_photo", "bot_edit_name", "bot_change_type",
    "transfer_accept", "transfer_reject", "transfer_confirm",
]

PAGE2_EDITABLE = {
    "open_bot_url":    ["label", "color", "emoji"],
    "back_to_main":    ["label", "color", "emoji"],
    "confirm_token":   ["label", "color", "emoji"],
    "bot_url":         ["color", "emoji"],
    "bot_delete":      ["color", "emoji"],
    "bot_manage":      ["label", "color", "emoji"],
    "check_sub":       ["color", "emoji"],
    "sub_channel_url":  ["color", "emoji"],
    "pay_topup":        ["label", "color", "emoji"],
    "pay_subscribe":    ["label", "color", "emoji"],
    "pay_paid_bots":    ["label", "color", "emoji"],
    "owner_self":       ["label", "color", "emoji"],
    "owner_other":      ["label", "color", "emoji"],
    "bot_transfer":     ["label", "color", "emoji"],
    "bot_edit_photo":   ["label", "color", "emoji"],
    "bot_edit_name":    ["label", "color", "emoji"],
    "bot_change_type":  ["label", "color", "emoji"],
    "transfer_accept":  ["label", "color", "emoji"],
    "transfer_reject":  ["label", "color", "emoji"],
    "transfer_confirm": ["label", "color", "emoji"],
}

PAGE2_URL_EDITABLE = ["bots_channel", "source_channel", "developer"]


@dev_router.callback_query(F.data == "dev:edit_buttons")
async def cb_edit_buttons(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()
    await _show_edit_page(callback, page=1)


@dev_router.callback_query(F.data == "editbtn:page:2")
async def cb_edit_buttons_page2(callback: CallbackQuery):
    await _show_edit_page(callback, page=2)


@dev_router.callback_query(F.data == "editbtn:page:1")
async def cb_edit_buttons_page1(callback: CallbackQuery):
    await _show_edit_page(callback, page=1)


async def _show_edit_page(callback: CallbackQuery, page: int):
    buttons  = await get_all_buttons()
    btn_map  = {b.button_key: b for b in buttons}
    rows     = []

    if page == 1:
        rows.append([InlineKeyboardButton(text="── أزرار القائمة الرئيسية ──", callback_data="dev:noop")])
        for key in ["create", "mybots", "help", "paid_create", "subscription", "bots_channel", "source_channel", "developer", "back"]:
            b     = btn_map.get(key)
            label = btn_label(b) if b else BUTTON_DISPLAY_NAMES.get(key, key)
            rows.append([InlineKeyboardButton(text=label, callback_data=f"editbtn:select:{key}")])

        rows.append([InlineKeyboardButton(text="── أزرار قائمة إنشاء البوت ──", callback_data="dev:noop")])
        for key in ["factory", "communication", "download", "decor", "buttons", "transcoding", "translation", "ai"]:
            b     = btn_map.get(key)
            label = btn_label(b) if b else BUTTON_DISPLAY_NAMES.get(key, key)
            rows.append([InlineKeyboardButton(text=label, callback_data=f"editbtn:select:{key}")])

        rows.append([
            InlineKeyboardButton(text="رجوع", callback_data="dev:panel", style="primary"),
            InlineKeyboardButton(text="› التالي",     callback_data="editbtn:page:2", style="success"),
        ])

    elif page == 2:
        rows.append([InlineKeyboardButton(text="── بقية أزرار لوحة المستخدمين ──", callback_data="dev:noop")])
        for key in PAGE2_BUTTONS:
            b     = btn_map.get(key)
            label = btn_label(b) if b else BUTTON_DISPLAY_NAMES.get(key, key)
            rows.append([InlineKeyboardButton(text=label, callback_data=f"editbtn:select:{key}")])

        rows.append([
            InlineKeyboardButton(text="‹ السابق", callback_data="editbtn:page:1", style="success"),
            InlineKeyboardButton(text="رجوع",     callback_data="dev:panel", style="primary"),
        ])

    await callback.message.edit_text(
        "» عزيزي المطور هذا هو قسم تعديل الأزرار.\n"
        "» يمكن تغيير لون واسم وإيموجي الزر الحالي:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=rows)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("editbtn:select:"))
async def cb_editbtn_select(callback: CallbackQuery):
    key = callback.data.split(":")[2]
    btn = await get_button(key)
    if not btn:
        await callback.answer("الزر غير موجود!", show_alert=True)
        return

    visible = "موجود ✅" if btn.is_visible else "مخفي ✖️"
    colors  = {"default": "عادي", "green": "أخضر", "blue": "أزرق", "red": "أحمر"}
    color   = colors.get(btn.color, btn.color)

    if btn.custom_emoji_id:
        emoji_info = "» الإيموجي: متحرك ✅\n"
    elif btn.emoji:
        emoji_info = f"» الإيموجي: {btn.emoji}\n"
    else:
        emoji_info = "» الإيموجي: لا يوجد\n"

    is_page2      = key in PAGE2_BUTTONS
    allowed       = PAGE2_EDITABLE.get(key, []) if is_page2 else ["label", "color", "emoji", "url", "visible"]
    is_url_editable = key in PAGE2_URL_EDITABLE or (not is_page2 and key not in PAGE2_BUTTONS)
    back_page     = "editbtn:page:2" if is_page2 else "dev:edit_buttons"

    kb_rows = []
    if "color" in allowed or not is_page2:
        kb_rows.append([InlineKeyboardButton(text="تعديل لون الزر",    callback_data=f"editbtn:color:{key}")])
    if "label" in allowed or not is_page2:
        kb_rows.append([InlineKeyboardButton(text="تعديل اسم الزر",    callback_data=f"editbtn:label:{key}")])
    if "emoji" in allowed or not is_page2:
        kb_rows.append([InlineKeyboardButton(text="تعديل إيموجي الزر", callback_data=f"editbtn:emoji:{key}")])
    if key in PAGE2_URL_EDITABLE:
        kb_rows.append([InlineKeyboardButton(text="تعديل الرابط",      callback_data=f"editbtn:url:{key}")])
    if key == "open_bot_url":
        kb_rows.append([InlineKeyboardButton(text="تعديل الرابط/النص", callback_data=f"editbtn:openbot:{key}")])
    if not is_page2:
        kb_rows.append([InlineKeyboardButton(text="إخفاء/إظهار الزر",  callback_data=f"editbtn:toggle:{key}")])
    kb_rows.append([InlineKeyboardButton(text="رجوع", callback_data=back_page, style="primary")])

    await callback.message.edit_text(
        f"» الزر المطلوب: <b>{btn.label}</b>\n"
        f"» حالة الزر: {visible}\n"
        f"» اللون الحالي: {color}\n"
        f"{emoji_info}"
        "» اختر الإجراء المطلوب تعديله لهذا الزر الآن:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=kb_rows)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("editbtn:url:"))
async def cb_editbtn_url(callback: CallbackQuery, state: FSMContext):
    key = callback.data.split(":")[2]
    btn = await get_button(key)
    await state.update_data(editing_btn_key=key)
    await state.set_state(DevStates.waiting_new_btn_url)
    await callback.message.edit_text(
        f"» الرابط الحالي: <code>{btn.url or 'لا يوجد'}</code>\n"
        "» أرسل الرابط الجديد:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data=f"editbtn:select:{key}", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_new_btn_url)
async def process_new_btn_url(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    data = await state.get_data()
    key  = data.get("editing_btn_key")
    url  = message.text.strip() if message.text else ""

    valid_prefixes = ("http://", "https://", "tg://", "t.me/")
    if not any(url.startswith(prefix) for prefix in valid_prefixes):
        await message.answer(
            "⚠️ أرسل رابطاً صحيحاً!\n"
            "الأنواع المقبولة:\n"
            "• https://\n"
            "• http://\n"
            "• tg://\n"
            "• t.me/"
        )
        return

    await update_button(key, url=url)
    await state.clear()
    await message.answer(
        "✅ تم تحديث الرابط.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="قسم التعديل", callback_data="dev:edit_buttons", style="primary")]
        ])
    )

@dev_router.callback_query(F.data.startswith("editbtn:openbot:"))
async def cb_editbtn_openbot(callback: CallbackQuery, state: FSMContext):
    key = callback.data.split(":")[2]
    btn = await get_button(key)
    await state.update_data(editing_btn_key=key)
    await state.set_state(DevStates.waiting_openbot_label)
    await callback.message.edit_text(
        f"» النص الحالي للزر: <b>{btn.label}</b>\n\n"
        "» أرسل النص الجديد للزر:\n"
        "<i>مثال: افتح بوتك</i>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data=f"editbtn:select:{key}", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_openbot_label)
async def process_openbot_label(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    data      = await state.get_data()
    key       = data.get("editing_btn_key")
    new_label = message.text.strip() if message.text else ""
    if not new_label:
        await message.answer("⚠️ أرسل نصاً صحيحاً!")
        return
    await state.update_data(openbot_new_label=new_label)
    await state.set_state(DevStates.waiting_openbot_username)
    await message.answer(
        f"» النص الجديد: <b>{new_label}</b>\n\n"
        "هل تريد إضافة @username البوت بعد النص؟",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="نعم، أضف @username", callback_data="openbot:with_username", style="success")],
            [InlineKeyboardButton(text="لا، النص فقط",       callback_data="openbot:without_username", style="success")],
        ])
    )


@dev_router.callback_query(F.data.startswith("openbot:"))
async def cb_openbot_username_choice(callback: CallbackQuery, state: FSMContext):
    data      = await state.get_data()
    key       = data.get("editing_btn_key")
    new_label = data.get("openbot_new_label", "")
    choice    = callback.data.split(":")[1]

    if choice == "with_username":
        final_label = f"{new_label} {{username}}"
    else:
        final_label = new_label

    await update_button(key, label=final_label)
    await state.clear()
    await callback.message.edit_text(
        f"✅ تم تحديث نص الزر إلى: <b>{final_label}</b>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="قسم التعديل", callback_data="dev:edit_buttons", style="primary")]
        ])
    )
    await callback.answer()



@dev_router.callback_query(F.data.startswith("editbtn:color:"))
async def cb_editbtn_color(callback: CallbackQuery):
    key = callback.data.split(":")[2]
    await callback.message.edit_text(
        "» قم باختيار لون الزر المطلوب الآن:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="أزرق",  callback_data=f"editbtn:setcolor:{key}:blue")],
            [InlineKeyboardButton(text="أخضر",  callback_data=f"editbtn:setcolor:{key}:green")],
            [InlineKeyboardButton(text="أحمر",  callback_data=f"editbtn:setcolor:{key}:red")],
            [InlineKeyboardButton(text="عادي",  callback_data=f"editbtn:setcolor:{key}:default")],
            [InlineKeyboardButton(text="رجوع",  callback_data=f"editbtn:select:{key}", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("editbtn:setcolor:"))
async def cb_editbtn_setcolor(callback: CallbackQuery):
    parts = callback.data.split(":")
    key   = parts[2]
    color = parts[3]
    await update_button(key, color=color)
    await callback.answer("✅ تم تغيير اللون.", show_alert=True)
    fake = type('obj', (object,), {'data': f"editbtn:select:{key}", 'message': callback.message, 'from_user': callback.from_user, 'answer': callback.answer})()
    await cb_editbtn_select(fake)


@dev_router.callback_query(F.data.startswith("editbtn:label:"))
async def cb_editbtn_label(callback: CallbackQuery, state: FSMContext):
    key = callback.data.split(":")[2]
    btn = await get_button(key)
    await state.update_data(editing_btn_key=key)
    await state.set_state(DevStates.waiting_new_btn_label)
    await callback.message.edit_text(
        f"» اسم الزر الحالي: <b>{btn.label}</b>\n"
        "» أرسل الاسم الجديد الآن:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data=f"editbtn:select:{key}", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_new_btn_label)
async def process_new_btn_label(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    data      = await state.get_data()
    key       = data.get("editing_btn_key")
    new_label = message.text.strip() if message.text else ""
    if not new_label:
        await message.answer("⚠️ أرسل اسماً صحيحاً!")
        return
    await update_button(key, label=new_label)
    await state.clear()
    await message.answer(
        f"✅ تم تغيير اسم الزر إلى: <b>{new_label}</b>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="قسم التعديل", callback_data="dev:edit_buttons", style="primary")]
        ])
    )

@dev_router.callback_query(F.data.startswith("editbtn:emoji:"))
async def cb_editbtn_emoji(callback: CallbackQuery, state: FSMContext):
    key = callback.data.split(":")[2]
    await state.update_data(editing_btn_key=key)
    await state.set_state(DevStates.waiting_new_btn_emoji)
    await callback.message.edit_text(
        "» أرسل الإيموجي المطلوب:\n\n"
        "» إيموجي عادي: أرسله مباشرة مثل 🔥\n"
        "» إيموجي متحرك: ارسله مباشرة من الستيكر باك\n"
        "» لحذف الإيموجي: أرسل ( - )",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data=f"editbtn:select:{key}", style="primary")]
        ])
    )
    await callback.answer()

@dev_router.message(DevStates.waiting_new_btn_emoji)
async def process_new_btn_emoji(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    data = await state.get_data()
    key  = data.get("editing_btn_key")
    text = message.text.strip() if message.text else ""

    if text == "-":
        await update_button(key, emoji=None, custom_emoji_id=None)
        await state.clear()
        await message.answer(
            "✅ تم حذف الإيموجي.",
            reply_markup=InlineKeyboardMarkup(inline_keyboard=[
                [InlineKeyboardButton(text="قسم التعديل", callback_data="dev:edit_buttons", style="primary")]
            ])
        )
        return

    custom_emoji_id = None
    if message.entities:
        for entity in message.entities:
            if entity.type == "custom_emoji":
                custom_emoji_id = entity.custom_emoji_id
                break

    if custom_emoji_id:
        await update_button(key, custom_emoji_id=custom_emoji_id, emoji=None)
        await state.clear()
        await message.answer(
            f"✅ تم تعيين الإيموجي المتحرك بنجاح!",
            reply_markup=InlineKeyboardMarkup(inline_keyboard=[
                [InlineKeyboardButton(text="قسم التعديل", callback_data="dev:edit_buttons", style="primary")]
            ])
        )
    else:
        await update_button(key, emoji=text, custom_emoji_id=None)
        await state.clear()
        await message.answer(
            f"✅ تم تعيين الإيموجي: {text}",
            reply_markup=InlineKeyboardMarkup(inline_keyboard=[
                [InlineKeyboardButton(text="قسم التعديل", callback_data="dev:edit_buttons", style="primary")]
            ])
        )

@dev_router.callback_query(F.data.startswith("editbtn:toggle:"))
async def cb_editbtn_toggle(callback: CallbackQuery):
    key = callback.data.split(":")[2]
    btn = await get_button(key)
    action = "إخفاء" if btn.is_visible else "إظهار"
    await callback.message.edit_text(
        f"» هل تريد <b>{action}</b> الزر <b>{btn.label}</b>؟",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=f"نعم، {action}", callback_data=f"editbtn:toggle_confirm:{key}", style="danger")],
            [InlineKeyboardButton(text="رجوع",           callback_data=f"editbtn:select:{key}", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("editbtn:toggle_confirm:"))
async def cb_editbtn_toggle_confirm(callback: CallbackQuery):
    key = callback.data.split(":")[2]
    btn = await get_button(key)
    await update_button(key, is_visible=not btn.is_visible)
    status = "مخفي" if btn.is_visible else "ظاهر"
    await callback.answer(f"✅ الزر أصبح {status}.", show_alert=True)
    fake = type('obj', (object,), {'data': f"editbtn:select:{key}", 'message': callback.message, 'from_user': callback.from_user, 'answer': callback.answer})()
    await cb_editbtn_select(fake)


async def _channel_exists_anywhere(channel_id: int) -> str | None:
    async with get_session() as session:
        r1 = await session.execute(
            select(MandatoryChannel).where(
                MandatoryChannel.channel_id == channel_id,
                MandatoryChannel.is_active == True
            )
        )
        if r1.scalar_one_or_none():
            return "قسم الاشتراك الإجباري"

        r2 = await session.execute(
            select(FundedChannel).where(
                FundedChannel.channel_id == channel_id,
                FundedChannel.is_active == True
            )
        )
        if r2.scalar_one_or_none():
            return "قسم الاشتراك الإجباري الثانوي"

    return None


@dev_router.callback_query(F.data == "dev:mandatory")
async def cb_mandatory_menu(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()
    await callback.message.edit_text(
        "» <b>عزيزي المطور هذا هو قسم الاشتراك الاجباري للمصنع</b>.\n» <b>يمكن اضافة وحذف وعرض القنوات المضافة من الازرار</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [
                InlineKeyboardButton(text="القنوات المضافة", callback_data="mand:list", style="success"),
                InlineKeyboardButton(text="إضافة قناة",      callback_data="mand:add", style="success"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="dev:panel", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "mand:list")
async def cb_mand_list(callback: CallbackQuery):
    channels = await get_mandatory_channels()
    if not channels:
        await callback.answer("لا توجد قنوات مضافة.", show_alert=True)
        return
    buttons = []
    for ch in channels:
        link = ch.invite_link or (f"https://t.me/{ch.channel_username}" if ch.channel_username else "#")
        buttons.append([
            InlineKeyboardButton(text=ch.channel_title, url=link, style="success"),
            InlineKeyboardButton(text="🗑️", callback_data=f"mand:delete:{ch.id}", style="danger"),
        ])
    buttons.append([InlineKeyboardButton(text="رجوع", callback_data="dev:mandatory", style="primary")])
    await callback.message.edit_text(
        "» <b>هذه هي قائمة قنوات الاشتراك المضافة مسبقاً</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("mand:delete:"))
async def cb_mand_delete(callback: CallbackQuery):
    ch_id = int(callback.data.split(":")[2])
    async with get_session() as session:
        result = await session.execute(select(MandatoryChannel).where(MandatoryChannel.id == ch_id))
        ch = result.scalar_one_or_none()
        if ch:
            ch.is_active = False
    await callback.answer("✅ تم حذف القناة.", show_alert=True)
    await cb_mand_list(callback)


@dev_router.callback_query(F.data == "mand:add")
async def cb_mand_add(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_mandatory_type)
    await callback.message.edit_text(
        "» <b>اختر الطريقة التي تريد عرض طلب الاشتراك فيها من المستخدم</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [
                InlineKeyboardButton(text="أزرار",      callback_data="mand:type:buttons", style="success"),
                InlineKeyboardButton(text="رسالة نصية", callback_data="mand:type:text", style="success"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="dev:mandatory", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("mand:type:"))
async def cb_mand_type(callback: CallbackQuery, state: FSMContext):
    display_type = callback.data.split(":")[2]
    await state.update_data(mand_display_type=display_type)
    await state.set_state(DevStates.waiting_mandatory_fwd)
    await callback.message.edit_text(
        "<b>عزيزي المطور يرجى توجيه رسالة من القناة سواء كانت عامة أو خاصة لإضافتها</b>.", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:mandatory", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_mandatory_fwd)
async def process_mand_fwd(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    if not message.forward_from_chat:
        await message.answer("⚠️ يرجى توجيه رسالة من القناة فقط!")
        return

    chat    = message.forward_from_chat
    chat_id = chat.id
    existing_section = await _channel_exists_anywhere(chat_id)
    if existing_section:
        await message.answer(
            f"⚠️ هذه القناة مضافة مسبقاً في <b>{existing_section}</b>!\n"
            "يرجى حذفها من ذلك القسم أولاً ثم إعادة الإضافة.",
            parse_mode="HTML", disable_web_page_preview=True)
        await state.clear()
        return

    try:
        member = await bot.get_chat_member(chat_id, (await bot.get_me()).id)
        if member.status not in ("administrator", "creator"):
            await message.answer("⚠️ يجب إضافة البوت كمشرف في القناة أولاً!")
            await state.clear()
            return
    except Exception:
        await message.answer("⚠️ لا يمكن الوصول للقناة. تأكد أن البوت مشرف فيها!")
        await state.clear()
        return

    invite_link = None
    if chat.username:
        invite_link = f"https://t.me/{chat.username}"
    else:
        try:
            link_obj    = await bot.create_chat_invite_link(chat_id)
            invite_link = link_obj.invite_link
        except Exception:
            pass

    data         = await state.get_data()
    display_type = data.get("mand_display_type", "buttons")

    async with get_session() as session:
        existing = await session.execute(
            select(MandatoryChannel).where(MandatoryChannel.channel_id == chat_id)
        )
        ex = existing.scalar_one_or_none()
        if ex:
            ex.is_active    = True
            ex.display_type = ChannelDisplayType(display_type)
            ex.invite_link  = invite_link
        else:
            session.add(MandatoryChannel(
                channel_id       = chat_id,
                channel_username = chat.username,
                channel_title    = chat.title or str(chat_id),
                invite_link      = invite_link,
                display_type     = ChannelDisplayType(display_type),
            ))

    await state.clear()
    await message.answer(
        f"✅ تم إضافة القناة <b>{chat.title}</b> بنجاح!",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="الاشتراك الإجباري", callback_data="dev:mandatory", style="primary")]
        ])
    )

async def _cobot_channel_exists_anywhere(channel_id: int) -> str | None:
    async with get_session() as session:
        r1 = await session.execute(
            select(CobotMandatoryChannel).where(
                CobotMandatoryChannel.channel_id == channel_id,
                CobotMandatoryChannel.is_active  == True
            )
        )
        if r1.scalar_one_or_none():
            return "اشتراك اجباري بالبوتات المصنوعة"

        r2 = await session.execute(
            select(CobotFundedChannel).where(
                CobotFundedChannel.channel_id == channel_id,
                CobotFundedChannel.is_active  == True
            )
        )
        if r2.scalar_one_or_none():
            return "تمويل اجباري بالبوتات المصنوعة"

    return None


@dev_router.callback_query(F.data == "dev:funded")
async def cb_funded_menu(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()
    await callback.message.edit_text(
        "» <b>عزيزي المطور هذا هو قسم تمويل القنوات بالمصنع</b>.\n\n» <b>هذا القسم مختص في اجراء تمويل لقناة انت من يحددها حيث سيطلب المصنع من المستخدمين الاشتراك في هذه القناة، عند اكتمال العدد المطلوب الذي تحدده انت سيتم ازالة القناة من القنوات الممولة</b>.", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="القنوات الممولة",    callback_data="funded:list", style="success")],
            [InlineKeyboardButton(text="إضافة قناة تمويل",  callback_data="funded:add", style="success")],
            [InlineKeyboardButton(text="رجوع",               callback_data="dev:panel", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "funded:list")
async def cb_funded_list(callback: CallbackQuery):
    channels = await get_funded_channels()
    if not channels:
        await callback.answer("لا توجد قنوات ممولة.", show_alert=True)
        return
    buttons = []
    for ch in channels:
        link = ch.invite_link or (f"https://t.me/{ch.channel_username}" if ch.channel_username else "#")
        buttons.append([
            InlineKeyboardButton(
                text=f"{ch.channel_title} ({ch.current_count}/{ch.target_count})",
                url=link, style="success"
            ),
            InlineKeyboardButton(text="🗑️", callback_data=f"funded:delete:{ch.id}", style="danger"),
        ])
    buttons.append([InlineKeyboardButton(text="رجوع", callback_data="dev:funded", style="primary")])
    await callback.message.edit_text(
        "» <b>هذه هي قائمة القنوات الجاري تمويلها حالياً</b>", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("funded:delete:"))
async def cb_funded_delete(callback: CallbackQuery):
    ch_id = int(callback.data.split(":")[2])
    async with get_session() as session:
        result = await session.execute(select(FundedChannel).where(FundedChannel.id == ch_id))
        ch = result.scalar_one_or_none()
        if ch:
            ch.is_active = False
    await callback.answer("✅ تم حذف القناة الممولة.", show_alert=True)
    await cb_funded_list(callback)


@dev_router.callback_query(F.data == "funded:add")
async def cb_funded_add(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_funded_type)
    await callback.message.edit_text(
        "» <b>اختر الطريقة التي تريد عرض طلب الاشتراك فيها من المستخدم</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [
                InlineKeyboardButton(text="أزرار",      callback_data="funded:type:buttons", style="success"),
                InlineKeyboardButton(text="رسالة نصية", callback_data="funded:type:text", style="success"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="dev:funded", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("funded:type:"))
async def cb_funded_type(callback: CallbackQuery, state: FSMContext):
    display_type = callback.data.split(":")[2]
    await state.update_data(funded_display_type=display_type)
    await state.set_state(DevStates.waiting_funded_count)
    await callback.message.edit_text(
        "» <b>ارسل عدد الأعضاء المطلوب إضافتهم إلى هذه القناة</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:funded", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_funded_count)
async def process_funded_count(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        count = int(message.text.strip())
        if count <= 0:
            raise ValueError
    except (ValueError, AttributeError):
        await message.answer("⚠️ أرسل رقماً صحيحاً أكبر من صفر!")
        return
    await state.update_data(funded_target_count=count)
    await state.set_state(DevStates.waiting_funded_fwd)
    await message.answer(
        "» <b>يرجى توجيه رسالة من القناة سواء كانت عامة أو خاصة لإضافتها<>/b.", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:funded", style="primary")]
        ])
    )


@dev_router.message(DevStates.waiting_funded_fwd)
async def process_funded_fwd(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    if not message.forward_from_chat:
        await message.answer("⚠️ يرجى توجيه رسالة من القناة فقط!")
        return

    chat    = message.forward_from_chat
    chat_id = chat.id
    existing_section = await _channel_exists_anywhere(chat_id)
    if existing_section:
        await message.answer(
            f"⚠️ هذه القناة مضافة مسبقاً في <b>{existing_section}</b>!\n"
            "يرجى حذفها من ذلك القسم أولاً ثم إعادة الإضافة.",
            parse_mode="HTML", disable_web_page_preview=True)
        await state.clear()
        return

    try:
        member = await bot.get_chat_member(chat_id, (await bot.get_me()).id)
        if member.status not in ("administrator", "creator"):
            await message.answer("⚠️ يجب إضافة البوت كمشرف في القناة أولاً!")
            await state.clear()
            return
    except Exception:
        await message.answer("⚠️ لا يمكن الوصول للقناة!")
        await state.clear()
        return

    invite_link = None
    if chat.username:
        invite_link = f"https://t.me/{chat.username}"
    else:
        try:
            link_obj    = await bot.create_chat_invite_link(chat_id)
            invite_link = link_obj.invite_link
        except Exception:
            pass

    data         = await state.get_data()
    display_type = data.get("funded_display_type", "buttons")
    target_count = data.get("funded_target_count", 100)

    async with get_session() as session:
        existing = await session.execute(
            select(FundedChannel).where(FundedChannel.channel_id == chat_id)
        )
        ex = existing.scalar_one_or_none()
        if ex:
            ex.is_active     = True
            ex.display_type  = ChannelDisplayType(display_type)
            ex.target_count  = target_count
            ex.current_count = 0
            ex.invite_link   = invite_link
            ex.completed_at  = None
        else:
            session.add(FundedChannel(
                channel_id       = chat_id,
                channel_username = chat.username,
                channel_title    = chat.title or str(chat_id),
                invite_link      = invite_link,
                display_type     = ChannelDisplayType(display_type),
                target_count     = target_count,
            ))

    await state.clear()
    await message.answer(
        f"✅ تم إضافة القناة الممولة <b>{chat.title}</b> بهدف <b>{target_count}</b> عضو!",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="قسم التمويل", callback_data="dev:funded", style="primary")]
        ])
    )

async def kb_factory_settings() -> InlineKeyboardMarkup:
    s       = await get_settings()
    sub_en  = "✅" if s.cobots_sub_enabled   else "✖️"
    fund_en = "✅" if s.cobots_funded_enabled else "✖️"
    notify  = "✅" if s.cobots_fund_notify    else "✖️"
    rights  = "✅" if s.cobots_maker_rights   else "✖️"

    return InlineKeyboardMarkup(inline_keyboard=[
        [InlineKeyboardButton(text="اشتراك اجباري بالبوتات المصنوعة",  callback_data="fs:cobot_mand", style="primary")],
        [InlineKeyboardButton(text="تمويل اجباري بالبوتات المصنوعة",   callback_data="fs:cobot_fund", style="primary")],
        [InlineKeyboardButton(text=f"اشعارات التمويل {notify}",        callback_data="fs:toggle_fund_notify", style="success")],
        [
            InlineKeyboardButton(text=f"ايقاف التمويل {fund_en}",     callback_data="fs:toggle_fund", style="success"),
            InlineKeyboardButton(text=f"ايقاف الاجباري {sub_en}",     callback_data="fs:toggle_sub", style="success"),
        ],
        [InlineKeyboardButton(text="اذاعة بالمصنوعات", callback_data="fs:cobot_bcast", style="primary")],
        [
            InlineKeyboardButton(text="تعيين حد الصنع",                callback_data="fs:set_max", style="success"),
            InlineKeyboardButton(text=f"حقوق الصانع {rights}",        callback_data="fs:toggle_rights", style="success"),
        ],
        [InlineKeyboardButton(text="تعديل نص التعليمات",              callback_data="fs:edit_help_text", style="primary")],
        [InlineKeyboardButton(text="تعديل كليشة ارسل توكن",            callback_data="fs:edit_token_tmpl", style="primary")],
        [InlineKeyboardButton(text="تعديل كليشة /start",               callback_data="fs:edit_start_tmpl", style="primary")],
        [
            InlineKeyboardButton(text="قفل البوت",                     callback_data="fs:close_bot", style="danger"),
            InlineKeyboardButton(text="فتح البوت",                     callback_data="fs:open_bot", style="danger"),
        ],
        [InlineKeyboardButton(text="رجوع",                             callback_data="dev:panel", style="primary")],
    ])


@dev_router.callback_query(F.data == "dev:factory_settings")
async def cb_factory_settings(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()
    await callback.message.edit_text(
        "⚙️ <b>اعدادات المصنع</b>",
        parse_mode="HTML",
        reply_markup=await kb_factory_settings()
    )
    await callback.answer()


@dev_router.callback_query(F.data.in_({"fs:toggle_fund_notify", "fs:toggle_fund", "fs:toggle_sub", "fs:toggle_rights"}))
async def cb_fs_toggle(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    s   = await get_settings()
    mp  = {
        "fs:toggle_fund_notify": ("cobots_fund_notify",   s.cobots_fund_notify),
        "fs:toggle_fund":        ("cobots_funded_enabled", s.cobots_funded_enabled),
        "fs:toggle_sub":         ("cobots_sub_enabled",    s.cobots_sub_enabled),
        "fs:toggle_rights":      ("cobots_maker_rights",   s.cobots_maker_rights),
    }
    field, current = mp[callback.data]
    await update_settings(**{field: not current})
    await callback.message.edit_reply_markup(reply_markup=await kb_factory_settings())
    await callback.answer()


@dev_router.callback_query(F.data == "fs:set_max")
async def cb_fs_set_max(callback: CallbackQuery, state: FSMContext):
    s = await get_settings()
    await state.set_state(DevStates.waiting_max_bots)
    await callback.message.edit_text(
        f"» الحد الحالي: <b>{s.max_bots_per_user}</b> بوتات لكل مستخدم\n"
        "» أرسل الحد الجديد:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:factory_settings", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_max_bots)
async def process_max_bots(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        max_b = int(message.text.strip())
        if max_b <= 0:
            raise ValueError
    except (ValueError, AttributeError):
        await message.answer("⚠️ أرسل رقماً صحيحاً أكبر من صفر!")
        return
    await update_settings(max_bots_per_user=max_b)
    await state.clear()
    await message.answer(
        f"✅ تم تعيين الحد إلى <b>{max_b}</b> بوتات لكل مستخدم.",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")]
        ])
    )


@dev_router.callback_query(F.data == "fs:edit_start_tmpl")
async def cb_edit_start_tmpl(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_start_template)
    await callback.message.edit_text(
        "» أرسل نص كليشة /start الجديدة:\n"
        "<i>يمكن استخدام {first_name} و {username} كمتغيرات.</i>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:factory_settings", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_start_template)
async def process_start_template(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    import json as _json
    entities_json = None
    if message.entities:
        entities_json = _json.dumps([
            {"type": e.type, "offset": e.offset, "length": e.length,
             "custom_emoji_id": getattr(e, "custom_emoji_id", None)}
            for e in message.entities
        ])
    await update_settings(
        start_template          = message.text or "",
        start_template_entities = entities_json,
    )
    await state.clear()
    await message.answer(
        "✅ تم تحديث كليشة /start.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")]
        ])
    )


@dev_router.callback_query(F.data == "fs:edit_help_text")
async def cb_edit_help_text(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    current = await get_help_text()
    await state.set_state(DevStates.waiting_help_text)
    await callback.message.edit_text(
        f"📖 <b>تعديل نص التعليمات</b>\n\nالنص الحالي:\n{current}\n\nأرسل النص الجديد:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:factory_settings", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_help_text)
async def process_help_text(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    await update_help_text(message.text or "")
    await state.clear()
    await message.answer(
        "✅ تم تحديث نص التعليمات.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")],
        ]),
    )


@dev_router.callback_query(F.data == "fs:edit_token_tmpl")
async def cb_edit_token_tmpl(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_token_template)
    await callback.message.edit_text(
        "» أرسل نص كليشة 'أرسل التوكن' الجديدة:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:factory_settings", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_token_template)
async def process_token_template(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    import json as _json
    entities_json = None
    if message.entities:
        entities_json = _json.dumps([
            {"type": e.type, "offset": e.offset, "length": e.length,
             "custom_emoji_id": getattr(e, "custom_emoji_id", None)}
            for e in message.entities
        ])
    await update_settings(
        token_template          = message.text or "",
        token_template_entities = entities_json,
    )
    await state.clear()
    await message.answer(
        "✅ تم تحديث كليشة التوكن.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")]
        ])
    )


@dev_router.callback_query(F.data == "fs:close_bot")
async def cb_close_bot(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_close_msg)
    await callback.message.edit_text(
        "» <b>ارسل الرسالة التي ستظهر للمستخدمين عندما يكون البوت مقفولاً<>/b:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:factory_settings", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_close_msg)
async def process_close_msg(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    await update_settings(is_open=False, closed_message=message.text or "")
    await state.clear()
    await message.answer(
        "🔴 تم قفل البوت.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")]
        ])
    )


@dev_router.callback_query(F.data == "fs:open_bot")
async def cb_open_bot(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_open_msg)
    await callback.message.edit_text(
        "» <b>ارسل الرسالة التي ستُرسل للمستخدمين عند فتح البوت</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:factory_settings", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_open_msg)
async def process_open_msg(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    open_msg = message.text or ""
    await update_settings(is_open=True, open_message=open_msg)
    await state.clear()
    users = await get_all_users_for_open_msg()
    sent = failed = 0
    for i, user in enumerate(users):
        try:
            await bot.send_message(user.id, open_msg)
            sent += 1
        except Exception:
            failed += 1
        if (i + 1) % BROADCAST_BATCH == 0:
            await asyncio.sleep(BROADCAST_DELAY)
    await message.answer(
        f"🟢 تم فتح البوت!\n📤 أُرسلت رسالة الفتح إلى: <b>{sent}</b> مستخدم",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")]
        ])
    )

@dev_router.callback_query(F.data == "fs:cobot_mand")
async def cb_cobot_mand(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()

    async with get_session() as session:
        result = await session.execute(
            select(CobotMandatoryChannel).where(CobotMandatoryChannel.is_active == True)
        )
        channels = result.scalars().all()

    buttons = []
    for ch in channels:
        link = ch.invite_link or (
            f"https://t.me/{ch.channel_username}" if ch.channel_username else "#"
        )
        buttons.append([
            InlineKeyboardButton(text=ch.channel_title, url=link, style="success"),
            InlineKeyboardButton(text="🗑️", callback_data=f"cobot_mand:del:{ch.id}", style="danger"),
        ])
    buttons.append([InlineKeyboardButton(text="إضافة قناة",    callback_data="cobot_mand:add", style="success")])
    buttons.append([InlineKeyboardButton(text="رجوع",           callback_data="dev:factory_settings", style="primary")])

    await callback.message.edit_text(
        "» <b>عزيزي المطور هذا هو قسم الاشتراك الاجباري بالبوتات المصنوعة بالمصنع</b>.\n\n» <b>في هذا القسم تستطيع ان تضيف قناة اشتراك اجباري بالبوتات التي صُنعت في المصنع بحيث انت تضيف القناة من هنا والبوتات التي صُنعت ستطلب اشتراكاً اجبارياً من المستخدمين الذين سيستخدمونها</b>.\n» <b>يمكن اضافة وحذف القنوات المضافة من الازرار</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cobot_mand:del:"))
async def cb_cobot_mand_del(callback: CallbackQuery):
    ch_id = int(callback.data.split(":")[2])
    async with get_session() as session:
        result = await session.execute(select(CobotMandatoryChannel).where(CobotMandatoryChannel.id == ch_id))
        ch = result.scalar_one_or_none()
        if ch:
            ch.is_active = False
    await callback.answer("✅ تم الحذف.", show_alert=True)
    await cb_cobot_mand(callback)


@dev_router.callback_query(F.data == "cobot_mand:add")
async def cb_cobot_mand_add(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_cobot_mand_type)
    await callback.message.edit_text(
        "» <b>اختر الطريقة التي تريد عرض طلب الاشتراك فيها من المستخدم بالبوت المصنوع</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [
                InlineKeyboardButton(text="أزرار",      callback_data="cobot_mand:type:buttons", style="success"),
                InlineKeyboardButton(text="رسالة نصية", callback_data="cobot_mand:type:text", style="success"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="fs:cobot_mand", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cobot_mand:type:"))
async def cb_cobot_mand_type(callback: CallbackQuery, state: FSMContext):
    display_type = callback.data.split(":")[2]
    await state.update_data(cobot_mand_display_type=display_type)
    await state.set_state(DevStates.waiting_cobot_mand_fwd)
    await callback.message.edit_text(
        "» <b>يرجى توجيه رسالة من القناة لإضافتها</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="fs:cobot_mand", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_cobot_mand_fwd)
async def process_cobot_mand_fwd(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    if not message.forward_from_chat:
        await message.answer("⚠️ يرجى توجيه رسالة من القناة فقط!")
        return

    chat    = message.forward_from_chat
    chat_id = chat.id

    try:
        member = await bot.get_chat_member(chat_id, (await bot.get_me()).id)
        if member.status not in ("administrator", "creator"):
            await message.answer("⚠️ يجب إضافة البوت كمشرف في القناة أولاً!")
            await state.clear()
            return
    except Exception:
        await message.answer("⚠️ لا يمكن الوصول للقناة!")
        await state.clear()
        return
    existing_section = await _cobot_channel_exists_anywhere(chat_id)
    if existing_section:
        await message.answer(
            f"⚠️ هذه القناة مضافة مسبقاً في <b>{existing_section}</b>!\n"
            "يرجى حذفها من ذلك القسم أولاً ثم إعادة الإضافة.",
            parse_mode="HTML", disable_web_page_preview=True)
        await state.clear()
        return

    invite_link = None
    if chat.username:
        invite_link = f"https://t.me/{chat.username}"
    else:
        try:
            link_obj    = await bot.create_chat_invite_link(chat_id)
            invite_link = link_obj.invite_link
        except Exception:
            pass

    data         = await state.get_data()
    display_type = data.get("cobot_mand_display_type", "buttons")

    async with get_session() as session:
        existing = await session.execute(
            select(CobotMandatoryChannel).where(CobotMandatoryChannel.channel_id == chat_id)
        )
        ex = existing.scalar_one_or_none()
        if ex:
            ex.is_active    = True
            ex.display_type = ChannelDisplayType(display_type)
            ex.invite_link  = invite_link
        else:
            session.add(CobotMandatoryChannel(
                channel_id       = chat_id,
                channel_username = chat.username,
                channel_title    = chat.title or str(chat_id),
                invite_link      = invite_link,
                display_type     = ChannelDisplayType(display_type),
            ))

    await state.clear()
    await message.answer(
        f"✅ تم إضافة <b>{chat.title}</b> كقناة اشتراك إجباري للبوتات المصنوعة!",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")]
        ])
    )

@dev_router.callback_query(F.data == "fs:cobot_fund")
async def cb_cobot_fund(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()

    async with get_session() as session:
        result = await session.execute(
            select(CobotFundedChannel).where(CobotFundedChannel.is_active == True)
        )
        channels = result.scalars().all()
    buttons = []
    for ch in channels:
        link = ch.invite_link or (
            f"https://t.me/{ch.channel_username}" if ch.channel_username else "#"
        )
        buttons.append([
            InlineKeyboardButton(
                text=f"{ch.channel_title} ({ch.current_count}/{ch.target_count})",
                url=link, style="success"
            ),
            InlineKeyboardButton(text="🗑️", callback_data=f"cobot_fund:del:{ch.id}", style="danger"),
        ])
    buttons.append([InlineKeyboardButton(text="إضافة قناة تمويل", callback_data="cobot_fund:add", style="success")])
    buttons.append([InlineKeyboardButton(text="رجوع",              callback_data="dev:factory_settings", style="primary")])

    await callback.message.edit_text(
        "» <b>عزيزي المطور هذا هو قسم تمويل القنوات بالبوتات المصنوعة</b>.\n\n» <b>هذا القسم مختص في اجراء تمويل لقناة انت من يحددها حيث سيطلب البوت المصنوع بالمصنع من المستخدمين الاشتراك في هذه القناة، عند اكتمال العدد المطلوب الذي تحدده انت سيتم ازالة القناة من القنوات الممولة</b>.", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cobot_fund:del:"))
async def cb_cobot_fund_del(callback: CallbackQuery):
    ch_id = int(callback.data.split(":")[2])
    async with get_session() as session:
        result = await session.execute(select(CobotFundedChannel).where(CobotFundedChannel.id == ch_id))
        ch = result.scalar_one_or_none()
        if ch:
            ch.is_active = False
    await callback.answer("✅ تم الحذف.", show_alert=True)
    await cb_cobot_fund(callback)


@dev_router.callback_query(F.data == "cobot_fund:add")
async def cb_cobot_fund_add(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_cobot_fund_type)
    await callback.message.edit_text(
        "» <b>اختر نوع عرض طلب الاشتراك الإجباري لهذه القناة الممولة في البوتات المصنوعة</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [
                InlineKeyboardButton(text="أزرار",      callback_data="cobot_fund:type:buttons", style="success"),
                InlineKeyboardButton(text="رسالة نصية", callback_data="cobot_fund:type:text", style="success"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="fs:cobot_fund", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cobot_fund:type:"))
async def cb_cobot_fund_type(callback: CallbackQuery, state: FSMContext):
    display_type = callback.data.split(":")[2]
    await state.update_data(cobot_fund_display_type=display_type)
    await state.set_state(DevStates.waiting_cobot_fund_count)
    await callback.message.edit_text(
        "» <b>ارسل عدد الأعضاء المطلوب لهذه القناة الممولة</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="fs:cobot_fund", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_cobot_fund_count)
async def process_cobot_fund_count(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        count = int(message.text.strip())
        if count <= 0:
            raise ValueError
    except (ValueError, AttributeError):
        await message.answer("⚠️ أرسل رقماً صحيحاً أكبر من صفر!")
        return
    await state.update_data(cobot_fund_target_count=count)
    await state.set_state(DevStates.waiting_cobot_fund_fwd)
    await message.answer(
        "» يرجى توجيه رسالة من القناة لإضافتها:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="fs:cobot_fund", style="primary")]
        ])
    )


@dev_router.message(DevStates.waiting_cobot_fund_fwd)
async def process_cobot_fund_fwd(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    if not message.forward_from_chat:
        await message.answer("⚠️ يرجى توجيه رسالة من القناة فقط!")
        return

    chat    = message.forward_from_chat
    chat_id = chat.id

    try:
        member = await bot.get_chat_member(chat_id, (await bot.get_me()).id)
        if member.status not in ("administrator", "creator"):
            await message.answer("⚠️ يجب إضافة البوت كمشرف في القناة أولاً!")
            await state.clear()
            return
    except Exception:
        await message.answer("⚠️ لا يمكن الوصول للقناة!")
        await state.clear()
        return
    existing_section = await _cobot_channel_exists_anywhere(chat_id)
    if existing_section:
        await message.answer(
            f"⚠️ هذه القناة مضافة مسبقاً في <b>{existing_section}</b>!\n"
            "يرجى حذفها من ذلك القسم أولاً ثم إعادة الإضافة.",
            parse_mode="HTML", disable_web_page_preview=True)
        await state.clear()
        return

    invite_link = None
    if chat.username:
        invite_link = f"https://t.me/{chat.username}"
    else:
        try:
            link_obj    = await bot.create_chat_invite_link(chat_id)
            invite_link = link_obj.invite_link
        except Exception:
            pass

    data         = await state.get_data()
    display_type = data.get("cobot_fund_display_type", "buttons")
    target_count = data.get("cobot_fund_target_count", 100)

    async with get_session() as session:
        existing = await session.execute(
            select(CobotFundedChannel).where(CobotFundedChannel.channel_id == chat_id)
        )
        ex = existing.scalar_one_or_none()
        if ex:
            ex.is_active     = True
            ex.display_type  = ChannelDisplayType(display_type)
            ex.target_count  = target_count
            ex.current_count = 0
            ex.invite_link   = invite_link
            ex.completed_at  = None
        else:
            session.add(CobotFundedChannel(
                channel_id       = chat_id,
                channel_username = chat.username,
                channel_title    = chat.title or str(chat_id),
                invite_link      = invite_link,
                display_type     = ChannelDisplayType(display_type),
                target_count     = target_count,
            ))

    await state.clear()
    await message.answer(
        f"✅ تم إضافة القناة الممولة <b>{chat.title}</b> بهدف <b>{target_count}</b> عضو للبوتات المصنوعة!",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="اعدادات المصنع", callback_data="dev:factory_settings", style="primary")]
        ])
    )

@dev_router.callback_query(F.data == "fs:cobot_bcast")
async def cb_cobot_bcast_menu(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    await state.clear()
    await callback.message.edit_text(
        "» <b>قسم الاذاعة لمستخدمي البوتات المصنوعة</b>.\n» <b>في هذا القسم تستطيع ان تقوم بعمل اذاعة من البوتات المصنوعة الى مستخدمين البوتات المصنوعة</b>.\n\n» <b>حدد نوع الاذاعة سواء رسالة موجهة او نصية</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [
                InlineKeyboardButton(text="إذاعة نصية",  callback_data="cobot_bcast:text", style="success"),
                InlineKeyboardButton(text="إذاعة موجهة", callback_data="cobot_bcast:forward", style="success"),
            ],
            [InlineKeyboardButton(text="رجوع", callback_data="dev:factory_settings", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "cobot_bcast:text")
async def cb_cobot_bcast_text(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_cobot_broadcast)
    await callback.message.edit_text(
        "» <b>ارسل رسالة الاذاعة المراد اذاعتها لجميع المستخدمين في البوتات المصنوعة الان</b>:", parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="fs:cobot_bcast", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data == "cobot_bcast:forward")
async def cb_cobot_bcast_fwd(callback: CallbackQuery, state: FSMContext):
    await state.set_state(DevStates.waiting_cobot_bcast_fwd)
    await callback.message.edit_text(
        "» قم بتوجيه الرسالة المطلوب إذاعتها لمستخدمي البوتات المصنوعة:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="fs:cobot_bcast", style="primary")]
        ])
    )
    await callback.answer()


async def _do_cobot_broadcast(bot: Bot, message: Message, forward: bool = False):
    async with get_session() as session:
        bots_result = await session.execute(
            select(BotModel).where(BotModel.is_active == True)
        )
        active_bots = bots_result.scalars().all()

    total_sent = total_failed = 0

    for bot_record in active_bots:
        if await _is_paid_bot_dev(bot_record.username):
            continue
        async with get_session() as session:
            users_result = await session.execute(
                select(CobotUser).where(
                    CobotUser.bot_id == bot_record.id,
                    CobotUser.is_blocked == False,
                )
            )
            cobot_users = users_result.scalars().all()

        if not cobot_users:
            continue

        cobot_bot = Bot(token=bot_record.token)
        try:
            for i, cu in enumerate(cobot_users):
                try:
                    if message.text:
                        await cobot_bot.send_message(chat_id=cu.user_id, text=message.text)
                    elif message.photo:
                        await cobot_bot.send_photo(chat_id=cu.user_id, photo=message.photo[-1].file_id, caption=message.caption)
                    elif message.video:
                        await cobot_bot.send_video(chat_id=cu.user_id, video=message.video.file_id, caption=message.caption)
                    elif message.document:
                        await cobot_bot.send_document(chat_id=cu.user_id, document=message.document.file_id, caption=message.caption)
                    elif message.voice:
                        await cobot_bot.send_voice(chat_id=cu.user_id, voice=message.voice.file_id, caption=message.caption)
                    elif message.audio:
                        await cobot_bot.send_audio(chat_id=cu.user_id, audio=message.audio.file_id, caption=message.caption)
                    elif message.sticker:
                        await cobot_bot.send_sticker(chat_id=cu.user_id, sticker=message.sticker.file_id)
                    else:
                        await cobot_bot.send_message(chat_id=cu.user_id, text="📢 إذاعة جديدة")
                    total_sent += 1
                except Exception:
                    total_failed += 1
                if (i + 1) % BROADCAST_BATCH == 0:
                    await asyncio.sleep(BROADCAST_DELAY)
        finally:
            await cobot_bot.session.close()

    return total_sent, total_failed

@dev_router.message(DevStates.waiting_cobot_broadcast)
async def process_cobot_broadcast(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    await state.clear()
    wait = await message.answer("⏳ جاري إرسال الإذاعة لمستخدمين البوتات المصنوعة...")
    sent, failed = await _do_cobot_broadcast(bot, message, forward=False)
    await wait.edit_text(
        f"» <b>تم ارسال الاذاعة الى كافة مستخدمين البوتات المصنوعة بالمصنع</b>.\n\n» <b>نجـح الارسال إلى: {sent} مستخدم</b>\n» <b>فشل الارسال إلى: {failed} مستخدم</b>",
        parse_mode="HTML", disable_web_page_preview=True)


@dev_router.message(DevStates.waiting_cobot_bcast_fwd)
async def process_cobot_bcast_fwd(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    await state.clear()
    wait = await message.answer("⏳ جاري إرسال الإذاعة لمستخدمين البوتات المصنوعة...")
    sent, failed = await _do_cobot_broadcast(bot, message, forward=True)
    await wait.edit_text(
        f"» <b>تم ارسال الاذاعة الى كافة مستخدمين البوتات المصنوعة بالمصنع</b>.\n\n» <b>نجـح الارسال إلى: {sent} مستخدم</b>\n» <b>فشل الارسال إلى: {failed} مستخدم</b>",
        parse_mode="HTML", disable_web_page_preview=True)

COBOTS_PAGE_SIZE = 10


async def build_cobots_page(page: int) -> tuple[list, int]:
    async with get_session() as session:
        result = await session.execute(
            select(BotModel).where(BotModel.is_active == True).order_by(BotModel.created_at.desc())
        )
        all_bots = result.scalars().all()
    total = len(all_bots)
    start = page * COBOTS_PAGE_SIZE
    end   = start + COBOTS_PAGE_SIZE
    return all_bots[start:end], total


async def kb_cobots_list(page: int) -> InlineKeyboardMarkup:
    bots, total = await build_cobots_page(page)
    total_pages = (total + COBOTS_PAGE_SIZE - 1) // COBOTS_PAGE_SIZE
    rows = []
    for bot in bots:
        rows.append([
            InlineKeyboardButton(text=f"@{bot.username}", url=f"https://t.me/{bot.username}", style="success"),
            InlineKeyboardButton(text="إدارة", callback_data=f"cbot:manage:{bot.id}:{page}", style="success"),
        ])
    nav = []
    if page > 0:
        nav.append(InlineKeyboardButton(text="‹ السابق", callback_data=f"cbot:page:{page - 1}", style="success"))
    if page < total_pages - 1:
        nav.append(InlineKeyboardButton(text="التالي ›", callback_data=f"cbot:page:{page + 1}", style="success"))
    if nav:
        rows.append(nav)
    rows.append([InlineKeyboardButton(text="رجوع", callback_data="dev:panel", style="primary")])
    return InlineKeyboardMarkup(inline_keyboard=rows)


@dev_router.callback_query(F.data == "dev:cobots")
async def cb_cobots(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True)
        return
    _, total = await build_cobots_page(0)
    await callback.message.edit_text(
        f"🤖 <b>البوتات المصنوعة ({total}):</b>",
        parse_mode="HTML",
        reply_markup=await kb_cobots_list(0)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cbot:page:"))
async def cb_cobots_page(callback: CallbackQuery):
    page = int(callback.data.split(":")[2])
    _, total = await build_cobots_page(page)
    await callback.message.edit_text(
        f"🤖 <b>البوتات المصنوعة ({total}):</b>",
        parse_mode="HTML",
        reply_markup=await kb_cobots_list(page)
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cbot:manage:"))
async def cb_cbot_manage(callback: CallbackQuery):
    parts  = callback.data.split(":")
    bot_id = int(parts[2])
    page   = int(parts[3])
    async with get_session() as session:
        result  = await session.execute(select(BotModel).where(BotModel.id == bot_id))
        bot_rec = result.scalar_one_or_none()
    if not bot_rec:
        await callback.answer("⚠️ البوت غير موجود!", show_alert=True)
        return
    status_btn = (
        InlineKeyboardButton(text="تشغيل البوت", callback_data=f"cbot:start:{bot_id}:{page}", style="success")
        if bot_rec.is_stopped else
        InlineKeyboardButton(text="إيقاف البوت",  callback_data=f"cbot:stop:{bot_id}:{page}", style="danger")
    )
    await callback.message.edit_text(
        f"⚙️ <b>إدارة البوت @{bot_rec.username}</b>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="📋 عرض المعلومات", callback_data=f"cbot:info:{bot_id}:{page}", style="success")],
            [InlineKeyboardButton(text="🗑 حذف البوت",     callback_data=f"cbot:delete_ask:{bot_id}:{page}", style="danger")],
            [status_btn],
            [InlineKeyboardButton(text="رجوع",             callback_data=f"cbot:page:{page}", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cbot:info:"))
async def cb_cbot_info(callback: CallbackQuery):
    parts  = callback.data.split(":")
    bot_id = int(parts[2])
    page   = int(parts[3])
    async with get_session() as session:
        result  = await session.execute(select(BotModel).where(BotModel.id == bot_id))
        bot_rec = result.scalar_one_or_none()
        if not bot_rec:
            await callback.answer("⚠️ البوت غير موجود!", show_alert=True)
            return
        owner_result = await session.execute(select(User).where(User.id == bot_rec.owner_id))
        owner        = owner_result.scalar_one_or_none()
        users_count  = (await session.execute(
            select(func.count(CobotUser.id)).where(CobotUser.bot_id == bot_id)
        )).scalar()
    owner_name = f"@{owner.username}" if owner and owner.username else (owner.first_name if owner else str(bot_rec.owner_id))
    await callback.message.edit_text(
        f"📋 <b>معلومات البوت:</b>\n\n"
        f"توكن البوت: <code>{bot_rec.token}</code>\n"
        f"مطور البوت: {owner_name}\n"
        f"اسم البوت: {bot_rec.bot_name}\n"
        f"يوزر البوت: @{bot_rec.username}\n"
        f"عدد مستخدميه: <b>{users_count}</b>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data=f"cbot:manage:{bot_id}:{page}", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cbot:delete_ask:"))
async def cb_cbot_delete_ask(callback: CallbackQuery):
    parts  = callback.data.split(":")
    bot_id = int(parts[2])
    page   = int(parts[3])
    await callback.message.edit_text(
        "⚠️ عزيزي المطور هل أنت متأكد من حذف بوت المستخدم؟",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="نعم، متأكد", callback_data=f"cbot:delete_confirm:{bot_id}:{page}", style="danger")],
            [InlineKeyboardButton(text="رجوع",        callback_data=f"cbot:manage:{bot_id}:{page}", style="primary")],
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cbot:delete_confirm:"))
async def cb_cbot_delete_confirm(callback: CallbackQuery, bot: Bot):
    parts  = callback.data.split(":")
    bot_id = int(parts[2])
    page   = int(parts[3])
    async with get_session() as session:
        result  = await session.execute(select(BotModel).where(BotModel.id == bot_id))
        bot_rec = result.scalar_one_or_none()
        if not bot_rec:
            await callback.answer("⚠️ البوت غير موجود!", show_alert=True)
            return
        import aiohttp
        try:
            async with aiohttp.ClientSession() as http:
                await http.post(
                    f"https://api.telegram.org/bot{bot_rec.token}/deleteWebhook",
                    timeout=aiohttp.ClientTimeout(total=10)
                )
        except Exception:
            pass
        owner_id       = bot_rec.owner_id
        bot_rec.is_active  = False
        bot_rec.is_stopped = True
    try:
        await bot.send_message(
            owner_id,
            f"⚠️ عزيزي المستخدم، تم حذف البوت <b>@{bot_rec.username}</b> من قبل الإدارة.",
            parse_mode="HTML", disable_web_page_preview=True)
    except Exception:
        pass
    await callback.message.edit_text(
        f"✅ تم حذف البوت @{bot_rec.username} بنجاح.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع للقائمة", callback_data=f"cbot:page:{page}", style="primary")]
        ])
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("cbot:stop:"))
async def cb_cbot_stop(callback: CallbackQuery, bot: Bot):
    parts  = callback.data.split(":")
    bot_id = int(parts[2])
    page   = int(parts[3])
    async with get_session() as session:
        result  = await session.execute(select(BotModel).where(BotModel.id == bot_id))
        bot_rec = result.scalar_one_or_none()
        if not bot_rec:
            await callback.answer("⚠️ البوت غير موجود!", show_alert=True)
            return
        bot_rec.is_stopped = True
        import aiohttp
        try:
            async with aiohttp.ClientSession() as http:
                await http.post(
                    f"https://api.telegram.org/bot{bot_rec.token}/deleteWebhook",
                    timeout=aiohttp.ClientTimeout(total=10)
                )
        except Exception:
            pass
        owner_id = bot_rec.owner_id
        username = bot_rec.username
    try:
        await bot.send_message(
            owner_id,
            f"⏸ عزيزي المستخدم، تم إيقاف البوت <b>@{username}</b> من قبل الإدارة.",
            parse_mode="HTML", disable_web_page_preview=True)
    except Exception:
        pass
    await callback.answer("✅ تم إيقاف بوت المستخدم بنجاح.", show_alert=True)
    await cb_cbot_manage(callback)


@dev_router.callback_query(F.data.startswith("cbot:start:"))
async def cb_cbot_start(callback: CallbackQuery, bot: Bot):
    parts  = callback.data.split(":")
    bot_id = int(parts[2])
    page   = int(parts[3])
    async with get_session() as session:
        result  = await session.execute(select(BotModel).where(BotModel.id == bot_id))
        bot_rec = result.scalar_one_or_none()
        if not bot_rec:
            await callback.answer("⚠️ البوت غير موجود!", show_alert=True)
            return
        bot_rec.is_stopped = False
        owner_id = bot_rec.owner_id
        username = bot_rec.username
        token    = bot_rec.token
    import aiohttp
    webhook_url = f"https://kodo.publicvm.com/kodo/bots/{username.lower()}"
    secret      = f"kodo_{username.lower()}_secret"
    try:
        async with aiohttp.ClientSession() as http:
            await http.post(
                f"https://api.telegram.org/bot{token}/setWebhook",
                json={
                    "url": webhook_url,
                    "secret_token": secret,
                    "allowed_updates": ["message", "callback_query", "edited_message", "my_chat_member"],
                },
                timeout=aiohttp.ClientTimeout(total=10)
            )
    except Exception:
        pass
    try:
        await bot.send_message(
            owner_id,
            f"▶️ عزيزي المستخدم، تم تشغيل البوت <b>@{username}</b> من قبل الإدارة.",
            parse_mode="HTML", disable_web_page_preview=True)
    except Exception:
        pass
    await callback.answer("✅ تم تشغيل بوت المستخدم بنجاح.", show_alert=True)
    await cb_cbot_manage(callback)


def _fmt_usd(cents: int) -> str:
    return f"{cents // 100}$" if cents % 100 == 0 else f"{cents / 100:.2f}$"


async def _build_payments_kb() -> InlineKeyboardMarkup:
    packages = await get_payment_packages()
    ps       = await get_payment_settings()
    rows     = []
    for pkg in packages:
        rows.append([InlineKeyboardButton(
            text          = f"{pkg.stars} 🌟 ➥ {_fmt_usd(pkg.usd)}",
            callback_data = f"pay:edit_pkg:{pkg.id}", style="success",)])
    rows.append([InlineKeyboardButton(text="تعيين سعر البوت",    callback_data="pay:set_bot_price", style="danger")])
    rows.append([InlineKeyboardButton(text="إضافة أسعار جديدة",  callback_data="pay:add_pkg", style="danger")])
    rows.append([InlineKeyboardButton(text=" رجوع",            callback_data="dev:panel", style="primary")])
    return InlineKeyboardMarkup(inline_keyboard=rows)


@dev_router.callback_query(F.data == "dev:payments")
async def cb_dev_payments(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.clear()
    ps = await get_payment_settings()
    await callback.message.edit_text(
        "💳 <b>قسم المدفوعات</b>\n\n"
        "عزيزي المطور، هذا هو قسم المدفوعات في المصنع.\n"
        "يمكنك إدارة باقات الشحن وأسعارها من خلال الأزرار أدناه. "
        "اضغط على أي باقة لتعديلها.\n\n"
        f"💰 سعر البوت الحالي: <b>{_fmt_usd(ps.bot_price_usd)}</b>",
        parse_mode="HTML",
        reply_markup=await _build_payments_kb(),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("pay:edit_pkg:"))
async def cb_edit_pkg(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    pkg_id = int(callback.data.split(":")[2])
    pkg    = await get_payment_package(pkg_id)
    if not pkg:
        await callback.answer("الباقة غير موجودة!", show_alert=True); return
    await state.set_state(DevStates.waiting_edit_pkg_value)
    await state.update_data(edit_pkg_id=pkg_id)
    await callback.message.edit_text(
        f"✏️ <b>تعديل الباقة</b>\n\n"
        f"السعر الحالي:\n"
        f"<b>{pkg.stars} 🌟 ➥ {_fmt_usd(pkg.usd)}</b>\n\n"
        "أرسل عدد النجوم والسعر بالشكل التالي:\n"
        "<code>210\n3$</code>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="🗑 حذف الباقة", callback_data=f"pay:del_pkg:{pkg_id}")],
            [InlineKeyboardButton(text="◀️ رجوع",       callback_data="dev:payments", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_edit_pkg_value)
async def process_edit_pkg(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    data = await state.get_data()
    pkg_id = data.get("edit_pkg_id")
    try:
        lines  = message.text.strip().splitlines()
        stars  = int(lines[0].strip())
        usd_s  = lines[1].strip().replace("$", "").replace(" ", "")
        usd_f  = float(usd_s)
        cents  = int(round(usd_f * 100))
        if stars <= 0 or cents <= 0:
            raise ValueError
    except Exception:
        await message.answer("❌ صيغة خاطئة. أرسل بالشكل:\n<code>210\n3$</code>", parse_mode="HTML", disable_web_page_preview=True)
        return
    await state.clear()
    await update_payment_package(pkg_id, stars, cents)
    note = await message.answer("✅ تم تحديث الأسعار بنجاح.")
    await asyncio.sleep(2)
    await note.delete()
    ps = await get_payment_settings()
    await message.answer(
        "💳 <b>قسم المدفوعات</b>\n\n"
        "عزيزي المطور، هذا هو قسم المدفوعات في المصنع.\n"
        "يمكنك إدارة باقات الشحن وأسعارها من خلال الأزرار أدناه. "
        "اضغط على أي باقة لتعديلها.\n\n"
        f"💰 سعر البوت الحالي: <b>{_fmt_usd(ps.bot_price_usd)}</b>",
        parse_mode="HTML",
        reply_markup=await _build_payments_kb(),
    )


@dev_router.callback_query(F.data.startswith("pay:del_pkg:"))
async def cb_del_pkg(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    pkg_id = int(callback.data.split(":")[2])
    await state.clear()
    await delete_payment_package(pkg_id)
    ps = await get_payment_settings()
    await callback.message.edit_text(
        "💳 <b>قسم المدفوعات</b>\n\n"
        "تم حذف الباقة بنجاح.\n\n"
        f"💰 سعر البوت الحالي: <b>{_fmt_usd(ps.bot_price_usd)}</b>",
        parse_mode="HTML",
        reply_markup=await _build_payments_kb(),
    )
    await callback.answer()


@dev_router.callback_query(F.data == "pay:add_pkg")
async def cb_add_pkg(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.set_state(DevStates.waiting_add_pkg_value)
    await callback.message.edit_text(
        "➕ <b>إضافة باقة جديدة</b>\n\n"
        "أرسل عدد النجوم والسعر بالشكل التالي:\n"
        "<code>2500\n50$</code>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="رجوع", callback_data="dev:payments", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_add_pkg_value)
async def process_add_pkg(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        lines  = message.text.strip().splitlines()
        stars  = int(lines[0].strip())
        usd_s  = lines[1].strip().replace("$", "").replace(" ", "")
        usd_f  = float(usd_s)
        cents  = int(round(usd_f * 100))
        if stars <= 0 or cents <= 0:
            raise ValueError
    except Exception:
        await message.answer("❌ صيغة خاطئة. أرسل بالشكل:\n<code>2500\n50$</code>", parse_mode="HTML", disable_web_page_preview=True)
        return
    await state.clear()
    await add_payment_package(stars, cents)
    note = await message.answer("✅ تمت إضافة الباقة بنجاح.")
    await asyncio.sleep(2)
    await note.delete()
    ps = await get_payment_settings()
    await message.answer(
        "💳 <b>قسم المدفوعات</b>\n\n"
        "عزيزي المطور، هذا هو قسم المدفوعات في المصنع.\n"
        "يمكنك إدارة باقات الشحن وأسعارها من خلال الأزرار أدناه. "
        "اضغط على أي باقة لتعديلها.\n\n"
        f"💰 سعر البوت الحالي: <b>{_fmt_usd(ps.bot_price_usd)}</b>",
        parse_mode="HTML",
        reply_markup=await _build_payments_kb(),
    )


@dev_router.callback_query(F.data == "pay:set_bot_price")
async def cb_set_bot_price(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.set_state(DevStates.waiting_bot_price_value)
    ps = await get_payment_settings()
    await callback.message.edit_text(
        "💰 <b>تعيين سعر البوت</b>\n\n"
        "عزيزي المطور، هذا القسم مسؤول عن تحديد سعر إنشاء البوت المدفوع.\n\n"
        f"السعر الحالي: <b>{_fmt_usd(ps.bot_price_usd)}</b> لكل بوت\n\n"
        "أرسل سعر البوت الواحد الآن (مثال: <code>2$</code>):",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data="dev:payments", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_bot_price_value)
async def process_bot_price(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        val   = message.text.strip().replace("$", "").replace(" ", "")
        price = float(val)
        cents = int(round(price * 100))
        if cents <= 0:
            raise ValueError
    except Exception:
        await message.answer("❌ أرسل قيمة صحيحة مثل: <code>2$</code> أو <code>2.5$</code>", parse_mode="HTML", disable_web_page_preview=True)
        return
    await state.clear()
    await update_bot_price(cents)
    await message.answer(f"✅ تم تحديث سعر البوت إلى <b>{_fmt_usd(cents)}</b>.", parse_mode="HTML", disable_web_page_preview=True)


@dev_router.callback_query(F.data == "dev:subscribers")
async def cb_subscribers(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.clear()
    async with get_session() as session:
        from information.models import BotSubscription as BotSubModel, User as UserModel, Bot as BotModel2
        result = await session.execute(
            select(BotSubModel).where(BotSubModel.is_active == True)
        )
        subs = result.scalars().all()

    if not subs:
        await callback.message.edit_text(
            "👥 لا يوجد مشتركون حالياً.",
            reply_markup=InlineKeyboardMarkup(inline_keyboard=[
                [InlineKeyboardButton(text=" رجوع", callback_data="dev:panel", style="primary")],
            ])
        )
        await callback.answer(); return

    user_ids = list({s.user_id for s in subs})
    rows = []
    for uid in user_ids:
        async with get_session() as session:
            res = await session.execute(select(UserModel).where(UserModel.id == uid))
            usr = res.scalar_one_or_none()
        name = f"{usr.first_name}" if usr else str(uid)
        rows.append([
            InlineKeyboardButton(text=name, url=f"tg://user?id={uid}", style="success"),
            InlineKeyboardButton(text="ادارة", callback_data=f"dev:sub_manage:{uid}", style="success"),
        ])
    rows.append([InlineKeyboardButton(text=" رجوع", callback_data="dev:panel", style="primary")])
    await callback.message.edit_text(
        "👥 <b>قسم المشتركين</b>\n\nالمستخدمون الذين لديهم بوتات مدفوعة:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=rows),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:sub_manage:"))
async def cb_sub_manage(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.clear()
    uid = int(callback.data.split(":")[2])

    async with get_session() as session:
        from information.models import User as UserModel
        res = await session.execute(select(UserModel).where(UserModel.id == uid))
        usr = res.scalar_one_or_none()

    name = f'<a href="tg://user?id={uid}">{usr.first_name if usr else uid}</a>'
    paid_bots   = await get_user_paid_bots(uid)
    unpaid_bots = await get_user_unpaid_bots(uid)

    sub = None
    if paid_bots:
        sub = await get_bot_subscription(paid_bots[0].id)

    started = sub.started_at.strftime("%d-%m-%Y") if sub else "—"
    expires = sub.expires_at.strftime("%d-%m-%Y") if sub else "—"

    paid_list   = "\n".join(f"{i+1}. @{b.username}" for i,b in enumerate(paid_bots))   or "لايوجد"
    unpaid_list = "\n".join(f"{i+1}. @{b.username}" for i,b in enumerate(unpaid_bots)) or "لايوجد"

    await callback.message.edit_text(
        f"👤 المستخدم: {name}\n"
        f"📅 تاريخ الاشتراك: {started}\n"
        f"⏳ تاريخ النفاذ: {expires}\n\n"
        f"💎 بوتاته المدفوعة:\n{paid_list}\n\n"
        f"🤖 بوتاته الغير مدفوعة:\n{unpaid_list}\n\n"
        f"يمكنك زيادة عدد أيام الاشتراك من خلال الأزرار:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="➕ زيادة مدة الاشتراك",  callback_data=f"dev:extend_sub:{uid}", style="success")],
            [InlineKeyboardButton(text="🚫 ايقاف الاشتراكات",    callback_data=f"dev:stop_subs:{uid}", style="danger")],
            [InlineKeyboardButton(text=" رجوع",               callback_data="dev:subscribers", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:extend_sub:"))
async def cb_extend_sub(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    uid = int(callback.data.split(":")[2])
    await state.set_state(DevStates.waiting_extend_days)
    await state.update_data(extend_uid=uid)
    await callback.message.edit_text(
        "➕ أرسل عدد الأيام المراد إضافتها لاشتراك المستخدم:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:sub_manage:{uid}", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_extend_days)
async def process_extend_days(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    data = await state.get_data()
    uid  = data.get("extend_uid")
    try:
        days = int(message.text.strip())
        if days <= 0: raise ValueError
    except Exception:
        await message.answer("❌ أرسل عدد أيام صحيح (مثلاً: 7)")
        return
    await state.clear()
    from datetime import timedelta
    paid_bots = await get_user_paid_bots(uid)
    count = 0
    for b in paid_bots:
        sub = await get_bot_subscription(b.id)
        if sub:
            async with get_session() as session:
                from information.models import BotSubscription as BotSubModel
                res = await session.execute(
                    select(BotSubModel).where(BotSubModel.bot_id == b.id, BotSubModel.is_active == True)
                )
                s = res.scalar_one_or_none()
                if s:
                    s.expires_at = s.expires_at + timedelta(days=days)
                    count += 1
    await message.answer(f"✅ تمت إضافة {days} يوم لـ {count} اشتراك للمستخدم.")


@dev_router.callback_query(F.data.startswith("dev:stop_subs:"))
async def cb_stop_subs_confirm(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    uid = int(callback.data.split(":")[2])
    await state.clear()
    await callback.message.edit_text(
        "⚠️ عزيزي المطور هذا الاجراء سيقوم بإيقاف وحذف جميع اشتراكات المستخدم المشترك، "
        "هل أنت متأكد من حذف الاشتراك؟",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="نعم، متأكد",   callback_data=f"dev:stop_subs_yes:{uid}", style="danger")],
            [InlineKeyboardButton(text=" رجوع",         callback_data=f"dev:sub_manage:{uid}", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:stop_subs_yes:"))
async def cb_stop_subs_yes(callback: CallbackQuery, bot: Bot):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    uid = int(callback.data.split(":")[2])
    async with get_session() as session:
        from information.models import User as UserModel
        res = await session.execute(select(UserModel).where(UserModel.id == uid))
        usr = res.scalar_one_or_none()
    name = usr.first_name if usr else str(uid)
    paid_bots = await get_user_paid_bots(uid)
    for b in paid_bots:
        await expire_bot_subscription(b.id)
    await callback.message.edit_text(
        f"✅ عزيزي المطور تم حذف جميع اشتراكات المستخدم.\n"
        f"كل البوتات التي أنشأها المستخدم <b>{name}</b> عادت إلى النسخة الغير مدفوعة.\n\n"
        f"تم إرسال إشعار بخصوص ذلك إلى المستخدم.",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data="dev:subscribers", style="primary")],
        ]),
    )
    try:
        await bot.send_message(
            uid,
            "⚠️ تم إيقاف جميع اشتراكاتك المدفوعة في البوت من قبل الادارة، "
            "تواصل مع المطور (@n_u_7) لمعرفة السبب!",
        )
    except Exception:
        pass
    await callback.answer()


BOTS_PER_PAGE = 15


async def _render_bots_page(callback: CallbackQuery, page: int, paid_only: bool):
    from information.models import Bot as BotModel2
    async with get_session() as session:
        q = select(BotModel2).where(BotModel2.is_active == True)
        if paid_only:
            q = q.where(BotModel2.is_paid == True)
        q = q.order_by(BotModel2.created_at.desc())
        result = await session.execute(q)
        all_bots = result.scalars().all()

    total   = len(all_bots)
    pages   = max(1, (total + BOTS_PER_PAGE - 1) // BOTS_PER_PAGE)
    page    = max(1, min(page, pages))
    start   = (page - 1) * BOTS_PER_PAGE
    bots    = all_bots[start:start + BOTS_PER_PAGE]
    prefix  = "paid_bots" if paid_only else "all_bots"
    title   = "البوتات المدفوعة 💎" if paid_only else "البوتات المصنوعة 🤖"

    rows = []
    for b in bots:
        rows.append([
            InlineKeyboardButton(text=f"@{b.username}", url=f"https://t.me/{b.username}", style="success"),
            InlineKeyboardButton(text="ادارة", callback_data=f"dev:bot_manage:{b.id}:{prefix}:{page}", style="success"),
        ])

    nav = []
    if page > 1:
        nav.append(InlineKeyboardButton(text=" السابق", callback_data=f"dev:{prefix}:{page-1}", style="success"))
    if page < pages:
        nav.append(InlineKeyboardButton(text="التالي", callback_data=f"dev:{prefix}:{page+1}", style="success"))
    if nav:
        rows.append(nav)
    rows.append([InlineKeyboardButton(text=" رجوع", callback_data="dev:panel", style="primary")])

    await callback.message.edit_text(
        f"<b>{title}</b>\n\nعدد البوتات: {total} بوت\n"
        f"القائمة {page} | البوتات {len(bots)}",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=rows),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:all_bots:"))
async def cb_all_bots(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.clear()
    page = int(callback.data.split(":")[2])
    await _render_bots_page(callback, page, paid_only=False)


@dev_router.callback_query(F.data.startswith("dev:paid_bots:"))
async def cb_dev_paid_bots(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.clear()
    page = int(callback.data.split(":")[2])
    await _render_bots_page(callback, page, paid_only=True)


@dev_router.callback_query(F.data.startswith("dev:bot_manage:"))
async def cb_bot_manage(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.clear()
    parts  = callback.data.split(":")
    bot_id = int(parts[2])
    prefix = parts[3]
    page   = parts[4]
    bot_rec = await get_bot_by_id(bot_id)
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    status   = "متوقف ⛔" if bot_rec.is_stopped else "يعمل ✅"
    stop_btn = " استئناف" if bot_rec.is_stopped else "⏹ ايقاف البوت"
    stop_cb  = f"dev:resume_bot:{bot_id}:{prefix}:{page}" if bot_rec.is_stopped else f"dev:stop_bot_confirm:{bot_id}:{prefix}:{page}"

    rows = []
    if bot_rec.is_paid:
        sub = await get_bot_subscription(bot_id)
        started = sub.started_at.strftime("%d-%m-%Y") if sub else "—"
        expires = sub.expires_at.strftime("%d-%m-%Y") if sub else "—"
        sub_text = (
            f"الاشتراك: مدفوع ✅\n"
            f"تاريخ الاشتراك: {started}\n"
            f"تاريخ الانتهاء: {expires}"
        )
        rows.append([InlineKeyboardButton(text="🗑 حذف البوت", callback_data=f"dev:del_bot_confirm:{bot_id}:{prefix}:{page}", style="danger")])
        rows.append([InlineKeyboardButton(text="🛑 ايقاف الاشتراك", callback_data=f"dev:sub_stop_confirm:{bot_id}:{prefix}:{page}", style="danger")])
        rows.append([
            InlineKeyboardButton(text="➕ زيادة الاشتراك", callback_data=f"dev:sub_extend:{bot_id}:{prefix}:{page}", style="success"),
            InlineKeyboardButton(text="➖ تقليل الاشتراك", callback_data=f"dev:sub_reduce:{bot_id}:{prefix}:{page}", style="success"),
        ])
        rows.append([
            InlineKeyboardButton(text=stop_btn, callback_data=stop_cb),
            InlineKeyboardButton(text=" نقل البوت", callback_data=f"dev:transfer_bot:{bot_id}:{prefix}:{page}", style="success"),
        ])
        rows.append([InlineKeyboardButton(text=" رجوع", callback_data=f"dev:{prefix}:{page}", style="primary")])
    else:
        sub_text = "الاشتراك: غير مدفوع ✖️"
        rows.append([InlineKeyboardButton(text="💎 جعل البوت مدفوع", callback_data=f"dev:make_paid_confirm:{bot_id}:{prefix}:{page}", style="success")])
        rows.append([InlineKeyboardButton(text="🗑 حذف البوت", callback_data=f"dev:del_bot_confirm:{bot_id}:{prefix}:{page}", style="danger")])
        rows.append([
            InlineKeyboardButton(text=stop_btn, callback_data=stop_cb),
            InlineKeyboardButton(text=" نقل البوت", callback_data=f"dev:transfer_bot:{bot_id}:{prefix}:{page}", style="success"),
        ])
        rows.append([InlineKeyboardButton(text=" رجوع", callback_data=f"dev:{prefix}:{page}", style="primary")])

    await callback.message.edit_text(
        f"🤖 البوت: @{bot_rec.username}\n"
        f"الحالة: {status}\n"
        f"{sub_text}\n\n"
        "اختر الاجراء المطلوب من خلال الازرار ادناه:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=rows),
    )
    await callback.answer()

async def _notify_bot_owner(bot: Bot, owner_id: int, text: str):
    try:
        await bot.send_message(owner_id, text, parse_mode="HTML", disable_web_page_preview=True)
    except Exception:
        pass


@dev_router.callback_query(F.data.startswith("dev:make_paid_confirm:"))
async def cb_make_paid_confirm(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = parts[2]; prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(int(bot_id))
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    await callback.message.edit_text(
        f"البوت: @{bot_rec.username}\n"
        f"الطلب: التحويل الى بوت مدفوع\n\n"
        "عزيزي المطور هل انت متأكد من جعل البوت مدفوعاً؟",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" نعم، متأكد", callback_data=f"dev:make_paid_yes:{bot_id}:{prefix}:{page}", style="success")],
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:make_paid_yes:"))
async def cb_make_paid_yes(callback: CallbackQuery, state: FSMContext, bot: Bot):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = int(parts[2]); prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(bot_id)
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    fbid = bot_rec.created_by_bot_id or 0
    await make_bot_paid(bot_id, bot_rec.owner_id, fbid)
    await _notify_bot_owner(bot, bot_rec.owner_id,
        f"💎 <b>تهانينا!</b>\nتم جعل بوتك @{bot_rec.username} مدفوعاً من قِبل الإدارة.")
    await callback.answer("✅ تم جعل البوت مدفوعاً.", show_alert=True)
    callback.data = f"dev:bot_manage:{bot_id}:{prefix}:{page}"
    await cb_bot_manage(callback, state)


@dev_router.callback_query(F.data.startswith("dev:sub_stop_confirm:"))
async def cb_sub_stop_confirm(callback: CallbackQuery):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = parts[2]; prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(int(bot_id))
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    await callback.message.edit_text(
        f"البوت: @{bot_rec.username}\n"
        f"الطلب: ايقاف الاشتراك\n\n"
        "عزيزي المطور هل انت متأكد من ايقاف اشتراك البوت؟",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" نعم، متأكد", callback_data=f"dev:sub_stop_yes:{bot_id}:{prefix}:{page}", style="danger")],
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:sub_stop_yes:"))
async def cb_sub_stop_yes(callback: CallbackQuery, state: FSMContext, bot: Bot):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = int(parts[2]); prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(bot_id)
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    await expire_bot_subscription(bot_id)
    await _notify_bot_owner(bot, bot_rec.owner_id,
        f"🛑 تم ايقاف اشتراك بوتك @{bot_rec.username} من قِبل الإدارة، وأصبح غير مدفوع.")
    await callback.answer("✅ تم ايقاف الاشتراك.", show_alert=True)
    callback.data = f"dev:bot_manage:{bot_id}:{prefix}:{page}"
    await cb_bot_manage(callback, state)


@dev_router.callback_query(F.data.startswith("dev:sub_extend:"))
async def cb_sub_extend(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = parts[2]; prefix = parts[3]; page = parts[4]
    await state.set_state(DevStates.waiting_extend_days)
    await state.update_data(sub_bot_id=int(bot_id), sub_prefix=prefix, sub_page=page)
    await callback.message.edit_text(
        "➕ <b>زيادة الاشتراك</b>\n\nأرسل عدد الأيام المراد إضافتها (مثال: <code>5</code>):",
        parse_mode="HTML", disable_web_page_preview=True,
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")]
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_extend_days)
async def cb_process_extend(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear(); return
    try:
        days = int(message.text.strip())
        if days <= 0:
            raise ValueError
    except Exception:
        await message.answer("⚠️ أرسل عدد أيام صحيح أكبر من صفر."); return
    data   = await state.get_data()
    bot_id = data.get("sub_bot_id")
    prefix = data.get("sub_prefix"); page = data.get("sub_page")
    await state.clear()
    res = await adjust_bot_subscription(bot_id, days)
    bot_rec = await get_bot_by_id(bot_id)
    if not res["ok"]:
        await message.answer("⚠️ تعذر تعديل الاشتراك (لا يوجد اشتراك نشط).")
        return
    new_exp = res["new_expires"].strftime("%d-%m-%Y")
    await message.answer(
        f"✅ تم زيادة اشتراك @{bot_rec.username} بمقدار {days} يوم.\nتاريخ الانتهاء الجديد: <b>{new_exp}</b>",
        parse_mode="HTML", disable_web_page_preview=True,
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")]
        ]),
    )
    if bot_rec:
        await _notify_bot_owner(bot, bot_rec.owner_id,
            f"➕ تم زيادة مدة اشتراك بوتك @{bot_rec.username} بمقدار {days} يوم من قِبل الإدارة.\nتاريخ الانتهاء الجديد: {new_exp}")


@dev_router.callback_query(F.data.startswith("dev:sub_reduce:"))
async def cb_sub_reduce(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = parts[2]; prefix = parts[3]; page = parts[4]
    await state.set_state(DevStates.waiting_reduce_days)
    await state.update_data(sub_bot_id=int(bot_id), sub_prefix=prefix, sub_page=page)
    await callback.message.edit_text(
        "➖ <b>تقليل الاشتراك</b>\n\nأرسل عدد الأيام المراد خصمها (مثال: <code>5</code>):",
        parse_mode="HTML", disable_web_page_preview=True,
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")]
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_reduce_days)
async def cb_process_reduce(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear(); return
    try:
        days = int(message.text.strip())
        if days <= 0:
            raise ValueError
    except Exception:
        await message.answer("⚠️ أرسل عدد أيام صحيح أكبر من صفر."); return
    data   = await state.get_data()
    bot_id = data.get("sub_bot_id")
    prefix = data.get("sub_prefix"); page = data.get("sub_page")
    res = await adjust_bot_subscription(bot_id, -days)
    bot_rec = await get_bot_by_id(bot_id)
    if not res["ok"]:
        if res["reason"] == "too_much":
            await message.answer(
                "⚠️ التقليل الذي اخترته يتجاوز تاريخ انتهاء الاشتراك.\n"
                "يجب أن ترسل عدد أيام أقل بحيث يبقى يوم واحد على الأقل."
            )
            return
        await message.answer("⚠️ تعذر تعديل الاشتراك (لا يوجد اشتراك نشط).")
        await state.clear()
        return
    await state.clear()
    new_exp = res["new_expires"].strftime("%d-%m-%Y")
    await message.answer(
        f"✅ تم تقليل اشتراك @{bot_rec.username} بمقدار {days} يوم.\nتاريخ الانتهاء الجديد: <b>{new_exp}</b>",
        parse_mode="HTML", disable_web_page_preview=True,
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")]
        ]),
    )
    if bot_rec:
        await _notify_bot_owner(bot, bot_rec.owner_id,
            f"➖ تم تقليل مدة اشتراك بوتك @{bot_rec.username} بمقدار {days} يوم من قِبل الإدارة.\nتاريخ الانتهاء الجديد: {new_exp}")



@dev_router.callback_query(F.data.startswith("dev:del_bot_confirm:"))
async def cb_del_bot_confirm(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = parts[2]; prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(int(bot_id))
    await callback.message.edit_text(
        f"⚠️ عزيزي المطور هذا الاجراء سيقوم بحذف البوت @{bot_rec.username if bot_rec else ''} "
        "وجميع بياناته بشكل نهائي من المصنع، هل أنت متأكد؟",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" نعم، متأكد",  callback_data=f"dev:del_bot_yes:{bot_id}:{prefix}:{page}", style="danger")],
            [InlineKeyboardButton(text=" رجوع",        callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:del_bot_yes:"))
async def cb_del_bot_yes(callback: CallbackQuery, bot: Bot):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = int(parts[2]); prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(bot_id)
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    owner_id = bot_rec.owner_id
    username = bot_rec.username
    import glob
    db_patterns = [
        f"/var/www/kodo/factory/cobots/*/database/{username.lower()}.db",
        f"/var/www/kodo/factory/cobots/*/database/{username}.db",
    ]
    for pattern in db_patterns:
        for db_file in glob.glob(pattern):
            try:
                import os; os.remove(db_file)
            except Exception:
                pass
    async with get_session() as session:
        from information.models import Bot as BotModel2, BotSubscription as BotSubModel
        await session.execute(
            select(BotSubModel).where(BotSubModel.bot_id == bot_id)
        )
        res_sub = await session.execute(select(BotSubModel).where(BotSubModel.bot_id == bot_id))
        sub = res_sub.scalar_one_or_none()
        if sub:
            await session.delete(sub)
        res_bot = await session.execute(select(BotModel2).where(BotModel2.id == bot_id))
        b = res_bot.scalar_one_or_none()
        if b:
            await session.delete(b)
    await callback.message.edit_text(
        "✅ تم حذف البوت وجميع بياناته.\nتم إرسال إشعار إلى المستخدم.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:{prefix}:{page}", style="primary")],
        ]),
    )
    try:
        await bot.send_message(
            owner_id,
            f"⚠️ تم حذف البوت @{username} وجميع بياناته نهائياً. "
            "تواصل مع المطور (@n_u_7) لمعرفة السبب!",
        )
    except Exception:
        pass
    await callback.answer()

@dev_router.callback_query(F.data.startswith("dev:stop_bot_confirm:"))
async def cb_stop_bot_confirm(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = parts[2]; prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(int(bot_id))
    await callback.message.edit_text(
        f"⚠️ عزيزي المطور هذا الاجراء سيقوم بإيقاف البوت @{bot_rec.username if bot_rec else ''} "
        "بشكل كامل، هل أنت متأكد؟",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" نعم، متأكد", callback_data=f"dev:stop_bot_yes:{bot_id}:{prefix}:{page}", style="danger")],
            [InlineKeyboardButton(text=" رجوع",       callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:stop_bot_yes:"))
async def cb_stop_bot_yes(callback: CallbackQuery, bot: Bot):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = int(parts[2]); prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(bot_id)
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    async with get_session() as session:
        from information.models import Bot as BotModel2
        res = await session.execute(select(BotModel2).where(BotModel2.id == bot_id))
        b = res.scalar_one_or_none()
        if b:
            b.is_stopped = True
    await callback.message.edit_text(
        f"✅ تم إيقاف البوت @{bot_rec.username}.\n"
        "لا يمكن لأي مستخدم بعد الآن استخدامه.\n\n"
        "تم إرسال إشعار إلى المستخدم.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:{prefix}:{page}", style="primary")],
        ]),
    )
    try:
        await bot.send_message(
            bot_rec.owner_id,
            f"⚠️ تم إيقاف البوت @{bot_rec.username}. "
            "تواصل مع المطور (@n_u_7) لمعرفة السبب!",
        )
    except Exception:
        pass
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:resume_bot:"))
async def cb_resume_bot(callback: CallbackQuery, bot: Bot):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = int(parts[2]); prefix = parts[3]; page = parts[4]
    bot_rec = await get_bot_by_id(bot_id)
    if not bot_rec:
        await callback.answer("البوت غير موجود!", show_alert=True); return
    async with get_session() as session:
        from information.models import Bot as BotModel2
        res = await session.execute(select(BotModel2).where(BotModel2.id == bot_id))
        b = res.scalar_one_or_none()
        if b:
            b.is_stopped = False
    await callback.message.edit_text(
        f"✅ تم استئناف البوت @{bot_rec.username}.\n\n"
        "تم إرسال إشعار إلى المستخدم.",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:{prefix}:{page}", style="primary")],
        ]),
    )
    try:
        await bot.send_message(
            bot_rec.owner_id,
            f"✅ تم استئناف البوت @{bot_rec.username} وهو يعمل الآن بشكل طبيعي.",
        )
    except Exception:
        pass
    await callback.answer()


@dev_router.callback_query(F.data.startswith("dev:transfer_bot:"))
async def cb_transfer_bot(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    parts  = callback.data.split(":")
    bot_id = int(parts[2]); prefix = parts[3]; page = parts[4]
    await state.set_state(DevStates.waiting_transfer_bot_user)
    await state.update_data(transfer_bot_id=bot_id, transfer_prefix=prefix, transfer_page=page)
    bot_rec = await get_bot_by_id(bot_id)
    await callback.message.edit_text(
        f"🔄 نقل ملكية البوت @{bot_rec.username if bot_rec else ''}\n\n"
        "أرسل user_id المستخدم الذي تريد نقل البوت إليه:",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text=" رجوع", callback_data=f"dev:bot_manage:{bot_id}:{prefix}:{page}", style="primary")],
        ]),
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_transfer_bot_user)
async def process_transfer_bot(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    data   = await state.get_data()
    bot_id = data.get("transfer_bot_id")
    prefix = data.get("transfer_prefix", "all_bots")
    page   = data.get("transfer_page", "1")
    try:
        new_uid = int(message.text.strip())
    except Exception:
        await message.answer("❌ أرسل user_id صحيح (أرقام فقط).")
        return

    async with get_session() as session:
        from information.models import User as UserModel
        res = await session.execute(select(UserModel).where(UserModel.id == new_uid))
        new_user = res.scalar_one_or_none()
    if not new_user:
        await message.answer("❌ المستخدم غير موجود في قاعدة البيانات. يجب أن يكون لديه تواصل مع البوت أولاً.")
        return
    bot_rec = await get_bot_by_id(bot_id)
    old_owner = bot_rec.owner_id if bot_rec else None
    async with get_session() as session:
        from information.models import Bot as BotModel2
        res = await session.execute(select(BotModel2).where(BotModel2.id == bot_id))
        b = res.scalar_one_or_none()
        if b:
            b.owner_id = new_uid
    await state.clear()
    await message.answer(
        f"✅ تم نقل ملكية البوت @{bot_rec.username if bot_rec else ''} "
        f"إلى المستخدم {new_user.first_name} (<code>{new_uid}</code>).",
        parse_mode="HTML",
    )

@dev_router.callback_query(F.data == "dev:transfer_balance")
async def cb_transfer_balance(callback: CallbackQuery, state: FSMContext):
    if not await is_dev_or_admin_db(callback.from_user.id):
        await callback.answer("⛔ غير مصرح!", show_alert=True); return
    await state.clear()
    await state.set_state(DevStates.waiting_transfer_user_id)
    await callback.message.edit_text(
        "» <b>تحويل مبلغ</b>\n\n"
        "» عزيزي المطور يجب إرسال ID المستخدم الذي تريد تحويل المبلغ له:",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="◀️ رجوع", callback_data="dev:panel")],
        ])
    )
    await callback.answer()


@dev_router.message(DevStates.waiting_transfer_user_id)
async def process_transfer_user_id(message: Message, state: FSMContext):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        user_id = int(message.text.strip())
    except Exception:
        await message.answer("⚠️ أرسل ID صحيح (أرقام فقط).")
        return
    async with get_session() as session:
        from information.models import User as UserModel
        res  = await session.execute(select(UserModel).where(UserModel.id == user_id))
        user = res.scalar_one_or_none()
    if not user:
        await message.answer(
            "⚠️ هذا المستخدم غير مسجل في المصنع.",
            reply_markup=InlineKeyboardMarkup(inline_keyboard=[
                [InlineKeyboardButton(text="◀️ رجوع", callback_data="dev:panel")],
            ])
        )
        return
    display = f"@{user.username}" if user.username else user.first_name
    await state.update_data(transfer_target_id=user_id, transfer_target_name=display)
    await state.set_state(DevStates.waiting_transfer_amount)
    await message.answer(
        f"» <b>المستخدم المستقبل:</b> {display}\n"
        f"» أرسل المبلغ المراد تحويله الآن (مثال: <code>15</code>):",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="◀️ رجوع", callback_data="dev:panel")],
        ])
    )


@dev_router.message(DevStates.waiting_transfer_amount)
async def process_transfer_amount(message: Message, state: FSMContext, bot: Bot):
    if message.text and message.text.startswith("/"):
        await state.clear()
        return
    try:
        amount = float(message.text.strip().replace("$", ""))
        cents  = int(round(amount * 100))
        if cents <= 0:
            raise ValueError
    except Exception:
        await message.answer("⚠️ أرسل مبلغاً صحيحاً (مثال: <code>15</code>).", parse_mode="HTML", disable_web_page_preview=True)
        return
    data        = await state.get_data()
    target_id   = data.get("transfer_target_id")
    target_name = data.get("transfer_target_name")
    await state.clear()
    await add_user_balance(target_id, cents)
    balance = await get_user_balance(target_id)
    await message.answer(
        f"✅ تم تحويل <b>{_fmt_usd(cents)}</b> إلى {target_name}.\n"
        f"رصيده الحالي: <b>{_fmt_usd(balance)}</b>",
        parse_mode="HTML",
        reply_markup=InlineKeyboardMarkup(inline_keyboard=[
            [InlineKeyboardButton(text="◀️ رجوع", callback_data="dev:panel")],
        ])
    )
    try:
        await bot.send_message(
            target_id,
            f"💰 تم إضافة <b>{_fmt_usd(cents)}</b> إلى رصيدك من قِبل الإدارة.\n"
            f"رصيدك الحالي: <b>{_fmt_usd(balance)}</b>",
            parse_mode="HTML",
        )
    except Exception:
        pass
