import logging
import asyncio
import re
import json
import os
import time
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, filters, ContextTypes
from telegram.error import BadRequest

# Configuration
BOT_TOKEN = "8798209749:AAEddqK7lZg8lf7rCSwOPCFIINVL_s2uSf0"
GROUP_IDS = [-1004352371674, -1004286362819]
REQUIRED_BIO_TEXT = "@morningcl"
USERS_DIR = "users"
MESSAGES_FILE = "messages.json"
FILTER_FILE = "filter.json"

# Enable logging
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)
logger = logging.getLogger(__name__)

# Store warning message IDs for cleanup
warning_messages = {}
# Store system message IDs (join/leave) for cleanup
system_messages = {}
# Cache for user data and admin status (with TTL)
user_cache = {}
admin_cache = {}
CACHE_TTL = 300  # 5 minutes

# Create users directory if it doesn't exist
if not os.path.exists(USERS_DIR):
    os.makedirs(USERS_DIR)

# Load messages from messages.json
def load_messages():
    """Load messages from messages.json"""
    if os.path.exists(MESSAGES_FILE):
        try:
            with open(MESSAGES_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
        except:
            pass
    return {}

messages = load_messages()

def load_filters():
    """Load filters from filter.json"""
    if os.path.exists(FILTER_FILE):
        try:
            with open(FILTER_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
        except:
            pass
    return {}

def save_filters(filters: dict):
    """Save filters to filter.json"""
    with open(FILTER_FILE, 'w', encoding='utf-8') as f:
        json.dump(filters, f, ensure_ascii=False, indent=2)

def get_cached_data(cache: dict, key: str, ttl: int = CACHE_TTL):
    """Get data from cache if not expired"""
    if key in cache:
        data, timestamp = cache[key]
        if time.time() - timestamp < ttl:
            return data
    return None

def set_cached_data(cache: dict, key: str, data: dict):
    """Set data in cache with current timestamp"""
    cache[key] = (data, time.time())

def get_user_file_path(user_id: int, username: str = None) -> str:
    """Get file path for user data"""
    if username:
        return os.path.join(USERS_DIR, f"{user_id},{username}.json")
    return os.path.join(USERS_DIR, f"{user_id}.json")

def load_user_data(user_id: int) -> dict:
    """Load user data from file by user_id (search all files matching user_id)"""
    try:
        for filename in os.listdir(USERS_DIR):
            if filename.startswith(f"{user_id},") or filename == f"{user_id}.json":
                file_path = os.path.join(USERS_DIR, filename)
                with open(file_path, 'r', encoding='utf-8') as f:
                    return json.load(f)
    except:
        pass
    return {}

def save_user_data(user_id: int, username: str = None, data: dict = None) -> None:
    """Save user data to file and clean up old files"""
    if data is None:
        return
    
    # Delete all old files for this user_id
    try:
        for filename in os.listdir(USERS_DIR):
            if filename.startswith(f"{user_id},") or filename == f"{user_id}.json":
                old_path = os.path.join(USERS_DIR, filename)
                # Don't delete if it's the same as the new path
                new_path = get_user_file_path(user_id, username)
                if old_path != new_path:
                    os.remove(old_path)
    except:
        pass
    
    # Save to new file
    file_path = get_user_file_path(user_id, username)
    with open(file_path, 'w', encoding='utf-8') as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

async def update_user_data(user, application: Application) -> dict:
    """Update user data and return changes"""
    try:
        user_chat = await application.bot.get_chat(user.id)
        current_data = {
            "id": user.id,
            "first_name": user.first_name if user.first_name else "",
            "last_name": user.last_name if user.last_name else "",
            "username": user.username if user.username else "",
            "bio": user_chat.bio if user_chat.bio else ""
        }
        
        # Load existing data by user_id (not username)
        existing_data = load_user_data(user.id)
        
        # Check for changes
        changes = []
        if existing_data:
            old_full_name = f"{existing_data.get('first_name', '')} {existing_data.get('last_name', '')}".strip()
            new_full_name = f"{current_data['first_name']} {current_data['last_name']}".strip()
            if old_full_name != new_full_name:
                changes.append(messages.get('name_change', 'nama: {old} → {new}').format(old=old_full_name, new=new_full_name))
            if existing_data.get("username") != current_data["username"]:
                old_username = existing_data.get('username') or "tidak ada"
                new_username = current_data["username"] or "tidak ada"
                changes.append(messages.get('username_change', 'username: {old} → {new}').format(old=old_username, new=new_username))
        
        # Save current data with new username in filename
        save_user_data(user.id, current_data["username"], current_data)
        
        return current_data, changes
    except Exception as e:
        logger.error(f"Error updating user data: {e}")
        return {}, []

async def is_admin(application: Application, user_id: int, chat_id: int) -> bool:
    """Check if user is admin in the chat (with caching)"""
    cache_key = f"{user_id}_{chat_id}"
    
    # Check cache first
    cached = get_cached_data(admin_cache, cache_key)
    if cached is not None:
        return cached
    
    try:
        chat_member = await application.bot.get_chat_member(chat_id, user_id)
        is_admin_status = chat_member.status in ['administrator', 'creator']
        logger.info(f"User {user_id} admin check - Status: {chat_member.status}, Is admin: {is_admin_status}")
        
        # Cache the result
        set_cached_data(admin_cache, cache_key, is_admin_status)
        
        return is_admin_status
    except Exception as e:
        logger.error(f"Error checking admin status: {e}")
        return False

async def has_permission(application: Application, user_id: int, chat_id: int, permission: str) -> bool:
    """Check if admin has specific permission"""
    try:
        chat_member = await application.bot.get_chat_member(chat_id, user_id)
        # Creator has all permissions
        if chat_member.status == 'creator':
            return True
        # Check specific permission for administrator
        if chat_member.status == 'administrator':
            return getattr(chat_member, permission, False)
        return False
    except Exception as e:
        logger.error(f"Error checking permission {permission}: {e}")
        return False

async def check_user_bio(user_id: int, application: Application) -> tuple[bool, str]:
    """Check if user's bio contains the required text (with caching)"""
    cache_key = f"bio_{user_id}"
    
    # Check cache first
    cached = get_cached_data(user_cache, cache_key, ttl=60)  # Cache bio for 1 minute
    if cached is not None:
        return cached.get('has_required_text', False), cached.get('bio', '')
    
    try:
        # Fetch user profile immediately without delay
        user = await application.bot.get_chat(user_id)
        bio = user.bio if user.bio else ""
        has_required_text = REQUIRED_BIO_TEXT.lower() in bio.lower()
        logger.info(f"User {user_id} bio check - Bio: '{bio}', Has required text: {has_required_text}")
        
        # Cache the result
        set_cached_data(user_cache, cache_key, {'has_required_text': has_required_text, 'bio': bio})
        
        return has_required_text, bio
    except Exception as e:
        logger.error(f"Error getting user bio: {e}")
        return False, ""

def get_user_display_name(user) -> str:
    """Get user display name with link and notification"""
    name = user.first_name if user.first_name else (user.last_name if user.last_name else str(user.id))
    # Use HTML format: <a href="tg://user?id=ID">name</a> - shows name, links to profile, notifies user
    return f'<a href="tg://user?id={user.id}">{name}</a>'

async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle incoming messages in the group"""
    if not update.message or not update.message.chat:
        return
    
    # Only process messages from the target groups
    if update.message.chat.id not in GROUP_IDS:
        return
    
    user = update.message.from_user
    if not user:
        return
    
    # Check for keyword filters first (before admin check)
    filters = load_filters()
    message_text = update.message.text or update.message.caption or ""
    
    for keyword, filter_data in filters.items():
        # Use word boundary to match whole words only
        pattern = r'\b' + re.escape(keyword) + r'\b'
        if re.search(pattern, message_text, re.IGNORECASE):
            try:
                # Handle different filter types
                if isinstance(filter_data, dict):
                    # New format with type information
                    filter_type = filter_data.get('type', 'text')
                    
                    if filter_type == 'text':
                        await update.message.reply_text(filter_data.get('content', ''), parse_mode='HTML', disable_web_page_preview=True)
                    elif filter_type == 'caption':
                        await update.message.reply_text(filter_data.get('content', ''), parse_mode='HTML', disable_web_page_preview=True)
                    elif filter_type == 'sticker':
                        await context.application.bot.send_sticker(chat_id=update.message.chat.id, sticker=filter_data.get('file_id'), reply_to_message_id=update.message.message_id)
                    elif filter_type == 'photo':
                        await context.application.bot.send_photo(chat_id=update.message.chat.id, photo=filter_data.get('file_id'), reply_to_message_id=update.message.message_id)
                    elif filter_type == 'video':
                        await context.application.bot.send_video(chat_id=update.message.chat.id, video=filter_data.get('file_id'), reply_to_message_id=update.message.message_id)
                    elif filter_type == 'animation':
                        await context.application.bot.send_animation(chat_id=update.message.chat.id, animation=filter_data.get('file_id'), reply_to_message_id=update.message.message_id)
                    elif filter_type == 'audio':
                        await context.application.bot.send_audio(chat_id=update.message.chat.id, audio=filter_data.get('file_id'), reply_to_message_id=update.message.message_id)
                    elif filter_type == 'voice':
                        await context.application.bot.send_voice(chat_id=update.message.chat.id, voice=filter_data.get('file_id'), reply_to_message_id=update.message.message_id)
                    elif filter_type == 'document':
                        await context.application.bot.send_document(chat_id=update.message.chat.id, document=filter_data.get('file_id'), reply_to_message_id=update.message.message_id)
                else:
                    # Old format (string only)
                    await update.message.reply_text(filter_data, parse_mode='HTML', disable_web_page_preview=True)
                
                logger.info(f"Filter '{keyword}' triggered by user {user.id}")
                return  # Don't process further if filter matched
            except Exception as e:
                logger.error(f"Error sending filter reply: {e}")
    
    # Check admin status (cached)
    is_user_admin = await is_admin(context.application, user.id, update.message.chat.id)
    
    # Skip if user is admin (admins are exempt from all checks)
    if is_user_admin:
        return
    
    # Run checks concurrently
    user_data_task = update_user_data(user, context.application)
    bio_check_task = check_user_bio(user.id, context.application)
    
    # Wait for both to complete
    user_data, changes = await user_data_task
    has_required_text, bio = await bio_check_task
    
    # Notify group if user changed name/username
    if changes:
        display_name = get_user_display_name(user)
        change_text = "\n".join(f"- {c}" for c in changes)
        await context.application.bot.send_message(
            chat_id=update.message.chat.id,
            text=messages.get('profile_change_notification', '{display_name} mengubah profil:\n{changes}').format(display_name=display_name, changes=change_text),
            parse_mode='HTML',
            disable_web_page_preview=True
        )
    
    # Check user bio on EVERY message (real-time check)
    if not has_required_text:
        try:
            # Delete the user's message
            await update.message.delete()
            
            # Mute the user (restrict sending messages)
            await context.application.bot.restrict_chat_member(
                chat_id=update.message.chat.id,
                user_id=user.id,
                permissions={"can_send_messages": False}
            )
            
            # Send warning message with inline button
            keyboard = [
                [InlineKeyboardButton(messages.get('verify_button', 'Verifikasi'), callback_data=f"verify_{user.id}")]
            ]
            reply_markup = InlineKeyboardMarkup(keyboard)
            
            display_name = get_user_display_name(user)
            warning_message = await context.application.bot.send_message(
                chat_id=update.message.chat.id,
                text=messages.get('warning_message', '{display_name} harap pasang @morningcl pada bio anda').format(display_name=display_name),
                reply_markup=reply_markup,
                parse_mode='HTML',
                disable_web_page_preview=True
            )
            
            # Store warning message ID for cleanup
            warning_messages[user.id] = warning_message.message_id
            
            logger.info(f"User {user.id} muted and warned for missing bio")
            
        except BadRequest as e:
            logger.error(f"Error handling message: {e}")
        except Exception as e:
            logger.error(f"Unexpected error: {e}")

async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle button clicks"""
    if not update.callback_query:
        return
    
    query = update.callback_query
    
    # Parse callback data
    callback_data = query.data
    if not callback_data.startswith("verify_"):
        return
    
    try:
        user_id = int(callback_data.split("_")[1])
    except (ValueError, IndexError):
        return
    
    # Only allow the user themselves to verify
    if query.from_user.id != user_id:
        await query.answer(
            text=messages.get('verification_only_self', 'Hanya pengguna yang bersangkutan yang bisa verifikasi.'),
            show_alert=True
        )
        return
    
    # Update user data
    user_data, changes = await update_user_data(query.from_user, context.application)
    
    # Check bio again
    has_required_text, bio = await check_user_bio(user_id, context.application)
    
    if not has_required_text:
        # Bio still doesn't have required text - show popup alert
        if not bio:
            # Bio is empty - likely privacy setting issue
            await query.answer(
                text=messages.get('bio_empty_error', 'Bio anda kosong. Pastikan pengaturan privacy akun telegram di set ke Everybody atau Semua agar bot bisa membacanya, lalu tambahkan @morningcl pada bio dan tunggu beberapa detik untuk verifikasi ulang'),
                show_alert=True
            )
        else:
            # Bio exists but doesn't have required text - show current bio
            await query.answer(
                text=messages.get('bio_incorrect_error', "Bio saat ini: '{bio}'. Ubah bio telegram anda dengan mencantumkan @morningcl, tunggu beberapa detik setelah mengubah bio lalu verifikasi ulang").format(bio=bio),
                show_alert=True
            )
    else:
        # Bio now has required text - unmute user and delete messages
        try:
            # Restore full user permissions (not just can_send_messages)
            await context.application.bot.restrict_chat_member(
                chat_id=update.message.chat.id,
                user_id=user_id,
                permissions={
                    "can_send_messages": True,
                    "can_send_media_messages": True,
                    "can_send_polls": True,
                    "can_send_other_messages": True,
                    "can_add_web_page_previews": True,
                    "can_change_info": False,
                    "can_invite_users": False,
                    "can_pin_messages": False
                }
            )
            
            # Delete the bot warning/welcome message
            await query.delete_message()
            
            # Delete the system join message if exists
            if user_id in system_messages:
                try:
                    await context.application.bot.delete_message(chat_id=update.message.chat.id, message_id=system_messages[user_id])
                    logger.info(f"Deleted system join message for user {user_id}")
                except Exception as e:
                    logger.error(f"Error deleting system message: {e}")
                del system_messages[user_id]
            
            # Remove from warning messages dict
            if user_id in warning_messages:
                del warning_messages[user_id]
            
            logger.info(f"User {user_id} unmuted and verified")
            
        except BadRequest as e:
            logger.error(f"Error unmuting user: {e}")
        except Exception as e:
            logger.error(f"Unexpected error: {e}")

async def handle_new_member(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle new members joining the group"""
    if not update.message or not update.message.chat:
        return
    
    # Only process messages from the target groups
    if update.message.chat.id not in GROUP_IDS:
        return
    
    for new_member in update.message.new_chat_members:
        user = new_member
        
        # Track the system join message for cleanup
        system_messages[user.id] = update.message.message_id
        
        # Update user data
        await update_user_data(user, context.application)
        
        # Skip if user is admin
        if await is_admin(context.application, user.id, update.message.chat.id):
            continue
        
        try:
            # Mute the new member immediately
            await context.application.bot.restrict_chat_member(
                chat_id=update.message.chat.id,
                user_id=user.id,
                permissions={"can_send_messages": False}
            )
            
            # Send welcome message with verification button
            display_name = get_user_display_name(user)
            keyboard = [
                [InlineKeyboardButton(messages.get('verify_button', 'Verifikasi'), callback_data=f"verify_{user.id}")]
            ]
            reply_markup = InlineKeyboardMarkup(keyboard)
            
            welcome_text = messages.get('welcome_message', 'Selamat datang {display_name}\n\nSilakan klik tombol di bawah untuk memverifikasi anda.').format(display_name=display_name)
            
            warning_message = await context.application.bot.send_message(
                chat_id=update.message.chat.id,
                text=welcome_text,
                reply_markup=reply_markup,
                parse_mode='HTML',
                disable_web_page_preview=True
            )
            
            # Store warning message ID for cleanup
            warning_messages[user.id] = warning_message.message_id
            
            logger.info(f"User {user.id} muted on join and welcome message sent")
            
        except BadRequest as e:
            logger.error(f"Error handling new member: {e}")
        except Exception as e:
            logger.error(f"Unexpected error: {e}")

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle /start command (legacy, replaced by start_command)"""
    await update.message.reply_text(
        messages.get('start_message', 'Selamat datang di bot @morningcl')
    )

async def extract_user_from_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    """Extract user ID from command - either from @username or reply"""
    # If replying to a message, use that user
    if update.message.reply_to_message and update.message.reply_to_message.from_user:
        return update.message.reply_to_message.from_user.id, update.message.reply_to_message.from_user
    
    # If @username provided in command
    if context.args and len(context.args) > 0:
        username = context.args[0].lstrip('@')
        
        # Try to find user in users folder by username
        try:
            for filename in os.listdir(USERS_DIR):
                if filename.endswith('.json'):
                    file_path = os.path.join(USERS_DIR, filename)
                    with open(file_path, 'r', encoding='utf-8') as f:
                        user_data = json.load(f)
                        if user_data.get('username', '').lower() == username.lower():
                            # Create a simple user object from stored data
                            from types import SimpleNamespace
                            user = SimpleNamespace(
                                id=user_data['id'],
                                first_name=user_data.get('first_name', ''),
                                last_name=user_data.get('last_name', ''),
                                username=user_data.get('username', '')
                            )
                            return user.id, user
        except:
            pass
        
        # If not found in users folder, try Telegram API (only works for public usernames)
        try:
            user = await context.application.bot.get_chat(username)
            return user.id, user
        except:
            pass
    
    return None, None

async def admin_only(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    """Check if user is admin"""
    if not update.message or not update.message.from_user:
        return False
    
    user_id = update.message.from_user.id
    chat_id = update.message.chat.id if update.message.chat else GROUP_IDS[0]
    
    return await is_admin(context.application, user_id, chat_id)

async def mute_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle mute command"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    user_id, user = await extract_user_from_command(update, context)
    
    if not user_id:
        await update.message.reply_text(messages.get('mute_command_format', 'Gunakan format: /mute @username reason (hanya username publik) atau reply ke user dengan /mute reason'))
        return
    
    # Check if target is admin
    if await is_admin(context.application, user_id, update.message.chat.id):
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('target_is_admin_mute', 'Tidak bisa mute {display_name} karena dia adalah admin').format(display_name=display_name), parse_mode='HTML')
        return
    
    reason = ' '.join(context.args[1:]) if len(context.args) > 1 else messages.get('no_reason', 'Tidak ada alasan')
    
    try:
        await context.application.bot.restrict_chat_member(
            chat_id=update.message.chat.id,
            user_id=user_id,
            permissions={"can_send_messages": False}
        )
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('mute_success', '{display_name} telah di-mute\nAlasan: {reason}').format(display_name=display_name, reason=reason), parse_mode='HTML')
        logger.info(f"User {user_id} muted by admin. Reason: {reason}")
    except Exception as e:
        await update.message.reply_text(messages.get('error_message', 'Terjadi kesalahan: {error}').format(error=e))

async def unmute_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle unmute command"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    user_id, user = await extract_user_from_command(update, context)
    
    if not user_id:
        await update.message.reply_text(messages.get('unmute_command_format', 'Gunakan format: /unmute @username (hanya username publik) atau reply ke user dengan /unmute'))
        return
    
    try:
        # Restore full user permissions (not just can_send_messages)
        await context.application.bot.restrict_chat_member(
            chat_id=update.message.chat.id,
            user_id=user_id,
            permissions={
                "can_send_messages": True,
                "can_send_media_messages": True,
                "can_send_polls": True,
                "can_send_other_messages": True,
                "can_add_web_page_previews": True,
                "can_change_info": False,
                "can_invite_users": False,
                "can_pin_messages": False
            }
        )
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('unmute_success', '{display_name} telah di-unmute').format(display_name=display_name), parse_mode='HTML')
        logger.info(f"User {user_id} unmuted by admin")
    except Exception as e:
        await update.message.reply_text(messages.get('error_message', 'Terjadi kesalahan: {error}').format(error=e))

async def kick_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle kick command"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    user_id, user = await extract_user_from_command(update, context)
    
    if not user_id:
        await update.message.reply_text(messages.get('kick_command_format', 'Gunakan format: /kick @username reason (hanya username publik) atau reply ke user dengan /kick reason'))
        return
    
    # Check if target is admin
    if await is_admin(context.application, user_id, update.message.chat.id):
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('target_is_admin_kick', 'Tidak bisa kick {display_name} karena dia adalah admin').format(display_name=display_name), parse_mode='HTML')
        return
    
    reason = ' '.join(context.args[1:]) if len(context.args) > 1 else messages.get('no_reason', 'Tidak ada alasan')
    
    try:
        await context.application.bot.ban_chat_member(chat_id=update.message.chat.id, user_id=user_id)
        await context.application.bot.unban_chat_member(chat_id=update.message.chat.id, user_id=user_id)
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('kick_success', '{display_name} telah di-kick\nAlasan: {reason}').format(display_name=display_name, reason=reason), parse_mode='HTML')
        logger.info(f"User {user_id} kicked by admin. Reason: {reason}")
    except Exception as e:
        await update.message.reply_text(messages.get('error_message', 'Terjadi kesalahan: {error}').format(error=e))

async def ban_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle ban command"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    user_id, user = await extract_user_from_command(update, context)
    
    if not user_id:
        await update.message.reply_text(messages.get('ban_command_format', 'Gunakan format: /ban @username reason (hanya username publik) atau reply ke user dengan /ban reason'))
        return
    
    # Check if target is admin
    if await is_admin(context.application, user_id, update.message.chat.id):
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('target_is_admin_ban', 'Tidak bisa ban {display_name} karena dia adalah admin').format(display_name=display_name), parse_mode='HTML')
        return
    
    reason = ' '.join(context.args[1:]) if len(context.args) > 1 else messages.get('no_reason', 'Tidak ada alasan')
    
    try:
        await context.application.bot.ban_chat_member(chat_id=update.message.chat.id, user_id=user_id)
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('ban_success', '{display_name} telah di-ban\nAlasan: {reason}').format(display_name=display_name, reason=reason), parse_mode='HTML')
        logger.info(f"User {user_id} banned by admin. Reason: {reason}")
    except Exception as e:
        await update.message.reply_text(messages.get('error_message', 'Terjadi kesalahan: {error}').format(error=e))

async def unban_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle unban command"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    user_id, user = await extract_user_from_command(update, context)
    
    if not user_id:
        await update.message.reply_text(messages.get('unban_command_format', 'Gunakan format: /unban @username (hanya username publik) atau reply ke user dengan /unban'))
        return
    
    try:
        await context.application.bot.unban_chat_member(chat_id=update.message.chat.id, user_id=user_id)
        display_name = get_user_display_name(user)
        await update.message.reply_text(messages.get('unban_success', '{display_name} telah di-unmute').format(display_name=display_name), parse_mode='HTML')
        logger.info(f"User {user_id} unbanned by admin")
    except Exception as e:
        await update.message.reply_text(messages.get('error_message', 'Terjadi kesalahan: {error}').format(error=e))

async def lock_all_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle lock all command - disable all member permissions"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    # Check if "all" argument is provided
    if not context.args or context.args[0].lower() != 'all':
        await update.message.reply_text("Gunakan format: /lock all")
        return
    
    try:
        # Set all permissions to False for all members
        await context.application.bot.set_chat_permissions(
            chat_id=update.message.chat.id,
            permissions={
                "can_send_messages": False,
                "can_send_media_messages": False,
                "can_send_polls": False,
                "can_send_other_messages": False,
                "can_add_web_page_previews": False,
                "can_change_info": False,
                "can_invite_users": False,
                "can_pin_messages": False
            }
        )
        await update.message.reply_text(messages.get('lock_all_success', 'Semua izin member udah dimatiin, grup jadi mode hening jir'), parse_mode='HTML')
        logger.info(f"Chat {update.message.chat.id} locked by admin")
    except Exception as e:
        await update.message.reply_text(messages.get('lock_all_error', 'Gagal matiin izin member: {error}').format(error=e), parse_mode='HTML')

async def unlock_all_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle unlock all command - restore all member permissions"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    # Check if "all" argument is provided
    if not context.args or context.args[0].lower() != 'all':
        await update.message.reply_text("Gunakan format: /unlock all")
        return
    
    try:
        # Set basic permissions to True for all members
        await context.application.bot.set_chat_permissions(
            chat_id=update.message.chat.id,
            permissions={
                "can_send_messages": True,
                "can_send_media_messages": True,
                "can_send_polls": True,
                "can_send_other_messages": True,
                "can_add_web_page_previews": True,
                "can_change_info": False,
                "can_invite_users": False,
                "can_pin_messages": False
            }
        )
        await update.message.reply_text(messages.get('unlock_all_success', 'Semua izin member udah dibuka, grup jadi rame lagi'), parse_mode='HTML')
        logger.info(f"Chat {update.message.chat.id} unlocked by admin")
    except Exception as e:
        await update.message.reply_text(messages.get('unlock_all_error', 'Gagal buka izin member: {error}').format(error=e), parse_mode='HTML')

async def filter_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle filter command - manage keyword filters"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    filters = load_filters()
    
    # List all filters if no arguments
    if not context.args:
        if not filters:
            await update.message.reply_text(messages.get('filter_empty', 'Belum ada filter yang di-set'), parse_mode='HTML')
        else:
            filter_list = "\n".join(f"• <b>{keyword}</b>" for keyword in filters.keys())
            await update.message.reply_text(messages.get('filter_list', '📋 <b>Daftar Filter:</b>\n\n{filters}').format(filters=filter_list), parse_mode='HTML')
        return
    
    # Add new filter if replying to a message
    if not update.message.reply_to_message:
        await update.message.reply_text(messages.get('filter_add_format', 'Reply ke pesan yang mau di-set sebagai filter, lalu gunakan format: /filter <keyword>'))
        return
    
    keyword = context.args[0]
    reply_msg = update.message.reply_to_message
    
    # Determine message type and content
    filter_data = {
        'type': 'text',
        'content': '',
        'file_id': None
    }
    
    if reply_msg.text:
        filter_data['type'] = 'text'
        filter_data['content'] = reply_msg.text
    elif reply_msg.caption:
        filter_data['type'] = 'caption'
        filter_data['content'] = reply_msg.caption
    elif reply_msg.sticker:
        filter_data['type'] = 'sticker'
        filter_data['file_id'] = reply_msg.sticker.file_id
    elif reply_msg.photo:
        filter_data['type'] = 'photo'
        filter_data['file_id'] = reply_msg.photo[-1].file_id
    elif reply_msg.video:
        filter_data['type'] = 'video'
        filter_data['file_id'] = reply_msg.video.file_id
    elif reply_msg.animation:
        filter_data['type'] = 'animation'
        filter_data['file_id'] = reply_msg.animation.file_id
    elif reply_msg.audio:
        filter_data['type'] = 'audio'
        filter_data['file_id'] = reply_msg.audio.file_id
    elif reply_msg.voice:
        filter_data['type'] = 'voice'
        filter_data['file_id'] = reply_msg.voice.file_id
    elif reply_msg.document:
        filter_data['type'] = 'document'
        filter_data['file_id'] = reply_msg.document.file_id
    else:
        await update.message.reply_text(messages.get('filter_no_text', 'Tipe pesan ini gak didukung buat filter'))
        return
    
    # Save filter
    filters[keyword] = filter_data
    save_filters(filters)
    await update.message.reply_text(messages.get('filter_added', 'Filter <b>{keyword}</b> dah gwej sev').format(keyword=keyword), parse_mode='HTML')
    logger.info(f"Filter '{keyword}' added by admin with type {filter_data['type']}")

async def stop_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle stop command - delete keyword filter"""
    if not await admin_only(update, context):
        return
    
    # Check if admin has permission to restrict members
    if not await has_permission(context.application, update.message.from_user.id, update.message.chat.id, 'can_restrict_members'):
        await update.message.reply_text("Lau sape mpruy")
        return
    
    if not context.args:
        await update.message.reply_text(messages.get('filter_del_format', 'Gunakan format: /stop <keyword>'))
        return
    
    filters = load_filters()
    keyword = context.args[0]
    
    if keyword in filters:
        del filters[keyword]
        save_filters(filters)
        await update.message.reply_text(messages.get('filter_deleted', 'Filter <b>{keyword}</b> dah diapus').format(keyword=keyword), parse_mode='HTML')
        logger.info(f"Filter '{keyword}' deleted by admin")
    else:
        await update.message.reply_text(messages.get('filter_not_found', 'Filter <b>{keyword}</b> kaga ada').format(keyword=keyword), parse_mode='HTML')

async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle /start command in private chat"""
    if not update.message or not update.message.chat:
        return
    
    # Only work in private chat
    if update.message.chat.type != 'private':
        return
    
    keyboard = [
        [InlineKeyboardButton(messages.get('help_button', 'Help'), callback_data="help")],
        [InlineKeyboardButton(messages.get('admin_button', 'Panggil Etmin'), callback_data="admin")]
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    
    start_text = messages.get('start_message', 'Selamat datang di bot @morningcl')
    
    await update.message.reply_text(start_text, reply_markup=reply_markup, parse_mode='HTML', disable_web_page_preview=True)

async def help_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle Help button callback"""
    query = update.callback_query
    await query.answer()
    
    help_text = messages.get('help_message', 'Help message')
    
    await query.edit_message_text(help_text, parse_mode='HTML', disable_web_page_preview=True)

async def admin_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle Panggil Etmin button callback"""
    query = update.callback_query
    await query.answer()
    
    keyboard = [
        [InlineKeyboardButton("Morning", url="https://t.me/maddragon66")],
        [InlineKeyboardButton("Gusyen Pesheng", url="https://t.me/gusionfasheng")],
        [InlineKeyboardButton("Rama Gantenk", url="https://t.me/Reckoner1")]
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    
    admin_text = messages.get('admin_message', '👑 <b>ETMIN DERMAWAN (GAK SOMBONG)</b>\n\nKlik tombol di bawah buat hubungin etmin:')
    
    await query.edit_message_text(admin_text, reply_markup=reply_markup, parse_mode='HTML', disable_web_page_preview=True)

def main() -> None:
    """Start the bot"""
    # Create the Application
    application = Application.builder().token(BOT_TOKEN).build()
    
    # Add handlers
    application.add_handler(CommandHandler("start", start_command))
    # Admin commands (only / prefix supported by Telegram)
    application.add_handler(CommandHandler("mute", mute_command))
    application.add_handler(CommandHandler("unmute", unmute_command))
    application.add_handler(CommandHandler("kick", kick_command))
    application.add_handler(CommandHandler("ban", ban_command))
    application.add_handler(CommandHandler("unban", unban_command))
    application.add_handler(CommandHandler("lock", lock_all_command))
    application.add_handler(CommandHandler("unlock", unlock_all_command))
    application.add_handler(CommandHandler("filter", filter_command))
    application.add_handler(CommandHandler("stop", stop_command))
    
    application.add_handler(MessageHandler(filters.StatusUpdate.NEW_CHAT_MEMBERS, handle_new_member))
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
    # Register specific callback handlers first, then general one
    application.add_handler(CallbackQueryHandler(help_callback, pattern="^help$"))
    application.add_handler(CallbackQueryHandler(admin_callback, pattern="^admin$"))
    application.add_handler(CallbackQueryHandler(button_callback))
    
    # Run the bot
    logger.info("Memulai bot...")
    application.run_polling(allowed_updates=Update.ALL_TYPES)

if __name__ == "__main__":
    main()
