from collections.abc import Awaitable, Callable
from typing import Any

from maxapi.filters.middleware import BaseMiddleware
from maxapi.types.updates.bot_started import BotStarted
from maxapi.types.updates.message_callback import MessageCallback
from maxapi.types.updates.message_created import MessageCreated

from bot.logging_setup import get_logger
from database.queries.bot_users import get_bot_user_by_max_id
from database.queries.message_log import log_message

logger = get_logger("bot.middleware")


def _user_label(bot_user: dict | None, user_id: int | None) -> str:
    if bot_user:
        name = bot_user.get("first_name") or bot_user.get("username") or ""
        return f"user_id={bot_user['max_user_id']} ({name})" if name else f"user_id={bot_user['max_user_id']}"
    return f"user_id={user_id}"


class AuthMiddleware(BaseMiddleware):
    async def __call__(
        self,
        handler: Callable[[Any, dict[str, Any]], Awaitable[Any]],
        event: Any,
        data: dict[str, Any],
    ) -> Any:
        update_type = getattr(event, "update_type", type(event).__name__)

        # BotStarted — всегда пропускаем
        if isinstance(event, BotStarted):
            logger.info("▶ bot_started | user_id=%s chat_id=%s", event.user.user_id, event.chat_id)
            return await handler(event, data)

        # /start — пропускаем без авторизации
        if isinstance(event, MessageCreated):
            body = event.message.body
            text = (body.text or "").strip() if body else ""
            if text.lower().startswith("/start"):
                ids = event.get_ids()
                logger.info("▶ /start | user_id=%s", ids[1])
                return await handler(event, data)

        # Получаем user_id
        ids = event.get_ids()
        user_id = ids[1] if ids else None
        chat_id = ids[0] if ids else None
        if user_id is None:
            return

        bot_user = await get_bot_user_by_max_id(user_id)

        if bot_user is None:
            logger.debug("⚠ unknown user_id=%s | %s — ignored", user_id, update_type)
            return

        if bot_user["is_blocked"]:
            logger.info("🚫 blocked %s | %s — ignored", _user_label(bot_user, user_id), update_type)
            return

        if not bot_user["is_authorized"]:
            # Пропускаем шаринг контакта — это шаг авторизации
            if isinstance(event, MessageCreated):
                body = event.message.body
                if body and body.attachments:
                    from maxapi.enums.attachment import AttachmentType
                    for att in body.attachments:
                        if getattr(att, "type", None) == AttachmentType.CONTACT:
                            logger.info(
                                "📱 contact shared | %s",
                                _user_label(bot_user, user_id),
                            )
                            data["bot_user"] = bot_user
                            return await handler(event, data)
            logger.debug("⚠ not authorized %s | %s — ignored", _user_label(bot_user, user_id), update_type)
            return

        data["bot_user"] = bot_user

        # Логируем входящие сообщения
        if isinstance(event, MessageCreated):
            body = event.message.body
            text_preview = ""
            atts = []
            if body:
                text_preview = (body.text or "")[:80]
                if body.attachments:
                    for a in body.attachments:
                        atts.append({"type": str(getattr(a, "type", ""))})
            logger.info(
                "💬 message | %s | chat=%s | text=%r | attachments=%s",
                _user_label(bot_user, user_id), chat_id,
                text_preview, [a["type"] for a in atts] or None,
            )
            await log_message(
                direction="in",
                max_user_id=user_id,
                max_chat_id=chat_id,
                message_id=body.mid if body else None,
                text=body.text if body else None,
                attachments=atts or None,
            )

        elif isinstance(event, MessageCallback):
            payload = event.callback.payload or ""
            logger.info(
                "🔘 callback | %s | chat=%s | payload=%r",
                _user_label(bot_user, user_id), chat_id, payload,
            )

        else:
            logger.info(
                "📨 %s | %s | chat=%s",
                update_type, _user_label(bot_user, user_id), chat_id,
            )

        return await handler(event, data)
