import logging
import re
import random
import asyncio
import json
import os
import sys
import aiohttp
from datetime import datetime, timedelta
from typing import Optional, Dict, List, Tuple, Any

from telegram import Update, ChatPermissions, ChatMember, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.constants import ParseMode
from telegram.ext import (
    Application, CommandHandler, MessageHandler, filters, CallbackContext,
    CallbackQueryHandler
)

# ===================== تنظیمات =====================
TOKEN = "7166830380:AAFClf7igInU02QNj1u6Z02iz8m4sevGcs8"
ADMIN_IDS = [6280011762]  # فوق‌ادمین‌ها

DEFAULT_FLOOD_LIMIT = 5
DEFAULT_FLOOD_WINDOW = 8
DEFAULT_FLOOD_MUTE_MIN = 2

logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)
logger = logging.getLogger(__name__)

# ===================== ذخیره‌سازی با JSON =====================
DATA_FILE = "bot_data.json"


class JSONStorage:
    def __init__(self, file_path: str):
        self.file_path = file_path
        self.data = self._load()
        self._save()

    def _load(self) -> dict:
        if os.path.exists(self.file_path):
            try:
                with open(self.file_path, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except:
                pass
        return self._default_data()

    def _default_data(self) -> dict:
        return {
            'settings': {},
            'locks': {},
            'warns': {},
            'word_filters': {},
            'user_status': {},
            'antiflood': {},
            'captcha': {},
            'reports': [],
            'user_data': {},
            'auto_reply': {},
            'reminders': [],
            'giveaways': [],
            'giveaway_participants': {},
            'tickets': [],
            'ticket_messages': [],
            'polls': [],
            'poll_votes': {},
            'daily_stats': {},
            'blacklist': {},
            'admin_roles': {},
            'night_mode': {},
            'dynamic_stickers': {},
            'api_commands': {},
            'pinned_messages': {},
            'auto_delete': {}
        }

    def _save(self):
        with open(self.file_path, 'w', encoding='utf-8') as f:
            json.dump(self.data, f, ensure_ascii=False, indent=2)

    # ---------- متدهای عمومی ----------
    def _get_dict(self, key: str) -> dict:
        if key not in self.data:
            self.data[key] = {}
        return self.data[key]

    def _get_list(self, key: str) -> list:
        if key not in self.data:
            self.data[key] = []
        return self.data[key]

    # ---------- تنظیمات ----------
    def get_setting(self, chat_id: int, key: str, default=None):
        settings = self._get_dict('settings')
        chat_settings = settings.get(str(chat_id), {})
        return chat_settings.get(key, default)

    def set_setting(self, chat_id: int, key: str, value):
        settings = self._get_dict('settings')
        chat_id_str = str(chat_id)
        if chat_id_str not in settings:
            settings[chat_id_str] = {}
        settings[chat_id_str][key] = str(value)
        self._save()

    # ---------- قفل‌ها ----------
    def get_lock(self, chat_id: int, lock_type: str) -> bool:
        locks = self._get_dict('locks')
        chat_locks = locks.get(str(chat_id), {})
        return chat_locks.get(lock_type, False)

    def set_lock(self, chat_id: int, lock_type: str, enabled: bool):
        locks = self._get_dict('locks')
        chat_id_str = str(chat_id)
        if chat_id_str not in locks:
            locks[chat_id_str] = {}
        locks[chat_id_str][lock_type] = enabled
        self._save()

    def get_all_locks(self, chat_id: int) -> Dict[str, bool]:
        locks = self._get_dict('locks')
        return locks.get(str(chat_id), {})

    # ---------- اخطارها ----------
    def get_warns(self, user_id: int, chat_id: int) -> int:
        warns = self._get_dict('warns')
        return warns.get(f"{user_id}_{chat_id}", 0)

    def add_warn(self, user_id: int, chat_id: int) -> int:
        warns = self._get_dict('warns')
        key = f"{user_id}_{chat_id}"
        new_count = warns.get(key, 0) + 1
        warns[key] = new_count
        self._save()
        return new_count

    def reset_warns(self, user_id: int, chat_id: int):
        warns = self._get_dict('warns')
        key = f"{user_id}_{chat_id}"
        if key in warns:
            del warns[key]
            self._save()

    # ---------- فیلتر کلمات ----------
    def get_word_filters(self, chat_id: int) -> set:
        word_filters = self._get_dict('word_filters')
        return set(word_filters.get(str(chat_id), []))

    def add_word_filter(self, chat_id: int, word: str):
        word_filters = self._get_dict('word_filters')
        chat_id_str = str(chat_id)
        if chat_id_str not in word_filters:
            word_filters[chat_id_str] = []
        if word not in word_filters[chat_id_str]:
            word_filters[chat_id_str].append(word)
            self._save()

    def remove_word_filter(self, chat_id: int, word: str):
        word_filters = self._get_dict('word_filters')
        chat_id_str = str(chat_id)
        if chat_id_str in word_filters and word in word_filters[chat_id_str]:
            word_filters[chat_id_str].remove(word)
            self._save()

    # ---------- وضعیت کاربر ----------
    def get_user_status(self, user_id: int, chat_id: int) -> Optional[datetime]:
        status = self._get_dict('user_status')
        val = status.get(f"{user_id}_{chat_id}")
        if val:
            return datetime.fromisoformat(val)
        return None

    def set_user_status(self, user_id: int, chat_id: int, dt: datetime):
        status = self._get_dict('user_status')
        status[f"{user_id}_{chat_id}"] = dt.isoformat()
        self._save()

    # ---------- ضد اسپم ----------
    def add_antiflood(self, user_id: int, time: datetime):
        antiflood = self._get_dict('antiflood')
        key = str(user_id)
        if key not in antiflood:
            antiflood[key] = []
        antiflood[key].append(time.isoformat())
        self._save()

    def get_antiflood(self, user_id: int, since: datetime) -> List[datetime]:
        antiflood = self._get_dict('antiflood')
        key = str(user_id)
        items = antiflood.get(key, [])
        result = []
        for t_str in items:
            t = datetime.fromisoformat(t_str)
            if t >= since:
                result.append(t)
        return result

    def clean_antiflood(self, user_id: int, before: datetime):
        antiflood = self._get_dict('antiflood')
        key = str(user_id)
        if key in antiflood:
            new_list = [t for t in antiflood[key] if datetime.fromisoformat(t) >= before]
            antiflood[key] = new_list
            self._save()

    # ---------- کپچا ----------
    def get_captcha(self, user_id: int, chat_id: int) -> Optional[dict]:
        captcha = self._get_dict('captcha')
        val = captcha.get(f"{user_id}_{chat_id}")
        if val:
            return {'code': val['code'], 'expire_at': datetime.fromisoformat(val['expire_at'])}
        return None

    def set_captcha(self, user_id: int, chat_id: int, code: str, expire_at: datetime):
        captcha = self._get_dict('captcha')
        captcha[f"{user_id}_{chat_id}"] = {'code': code, 'expire_at': expire_at.isoformat()}
        self._save()

    def delete_captcha(self, user_id: int, chat_id: int):
        captcha = self._get_dict('captcha')
        key = f"{user_id}_{chat_id}"
        if key in captcha:
            del captcha[key]
            self._save()

    # ---------- گزارش‌ها ----------
    def add_report(self, chat_id: int, reporter_id: int, reporter_name: str,
                   target_id: int, target_name: str, message_id: int, reason: str):
        reports = self._get_list('reports')
        reports.append({
            'chat_id': chat_id,
            'reporter_id': reporter_id,
            'reporter_name': reporter_name,
            'target_id': target_id,
            'target_name': target_name,
            'message_id': message_id,
            'reason': reason,
            'time': datetime.now().isoformat()
        })
        self._save()

    # ---------- داده‌های کاربر ----------
    def set_user_data(self, user_id: int, key: str, value):
        user_data = self._get_dict('user_data')
        uid = str(user_id)
        if uid not in user_data:
            user_data[uid] = {}
        user_data[uid][key] = str(value)
        self._save()

    def get_user_data(self, user_id: int, key: str, default=None):
        user_data = self._get_dict('user_data')
        uid = str(user_id)
        if uid in user_data:
            return user_data[uid].get(key, default)
        return default

    # ---------- پاسخگوی خودکار ----------
    def get_auto_reply(self, chat_id: int, keyword: str) -> Optional[str]:
        auto_reply = self._get_dict('auto_reply')
        chat_replies = auto_reply.get(str(chat_id), {})
        return chat_replies.get(keyword)

    def set_auto_reply(self, chat_id: int, keyword: str, reply: str):
        auto_reply = self._get_dict('auto_reply')
        chat_id_str = str(chat_id)
        if chat_id_str not in auto_reply:
            auto_reply[chat_id_str] = {}
        auto_reply[chat_id_str][keyword] = reply
        self._save()

    def delete_auto_reply(self, chat_id: int, keyword: str):
        auto_reply = self._get_dict('auto_reply')
        chat_id_str = str(chat_id)
        if chat_id_str in auto_reply and keyword in auto_reply[chat_id_str]:
            del auto_reply[chat_id_str][keyword]
            self._save()

    def get_all_auto_replies(self, chat_id: int) -> List[tuple]:
        auto_reply = self._get_dict('auto_reply')
        chat_replies = auto_reply.get(str(chat_id), {})
        return list(chat_replies.items())

    # ---------- یادآوری ----------
    def add_reminder(self, user_id: int, chat_id: int, message: str, remind_at: datetime):
        reminders = self._get_list('reminders')
        reminders.append({
            'user_id': user_id,
            'chat_id': chat_id,
            'message': message,
            'remind_at': remind_at.isoformat(),
            'done': False
        })
        self._save()

    def get_due_reminders(self) -> List[tuple]:
        reminders = self._get_list('reminders')
        now = datetime.now().isoformat()
        due = []
        for idx, r in enumerate(reminders):
            if not r['done'] and r['remind_at'] <= now:
                due.append((idx, r['user_id'], r['chat_id'], r['message']))
        return due

    def mark_reminder_done(self, reminder_id: int):
        reminders = self._get_list('reminders')
        if 0 <= reminder_id < len(reminders):
            reminders[reminder_id]['done'] = True
            self._save()

    # ---------- قرعه‌کشی ----------
    def add_giveaway(self, chat_id: int, prize: str, end_at: datetime, winner_count: int) -> int:
        giveaways = self._get_list('giveaways')
        gid = len(giveaways)
        giveaways.append({
            'id': gid,
            'chat_id': chat_id,
            'prize': prize,
            'end_at': end_at.isoformat(),
            'winner_count': winner_count,
            'done': False
        })
        self._save()
        return gid

    def get_active_giveaways(self, chat_id: int) -> List[tuple]:
        giveaways = self._get_list('giveaways')
        now = datetime.now().isoformat()
        return [(g['id'], g['prize'], g['end_at'], g['winner_count'])
                for g in giveaways if g['chat_id'] == chat_id and g['end_at'] > now and not g['done']]

    def get_giveaway_by_id(self, giveaway_id: int):
        giveaways = self._get_list('giveaways')
        for g in giveaways:
            if g['id'] == giveaway_id:
                return (g['chat_id'], g['prize'], g['end_at'], g['winner_count'])
        return None

    def add_giveaway_participant(self, giveaway_id: int, user_id: int):
        participants = self._get_dict('giveaway_participants')
        key = str(giveaway_id)
        if key not in participants:
            participants[key] = []
        if user_id not in participants[key]:
            participants[key].append(user_id)
            self._save()

    def get_giveaway_participants(self, giveaway_id: int) -> List[int]:
        participants = self._get_dict('giveaway_participants')
        return participants.get(str(giveaway_id), [])

    def finish_giveaway(self, giveaway_id: int):
        giveaways = self._get_list('giveaways')
        for g in giveaways:
            if g['id'] == giveaway_id:
                g['done'] = True
                self._save()
                break

    # ---------- تیکت‌ها ----------
    def create_ticket(self, chat_id: int, user_id: int, subject: str, description: str) -> int:
        tickets = self._get_list('tickets')
        tid = len(tickets)
        tickets.append({
            'id': tid,
            'chat_id': chat_id,
            'user_id': user_id,
            'subject': subject,
            'description': description,
            'status': 'open',
            'created_at': datetime.now().isoformat(),
            'closed_at': None
        })
        self._save()
        return tid

    def get_open_tickets(self, chat_id: int) -> List[tuple]:
        tickets = self._get_list('tickets')
        return [(t['id'], t['user_id'], t['subject'], t['created_at'])
                for t in tickets if t['chat_id'] == chat_id and t['status'] == 'open']

    def get_ticket(self, ticket_id: int):
        tickets = self._get_list('tickets')
        for t in tickets:
            if t['id'] == ticket_id:
                return (t['id'], t['user_id'], t['subject'], t['description'], t['status'], t['created_at'])
        return None

    def close_ticket(self, ticket_id: int):
        tickets = self._get_list('tickets')
        for t in tickets:
            if t['id'] == ticket_id:
                t['status'] = 'closed'
                t['closed_at'] = datetime.now().isoformat()
                self._save()
                break

    def add_ticket_message(self, ticket_id: int, user_id: int, message: str, is_admin: bool):
        msgs = self._get_list('ticket_messages')
        msgs.append({
            'ticket_id': ticket_id,
            'user_id': user_id,
            'message': message,
            'time': datetime.now().isoformat(),
            'is_admin': is_admin
        })
        self._save()

    def get_ticket_messages(self, ticket_id: int) -> List[tuple]:
        msgs = self._get_list('ticket_messages')
        return [(m['user_id'], m['message'], m['time'], m['is_admin'])
                for m in msgs if m['ticket_id'] == ticket_id]

    # ---------- نظرسنجی ----------
    def create_poll(self, chat_id: int, question: str, options: List[str], created_by: int) -> int:
        polls = self._get_list('polls')
        pid = len(polls)
        polls.append({
            'id': pid,
            'chat_id': chat_id,
            'question': question,
            'options': options,
            'created_by': created_by,
            'created_at': datetime.now().isoformat(),
            'is_active': True
        })
        self._save()
        return pid

    def get_active_polls(self, chat_id: int) -> List[tuple]:
        polls = self._get_list('polls')
        return [(p['id'], p['question'], p['options'], p['created_by'], p['created_at'])
                for p in polls if p['chat_id'] == chat_id and p['is_active']]

    def get_poll(self, poll_id: int):
        polls = self._get_list('polls')
        for p in polls:
            if p['id'] == poll_id:
                return (p['chat_id'], p['question'], p['options'], p['created_by'], p['created_at'], p['is_active'])
        return None

    def vote_poll(self, poll_id: int, user_id: int, option_index: int):
        votes = self._get_dict('poll_votes')
        key = str(poll_id)
        if key not in votes:
            votes[key] = {}
        votes[key][str(user_id)] = option_index
        self._save()

    def get_poll_results(self, poll_id: int) -> Dict[int, int]:
        votes = self._get_dict('poll_votes')
        key = str(poll_id)
        if key not in votes:
            return {}
        result = {}
        for uid, opt in votes[key].items():
            result[opt] = result.get(opt, 0) + 1
        return result

    def close_poll(self, poll_id: int):
        polls = self._get_list('polls')
        for p in polls:
            if p['id'] == poll_id:
                p['is_active'] = False
                self._save()
                break

    # ---------- متدهای جدید ----------
    def increment_daily_stats(self, chat_id: int, field: str):
        daily = self._get_dict('daily_stats')
        chat_id_str = str(chat_id)
        today = datetime.now().date().isoformat()
        if chat_id_str not in daily:
            daily[chat_id_str] = {}
        if today not in daily[chat_id_str]:
            daily[chat_id_str][today] = {'messages': 0, 'joins': 0, 'leaves': 0}
        daily[chat_id_str][today][field] += 1
        self._save()

    def get_daily_stats(self, chat_id: int, days: int = 7) -> List[tuple]:
        daily = self._get_dict('daily_stats')
        chat_id_str = str(chat_id)
        if chat_id_str not in daily:
            return []
        start = (datetime.now() - timedelta(days=days)).date().isoformat()
        result = []
        for date_str, stats in sorted(daily[chat_id_str].items()):
            if date_str >= start:
                result.append((date_str, stats['messages'], stats['joins'], stats['leaves']))
        return result

    # Blacklist
    def add_blacklist(self, user_id: int, reason: str, added_by: int):
        blacklist = self._get_dict('blacklist')
        blacklist[str(user_id)] = {
            'reason': reason,
            'added_by': added_by,
            'added_at': datetime.now().isoformat()
        }
        self._save()

    def remove_blacklist(self, user_id: int):
        blacklist = self._get_dict('blacklist')
        if str(user_id) in blacklist:
            del blacklist[str(user_id)]
            self._save()

    def is_blacklisted(self, user_id: int) -> bool:
        blacklist = self._get_dict('blacklist')
        return str(user_id) in blacklist

    def get_blacklist(self) -> List[tuple]:
        blacklist = self._get_dict('blacklist')
        return [(int(uid), info['reason'], info['added_by'], info['added_at'])
                for uid, info in blacklist.items()]

    # Admin roles
    def set_temp_admin(self, chat_id: int, user_id: int, until: datetime):
        admin_roles = self._get_dict('admin_roles')
        chat_id_str = str(chat_id)
        if chat_id_str not in admin_roles:
            admin_roles[chat_id_str] = {}
        admin_roles[chat_id_str][str(user_id)] = until.isoformat()
        self._save()

    def remove_temp_admin(self, chat_id: int, user_id: int):
        admin_roles = self._get_dict('admin_roles')
        chat_id_str = str(chat_id)
        if chat_id_str in admin_roles and str(user_id) in admin_roles[chat_id_str]:
            del admin_roles[chat_id_str][str(user_id)]
            self._save()

    def get_temp_admins(self, chat_id: int) -> List[tuple]:
        admin_roles = self._get_dict('admin_roles')
        chat_id_str = str(chat_id)
        if chat_id_str not in admin_roles:
            return []
        now = datetime.now().isoformat()
        result = []
        for uid, until in admin_roles[chat_id_str].items():
            if until > now:
                result.append((int(uid), until))
        return result

    def is_temp_admin(self, chat_id: int, user_id: int) -> bool:
        admin_roles = self._get_dict('admin_roles')
        chat_id_str = str(chat_id)
        if chat_id_str not in admin_roles:
            return False
        if str(user_id) not in admin_roles[chat_id_str]:
            return False
        return admin_roles[chat_id_str][str(user_id)] > datetime.now().isoformat()

    # Night mode
    def set_night_mode(self, chat_id: int, start: str, end: str, enabled: bool):
        night_mode = self._get_dict('night_mode')
        night_mode[str(chat_id)] = {
            'start_time': start,
            'end_time': end,
            'enabled': enabled
        }
        self._save()

    def get_night_mode(self, chat_id: int) -> Optional[tuple]:
        night_mode = self._get_dict('night_mode')
        data = night_mode.get(str(chat_id))
        if data:
            return (data['start_time'], data['end_time'], data['enabled'])
        return None

    # Dynamic stickers
    def set_sticker(self, event: str, file_id: str):
        stickers = self._get_dict('dynamic_stickers')
        stickers[event] = file_id
        self._save()

    def get_sticker(self, event: str) -> Optional[str]:
        stickers = self._get_dict('dynamic_stickers')
        return stickers.get(event)

    # API commands
    def set_api_command(self, chat_id: int, command: str, url: str, method: str = 'GET'):
        api = self._get_dict('api_commands')
        chat_id_str = str(chat_id)
        if chat_id_str not in api:
            api[chat_id_str] = {}
        api[chat_id_str][command] = {'url': url, 'method': method}
        self._save()

    def get_api_command(self, chat_id: int, command: str) -> Optional[tuple]:
        api = self._get_dict('api_commands')
        chat_id_str = str(chat_id)
        if chat_id_str in api and command in api[chat_id_str]:
            cmd = api[chat_id_str][command]
            return (cmd['url'], cmd['method'])
        return None

    def delete_api_command(self, chat_id: int, command: str):
        api = self._get_dict('api_commands')
        chat_id_str = str(chat_id)
        if chat_id_str in api and command in api[chat_id_str]:
            del api[chat_id_str][command]
            self._save()

    # Pinned messages
    def add_pinned(self, chat_id: int, message_id: int):
        pinned = self._get_dict('pinned_messages')
        chat_id_str = str(chat_id)
        if chat_id_str not in pinned:
            pinned[chat_id_str] = []
        if message_id not in pinned[chat_id_str]:
            pinned[chat_id_str].append(message_id)
            self._save()

    def get_pinned(self, chat_id: int) -> List[int]:
        pinned = self._get_dict('pinned_messages')
        return pinned.get(str(chat_id), [])

    def remove_pinned(self, chat_id: int, message_id: int):
        pinned = self._get_dict('pinned_messages')
        chat_id_str = str(chat_id)
        if chat_id_str in pinned and message_id in pinned[chat_id_str]:
            pinned[chat_id_str].remove(message_id)
            self._save()

    # Auto-delete
    def set_auto_delete(self, chat_id: int, user_id: int, delay: int):
        auto = self._get_dict('auto_delete')
        chat_id_str = str(chat_id)
        if chat_id_str not in auto:
            auto[chat_id_str] = {}
        auto[chat_id_str][str(user_id)] = delay
        self._save()

    def get_auto_delete(self, chat_id: int, user_id: int) -> Optional[int]:
        auto = self._get_dict('auto_delete')
        chat_id_str = str(chat_id)
        if chat_id_str in auto:
            return auto[chat_id_str].get(str(user_id))
        return None


# نمونه ذخیره‌سازی
db = JSONStorage(DATA_FILE)

# ===================== دیکشنری جامع دستورات فارسی =====================
PERSIAN_COMMANDS = {
    # عمومی
    "راهنما": "help", "کمک": "help", "help": "help",
    "پنل": "menu", "تنظیمات": "menu", "مدیریت": "menu", "menu": "menu",
    "قوانین": "rules", "قانون": "rules", "rules": "rules",
    "خوش آمدگویی": "welcome", "خوش آمد": "welcome", "خوشآمد": "welcome", "welcome": "welcome",
    "اطلاعات": "info", "مشخصات گروه": "info", "وضعیت": "info", "info": "info",
    "آمار": "stats", "گزارش": "stats", "stats": "stats",
    "برترین": "top", "رتبه": "top", "رتبه‌بندی": "top", "top": "top",
    "پین": "pin", "سنجاق": "pin", "سنجاق کن": "pin", "پین کن": "pin", "پین بزن": "pin",
    "سنجاق بزن": "pin", "سنجاق کن": "pin", "pin": "pin",
    "سنجاق‌شده": "pinned", "پین شده": "pinned", "pinned": "pinned","مشخصات": "userinfo",
"اطلاعات کاربر": "userinfo",
"کاربر": "userinfo",

    # مدیریتی
    "اخطار": "warn", "اخطار بده": "warn", "اخطار بزن": "warn", "warn": "warn",
    "حذف اخطار": "unwarn", "پاک کردن اخطار": "unwarn", "unwarn": "unwarn",
    "اخراج": "kick", "بیرون کن": "kick", "اخراج کن": "kick", "kick": "kick",
    "بن": "ban", "مسدود": "ban", "مسدود کن": "ban", "بلاک": "ban", "ban": "ban",
    "آنبن": "unban", "لغو بن": "unban", "رفع مسدودیت": "unban", "unban": "unban",
    "میت": "mute", "سکوت": "mute", "خاموش": "mute", "mute": "mute",
    "آنمیت": "unmute", "لغو سکوت": "unmute", "صدا": "unmute", "unmute": "unmute",
    "پاکسازی": "purge", "پاک کن": "purge", "حذف پیام‌ها": "purge", "purge": "purge",
    "برداشتن پین": "unpin", "لغو سنجاق": "unpin", "unpin": "unpin",
    "پاک کن": "clean", "حذف": "clean", "clean": "clean",
    "ارسال انبوه": "broadcast", "ارسال به همه": "broadcast", "broadcast": "broadcast",
    "افزودن ادمین": "addadmin", "ادمین موقت": "addadmin", "addadmin": "addadmin",
    "لیست سیاه": "blacklist", "سیاه‌لیست": "blacklist", "blacklist": "blacklist",
    "حالت شب": "nightmode", "شب": "nightmode", "nightmode": "nightmode",

    # تنظیمات
    "تنظیم قوانین": "setrules", "قوانین جدید": "setrules", "setrules": "setrules",
    "تنظیم خوش‌آمدگویی": "setwelcome", "setwelcome": "setwelcome",
    "اسلومود": "slowmode", "کند کردن": "slowmode", "slowmode": "slowmode",
    "زمان کپچا": "captchatime", "captchatime": "captchatime",
    "افزودن کلمه": "addword", "کلمه ممنوع": "addword", "addword": "addword",
    "حذف کلمه": "delword", "لغو کلمه ممنوع": "delword", "delword": "delword",
    "پاسخ خودکار": "addreply", "افزودن پاسخ": "addreply", "addreply": "addreply",
    "حذف پاسخ خودکار": "delreply", "delreply": "delreply",
    "یادآوری": "remind", "یادآور": "remind", "remind": "remind",
    "عضویت اجباری": "setforce", "کانال اجباری": "setforce", "setforce": "setforce",

    # قرعه‌کشی
    "قرعه‌کشی": "giveaway", "قرعه": "giveaway", "giveaway": "giveaway",
    "شرکت": "join", "ثبت نام": "join", "join": "join",

    # تیکت
    "تیکت": "ticket", "پشتیبانی": "ticket", "ticket": "ticket",
    "تیکت‌ها": "tickets", "لیست تیکت": "tickets", "tickets": "tickets",
    "پاسخ تیکت": "replyticket", "replyticket": "replyticket",
    "بستن تیکت": "closeticket", "closeticket": "closeticket",

    # نظرسنجی
    "نظرسنجی": "poll", "نظرخواهی": "poll", "poll": "poll",
    "رای": "vote", "رای دادن": "vote", "vote": "vote",

    # API و پشتیبان
    "افزودن API": "addapi", "addapi": "addapi",
    "حذف API": "delapi", "delapi": "delapi",
    "پشتیبان": "backup", "بکاپ": "backup", "backup": "backup",
    "ری‌استارت": "restart", "راه‌اندازی مجدد": "restart", "restart": "restart",
}


# ===================== توابع کمکی =====================
async def is_admin(chat, user_id: int) -> bool:
    if user_id in ADMIN_IDS:
        return True
    if db.is_temp_admin(chat.id, user_id):
        return True
    try:
        member = await chat.get_member(user_id)
        return member.status in [ChatMember.ADMINISTRATOR, ChatMember.OWNER]
    except Exception:
        return False


async def log_action(chat_id: int, text: str):
    log_chat_id = db.get_setting(chat_id, 'log_chat', None)
    if log_chat_id:
        try:
            app = Application.builder().token(TOKEN).build()
            await app.bot.send_message(int(log_chat_id), text, parse_mode=ParseMode.HTML)
        except Exception as e:
            logger.error(f"Log error: {e}")


def get_warn_action_text(action: str) -> str:
    mapping = {'mute': 'سکوت', 'kick': 'اخراج', 'ban': 'مسدودیت'}
    return mapping.get(action, 'مسدودیت')


# ===================== دکوراتور مدیریت خطا =====================
def safe_command(func):
    async def wrapper(update: Update, context: CallbackContext):
        try:
            await func(update, context)
        except Exception as e:
            logger.error(f"Error in {func.__name__}: {e}", exc_info=True)
            try:
                await update.message.reply_text(f"❌ خطا: {str(e)[:200]}")
            except:
                pass

    return wrapper


# ===================== منوهای بهبودیافته =====================
async def main_menu(chat_id: int):
    keyboard = [
        [InlineKeyboardButton("🔒 قفل‌های مدیا و متن", callback_data="menu_locks")],
        [InlineKeyboardButton("⚙️ تنظیمات اصلی", callback_data="menu_settings")],
        [InlineKeyboardButton("🚫 فیلتر کلمات", callback_data="menu_wordfilter")],
        [InlineKeyboardButton("📊 آمار و اطلاعات", callback_data="menu_stats")],
        [InlineKeyboardButton("⚡ تنظیمات پیشرفته", callback_data="menu_advanced")],
        [InlineKeyboardButton("🎁 قرعه‌کشی", callback_data="menu_giveaway"),
         InlineKeyboardButton("🎫 تیکت", callback_data="menu_ticket")],
        [InlineKeyboardButton("🗳 نظرسنجی", callback_data="menu_poll"),
         InlineKeyboardButton("👥 ادمین‌ها", callback_data="menu_admins")],
        [InlineKeyboardButton("🚫 لیست سیاه", callback_data="menu_blacklist"),
         InlineKeyboardButton("🌙 حالت شب", callback_data="menu_night")],
        [InlineKeyboardButton("❌ بستن پنل", callback_data="close_menu")]
    ]
    return InlineKeyboardMarkup(keyboard)


async def locks_menu(chat_id: int):
    lock_groups = {
        "🔗 لینک": "link", "🖼 عکس": "photo", "🎬 ویدیو": "video",
        "😜 استیکر": "sticker", "🎙 ویس": "voice", "@ آی‌دی": "mention",
        "↪️ فوروارد": "forward", "🤖 ربات": "bot", "# هشتگ": "hashtag",
        "📄 سند": "document", "🎵 صدا": "audio", "📍 مکان": "location",
        "📇 مخاطب": "contact", "📊 نظرسنجی": "poll", "🎲 تاس": "dice"
    }
    keyboard = []
    row = []
    for name, lock_type in lock_groups.items():
        status = "🟢" if db.get_lock(chat_id, lock_type) else "🔴"
        row.append(InlineKeyboardButton(f"{status} {name}", callback_data=f"lock_{lock_type}"))
        if len(row) == 3:
            keyboard.append(row)
            row = []
    if row:
        keyboard.append(row)
    keyboard.append([
        InlineKeyboardButton("🔓 همه باز", callback_data="all_off"),
        InlineKeyboardButton("🔒 همه قفل", callback_data="all_on")
    ])
    keyboard.append([InlineKeyboardButton("🔙 بازگشت به منو", callback_data="menu_main")])
    return InlineKeyboardMarkup(keyboard)


async def settings_menu(chat_id: int):
    slow = int(db.get_setting(chat_id, 'slowmode_sec', 0))
    captcha_timeout = int(db.get_setting(chat_id, 'captcha_timeout', 60))
    welcome_enabled = "✅" if int(db.get_setting(chat_id, 'welcome_enabled', 1)) else "❌"
    warn_limit = int(db.get_setting(chat_id, 'warn_limit', 3))
    flood_limit = int(db.get_setting(chat_id, 'flood_limit', DEFAULT_FLOOD_LIMIT))
    flood_window = int(db.get_setting(chat_id, 'flood_window', DEFAULT_FLOOD_WINDOW))
    flood_mute = int(db.get_setting(chat_id, 'flood_mute_min', DEFAULT_FLOOD_MUTE_MIN))
    warn_action = db.get_setting(chat_id, 'warn_action', 'ban')
    captcha_type = db.get_setting(chat_id, 'captcha_type', 'numeric')
    anti_raid = "✅" if int(db.get_setting(chat_id, 'anti_raid', 0)) else "❌"
    auto_clean = int(db.get_setting(chat_id, 'auto_clean_days', 0))

    keyboard = [
        [InlineKeyboardButton(f"⏱ اسلومود: {slow}s", callback_data="step_slowmode"),
         InlineKeyboardButton(f"🛡 کپچا: {captcha_timeout}s", callback_data="step_captcha")],
        [InlineKeyboardButton(f"🎉 خوش‌آمد: {welcome_enabled}", callback_data="toggle_welcome"),
         InlineKeyboardButton(f"⚠️ حد اخطار: {warn_limit}", callback_data="step_warn")],
        [InlineKeyboardButton(f"🌊 ضداسپم: {flood_limit}/{flood_window}s → {flood_mute}m", callback_data="step_flood")],
        [InlineKeyboardButton(f"⚡ عمل اخطار: {get_warn_action_text(warn_action)}", callback_data="step_warn_action"),
         InlineKeyboardButton(f"🧩 نوع کپچا: {captcha_type}", callback_data="step_captcha_type")],
        [InlineKeyboardButton(f"🛡 ضدحمله: {anti_raid}", callback_data="toggle_anti_raid"),
         InlineKeyboardButton(f"🗑 پاکسازی: {auto_clean} روز", callback_data="step_auto_clean")],
        [InlineKeyboardButton("🔙 بازگشت به منو", callback_data="menu_main")]
    ]
    return InlineKeyboardMarkup(keyboard)


async def advanced_menu(chat_id: int):
    log_chat = db.get_setting(chat_id, 'log_chat', None)
    log_text = f"✅ {log_chat}" if log_chat else "❌"
    force_subscribe = db.get_setting(chat_id, 'force_subscribe_channel', None)
    force_text = f"✅ {force_subscribe}" if force_subscribe else "❌"

    keyboard = [
        [InlineKeyboardButton(f"📋 لاگ‌چت: {log_text}", callback_data="set_log_chat"),
         InlineKeyboardButton(f"📢 عضویت اجباری: {force_text}", callback_data="set_force_subscribe")],
        [InlineKeyboardButton("🤖 پاسخگوی خودکار", callback_data="menu_auto_reply")],
        [InlineKeyboardButton("🔙 بازگشت به منو", callback_data="menu_main")]
    ]
    return InlineKeyboardMarkup(keyboard)


async def word_filter_menu(chat_id: int):
    words = db.get_word_filters(chat_id)
    text = "📋 <b>کلمات فیلتر شده</b>\n\n" + ("\n".join(f"• <code>{w}</code>" for w in words) if words else "هیچ")
    text += "\n\n<i>/addword و /delword</i>"
    keyboard = [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_main")]]
    return InlineKeyboardMarkup(keyboard), text


async def auto_reply_menu(chat_id: int):
    replies = db.get_all_auto_replies(chat_id)
    text = "🤖 <b>پاسخ‌های خودکار</b>\n\n"
    if replies:
        for kw, rep in replies:
            text += f"• <code>{kw}</code> -> {rep[:30]}...\n"
    else:
        text += "هیچ"
    text += "\n<i>/addreply و /delreply</i>"
    keyboard = [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_advanced")]]
    return InlineKeyboardMarkup(keyboard), text


# ===================== دستورات =====================
@safe_command
async def start(update: Update, context: CallbackContext):
    await update.message.reply_text(
        "🤖 <b>ربات مدیریت گروه فوق‌پیشرفته</b>\n\n"
        "✅ قفل‌های پیشرفته\n✅ اخطار سطوح مختلف\n✅ کپچا هوشمند\n"
        "✅ ضداسپم و ضدحمله\n✅ فیلتر کلمات\n✅ پاسخگوی خودکار\n"
        "✅ تیکت پشتیبانی\n✅ نظرسنجی\n✅ قرعه‌کشی\n✅ یادآوری\n"
        "✅ عضویت اجباری\n✅ لیست سیاه\n✅ حالت شب\n"
        "✅ استیکر پویا\n✅ ادمین موقت\n✅ آمار پیشرفته\n"
        "✅ ارسال انبوه\n✅ مدیریت API\n\n"
        "📌 /menu برای پنل ادمین\n📌 /help برای راهنما",
        parse_mode=ParseMode.HTML
    )


@safe_command
async def help_command(update: Update, context: CallbackContext):
    text = """
👑 <b>راهنمای ربات</b>

<b>دستورات عمومی:</b>
• /menu - پنل مدیریت
• /rules - قوانین
• /welcome - پیام خوش‌آمدگویی
• /info - اطلاعات گروه
• /userinfo (ریپلای) - اطلاعات کاربر
• /report (ریپلای) [متن] - گزارش
• /stats - آمار پیشرفته
• /top - رتبه‌بندی
• /pinned - پیام‌های سنجاق‌شده

<b>دستورات ادمین:</b>
• /warn (ریپلای) - اخطار
• /unwarn (ریپلای) - حذف اخطار
• /mute (ریپلای) [دقیقه] - سکوت
• /unmute (ریپلای) - لغو سکوت
• /kick (ریپلای) - اخراج
• /ban (ریپلای) [دقیقه] - بن
• /unban (ریپلای) - لغو بن
• /purge (ریپلای) - پاکسازی
• /pin (ریپلای) - سنجاق
• /unpin - برداشتن سنجاق
• /clean (ریپلای) - حذف پیام کاربر
• /broadcast [متن] - ارسال به همه
• /addadmin (ریپلای) [دقیقه] - ادمین موقت
• /blacklist add/remove (ریپلای) - لیست سیاه
• /nightmode start end [off] - حالت شب

<b>تنظیمات:</b>
• /setrules [متن]
• /setwelcome [متن] (متغیرها: {user}, {mention}, {username}, {date}, {chat})
• /slowmode [ثانیه]
• /captchatime [ثانیه]
• /addword [کلمه]
• /delword [کلمه]
• /setwarnaction mute/kick/ban
• /setlogchat (ریپلای)
• /setcaptchatype numeric/math
• /addreply کلمه|پاسخ
• /delreply کلمه
• /setforce @channel
• /remind 10m|متن
• /setsticker event (ریپلای به استیکر)
• /setautodelete (ریپلای) [ثانیه]
• /addapi command|url|method
• /delapi command

<b>قرعه‌کشی:</b>
• /giveaway جایزه|مدت(دقیقه)|تعدادبرنده
• /join آیدی

<b>نظرسنجی:</b>
• /poll سوال|گزینه1|گزینه2|...
• /vote آیدی|شماره

<b>تیکت:</b>
• /ticket موضوع
• /tickets - لیست
• /replyticket آیدی|متن
• /closeticket آیدی

<b>دستورات فارسی (بدون اسلش):</b>
راهنما, پنل, قوانین, خوش‌آمدگویی, اطلاعات, آمار, لیست سیاه, حالت شب
و نیز: پین, پین کن, پین بزن, سنجاق, سنجاق کن, سنجاق بزن
"""
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


@safe_command
async def menu_command(update: Update, context: CallbackContext):
    if update.effective_chat.type == "private":
        await update.message.reply_text("⚠️ فقط در گروه.")
        return
    if not await is_admin(update.effective_chat, update.effective_user.id):
        await update.message.reply_text("⛔ ادمین نیستید.")
        return
    await update.message.reply_text(
        "⚙️ <b>پنل مدیریت</b>",
        reply_markup=await main_menu(update.effective_chat.id),
        parse_mode=ParseMode.HTML
    )


@safe_command
async def rules_command(update: Update, context: CallbackContext):
    chat_id = update.effective_chat.id
    rules = db.get_setting(chat_id, 'rules', 'ثبت نشده.')
    await update.message.reply_text(f"📜 <b>قوانین</b>\n\n{rules}", parse_mode=ParseMode.HTML)


@safe_command
async def welcome_command(update: Update, context: CallbackContext):
    chat_id = update.effective_chat.id
    msg = db.get_setting(chat_id, 'welcome_msg', 'تنظیم نشده.')
    await update.message.reply_text(f"🎉 <b>پیام خوش‌آمدگویی</b>\n\n{msg}", parse_mode=ParseMode.HTML)


@safe_command
async def info_command(update: Update, context: CallbackContext):
    chat = update.effective_chat
    count = await chat.get_member_count()
    locks = db.get_all_locks(chat.id)
    active = [k for k, v in locks.items() if v]
    text = (f"📊 <b>وضعیت گروه</b>\n\n👥 تعداد اعضا: {count}\n"
            f"⏱ اسلومود: {db.get_setting(chat.id, 'slowmode_sec', 0)} ثانیه\n"
            f"🛡 زمان کپچا: {db.get_setting(chat.id, 'captcha_timeout', 60)} ثانیه\n"
            f"⚠️ حد اخطار: {db.get_setting(chat.id, 'warn_limit', 3)}\n"
            f"⚡ عمل اخطار: {get_warn_action_text(db.get_setting(chat.id, 'warn_action', 'ban'))}\n"
            f"🔒 قفل‌ها: {', '.join(active) if active else 'هیچ'}")
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


@safe_command
async def userinfo_command(update: Update, context: CallbackContext):
    user = None
    if update.message.reply_to_message:
        user = update.message.reply_to_message.from_user
    elif context.args:
        try:
            user_id = int(context.args[0])
            user = await context.bot.get_chat(user_id)
        except:
            pass
    if not user:
        user = update.effective_user
    chat_id = update.effective_chat.id
    warns = db.get_warns(user.id, chat_id)
    msg_count = db.get_user_data(user.id, 'message_count') or 0
    join_date = db.get_user_data(user.id, 'join_date')
    text = f"👤 <b>اطلاعات کاربر</b>\n\nنام: {user.full_name}\nآیدی: <code>{user.id}</code>\nپیام‌ها: {msg_count}\nاخطارها: {warns}"
    if join_date:
        text += f"\nتاریخ پیوستن: {join_date}"
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


@safe_command
async def report_command(update: Update, context: CallbackContext):
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام ریپلای کنید.")
        return
    target_msg = update.message.reply_to_message
    reason = ' '.join(context.args) or 'بدون توضیح'
    db.add_report(update.effective_chat.id, update.effective_user.id, update.effective_user.full_name,
                  target_msg.from_user.id, target_msg.from_user.full_name, target_msg.message_id, reason)
    await update.message.reply_text("✅ گزارش به ادمین‌ها ارسال شد.")
    admins = await update.effective_chat.get_administrators()
    for admin in admins:
        if admin.user.is_bot:
            continue
        try:
            await context.bot.send_message(admin.user.id,
                                           f"📢 گزارش در {update.effective_chat.title}\nاز: {update.effective_user.full_name}\nکاربر: {target_msg.from_user.full_name}\nدلیل: {reason}")
        except:
            pass


@safe_command
async def stats_advanced(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    chat_id = update.effective_chat.id
    stats = db.get_daily_stats(chat_id, 7)
    if not stats:
        await update.message.reply_text("آماری موجود نیست.")
        return
    max_msgs = max((row[1] for row in stats), default=0)
    text = "📊 <b>آمار گروه (۷ روز اخیر)</b>\n\n"
    for date, msgs, joins, leaves in stats:
        dt = datetime.strptime(date, "%Y-%m-%d").strftime("%d/%m")
        bar = "█" * int(msgs / (max_msgs + 1) * 10) if max_msgs > 0 else ""
        text += f"📅 {dt}: {msgs} پیام {bar}\n"
    text += f"\nکل پیام‌ها: {sum(row[1] for row in stats)}"
    text += f"\nکل ورودها: {sum(row[2] for row in stats)}"
    text += f"\nکل خروج‌ها: {sum(row[3] for row in stats)}"
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


@safe_command
async def top_users(update: Update, context: CallbackContext):
    # دریافت از دیتابیس JSON
    user_data = db._get_dict('user_data')
    users = []
    for uid_str, data in user_data.items():
        if 'message_count' in data:
            users.append((int(uid_str), int(data['message_count'])))
    users.sort(key=lambda x: x[1], reverse=True)
    users = users[:10]
    if not users:
        await update.message.reply_text("هنوز آماری موجود نیست.")
        return
    text = "🏆 <b>برترین کاربران</b>\n\n"
    for idx, (uid, cnt) in enumerate(users, 1):
        try:
            user = await context.bot.get_chat(uid)
            name = user.full_name
        except:
            name = f"کاربر {uid}"
        text += f"{idx}. {name} - {cnt} پیام\n"
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


@safe_command
async def pinned_command(update: Update, context: CallbackContext):
    chat_id = update.effective_chat.id
    pins = db.get_pinned(chat_id)
    if not pins:
        await update.message.reply_text("هیچ پیام سنجاق‌شده‌ای نیست.")
        return
    text = "📌 <b>پیام‌های سنجاق‌شده</b>\n" + "\n".join(f"• پیام {mid}" for mid in pins)
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


# ----- دستورات ادمین (کامل) -----
@safe_command
async def warn_user(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام ریپلای کنید.")
        return
    target = update.message.reply_to_message.from_user
    if target.id in ADMIN_IDS or target.id == context.bot.id:
        await update.message.reply_text("⛔ نمی‌توان ادمین را اخطار داد.")
        return
    chat_id = update.effective_chat.id
    count = db.add_warn(target.id, chat_id)
    limit = int(db.get_setting(chat_id, 'warn_limit', 3))
    reason = ' '.join(context.args) or 'نامشخص'
    await update.message.reply_text(f"⚠️ {target.full_name} اخطار {count}/{limit}\nدلیل: {reason}",
                                    parse_mode=ParseMode.HTML)
    await log_action(chat_id, f"⚠️ اخطار به {target.full_name} - دلیل: {reason}")
    sticker_id = db.get_sticker('warn')
    if sticker_id:
        try:
            await context.bot.send_sticker(chat_id, sticker_id)
        except:
            pass
    if count >= limit:
        action = db.get_setting(chat_id, 'warn_action', 'ban')
        try:
            if action == 'mute':
                await update.effective_chat.restrict_member(target.id,
                                                            permissions=ChatPermissions(can_send_messages=False),
                                                            until_date=datetime.now() + timedelta(minutes=10))
                await update.message.reply_text(f"🔇 {target.full_name} ۱۰ دقیقه ساکت شد.")
            elif action == 'kick':
                await update.effective_chat.ban_member(target.id)
                await update.effective_chat.unban_member(target.id)
                await update.message.reply_text(f"👢 {target.full_name} اخراج شد.")
            else:
                await update.effective_chat.ban_member(target.id)
                await update.message.reply_text(f"🚫 {target.full_name} بن شد.")
            db.reset_warns(target.id, chat_id)
        except Exception as e:
            await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def unwarn_user(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        return
    target = update.message.reply_to_message.from_user
    db.reset_warns(target.id, update.effective_chat.id)
    await update.message.reply_text(f"✅ اخطارهای {target.full_name} پاک شد.")


@safe_command
async def kick_user(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        return
    target = update.message.reply_to_message.from_user
    if target.id in ADMIN_IDS or target.id == context.bot.id:
        return
    try:
        await update.effective_chat.ban_member(target.id)
        await update.effective_chat.unban_member(target.id)
        await update.message.reply_text(f"👢 {target.full_name} اخراج شد.")
        await log_action(update.effective_chat.id, f"👢 اخراج {target.full_name}")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def ban_user(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        return
    target = update.message.reply_to_message.from_user
    if target.id in ADMIN_IDS or target.id == context.bot.id:
        return
    minutes = int(context.args[0]) if context.args and context.args[0].isdigit() else 60
    until = datetime.now() + timedelta(minutes=minutes)
    try:
        await update.effective_chat.ban_member(target.id, until_date=until)
        await update.message.reply_text(f"⛔ {target.full_name} به مدت {minutes} دقیقه بن شد.")
        await log_action(update.effective_chat.id, f"⛔ بن {target.full_name} {minutes} دقیقه")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def unban_user(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        return
    target = update.message.reply_to_message.from_user
    try:
        await update.effective_chat.unban_member(target.id)
        await update.message.reply_text(f"✅ بن {target.full_name} لغو شد.")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def mute_user(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        return
    target = update.message.reply_to_message.from_user
    if target.id in ADMIN_IDS or target.id == context.bot.id:
        return
    minutes = int(context.args[0]) if context.args and context.args[0].isdigit() else 10
    until = datetime.now() + timedelta(minutes=minutes)
    try:
        await update.effective_chat.restrict_member(target.id, permissions=ChatPermissions(can_send_messages=False),
                                                    until_date=until)
        await update.message.reply_text(f"🔇 {target.full_name} {minutes} دقیقه ساکت شد.")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def unmute_user(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        return
    target = update.message.reply_to_message.from_user
    try:
        await update.effective_chat.restrict_member(
            target.id,
            permissions=ChatPermissions(can_send_messages=True, can_send_media_messages=True,
                                        can_send_other_messages=True, can_add_web_page_previews=True)
        )
        await update.message.reply_text(f"🔊 {target.full_name} آنمیت شد.")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def purge_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        return
    start = update.message.reply_to_message.message_id
    end = update.message.message_id
    tasks = [update.effective_chat.delete_message(mid) for mid in range(start, end + 1)]
    await asyncio.gather(*tasks, return_exceptions=True)


@safe_command
async def set_rules(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        return
    rules = ' '.join(context.args)
    db.set_setting(update.effective_chat.id, 'rules', rules)
    await update.message.reply_text("✅ قوانین به‌روز شد.")


@safe_command
async def set_welcome(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        return
    welcome = ' '.join(context.args)
    db.set_setting(update.effective_chat.id, 'welcome_msg', welcome)
    await update.message.reply_text("✅ پیام خوش‌آمدگویی به‌روز شد.")


@safe_command
async def slowmode_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args or not context.args[0].isdigit():
        return
    sec = int(context.args[0])
    db.set_setting(update.effective_chat.id, 'slowmode_sec', sec)
    await update.message.reply_text(f"✅ اسلومود: {sec} ثانیه")


@safe_command
async def captchatime_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args or not context.args[0].isdigit():
        return
    sec = int(context.args[0])
    db.set_setting(update.effective_chat.id, 'captcha_timeout', sec)
    await update.message.reply_text(f"✅ زمان کپچا: {sec} ثانیه")


@safe_command
async def add_word(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        return
    word = context.args[0].lower()
    db.add_word_filter(update.effective_chat.id, word)
    await update.message.reply_text(f"✅ کلمه <code>{word}</code> فیلتر شد.", parse_mode=ParseMode.HTML)


@safe_command
async def del_word(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        return
    word = context.args[0].lower()
    db.remove_word_filter(update.effective_chat.id, word)
    await update.message.reply_text(f"✅ کلمه <code>{word}</code> حذف شد.", parse_mode=ParseMode.HTML)


@safe_command
async def set_warn_action(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args or context.args[0].lower() not in ['mute', 'kick', 'ban']:
        await update.message.reply_text("⚠️ mute/kick/ban را انتخاب کنید.")
        return
    action = context.args[0].lower()
    db.set_setting(update.effective_chat.id, 'warn_action', action)
    await update.message.reply_text(f"✅ عمل اخطار: {get_warn_action_text(action)}")


@safe_command
async def set_log_chat(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام در چت لاگ ریپلای کنید.")
        return
    log_chat_id = update.message.reply_to_message.chat.id
    db.set_setting(update.effective_chat.id, 'log_chat', str(log_chat_id))
    await update.message.reply_text(f"✅ چت لاگ: {log_chat_id}")


@safe_command
async def set_captcha_type(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args or context.args[0].lower() not in ['numeric', 'math']:
        await update.message.reply_text("⚠️ numeric یا math را وارد کنید.")
        return
    t = context.args[0].lower()
    db.set_setting(update.effective_chat.id, 'captcha_type', t)
    await update.message.reply_text(f"✅ نوع کپچا: {t}")


@safe_command
async def backup_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    try:
        with open(DATA_FILE, 'rb') as f:
            await update.message.reply_document(document=f, filename=DATA_FILE)
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


# ----- دستورات جدید -----
@safe_command
async def broadcast(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ متن پیام را وارد کنید.")
        return
    message = ' '.join(context.args)
    chat = update.effective_chat
    members = []
    try:
        async for member in chat.get_members():
            if not member.user.is_bot:
                members.append(member.user.id)
    except Exception as e:
        await update.message.reply_text(f"خطا: {e}")
        return
    if not members:
        await update.message.reply_text("هیچ عضو غیررباتی یافت نشد.")
        return
    await update.message.reply_text(f"در حال ارسال به {len(members)} عضو...")
    sent = 0
    for uid in members:
        try:
            await context.bot.send_message(uid, message)
            sent += 1
            await asyncio.sleep(0.05)
        except:
            pass
    await update.message.reply_text(f"✅ ارسال به {sent} عضو.")


@safe_command
async def add_temp_admin(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام کاربر ریپلای کنید.")
        return
    target = update.message.reply_to_message.from_user
    if target.id in ADMIN_IDS:
        await update.message.reply_text("⛔ نمی‌توان به فوق‌ادمین نقش داد.")
        return
    if not context.args or not context.args[0].isdigit():
        await update.message.reply_text("⚠️ مدت زمان به دقیقه را وارد کنید.")
        return
    minutes = int(context.args[0])
    until = datetime.now() + timedelta(minutes=minutes)
    db.set_temp_admin(update.effective_chat.id, target.id, until)
    try:
        await update.effective_chat.promote_chat_member(
            target.id,
            can_change_info=True,
            can_delete_messages=True,
            can_invite_users=True,
            can_restrict_members=True,
            can_pin_messages=True,
            can_promote_members=False
        )
    except Exception as e:
        await update.message.reply_text(f"❌ خطا در ارتقا: {e}")
        return
    await update.message.reply_text(f"✅ {target.full_name} به مدت {minutes} دقیقه ادمین شد.")
    context.job_queue.run_once(remove_temp_admin_job, seconds=minutes * 60,
                               data={'chat_id': update.effective_chat.id, 'user_id': target.id})


async def remove_temp_admin_job(context: CallbackContext):
    data = context.job.data
    chat_id, user_id = data['chat_id'], data['user_id']
    db.remove_temp_admin(chat_id, user_id)
    try:
        chat = await context.bot.get_chat(chat_id)
        await chat.promote_chat_member(
            user_id,
            can_change_info=False,
            can_delete_messages=False,
            can_invite_users=False,
            can_restrict_members=False,
            can_pin_messages=False,
            can_promote_members=False
        )
    except Exception as e:
        logger.error(f"Demote error: {e}")


@safe_command
async def blacklist_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        bl = db.get_blacklist()
        if not bl:
            await update.message.reply_text("لیست سیاه خالی است.")
            return
        text = "🚫 <b>لیست سیاه</b>\n\n" + "\n".join(f"• {uid} - {reason}" for uid, reason, _, _ in bl)
        await update.message.reply_text(text, parse_mode=ParseMode.HTML)
        return
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام کاربر ریپلای کنید.")
        return
    target = update.message.reply_to_message.from_user
    action = context.args[0].lower()
    if action == 'add':
        reason = ' '.join(context.args[1:]) or 'بدون دلیل'
        db.add_blacklist(target.id, reason, update.effective_user.id)
        await update.message.reply_text(f"✅ {target.full_name} به لیست سیاه اضافه شد.")
    elif action == 'remove':
        db.remove_blacklist(target.id)
        await update.message.reply_text(f"✅ {target.full_name} از لیست سیاه خارج شد.")
    else:
        await update.message.reply_text("⚠️ add یا remove را استفاده کنید.")


@safe_command
async def night_mode_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    args = context.args
    if len(args) >= 2:
        start, end = args[0], args[1]
        try:
            datetime.strptime(start, "%H:%M")
            datetime.strptime(end, "%H:%M")
        except:
            await update.message.reply_text("⚠️ فرمت HH:MM")
            return
        enabled = 1 if len(args) < 3 or args[2].lower() != 'off' else 0
        db.set_night_mode(update.effective_chat.id, start, end, enabled)
        await update.message.reply_text(f"✅ حالت شب {'فعال' if enabled else 'غیرفعال'} شد ({start} تا {end}).")
    else:
        nm = db.get_night_mode(update.effective_chat.id)
        if nm:
            start, end, enabled = nm
            status = "فعال" if enabled else "غیرفعال"
            await update.message.reply_text(f"🌙 حالت شب: {status} - از {start} تا {end}")
        else:
            await update.message.reply_text("حالت شب تنظیم نشده.")


@safe_command
async def set_sticker_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ رویداد را وارد کنید: /setsticker welcome")
        return
    event = context.args[0]
    if not update.message.reply_to_message or not update.message.reply_to_message.sticker:
        await update.message.reply_text("⚠️ روی یک استیکر ریپلای کنید.")
        return
    file_id = update.message.reply_to_message.sticker.file_id
    db.set_sticker(event, file_id)
    await update.message.reply_text(f"✅ استیکر برای رویداد {event} تنظیم شد.")


@safe_command
async def set_auto_delete_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام کاربر ریپلای کنید.")
        return
    target = update.message.reply_to_message.from_user
    if not context.args or not context.args[0].isdigit():
        await update.message.reply_text("⚠️ زمان را به ثانیه وارد کنید.")
        return
    delay = int(context.args[0])
    db.set_auto_delete(update.effective_chat.id, target.id, delay)
    await update.message.reply_text(f"✅ پیام‌های {target.full_name} پس از {delay} ثانیه حذف می‌شوند.")


@safe_command
async def add_reply(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args or '|' not in ' '.join(context.args):
        await update.message.reply_text("⚠️ فرمت: /addreply کلمه|پاسخ")
        return
    parts = ' '.join(context.args).split('|', 1)
    if len(parts) != 2:
        await update.message.reply_text("⚠️ فرمت صحیح نیست.")
        return
    keyword, reply = parts[0].strip().lower(), parts[1].strip()
    db.set_auto_reply(update.effective_chat.id, keyword, reply)
    await update.message.reply_text(f"✅ پاسخ خودکار برای <code>{keyword}</code> تنظیم شد.", parse_mode=ParseMode.HTML)


@safe_command
async def del_reply(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ کلمه را وارد کنید.")
        return
    keyword = context.args[0].lower()
    db.delete_auto_reply(update.effective_chat.id, keyword)
    await update.message.reply_text(f"✅ پاسخ خودکار <code>{keyword}</code> حذف شد.", parse_mode=ParseMode.HTML)


@safe_command
async def remind_command(update: Update, context: CallbackContext):
    if not context.args:
        await update.message.reply_text("⚠️ فرمت: /remind 10m|متن")
        return
    parts = ' '.join(context.args).split('|', 1)
    if len(parts) != 2:
        await update.message.reply_text("⚠️ فرمت صحیح نیست.")
        return
    time_str, message = parts[0].strip(), parts[1].strip()
    units = {'m': 60, 'h': 3600, 'd': 86400}
    unit = time_str[-1]
    if unit not in units:
        await update.message.reply_text("⚠️ واحد m/h/d")
        return
    try:
        value = int(time_str[:-1])
    except:
        await update.message.reply_text("⚠️ مقدار عددی وارد کنید.")
        return
    seconds = value * units[unit]
    remind_at = datetime.now() + timedelta(seconds=seconds)
    db.add_reminder(update.effective_user.id, update.effective_chat.id, message, remind_at)
    await update.message.reply_text(f"✅ یادآوری برای {value}{unit} دیگر تنظیم شد.")


@safe_command
async def giveaway_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args or '|' not in ' '.join(context.args):
        await update.message.reply_text("⚠️ فرمت: /giveaway جایزه|مدت(دقیقه)|تعدادبرنده")
        return
    parts = ' '.join(context.args).split('|')
    if len(parts) != 3:
        await update.message.reply_text("⚠️ فرمت صحیح نیست.")
        return
    prize, duration_str, winners_str = parts[0].strip(), parts[1].strip(), parts[2].strip()
    try:
        duration, winners = int(duration_str), int(winners_str)
    except:
        await update.message.reply_text("⚠️ مدت و تعداد برنده باید عدد باشند.")
        return
    end_at = datetime.now() + timedelta(minutes=duration)
    gid = db.add_giveaway(update.effective_chat.id, prize, end_at, winners)
    await update.message.reply_text(
        f"🎁 <b>قرعه‌کشی</b>\nجایزه: {prize}\nمدت: {duration} دقیقه\nبرندگان: {winners}\nآیدی: <code>{gid}</code>\n/join {gid}",
        parse_mode=ParseMode.HTML
    )


@safe_command
async def join_giveaway(update: Update, context: CallbackContext):
    if not context.args:
        await update.message.reply_text("⚠️ /join <id>")
        return
    try:
        gid = int(context.args[0])
    except:
        await update.message.reply_text("⚠️ آیدی نامعتبر.")
        return
    giveaway = db.get_giveaway_by_id(gid)
    if not giveaway:
        await update.message.reply_text("❌ قرعه‌کشی یافت نشد.")
        return
    chat_id, prize, end_at, winners = giveaway
    if chat_id != update.effective_chat.id:
        await update.message.reply_text("❌ متعلق به این گروه نیست.")
        return
    if datetime.fromisoformat(end_at) < datetime.now():
        await update.message.reply_text("❌ به پایان رسیده.")
        return
    db.add_giveaway_participant(gid, update.effective_user.id)
    await update.message.reply_text(f"✅ در قرعه‌کشی {prize} ثبت نام شدید.")


@safe_command
async def ticket_command(update: Update, context: CallbackContext):
    if not context.args:
        await update.message.reply_text("⚠️ /ticket موضوع")
        return
    subject = ' '.join(context.args)
    description = "توضیحی وارد نشده"
    tid = db.create_ticket(update.effective_chat.id, update.effective_user.id, subject, description)
    await update.message.reply_text(f"✅ تیکت {tid} ایجاد شد.")
    admins = await update.effective_chat.get_administrators()
    for admin in admins:
        if admin.user.is_bot: continue
        try:
            await context.bot.send_message(admin.user.id,
                                           f"🎫 تیکت جدید در {update.effective_chat.title}\nآیدی: {tid}\nکاربر: {update.effective_user.full_name}\nموضوع: {subject}")
        except:
            pass


@safe_command
async def tickets_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    tickets = db.get_open_tickets(update.effective_chat.id)
    if not tickets:
        await update.message.reply_text("هیچ تیکت بازی وجود ندارد.")
        return
    text = "📋 <b>تیکت‌های باز</b>\n\n" + "\n".join(
        f"{tid}: {sub} (کاربر {uid}) - {created}" for tid, uid, sub, created in tickets)
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


@safe_command
async def reply_ticket(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args or '|' not in ' '.join(context.args):
        await update.message.reply_text("⚠️ /replyticket آیدی|متن")
        return
    parts = ' '.join(context.args).split('|', 1)
    try:
        tid = int(parts[0])
    except:
        await update.message.reply_text("⚠️ آیدی نامعتبر.")
        return
    msg = parts[1].strip()
    ticket = db.get_ticket(tid)
    if not ticket:
        await update.message.reply_text("❌ تیکت یافت نشد.")
        return
    db.add_ticket_message(tid, update.effective_user.id, msg, is_admin=True)
    try:
        await context.bot.send_message(ticket[1], f"پاسخ به تیکت {tid}:\n{msg}")
    except:
        pass
    await update.message.reply_text(f"✅ پاسخ به تیکت {tid} ارسال شد.")


@safe_command
async def close_ticket(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ /closeticket آیدی")
        return
    try:
        tid = int(context.args[0])
    except:
        await update.message.reply_text("⚠️ آیدی نامعتبر.")
        return
    db.close_ticket(tid)
    await update.message.reply_text(f"✅ تیکت {tid} بسته شد.")


@safe_command
async def poll_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ /poll سوال|گزینه1|گزینه2|...")
        return
    parts = ' '.join(context.args).split('|')
    if len(parts) < 3:
        await update.message.reply_text("⚠️ حداقل یک گزینه.")
        return
    question = parts[0]
    options = parts[1:]
    pid = db.create_poll(update.effective_chat.id, question, options, update.effective_user.id)
    text = f"🗳 <b>{question}</b>\n\n"
    for i, opt in enumerate(options):
        text += f"{i + 1}. {opt}\n"
    text += f"\n/vote {pid} <شماره>"
    await update.message.reply_text(text, parse_mode=ParseMode.HTML)


@safe_command
async def vote_command(update: Update, context: CallbackContext):
    if not context.args or len(context.args) != 2:
        await update.message.reply_text("⚠️ /vote آیدی شماره")
        return
    try:
        pid = int(context.args[0])
        option = int(context.args[1]) - 1
    except:
        await update.message.reply_text("⚠️ مقادیر نامعتبر.")
        return
    poll = db.get_poll(pid)
    if not poll or poll[0] != update.effective_chat.id:
        await update.message.reply_text("❌ نظرسنجی یافت نشد.")
        return
    if not poll[5]:
        await update.message.reply_text("❌ نظرسنجی بسته شده.")
        return
    options = json.loads(poll[2])
    if option < 0 or option >= len(options):
        await update.message.reply_text("❌ شماره نامعتبر.")
        return
    db.vote_poll(pid, update.effective_user.id, option)
    await update.message.reply_text(f"✅ رای شما به گزینه {option + 1} ثبت شد.")


@safe_command
async def set_force_subscribe(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ /setforce @channel")
        return
    channel = context.args[0].strip()
    db.set_setting(update.effective_chat.id, 'force_subscribe_channel', channel)
    await update.message.reply_text(f"✅ عضویت اجباری در {channel} تنظیم شد.")


@safe_command
async def add_api_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ /addapi command|url|method")
        return
    parts = ' '.join(context.args).split('|')
    if len(parts) != 3:
        await update.message.reply_text("⚠️ فرمت صحیح نیست.")
        return
    cmd, url, method = parts[0].strip(), parts[1].strip(), parts[2].strip().upper()
    if method not in ['GET', 'POST']:
        await update.message.reply_text("⚠️ متد GET یا POST")
        return
    db.set_api_command(update.effective_chat.id, cmd, url, method)
    await update.message.reply_text(f"✅ دستور /{cmd} به API متصل شد.")


@safe_command
async def del_api_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not context.args:
        await update.message.reply_text("⚠️ نام دستور را وارد کنید.")
        return
    cmd = context.args[0].strip()
    db.delete_api_command(update.effective_chat.id, cmd)
    await update.message.reply_text(f"✅ دستور /{cmd} حذف شد.")


async def handle_api_command(update: Update, context: CallbackContext):
    text = update.message.text
    if not text.startswith('/'):
        return
    cmd = text.split()[0][1:].lower()
    chat_id = update.effective_chat.id
    api_info = db.get_api_command(chat_id, cmd)
    if not api_info:
        return
    url, method = api_info
    try:
        async with aiohttp.ClientSession() as session:
            if method == 'GET':
                async with session.get(url) as resp:
                    result = await resp.text()
            else:
                async with session.post(url) as resp:
                    result = await resp.text()
        await update.message.reply_text(f"📡 پاسخ API:\n{result[:4000]}")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def pin_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام ریپلای کنید.")
        return
    msg = update.message.reply_to_message
    try:
        await msg.pin()
        db.add_pinned(update.effective_chat.id, msg.message_id)
        await update.message.reply_text("📌 پیام سنجاق شد.")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def unpin_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    try:
        await update.effective_chat.unpin_message()
        await update.message.reply_text("📌 سنجاق برداشته شد.")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def clean_command(update: Update, context: CallbackContext):
    if not await is_admin(update.effective_chat, update.effective_user.id):
        return
    if not update.message.reply_to_message:
        await update.message.reply_text("⚠️ روی پیام کاربر ریپلای کنید.")
        return
    try:
        await update.message.reply_to_message.delete()
        await update.message.reply_text("🗑 پیام حذف شد.")
    except Exception as e:
        await update.message.reply_text(f"❌ خطا: {e}")


@safe_command
async def restart_command(update: Update, context: CallbackContext):
    if update.effective_user.id not in ADMIN_IDS:
        await update.message.reply_text("⛔ فقط فوق‌ادمین.")
        return
    await update.message.reply_text("🔄 در حال ری‌استارت...")
    import os, sys
    os.execv(sys.executable, ['python'] + sys.argv)


# ===================== فیلتر پیام‌ها =====================
async def global_content_filter(update: Update, context: CallbackContext):
    if not update.effective_chat or update.effective_chat.type == "private":
        return
    chat_id = update.effective_chat.id
    user_id = update.effective_user.id
    msg = update.effective_message
    if not msg:
        return

    db.increment_daily_stats(chat_id, 'messages')
    current = int(db.get_user_data(user_id, 'message_count') or 0)
    db.set_user_data(user_id, 'message_count', current + 1)

    if db.is_blacklisted(user_id):
        await msg.delete()
        await update.effective_chat.send_message("⛔ شما در لیست سیاه هستید.")
        return

    nm = db.get_night_mode(chat_id)
    if nm:
        start, end, enabled = nm
        if enabled:
            now = datetime.now().time()
            start_t = datetime.strptime(start, "%H:%M").time()
            end_t = datetime.strptime(end, "%H:%M").time()
            if start_t <= now <= end_t and not await is_admin(update.effective_chat, user_id):
                await msg.delete()
                await update.effective_chat.send_message("🌙 حالت شب فعال است.")
                return

    delay = db.get_auto_delete(chat_id, user_id)
    if delay:
        context.job_queue.run_once(lambda c: c.bot.delete_message(chat_id, msg.message_id), delay)

    force = db.get_setting(chat_id, 'force_subscribe_channel')
    if force:
        try:
            member = await context.bot.get_chat_member(force, user_id)
            if member.status in [ChatMember.LEFT, ChatMember.BANNED]:
                await msg.delete()
                await update.effective_chat.send_message(f"⚠️ در کانال {force} عضو شوید.")
                return
        except:
            pass

    text = (msg.text or msg.caption or "").lower()
    banned = db.get_word_filters(chat_id)
    if any(w in text for w in banned):
        await msg.delete()
        await log_action(chat_id, f"🚫 حذف پیام از {update.effective_user.first_name} (کلمه ممنوع)")
        return

    locks = db.get_all_locks(chat_id)
    if locks.get("link") and re.search(r'(https?://[^\s]+|t\.me/[^\s]+)', text):
        await msg.delete();
        return
    if locks.get("mention") and "@" in text:
        await msg.delete();
        return
    if locks.get("hashtag") and "#" in text:
        await msg.delete();
        return
    if locks.get("photo") and msg.photo:
        await msg.delete();
        return
    if locks.get("video") and msg.video:
        await msg.delete();
        return
    if locks.get("sticker") and msg.sticker:
        await msg.delete();
        return
    if locks.get("voice") and msg.voice:
        await msg.delete();
        return
    if locks.get("forward") and msg.forward_date:
        await msg.delete();
        return
    if locks.get("document") and msg.document:
        await msg.delete();
        return
    if locks.get("audio") and msg.audio:
        await msg.delete();
        return
    if locks.get("location") and (msg.location or msg.venue):
        await msg.delete();
        return
    if locks.get("contact") and msg.contact:
        await msg.delete();
        return
    if locks.get("poll") and msg.poll:
        await msg.delete();
        return
    if locks.get("dice") and msg.dice:
        await msg.delete();
        return

    slow = int(db.get_setting(chat_id, 'slowmode_sec', 0))
    if slow > 0:
        last = db.get_user_status(user_id, chat_id)
        now = datetime.now()
        if last and (now - last).total_seconds() < slow:
            await msg.delete()
            return
        db.set_user_status(user_id, chat_id, now)

    flood_limit = int(db.get_setting(chat_id, 'flood_limit', DEFAULT_FLOOD_LIMIT))
    flood_window = int(db.get_setting(chat_id, 'flood_window', DEFAULT_FLOOD_WINDOW))
    flood_mute = int(db.get_setting(chat_id, 'flood_mute_min', DEFAULT_FLOOD_MUTE_MIN))
    now = datetime.now()
    since = now - timedelta(seconds=flood_window)
    db.clean_antiflood(user_id, since)
    db.add_antiflood(user_id, now)
    history = db.get_antiflood(user_id, since)
    if len(history) > flood_limit:
        until = now + timedelta(minutes=flood_mute)
        try:
            await update.effective_chat.restrict_member(user_id, permissions=ChatPermissions(can_send_messages=False),
                                                        until_date=until)
            await msg.delete()
            await update.effective_chat.send_message(
                f"🌊 {update.effective_user.first_name} {flood_mute} دقیقه ساکت شد.")
            await log_action(chat_id, f"🌊 سکوت {update.effective_user.first_name} (اسپم)")
        except:
            pass
        return

    for keyword, reply in db.get_all_auto_replies(chat_id):
        if keyword in text:
            await msg.reply_text(reply)
            break


# ===================== ورود عضو جدید (کپچا) =====================
async def welcome_new_members(update: Update, context: CallbackContext):
    chat_id = update.effective_chat.id
    db.increment_daily_stats(chat_id, 'joins')
    for member in update.message.new_chat_members:
        if member.id == context.bot.id:
            continue
        try:
            db.set_user_data(member.id, 'join_date', datetime.now().isoformat())
            if int(db.get_setting(chat_id, 'anti_raid', 0)):
                if not hasattr(context, 'chat_data'):
                    context.chat_data = {}
                if chat_id not in context.chat_data:
                    context.chat_data[chat_id] = {'join_times': []}
                now = datetime.now()
                context.chat_data[chat_id]['join_times'] = [t for t in context.chat_data[chat_id]['join_times'] if
                                                            now - t < timedelta(seconds=60)]
                context.chat_data[chat_id]['join_times'].append(now)
                if len(context.chat_data[chat_id]['join_times']) > 5:
                    try:
                        await update.effective_chat.restrict_member(member.id, permissions=ChatPermissions(
                            can_send_messages=False))
                        await update.effective_chat.send_message(f"🛡 ضدحمله: {member.full_name} محدود شد.")
                        await log_action(chat_id, f"🛡 ضدحمله: {member.full_name} محدود شد")
                    except:
                        pass
                    continue

            if int(db.get_setting(chat_id, 'welcome_enabled', 1)):
                captcha_type = db.get_setting(chat_id, 'captcha_type', 'numeric')
                if captcha_type == 'math':
                    a, b = random.randint(1, 10), random.randint(1, 10)
                    code = str(a + b)
                    question = f"{a} + {b} = ?"
                else:
                    code = str(random.randint(1000, 9999))
                    question = f"کد: <code>{code}</code>"
                timeout = int(db.get_setting(chat_id, 'captcha_timeout', 60))
                db.set_captcha(member.id, chat_id, code, datetime.now() + timedelta(seconds=timeout))

                try:
                    await update.effective_chat.restrict_member(member.id,
                                                                permissions=ChatPermissions(can_send_messages=False))
                except Exception as e:
                    logger.error(f"Could not restrict: {e}")

                try:
                    keyboard = InlineKeyboardMarkup(
                        [[InlineKeyboardButton("✅ من ربات نیستم", callback_data=f"verify_{member.id}_{code}")]])
                    await update.effective_chat.send_message(
                        f"🌟 خوش آمدی <b>{member.full_name}</b>\n\nسوال: {question}\n⏳ زمان: {timeout}s",
                        reply_markup=keyboard,
                        parse_mode=ParseMode.HTML
                    )
                    await log_action(chat_id, f"🆕 کپچا برای {member.full_name} ارسال شد")
                    sticker_id = db.get_sticker('welcome')
                    if sticker_id:
                        try:
                            await context.bot.send_sticker(chat_id, sticker_id)
                        except:
                            pass
                except Exception as e:
                    logger.error(f"Captcha send error: {e}")

        except Exception as e:
            logger.error(f"Welcome error: {e}", exc_info=True)


# ===================== دکمه‌ها =====================
async def button_handler(update: Update, context: CallbackContext):
    query = update.callback_query
    try:
        await query.answer()
        user_id = query.from_user.id
        chat_id = query.message.chat.id
        data = query.data

        if data.startswith("verify_"):
            _, target_id, code = data.split("_")
            if user_id != int(target_id):
                await query.answer("❌ این دکمه برای شما نیست.", show_alert=True)
                return
            captcha_data = db.get_captcha(user_id, chat_id)
            if captcha_data and captcha_data['code'] == code and datetime.now() < captcha_data['expire_at']:
                try:
                    await query.message.chat.restrict_member(
                        user_id,
                        permissions=ChatPermissions(can_send_messages=True, can_send_media_messages=True,
                                                    can_send_other_messages=True, can_add_web_page_previews=True)
                    )
                    await query.edit_message_text("✅ هویت تأیید شد! خوش آمدید.")
                    db.delete_captcha(user_id, chat_id)
                    welcome_msg = db.get_setting(chat_id, 'welcome_msg', '🌟 خوش آمدی {user} به {chat}!')
                    user_full = query.from_user.full_name
                    mention = f"<a href='tg://user?id={user_id}'>{user_full}</a>"
                    username = f"@{query.from_user.username}" if query.from_user.username else "بدون یوزرنیم"
                    date_now = datetime.now().strftime("%Y-%m-%d %H:%M")
                    welcome_msg = welcome_msg.replace('{user}', user_full).replace('{mention}', mention)
                    welcome_msg = welcome_msg.replace('{username}', username).replace('{date}', date_now)
                    welcome_msg = welcome_msg.replace('{chat}', query.message.chat.title)
                    await query.message.reply_text(welcome_msg, parse_mode=ParseMode.HTML)
                    sticker_id = db.get_sticker('welcome')
                    if sticker_id:
                        try:
                            await context.bot.send_sticker(chat_id, sticker_id)
                        except:
                            pass
                except Exception as e:
                    await query.edit_message_text(f"❌ خطا: {e}")
            else:
                await query.answer("❌ کد منقضی یا اشتباه است.", show_alert=True)
            return

        if not await is_admin(query.message.chat, user_id):
            await query.answer("⛔ شما ادمین نیستید.", show_alert=True)
            return

        # منوها
        if data == "menu_main":
            await query.edit_message_text("⚙️ منوی اصلی", reply_markup=await main_menu(chat_id),
                                          parse_mode=ParseMode.HTML)
        elif data == "menu_locks":
            await query.edit_message_text("🔒 قفل‌ها", reply_markup=await locks_menu(chat_id), parse_mode=ParseMode.HTML)
        elif data == "menu_settings":
            await query.edit_message_text("⚙️ تنظیمات", reply_markup=await settings_menu(chat_id),
                                          parse_mode=ParseMode.HTML)
        elif data == "menu_wordfilter":
            markup, text = await word_filter_menu(chat_id)
            await query.edit_message_text(text, reply_markup=markup, parse_mode=ParseMode.HTML)
        elif data == "menu_advanced":
            await query.edit_message_text("⚡ تنظیمات پیشرفته", reply_markup=await advanced_menu(chat_id),
                                          parse_mode=ParseMode.HTML)
        elif data == "menu_auto_reply":
            markup, text = await auto_reply_menu(chat_id)
            await query.edit_message_text(text, reply_markup=markup, parse_mode=ParseMode.HTML)
        elif data == "menu_stats":
            stats = db.get_daily_stats(chat_id, 7)
            text = "📊 آمار (۷ روز):\n" + "\n".join(f"{d}: {m} پیام" for d, m, _, _ in stats)
            await query.edit_message_text(text, parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_main")]]))
        elif data == "menu_blacklist":
            bl = db.get_blacklist()
            text = "🚫 لیست سیاه:\n" + ("\n".join(f"{uid} - {reason}" for uid, reason, _, _ in bl) if bl else "خالی")
            await query.edit_message_text(text, parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_main")]]))
        elif data == "menu_night":
            nm = db.get_night_mode(chat_id)
            text = f"🌙 حالت شب: {nm[2] if nm else 'تنظیم نشده'}" if nm else "تنظیم نشده"
            await query.edit_message_text(text, parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_main")]]))
        elif data == "menu_admins":
            admins = db.get_temp_admins(chat_id)
            text = "👥 ادمین‌های موقت:\n" + (
                "\n".join(f"{uid} تا {until}" for uid, until in admins) if admins else "هیچ")
            await query.edit_message_text(text, parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(
                [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_main")]]))
        elif data in ["menu_giveaway", "menu_ticket", "menu_poll"]:
            titles = {"menu_giveaway": "🎁 قرعه‌کشی", "menu_ticket": "🎫 تیکت", "menu_poll": "🗳 نظرسنجی"}
            await query.edit_message_text(f"{titles[data]}\n\nاز دستورات مربوطه استفاده کنید.",
                                          parse_mode=ParseMode.HTML, reply_markup=InlineKeyboardMarkup(
                    [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_main")]]))
        elif data == "close_menu":
            await query.message.delete()

        # قفل‌ها
        elif data.startswith("lock_"):
            lt = data.split("_")[1]
            db.set_lock(chat_id, lt, not db.get_lock(chat_id, lt))
            await query.edit_message_reply_markup(reply_markup=await locks_menu(chat_id))
        elif data == "all_on":
            for lt in ["link", "photo", "video", "sticker", "voice", "mention", "forward", "bot", "hashtag", "document",
                       "audio", "location", "contact", "poll", "dice"]:
                db.set_lock(chat_id, lt, True)
            await query.edit_message_reply_markup(reply_markup=await locks_menu(chat_id))
        elif data == "all_off":
            for lt in ["link", "photo", "video", "sticker", "voice", "mention", "forward", "bot", "hashtag", "document",
                       "audio", "location", "contact", "poll", "dice"]:
                db.set_lock(chat_id, lt, False)
            await query.edit_message_reply_markup(reply_markup=await locks_menu(chat_id))

        # تنظیمات
        elif data in ["step_slowmode", "step_captcha", "step_warn", "step_flood", "step_auto_clean"]:
            mapping = {
                "step_slowmode": ("slowmode_sec", 5, 120),
                "step_captcha": ("captcha_timeout", 5, 300),
                "step_warn": ("warn_limit", 1, 10),
                "step_flood": ("flood_limit", 1, 20),
                "step_auto_clean": ("auto_clean_days", 1, 30)
            }
            key, step, max_val = mapping[data]
            val = int(db.get_setting(chat_id, key, 0))
            new_val = val + step
            if new_val > max_val:
                new_val = 0
            db.set_setting(chat_id, key, new_val)
            await query.edit_message_reply_markup(reply_markup=await settings_menu(chat_id))
        elif data == "toggle_welcome":
            current = int(db.get_setting(chat_id, 'welcome_enabled', 1))
            db.set_setting(chat_id, 'welcome_enabled', 0 if current else 1)
            await query.edit_message_reply_markup(reply_markup=await settings_menu(chat_id))
        elif data == "step_warn_action":
            actions = ['mute', 'kick', 'ban']
            current = db.get_setting(chat_id, 'warn_action', 'ban')
            idx = (actions.index(current) + 1) % len(actions)
            db.set_setting(chat_id, 'warn_action', actions[idx])
            await query.edit_message_reply_markup(reply_markup=await settings_menu(chat_id))
        elif data == "step_captcha_type":
            types = ['numeric', 'math']
            current = db.get_setting(chat_id, 'captcha_type', 'numeric')
            idx = (types.index(current) + 1) % len(types)
            db.set_setting(chat_id, 'captcha_type', types[idx])
            await query.edit_message_reply_markup(reply_markup=await settings_menu(chat_id))
        elif data == "toggle_anti_raid":
            current = int(db.get_setting(chat_id, 'anti_raid', 0))
            db.set_setting(chat_id, 'anti_raid', 0 if current else 1)
            await query.edit_message_reply_markup(reply_markup=await settings_menu(chat_id))
        elif data in ["set_log_chat", "set_force_subscribe"]:
            cmd = data.replace('set_', '')
            await query.edit_message_text(f"⚠️ دستور /{cmd} را اجرا کنید.", parse_mode=ParseMode.HTML,
                                          reply_markup=InlineKeyboardMarkup(
                                              [[InlineKeyboardButton("🔙 بازگشت", callback_data="menu_advanced")]]))

    except Exception as e:
        logger.error(f"Button handler error: {e}", exc_info=True)
        try:
            await query.edit_message_text(f"❌ خطا: {str(e)[:200]}")
        except:
            pass


# ===================== دستورات فارسی (بدون اسلش) =====================
async def persian_command_handler(update: Update, context: CallbackContext):
    text = update.message.text.strip()
    command = PERSIAN_COMMANDS.get(text)
    if not command:
        return

    command_map = {
        "help": help_command,
        "menu": menu_command,
        "rules": rules_command,
        "welcome": welcome_command,
        "info": info_command,
        "stats": stats_advanced,
        "top": top_users,
        "pinned": pinned_command,
        "warn": warn_user,
        "unwarn": unwarn_user,
        "kick": kick_user,
        "ban": ban_user,
        "unban": unban_user,
        "mute": mute_user,
        "unmute": unmute_user,
        "purge": purge_command,
        "pin": pin_command,
        "unpin": unpin_command,
        "clean": clean_command,
        "broadcast": broadcast,
        "addadmin": add_temp_admin,
        "blacklist": blacklist_command,
        "nightmode": night_mode_command,
        "setrules": set_rules,
        "setwelcome": set_welcome,
        "slowmode": slowmode_command,
        "captchatime": captchatime_command,
        "addword": add_word,
        "delword": del_word,
        "addreply": add_reply,
        "delreply": del_reply,
        "remind": remind_command,
        "giveaway": giveaway_command,
        "join": join_giveaway,
        "ticket": ticket_command,
        "tickets": tickets_command,
        "replyticket": reply_ticket,
        "closeticket": close_ticket,
        "poll": poll_command,
        "vote": vote_command,
        "setforce": set_force_subscribe,
        "addapi": add_api_command,
        "delapi": del_api_command,
        "backup": backup_command,
        "restart": restart_command,
        "userinfo": userinfo_command,
    }

    func = command_map.get(command)
    if func:
        await func(update, context)


# ===================== یادآوری =====================
async def reminder_checker(context: CallbackContext):
    due = db.get_due_reminders()
    for idx, user_id, chat_id, message in due:
        try:
            await context.bot.send_message(chat_id, f"⏰ یادآوری: {message}")
        except Exception as e:
            logger.error(f"Reminder error: {e}")
        db.mark_reminder_done(idx)


# ===================== تابع ساخت Regex =====================
def build_persian_regex():
    keywords = '|'.join(re.escape(key) for key in PERSIAN_COMMANDS.keys())
    return rf'^[ \t]*({keywords})[ \t]*$'


# ===================== اجرا =====================
def main() -> None:
    application = Application.builder().token(TOKEN).build()

    # دستورات
    handlers = [
        CommandHandler("start", start),
        CommandHandler("help", help_command),
        CommandHandler("menu", menu_command, filters=filters.ChatType.GROUPS),
        CommandHandler("rules", rules_command, filters=filters.ChatType.GROUPS),
        CommandHandler("welcome", welcome_command, filters=filters.ChatType.GROUPS),
        CommandHandler("info", info_command, filters=filters.ChatType.GROUPS),
        CommandHandler("userinfo", userinfo_command, filters=filters.ChatType.GROUPS),
        CommandHandler("report", report_command, filters=filters.ChatType.GROUPS),
        CommandHandler("stats", stats_advanced, filters=filters.ChatType.GROUPS),
        CommandHandler("top", top_users, filters=filters.ChatType.GROUPS),
        CommandHandler("pinned", pinned_command, filters=filters.ChatType.GROUPS),
        CommandHandler("warn", warn_user, filters=filters.ChatType.GROUPS),
        CommandHandler("unwarn", unwarn_user, filters=filters.ChatType.GROUPS),
        CommandHandler("kick", kick_user, filters=filters.ChatType.GROUPS),
        CommandHandler("ban", ban_user, filters=filters.ChatType.GROUPS),
        CommandHandler("unban", unban_user, filters=filters.ChatType.GROUPS),
        CommandHandler("mute", mute_user, filters=filters.ChatType.GROUPS),
        CommandHandler("unmute", unmute_user, filters=filters.ChatType.GROUPS),
        CommandHandler("purge", purge_command, filters=filters.ChatType.GROUPS),
        CommandHandler("setrules", set_rules, filters=filters.ChatType.GROUPS),
        CommandHandler("setwelcome", set_welcome, filters=filters.ChatType.GROUPS),
        CommandHandler("slowmode", slowmode_command, filters=filters.ChatType.GROUPS),
        CommandHandler("captchatime", captchatime_command, filters=filters.ChatType.GROUPS),
        CommandHandler("addword", add_word, filters=filters.ChatType.GROUPS),
        CommandHandler("delword", del_word, filters=filters.ChatType.GROUPS),
        CommandHandler("setwarnaction", set_warn_action, filters=filters.ChatType.GROUPS),
        CommandHandler("setlogchat", set_log_chat, filters=filters.ChatType.GROUPS),
        CommandHandler("setcaptchatype", set_captcha_type, filters=filters.ChatType.GROUPS),
        CommandHandler("backup", backup_command, filters=filters.ChatType.GROUPS),
        CommandHandler("broadcast", broadcast, filters=filters.ChatType.GROUPS),
        CommandHandler("addadmin", add_temp_admin, filters=filters.ChatType.GROUPS),
        CommandHandler("blacklist", blacklist_command, filters=filters.ChatType.GROUPS),
        CommandHandler("nightmode", night_mode_command, filters=filters.ChatType.GROUPS),
        CommandHandler("setsticker", set_sticker_command, filters=filters.ChatType.GROUPS),
        CommandHandler("setautodelete", set_auto_delete_command, filters=filters.ChatType.GROUPS),
        CommandHandler("addreply", add_reply, filters=filters.ChatType.GROUPS),
        CommandHandler("delreply", del_reply, filters=filters.ChatType.GROUPS),
        CommandHandler("remind", remind_command, filters=filters.ChatType.GROUPS),
        CommandHandler("giveaway", giveaway_command, filters=filters.ChatType.GROUPS),
        CommandHandler("join", join_giveaway, filters=filters.ChatType.GROUPS),
        CommandHandler("ticket", ticket_command, filters=filters.ChatType.GROUPS),
        CommandHandler("tickets", tickets_command, filters=filters.ChatType.GROUPS),
        CommandHandler("replyticket", reply_ticket, filters=filters.ChatType.GROUPS),
        CommandHandler("closeticket", close_ticket, filters=filters.ChatType.GROUPS),
        CommandHandler("poll", poll_command, filters=filters.ChatType.GROUPS),
        CommandHandler("vote", vote_command, filters=filters.ChatType.GROUPS),
        CommandHandler("setforce", set_force_subscribe, filters=filters.ChatType.GROUPS),
        CommandHandler("addapi", add_api_command, filters=filters.ChatType.GROUPS),
        CommandHandler("delapi", del_api_command, filters=filters.ChatType.GROUPS),
        CommandHandler("pin", pin_command, filters=filters.ChatType.GROUPS),
        CommandHandler("unpin", unpin_command, filters=filters.ChatType.GROUPS),
        CommandHandler("clean", clean_command, filters=filters.ChatType.GROUPS),
        CommandHandler("restart", restart_command),
    ]
    for handler in handlers:
        application.add_handler(handler)

    # هندلر API
    application.add_handler(MessageHandler(filters.Regex(r'^/[a-zA-Z0-9_]+$'), handle_api_command))

    # دکمه‌ها
    application.add_handler(CallbackQueryHandler(button_handler))

    # ورود اعضا
    application.add_handler(MessageHandler(filters.StatusUpdate.NEW_CHAT_MEMBERS, welcome_new_members))

    # دستورات فارسی (با دیکشنری جامع)
    application.add_handler(MessageHandler(
        filters.Regex(build_persian_regex()),
        persian_command_handler
    ))

    # فیلتر اصلی پیام‌ها (باید آخرین باشد)
    application.add_handler(MessageHandler(
        (filters.TEXT | filters.ATTACHMENT) & ~filters.COMMAND,
        global_content_filter
    ))

    # JobQueue
    job_queue = application.job_queue
    if job_queue:
        job_queue.run_repeating(reminder_checker, interval=60, first=10)

    print("🚀 ربات با ذخیره‌سازی JSON و دیکشنری جامع دستورات فارسی راه‌اندازی شد!")
    application.run_polling()


if __name__ == "__main__":
    main()