"""Bot/dispatcher factory."""

from __future__ import annotations

import logging
from typing import Any

from aiogram import Bot, Dispatcher
from aiogram.client.default import DefaultBotProperties
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.client.telegram import TelegramAPIServer
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.types import ErrorEvent

from app.config import Settings
from app.context import AppContext
from app.handlers import admin, jobs, start, urls
from app.handlers import settings as settings_handlers
from app.middlewares import AccessMiddleware, RateLimitMiddleware

logger = logging.getLogger(__name__)


def create_bot(settings: Settings) -> Bot:
    api = (
        TelegramAPIServer.from_base(settings.telegram_api_base_url)
        if settings.telegram_api_base_url
        else None
    )
    session = AiohttpSession(
        api=api or TelegramAPIServer.from_base("https://api.telegram.org"),
        timeout=float(settings.telegram_upload_timeout + 30),
        proxy=settings.proxy_url,
    )
    return Bot(
        token=settings.bot_token.get_secret_value(),
        session=session,
        default=DefaultBotProperties(
            parse_mode=None,
            link_preview_is_disabled=True,
        ),
    )


async def _on_error(event: ErrorEvent) -> None:
    exc = event.exception
    logger.error(
        "unhandled update error: %s",
        type(exc).__name__,
        exc_info=(type(exc), exc, exc.__traceback__),
    )


def build_dispatcher(ctx: AppContext) -> Dispatcher:
    dispatcher = Dispatcher(storage=MemoryStorage())
    dispatcher["ctx"] = ctx

    dispatcher.message.outer_middleware(AccessMiddleware(ctx.settings.admin_ids))
    dispatcher.callback_query.outer_middleware(
        AccessMiddleware(ctx.settings.admin_ids)
    )
    dispatcher.message.middleware(
        RateLimitMiddleware(ctx.settings.user_rate_limit_seconds)
    )
    dispatcher.callback_query.middleware(
        RateLimitMiddleware(ctx.settings.user_rate_limit_seconds)
    )

    dispatcher.include_router(start.router)
    dispatcher.include_router(urls.router)
    dispatcher.include_router(jobs.router)
    dispatcher.include_router(settings_handlers.router)
    dispatcher.include_router(admin.router)

    dispatcher.errors.register(_on_error)
    return dispatcher


def workflow_summary(ctx: AppContext) -> dict[str, Any]:
    """Small helper for logs/tests; never includes the token."""

    return {
        "allowed_domains": len(ctx.settings.allowed_domains),
        "max_concurrent_downloads": ctx.settings.max_concurrent_downloads,
        "browser_fallback": ctx.settings.browser_fallback_enabled,
        "ffmpeg_available": ctx.processor.available,
    }
