import asyncio
import logging

from pydantic_ai import Agent
from telegram import Update
from telegram.ext import Application, CallbackQueryHandler

from app.agent.deps import Deps
from app.channels.telegram.ask_user import handle_callback_query
from app.channels.telegram.handlers import (
    _process_message,
    create_message_handler,
    create_start_command_handler,
)
from app.context import Context
from app.context.state import State
from app.settings import Contacts

logger = logging.getLogger(__name__)


async def run_telegram_bot(ctx: Context, agent_state: State[Agent[Deps, str]]) -> None:
    config = ctx.settings.get()
    application = (
        Application.builder()
        .token(config.channels.telegram_bot_token)
        .concurrent_updates(True)
        .build()
    )

    async def _notify_telegram_authorized(user_id: int) -> None:
        contacts = ctx.contacts.get()
        entry = contacts.telegram.get(str(user_id))
        if entry is None or not entry.pending_messages:
            return

        pending = entry.pending_messages
        ctx.contacts.set(
            lambda c: c.model_copy(
                update={
                    "telegram": {
                        **c.telegram,
                        str(user_id): entry.model_copy(update={"pending_messages": []}),
                    }
                }
            )
        )

        numbered = "\n".join(f"{i + 1}. {msg}" for i, msg in enumerate(pending))
        user_input = (
            f"[Sistema: este usuário acabou de ser autorizado."
            f" Antes da autorização, enviou as seguintes mensagens:\n{numbered}]"
        )

        await _process_message(
            ctx=ctx,
            agent=agent_state.get(),
            user_input=user_input,
            user_id=user_id,
            bot=application.bot,
            chat_id=user_id,
        )

    known_tg_authorized: set[int] = {
        c.user_id for c in ctx.contacts.get().telegram_contacts if c.authorized
    }

    def _on_contacts_change(new_contacts: Contacts) -> None:
        nonlocal known_tg_authorized
        new_authorized = {c.user_id for c in new_contacts.telegram_contacts if c.authorized}
        newly = new_authorized - known_tg_authorized
        known_tg_authorized = new_authorized
        for uid in newly:
            asyncio.create_task(_notify_telegram_authorized(uid))

    ctx.contacts.subscribe(_on_contacts_change)

    start_command_handler = create_start_command_handler(ctx=ctx)
    message_handler = create_message_handler(ctx=ctx, agent_state=agent_state)

    application.add_handler(start_command_handler)
    application.add_handler(message_handler)
    application.add_handler(CallbackQueryHandler(handle_callback_query))

    await application.initialize()
    await application.start()

    try:
        logger.info("Bot started and polling for messages")
        if application.updater is not None:
            await application.updater.start_polling(allowed_updates=list(Update.ALL_TYPES))
        await asyncio.Event().wait()
    finally:
        if application.updater is not None:
            await application.updater.stop()
        await application.stop()
        await application.shutdown()
