from typing import Callable
from typing import Any
from typing import Sequence
import functools


def apply_middlewares(
    func: Callable[..., Any], middlewares: Sequence[Callable[..., Any]]
) -> Callable[..., Any]:
    """
    Apply a list of middlewares to a source function.

    - Middlewares must be structured as: ``middleware(next, *args, **kwargs)``
      and call the next middleware inline.

    >>> def square(x): return x ** 2
    >>> def double(next, x): return next(x * 2)
    >>> def substract_one(next, x): return next(x - 1)

    >>> final = apply_middlewares(square, [double, substract_one])

    >>> final(2)  # ((2 - 1) * 2) ^ 2
    4

    >>> final(10)  # ((10 - 1) * 2) ^ 2
    324
    """
    tail = func
    for mw in middlewares:
        if not callable(mw):
            raise TypeError("Middleware should be a callable")

        tail = functools.partial(mw, tail)

    return tail