"""Middleware system for the DexFather SDK.

Middlewares wrap the update dispatch pipeline and execute in
registration order (first registered = outermost).  Each middleware
receives the next handler in the chain plus the incoming
:class:`~dexfather.types.Update` and can run arbitrary pre/post
processing.

Usage::

    from dexfather.middleware import BaseMiddleware, LoggingMiddleware

    class TimingMiddleware(BaseMiddleware):
        async def __call__(self, handler, update, bot):
            import time
            start = time.monotonic()
            result = await handler(update, bot)
            elapsed = (time.monotonic() - start) * 1000
            print(f"Update {update.update_id} handled in {elapsed:.1f}ms")
            return result

    bot.add_middleware(TimingMiddleware())
    bot.add_middleware(LoggingMiddleware())
"""

from __future__ import annotations

from typing import Any, Awaitable, Callable, Protocol, runtime_checkable

from .types import Update


@runtime_checkable
class Middleware(Protocol):
    """Protocol for middleware classes."""

    async def __call__(
        self,
        handler: Callable[[Update, Any], Awaitable[Any]],
        update: Update,
        bot: Any,
    ) -> Any: ...


class BaseMiddleware:
    """Base class for user-defined middlewares.

    Override ``__call__`` to add pre/post processing around update
    handling.  The default implementation simply passes through to the
    next handler in the chain.

    Example::

        class TimingMiddleware(BaseMiddleware):
            async def __call__(self, handler, update, bot):
                start = time.monotonic()
                result = await handler(update, bot)
                elapsed = (time.monotonic() - start) * 1000
                print(f"Update {update.update_id} handled in {elapsed:.1f}ms")
                return result
    """

    async def __call__(
        self,
        handler: Callable[[Update, Any], Awaitable[Any]],
        update: Update,
        bot: Any,
    ) -> Any:
        return await handler(update, bot)


class LoggingMiddleware(BaseMiddleware):
    """Built-in middleware that logs every incoming update with structlog."""

    async def __call__(
        self,
        handler: Callable[[Update, Any], Awaitable[Any]],
        update: Update,
        bot: Any,
    ) -> Any:
        from ._logging import get_logger

        log = get_logger("dexfather.middleware")
        log.info(
            "update_received",
            update_id=update.update_id,
            has_message=update.message is not None,
            has_callback=update.callback_query is not None,
            has_inline=update.inline_query is not None,
        )
        try:
            result = await handler(update, bot)
            log.info("update_handled", update_id=update.update_id)
            return result
        except Exception as e:
            log.error(
                "update_error",
                update_id=update.update_id,
                error=str(e),
                exc_info=True,
            )
            raise
