"""
Управление вебхуком бота через класс-менеджер
"""
import secrets
from typing import Optional

from aiohttp import web
from aiogram import Bot, Dispatcher
from aiogram.types import WebhookInfo
from aiogram.webhook.aiohttp_server import SimpleRequestHandler, setup_application

from configs import settings
from middleware.loggers import logger

__all__ = ('WebhookManager',)


class WebhookManager:
    """
    Менеджер для управления webhook режимом.

    Инкапсулирует всю логику работы с webhook:
    - Создание aiohttp приложения
    - Регистрация handlers
    - Установка/удаление webhook
    - Запуск webhook сервера

    Attributes:
        bot: Экземпляр бота
        dp: Диспетчер
        app: aiohttp приложение
        secret_token: Секретный токен для webhook
    """

    def __init__(self, bot: Bot, dp: Dispatcher):
        """
        Args:
            bot: Экземпляр бота
            dp: Диспетчер
        """
        self.bot = bot
        self.dp = dp
        self.app = web.Application()
        self._configured = False

        # Генерируем или используем существующий токен
        self.secret_token = self._get_or_generate_token()

    def _get_or_generate_token(self) -> str:
        """
        Получает токен из настроек или генерирует новый.

        Returns:
            str: Секретный токен
        """
        if hasattr(settings, 'SECRET_TOKEN') and settings.SECRET_TOKEN:
            logger.debug("Используется SECRET_TOKEN из настроек", log_type='WEBHOOK')
            return settings.SECRET_TOKEN

        # Генерируем случайный токен (32 символа)
        token = secrets.token_urlsafe(32)
        logger.info(
            f"🔐 Сгенерирован новый SECRET_TOKEN: {token[:8]}...",
            log_type='WEBHOOK'
        )
        return token

    async def get_info(self) -> WebhookInfo:
        """
        Получает информацию о текущем вебхуке.

        Returns:
            WebhookInfo: Информация о вебхуке
        """
        try:
            info = await self.bot.get_webhook_info()
            logger.debug(
                f"Webhook URL: {info.url or 'не установлен'}",
                log_type='WEBHOOK'
            )
            return info
        except Exception as e:
            logger.error(
                f"Ошибка получения информации о вебхуке: {e}",
                log_type='WEBHOOK'
            )
            raise

    async def delete(self, drop_pending_updates: bool = True) -> bool:
        """
        Удаляет текущий вебхук.

        Args:
            drop_pending_updates: Удалить накопленные обновления

        Returns:
            bool: True если удаление успешно
        """
        try:
            result = await self.bot.delete_webhook(
                drop_pending_updates=drop_pending_updates
            )

            if result:
                logger.success("✓ Вебхук успешно удален", log_type='WEBHOOK')
            else:
                logger.debug("Вебхук не был установлен", log_type='WEBHOOK')

            return result

        except Exception as e:
            logger.error(f"Ошибка удаления вебхука: {e}", log_type='WEBHOOK')
            return False

    async def setup(
        self,
        webhook_url: Optional[str] = None,
        secret_token: Optional[str] = None,
        drop_pending_updates: bool = True
    ) -> bool:
        """
        Устанавливает вебхук для бота.

        Args:
            webhook_url: URL вебхука (если None, берется из settings)
            secret_token: Секретный токен (если None, используется self.secret_token)
            drop_pending_updates: Удалить накопленные обновления

        Returns:
            bool: True если установка успешна
        """
        url = webhook_url or settings.WEBHOOK_URL
        token = secret_token or self.secret_token

        if not url:
            logger.error("WEBHOOK_URL не установлен", log_type='WEBHOOK')
            return False

        try:
            # Проверяем текущий webhook
            current_info = await self.bot.get_webhook_info()

            # Если уже установлен правильный URL, не трогаем
            if current_info.url == url:
                logger.info(
                    f"✓ Webhook уже установлен на {url}",
                    log_type='WEBHOOK'
                )
                return True

            # Удаляем старый webhook если есть
            if current_info.url:
                logger.debug(f"Удаление старого webhook: {current_info.url}", log_type='WEBHOOK')
                await self.delete(drop_pending_updates=drop_pending_updates)

                # Небольшая задержка
                import asyncio
                await asyncio.sleep(0.5)

            # Устанавливаем новый
            result = await self.bot.set_webhook(
                url=url,
                secret_token=token,
                drop_pending_updates=drop_pending_updates
            )

            if result:
                logger.success(f"✓ Вебхук установлен: {url}", log_type='WEBHOOK')
            else:
                logger.error("❌ Не удалось установить вебхук", log_type='WEBHOOK')

            return result

        except Exception as e:
            logger.error(f"❌ Ошибка установки вебхука: {e}", log_type='WEBHOOK')
            return False

    def configure(
        self,
        webhook_path: Optional[str] = None,
        secret_token: Optional[str] = None
    ) -> None:
        """
        Конфигурирует webhook handler для aiohttp app.

        Args:
            webhook_path: Путь для webhook (если None, извлекается из WEBHOOK_URL)
            secret_token: Секретный токен (если None, используется self.secret_token)
        """
        if self._configured:
            logger.warning("Webhook уже сконфигурирован", log_type='WEBHOOK')
            return

        # Определяем путь из WEBHOOK_URL
        if webhook_path:
            path = webhook_path
        elif settings.WEBHOOK_URL:
            from urllib.parse import urlparse
            parsed = urlparse(settings.WEBHOOK_URL)
            path = parsed.path if parsed.path else "/webhook"
        else:
            path = "/webhook"

        # Используем токен
        token = secret_token or self.secret_token

        # Создаём webhook handler
        webhook_handler = SimpleRequestHandler(
            dispatcher=self.dp,
            bot=self.bot,
            secret_token=token
        )

        # Регистрируем в aiohttp app
        webhook_handler.register(self.app, path=path)
        setup_application(self.app, self.dp, bot=self.bot)

        self._configured = True
        logger.success(
            f"✓ Webhook handler настроен на путь: {path}",
            log_type='WEBHOOK'
        )

    def run(
        self,
        host: Optional[str] = None,
        port: Optional[int] = None,
        access_log: Optional[bool] = None
    ) -> None:
        """
        Запускает webhook сервер (блокирующий вызов).

        Args:
            host: Хост сервера (если None, берется из settings)
            port: Порт сервера (если None, берется из settings)
            access_log: Логировать запросы (если None, берется из settings)
        """
        if not self._configured:
            logger.error(
                "Webhook не сконфигурирован! Вызовите configure() перед run()",
                log_type='WEBHOOK'
            )
            return

        host = host or settings.WEBAPP_HOST
        port = port or settings.WEBAPP_PORT
        access_log_enabled = access_log if access_log is not None else settings.ACCES_LOG

        logger.info(
            f"🌐 Запуск webhook сервера: {host}:{port}",
            log_type='WEBHOOK'
        )

        web.run_app(
            self.app,
            host=host,
            port=port,
            access_log=logger if access_log_enabled else None
        )
