from collections.abc import Callable
from typing import Any, TypeVar, overload

from .pipe import pipe

A = TypeVar('A')
B = TypeVar('B')
C = TypeVar('C')
D = TypeVar('D')
E = TypeVar('E')
F = TypeVar('F')
G = TypeVar('G')
H = TypeVar('H')
I = TypeVar('I')
J = TypeVar('J')
K = TypeVar('K')
L = TypeVar('L')
M = TypeVar('M')
N = TypeVar('N')
O = TypeVar('O')
P = TypeVar('P')


@overload
def piped(funcA: Callable[[A], B], /) -> Callable[[A], B]: ...


@overload
def piped(funcA: Callable[[A], B], funcB: Callable[[B], C], /) -> Callable[[A], C]: ...


@overload
def piped(funcA: Callable[[A], B], funcB: Callable[[B], C], funcC: Callable[[C], D], /) -> Callable[[A], D]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    /,
) -> Callable[[A], E]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    /,
) -> Callable[[A], F]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    /,
) -> Callable[[A], G]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    /,
) -> Callable[[A], H]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    /,
) -> Callable[[A], I]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    funcI: Callable[[I], J],
    /,
) -> Callable[[A], J]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    funcI: Callable[[I], J],
    funcJ: Callable[[J], K],
    /,
) -> Callable[[A], K]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    funcI: Callable[[I], J],
    funcJ: Callable[[J], K],
    funcK: Callable[[K], L],
    /,
) -> Callable[[A], L]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    funcI: Callable[[I], J],
    funcJ: Callable[[J], K],
    funcK: Callable[[K], L],
    funcL: Callable[[L], M],
    /,
) -> Callable[[A], M]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    funcI: Callable[[I], J],
    funcJ: Callable[[J], K],
    funcK: Callable[[K], L],
    funcL: Callable[[L], M],
    funcM: Callable[[M], N],
    /,
) -> Callable[[A], N]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    funcI: Callable[[I], J],
    funcJ: Callable[[J], K],
    funcK: Callable[[K], L],
    funcL: Callable[[L], M],
    funcM: Callable[[M], N],
    funcN: Callable[[N], O],
    /,
) -> Callable[[A], O]: ...


@overload
def piped(
    funcA: Callable[[A], B],
    funcB: Callable[[B], C],
    funcC: Callable[[C], D],
    funcD: Callable[[D], E],
    funcE: Callable[[E], F],
    funcF: Callable[[F], G],
    funcG: Callable[[G], H],
    funcH: Callable[[H], I],
    funcI: Callable[[I], J],
    funcJ: Callable[[J], K],
    funcK: Callable[[K], L],
    funcL: Callable[[L], M],
    funcM: Callable[[M], N],
    funcN: Callable[[N], O],
    funcO: Callable[[O], P],
    /,
) -> Callable[[A], P]: ...


def piped(*functions: Any) -> Any:
    """
    Data last version of `pipe`.

    Parameters
    ----------
    *functions : Callable
        The functions to compose (positional-only).

    Returns
    -------
    Callable
        The function composed of the given functions.

    See Also
    --------
    pipe

    Examples
    --------
    Data last:
    >>> list(R.map([{'a': 1}, {'a': 2}, {'a': 3}], R.piped(R.prop('a'), R.default_to(0), R.add(1))))
    [2, 3, 4]

    """
    return lambda x: pipe(x, *functions)  # pyright: ignore[reportUnknownVariableType, reportUnknownArgumentType, reportUnknownLambdaType]
