# extergram/core.py

import requests
import json
import time
import asyncio
import inspect
from .ui import ButtonsDesign
from .api_types import Update
from .ext import BaseHandler, MessageHandler, CallbackQueryHandler
from .errors import APIError

class Bot:
    """
    Основной класс для создания Telegram-бота и взаимодействия с API.
    """
    def __init__(self, token: str):
        self.token = token
        self.api_url = f"https://api.telegram.org/bot{self.token}/"
        self.handlers = []
        self._offset = None

    def _make_request(self, method: str, params: dict = None):
        response = requests.post(self.api_url + method, json=params)
        data = response.json()
        if not data.get('ok'):
            raise APIError(data.get('description', 'Unknown error'), data.get('error_code', -1))
        return data

    # --- Новый способ добавления обработчиков ---
    def add_handler(self, handler: BaseHandler):
        """
        Регистрирует новый обработчик событий.
        """
        if not isinstance(handler, BaseHandler):
            raise TypeError("handler must be an instance of BaseHandler")
        self.handlers.append(handler)

    # --- Старые методы-декораторы (теперь используют новую систему) ---
    def on_message(self):
        def decorator(func):
            self.add_handler(MessageHandler(func))
            return func
        return decorator

    def on_callback_query(self):
        def decorator(func):
            self.add_handler(CallbackQueryHandler(func))
            return func
        return decorator

    def _process_updates(self, updates: list):
        if not updates:
            return

        for raw_update in updates:
            self._offset = raw_update['update_id'] + 1
            update = Update(raw_update)

            event = None
            if update.message:
                event = update.message
            elif update.callback_query:
                event = update.callback_query
            
            if event:
                for handler in self.handlers:
                    if handler.check_update(event):
                        # Поддержка синхронных и асинхронных функций
                        if inspect.iscoroutinefunction(handler.callback):
                            asyncio.run(handler.callback(event))
                        else:
                            handler.callback(event)

    def polling(self, interval: int = 0, timeout: int = 30):
        """Запускает бота в режиме длинного опроса."""
        print("Bot started polling...")
        while True:
            try:
                updates_data = self.get_updates(offset=self._offset, timeout=timeout)
                self._process_updates(updates_data.get('result', []))
            except APIError as e:
                print(f"API Error: {e}")
            except Exception as e:
                print(f"An error occurred: {e}")
                time.sleep(5)
            
            time.sleep(interval)

    # --- Методы API ---
    def get_updates(self, offset: int = None, timeout: int = 30):
        params = {'timeout': timeout, 'offset': offset}
        return self._make_request('getUpdates', params)

    def send_message(self, chat_id: int, text: str, parse_mode: str = None, reply_markup: dict = None):
        params = {'chat_id': chat_id, 'text': text}
        if parse_mode:
            params['parse_mode'] = parse_mode
        if isinstance(reply_markup, ButtonsDesign):
            params['reply_markup'] = reply_markup.to_dict()
        elif reply_markup:
            params['reply_markup'] = reply_markup
        return self._make_request('sendMessage', params)

    def edit_message_text(self, chat_id: int, message_id: int, text: str, parse_mode: str = None, reply_markup: dict = None):
        params = {'chat_id': chat_id, 'message_id': message_id, 'text': text}
        if parse_mode:
            params['parse_mode'] = parse_mode
        if isinstance(reply_markup, ButtonsDesign):
            params['reply_markup'] = reply_markup.to_dict()
        elif reply_markup:
            params['reply_markup'] = reply_markup
        return self._make_request('editMessageText', params)
    
    def answer_callback_query(self, callback_query_id: str, text: str = None, show_alert: bool = False):
        params = {'callback_query_id': callback_query_id}
        if text:
            params['text'] = text
        params['show_alert'] = show_alert
        return self._make_request('answerCallbackQuery', params)
        
    def delete_message(self, chat_id: int, message_id: int):
        params = {'chat_id': chat_id, 'message_id': message_id}
        return self._make_request('deleteMessage', params)