"""
Проста бібліотека для створення Telegram ботів
Спеціально для школярів - без складних конструкцій!

Simple library for creating Telegram bots
Specially for students - no complex constructs!
"""

from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
import asyncio
from typing import Callable, Optional
import traceback
import sys


class SimpleBot:
    """
    Простий Telegram бот для навчання
    
    Приклад використання:
        bot = SimpleBot("YOUR_TOKEN")
        
        bot.on_command("start", "Hello!")
        bot.start()
    """
    
    def __init__(self, token: str):
        """
        Створює нового бота
        
        token: токен від @BotFather в Telegram
        """
        if not token or token == "YOUR_TOKEN" or token == "ВАШ_ТОКЕН":
            print("""
❌ ПОМИЛКА: Ти не вказав токен бота!

📝 Як отримати токен:
1. Відкрий Telegram
2. Знайди @BotFather
3. Напиши йому: /newbot
4. Дай ім'я своєму боту
5. Скопіюй токен (довгий рядок типу 1234567890:ABCdef...)

💡 Потім вставте його в код:
   bot = SimpleBot("1234567890:ABCdef...")
""")
            sys.exit(1)
        
        self._token = token
        self._app = None
        self._command_handlers = {}
        self._message_handlers = []
        self._error_handler = None
        
    def on_command(self, command: str, function_or_text):
        """
        Що робити коли користувач надсилає команду
        
        command: назва команди без / (наприклад: "start", "help")
        function_or_text: або функція, або просто текст для відправки
        
        Приклад 1 (дуже просто - тільки текст):
            bot.on_command("start", "Привіт! 👋")
            bot.on_command("help", "Я можу тобі допомогти!")
        
        Приклад 2 (з функцією):
            def hello(message):
                bot.send(message, "Hello!")
            bot.on_command("start", hello)
        """
        if command.startswith('/'):
            command = command[1:]
        
        # Якщо це рядок, створюємо просту функцію яка його надсилає
        if isinstance(function_or_text, str):
            text = function_or_text
            def simple_handler(message):
                self.send(message, text)
            self._command_handlers[command] = simple_handler
        else:
            # Це функція, реєструємо її
            self._command_handlers[command] = function_or_text
        
    def on_message(self, function):
        """
        Що робити коли користувач надсилає звичайне повідомлення
        
        function: яку функцію викликати. Отримує message як параметр
        
        Приклад:
            def echo(message):
                text = bot.get_text(message)
                bot.send(message, f"Ти написав: {text}")
            
            bot.on_message(echo)
        """
        self._message_handlers.append(function)
    
    def on_error(self, function):
        """
        Що робити якщо виникла помилка
        
        function: функція для обробки помилки. Отримує текст помилки
        
        Приклад:
            def handle_error(error):
                print(f"Щось пішло не так: {error}")
            
            bot.on_error(handle_error)
        """
        self._error_handler = function
        
    def send(self, message, text: str):
        """
        Надіслати відповідь користувачу
        
        message: повідомлення від користувача
        text: що надіслати
        
        Приклад:
            bot.send(message, "Привіт!")
        """
        try:
            chat_id = self._get_chat_id(message)
            loop = asyncio.get_event_loop()
            if loop.is_running():
                asyncio.create_task(
                    self._app.bot.send_message(chat_id=chat_id, text=text)
                )
            else:
                loop.run_until_complete(
                    self._app.bot.send_message(chat_id=chat_id, text=text)
                )
        except Exception as e:
            self._handle_error(f"Помилка при надсиланні: {e}")
    
    def send_photo(self, message, photo_path: str, caption: str = ""):
        """
        Надіслати фото користувачу
        
        message: повідомлення від користувача
        photo_path: шлях до файлу з фото
        caption: текст під фото (не обов'язково)
        
        Приклад:
            bot.send_photo(message, "cat.jpg", "Ось кіт!")
        """
        try:
            chat_id = self._get_chat_id(message)
            loop = asyncio.get_event_loop()
            
            async def _send():
                with open(photo_path, 'rb') as photo:
                    await self._app.bot.send_photo(
                        chat_id=chat_id, 
                        photo=photo, 
                        caption=caption
                    )
            
            if loop.is_running():
                asyncio.create_task(_send())
            else:
                loop.run_until_complete(_send())
        except Exception as e:
            self._handle_error(f"Помилка при надсиланні фото: {e}")
    
    def get_text(self, message) -> str:
        """
        Отримати текст з повідомлення користувача
        
        message: повідомлення від користувача
        
        Повертає: текст повідомлення
        
        Приклад:
            text = bot.get_text(message)
            print(f"Користувач написав: {text}")
        """
        if hasattr(message, 'message') and message.message:
            return message.message.text or ""
        return ""
    
    def get_name(self, message) -> str:
        """
        Отримати ім'я користувача
        
        message: повідомлення від користувача
        
        Повертає: ім'я користувача
        """
        if hasattr(message, 'message') and message.message:
            user = message.message.from_user
            return user.first_name or user.username or "Анонім"
        return "Анонім"
    
    def _get_chat_id(self, message):
        """Внутрішня функція для отримання chat_id"""
        if hasattr(message, 'message') and message.message:
            return message.message.chat_id
        elif hasattr(message, 'chat_id'):
            return message.chat_id
        else:
            raise ValueError("Неможливо знайти chat_id")
    
    def _handle_error(self, error_text: str):
        """Внутрішня функція для обробки помилок"""
        print(f"❌ ПОМИЛКА: {error_text}")
        print("─" * 50)
        
        if self._error_handler:
            try:
                self._error_handler(error_text)
            except Exception as e:
                print(f"Помилка в обробнику помилок: {e}")
    
    def _create_command_handler(self, command: str):
        """Внутрішня функція для створення обробника команди"""
        function = self._command_handlers[command]
        
        async def handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
            try:
                # Викликаємо функцію користувача
                result = function(update)
                # Якщо це coroutine, await його
                if asyncio.iscoroutine(result):
                    await result
            except Exception as e:
                error = f"Помилка в команді /{command}:\n{traceback.format_exc()}"
                self._handle_error(error)
        
        return handler
    
    def _create_message_handler(self, function: Callable):
        """Внутрішня функція для створення обробника повідомлень"""
        async def handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
            try:
                result = function(update)
                if asyncio.iscoroutine(result):
                    await result
            except Exception as e:
                error = f"Помилка при обробці повідомлення:\n{traceback.format_exc()}"
                self._handle_error(error)
        
        return handler
    
    def start(self):
        """
        Запустити бота
        
        Після виклику цієї функції бот почне працювати.
        Програма буде чекати повідомлень від користувачів.
        
        Приклад:
            bot.start()
        """
        print("🤖 Запускаю бота...")
        print("─" * 50)
        
        try:
            # Створюємо додаток
            self._app = Application.builder().token(self._token).build()
            
            # Додаємо обробники команд
            for command, function in self._command_handlers.items():
                handler = self._create_command_handler(command)
                self._app.add_handler(CommandHandler(command, handler))
                print(f"✅ Команда /{command} готова")
            
            # Додаємо обробники повідомлень
            for function in self._message_handlers:
                handler = self._create_message_handler(function)
                self._app.add_handler(
                    MessageHandler(filters.TEXT & ~filters.COMMAND, handler)
                )
                print(f"✅ Обробник повідомлень готовий")
            
            print("─" * 50)
            print("🎉 Бот працює! Натисни Ctrl+C щоб зупинити")
            print("─" * 50)
            
            # Запускаємо
            self._app.run_polling(allowed_updates=Update.ALL_TYPES)
            
        except Exception as e:
            error = f"Критична помилка при запуску:\n{traceback.format_exc()}"
            self._handle_error(error)
            print("\n💡 Підказки:")
            print("1. Перевір чи правильний токен від @BotFather")
            print("2. Перевір підключення до інтернету")
            print("3. Переконайся що бібліотека python-telegram-bot встановлена")
            print("   Встанови командою: pip install python-telegram-bot")
