import telebot
from telebot.types import ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup, InlineKeyboardButton, ReplyKeyboardRemove, ForceReply
import sys
import traceback
import os
import requests
from io import BytesIO

class telegram:
    def __init__(self):
        self.bot = None
        self.commandhandlers = {}
        self.messagehandler = None
        
    def commands(self, commandlist):
        def decorator(func):
            for cmd in commandlist:
                self.commandhandlers[cmd] = func
            return func
        return decorator
    
    def message(self):
        def decorator(func):
            self.messagehandler = func
            return func
        return decorator
    
    def run(self, token):
        try:
            self.bot = telebot.TeleBot(token)
            
            for cmd, handler in self.commandhandlers.items():
                @self.bot.message_handler(commands=[cmd])
                def handlecommand(message, handler=handler):
                    try:
                        result = handler(message)
                        self.response(message, result)
                    except Exception:
                        error_msg = self.get_clean_error()
                        print(f"Handler Error: {error_msg}")
                        self.bot.reply_to(message, "Command execution failed")
            
            if self.messagehandler:
                @self.bot.message_handler(func=lambda message: True)
                def handlemessage(message):
                    try:
                        result = self.messagehandler(message)
                        self.response(message, result)
                    except Exception:
                        error_msg = self.get_clean_error()
                        print(f"Message Error: {error_msg}")
                        self.bot.reply_to(message, "Message processing failed")
            
            print("Bot running")
            self.bot.polling(none_stop=True, timeout=60)
            
        except Exception:
            error_msg = self.get_clean_error()
            print(f"Bot Error: {error_msg}")
    
    def get_clean_error(self):
        exc_type, exc_value, exc_traceback = sys.exc_info()
        tb_list = traceback.format_exception(exc_type, exc_value, exc_traceback)
        clean_tb = []
        for line in tb_list:
            if 'file' not in line.lower() and 'line' not in line.lower():
                clean_tb.append(line.strip())
        return ' '.join(clean_tb).replace('\n', ' ')
    
    def get_file_content(self, file_input):
        if isinstance(file_input, str):
            if file_input.startswith(('http://', 'https://')):
                response = requests.get(file_input)
                response.raise_for_status()
                return BytesIO(response.content)
            elif os.path.exists(file_input):
                with open(file_input, 'rb') as f:
                    return BytesIO(f.read())
            else:
                return file_input
        return file_input
    
    def response(self, message, result):
        try:
            if isinstance(result, dict):
                msg_type = result.get('type')
                
                if msg_type == 'photo':
                    photo_content = self.get_file_content(result['url'])
                    self.bot.send_photo(message.chat.id, photo_content, caption=result.get('caption', ''))
                
                elif msg_type == 'video':
                    video_content = self.get_file_content(result['url'])
                    self.bot.send_video(message.chat.id, video_content, caption=result.get('caption', ''))
                
                elif msg_type == 'audio':
                    audio_content = self.get_file_content(result['url'])
                    self.bot.send_audio(message.chat.id, audio_content, caption=result.get('caption', ''))
                
                elif msg_type == 'document':
                    doc_content = self.get_file_content(result['url'])
                    self.bot.send_document(message.chat.id, doc_content, caption=result.get('caption', ''))
                
                elif msg_type == 'location':
                    self.bot.send_location(message.chat.id, result['lat'], result['lon'])
                
                elif msg_type == 'contact':
                    self.bot.send_contact(message.chat.id, result['phone'], result['first_name'], result.get('last_name', ''))
                
                elif msg_type == 'poll':
                    self.bot.send_poll(message.chat.id, result['question'], result['options'])
                
                elif msg_type == 'dice':
                    self.bot.send_dice(message.chat.id, result.get('emoji', '🎲'))
                
                elif msg_type == 'sticker':
                    sticker_content = self.get_file_content(result['url'])
                    self.bot.send_sticker(message.chat.id, sticker_content)
                
                elif msg_type == 'voice':
                    voice_content = self.get_file_content(result['url'])
                    self.bot.send_voice(message.chat.id, voice_content, caption=result.get('caption', ''))
                
                elif msg_type == 'animation':
                    animation_content = self.get_file_content(result['url'])
                    self.bot.send_animation(message.chat.id, animation_content, caption=result.get('caption', ''))
                
                elif msg_type == 'venue':
                    self.bot.send_venue(message.chat.id, result['lat'], result['lon'], result['title'], result['address'])
                
                elif msg_type == 'keyboard':
                    markup = ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=result.get('one_time', False))
                    for row in result['buttons']:
                        markup.add(*[KeyboardButton(btn) for btn in row])
                    self.bot.send_message(message.chat.id, result['text'], reply_markup=markup)
                
                elif msg_type == 'inline':
                    markup = InlineKeyboardMarkup()
                    for row in result['buttons']:
                        row_buttons = []
                        for btn in row:
                            if btn.get('url'):
                                row_buttons.append(InlineKeyboardButton(btn['text'], url=btn['url']))
                            elif btn.get('data'):
                                row_buttons.append(InlineKeyboardButton(btn['text'], callback_data=btn['data']))
                            else:
                                row_buttons.append(InlineKeyboardButton(btn['text']))
                        markup.add(*row_buttons)
                    self.bot.send_message(message.chat.id, result['text'], reply_markup=markup)
                
                elif msg_type == 'remove_keyboard':
                    self.bot.send_message(message.chat.id, result['text'], reply_markup=ReplyKeyboardRemove())
                
                elif msg_type == 'force_reply':
                    self.bot.send_message(message.chat.id, result['text'], reply_markup=ForceReply())
                
                elif msg_type == 'delete':
                    self.bot.delete_message(message.chat.id, message.message_id)
                
                elif msg_type == 'edit':
                    self.bot.edit_message_text(result['text'], message.chat.id, message.message_id)
                
                elif msg_type == 'edit_reply_markup':
                    self.bot.edit_message_reply_markup(message.chat.id, message.message_id, reply_markup=result['markup'])
                
                elif msg_type == 'pin':
                    self.bot.pin_chat_message(message.chat.id, message.message_id)
                
                elif msg_type == 'unpin':
                    self.bot.unpin_chat_message(message.chat.id, message.message_id)
                
                elif msg_type == 'unpin_all':
                    self.bot.unpin_all_chat_messages(message.chat.id)
                
                elif msg_type == 'forward':
                    self.bot.forward_message(result['to_chat_id'], message.chat.id, message.message_id)
                
                elif msg_type == 'copy':
                    self.bot.copy_message(result['to_chat_id'], message.chat.id, message.message_id)
                
                elif msg_type == 'restrict':
                    self.bot.restrict_chat_member(message.chat.id, result['user_id'], 
                                                until_date=result.get('until_date'),
                                                can_send_messages=result.get('can_send_messages', False),
                                                can_send_media_messages=result.get('can_send_media_messages', False),
                                                can_send_polls=result.get('can_send_polls', False),
                                                can_send_other_messages=result.get('can_send_other_messages', False),
                                                can_add_web_page_previews=result.get('can_add_web_page_previews', False))
                
                elif msg_type == 'promote':
                    self.bot.promote_chat_member(message.chat.id, result['user_id'],
                                               can_change_info=result.get('can_change_info', False),
                                               can_post_messages=result.get('can_post_messages', False),
                                               can_edit_messages=result.get('can_edit_messages', False),
                                               can_delete_messages=result.get('can_delete_messages', False),
                                               can_invite_users=result.get('can_invite_users', False),
                                               can_restrict_members=result.get('can_restrict_members', False),
                                               can_pin_messages=result.get('can_pin_messages', False),
                                               can_promote_members=result.get('can_promote_members', False))
                
                elif msg_type == 'ban':
                    self.bot.ban_chat_member(message.chat.id, result['user_id'], until_date=result.get('until_date'))
                
                elif msg_type == 'unban':
                    self.bot.unban_chat_member(message.chat.id, result['user_id'])
                
                elif msg_type == 'kick':
                    self.bot.kick_chat_member(message.chat.id, result['user_id'])
                
                elif msg_type == 'leave':
                    self.bot.leave_chat(message.chat.id)
                
                elif msg_type == 'get_chat':
                    chat_info = self.bot.get_chat(message.chat.id)
                    return str(chat_info)
                
                elif msg_type == 'get_chat_members_count':
                    count = self.bot.get_chat_members_count(message.chat.id)
                    return f"Chat members: {count}"
                
                elif msg_type == 'get_chat_member':
                    member = self.bot.get_chat_member(message.chat.id, result['user_id'])
                    return str(member)
                
                elif msg_type == 'set_chat_title':
                    self.bot.set_chat_title(message.chat.id, result['title'])
                
                elif msg_type == 'set_chat_description':
                    self.bot.set_chat_description(message.chat.id, result['description'])
                
                elif msg_type == 'set_chat_photo':
                    photo_content = self.get_file_content(result['url'])
                    self.bot.set_chat_photo(message.chat.id, photo_content)
                
                elif msg_type == 'delete_chat_photo':
                    self.bot.delete_chat_photo(message.chat.id)
                
                elif msg_type == 'export_chat_invite_link':
                    invite_link = self.bot.export_chat_invite_link(message.chat.id)
                    return f"Invite link: {invite_link}"
                
                else:
                    self.bot.reply_to(message, str(result))
            else:
                self.bot.reply_to(message, str(result))
                
        except Exception:
            error_msg = self.get_clean_error()
            print(f"Response Error: {error_msg}")
            self.bot.reply_to(message, "Failed to send response")