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

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 pipe(data: A, funcA: Callable[[A], B], /) -> B: ...


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


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


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


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


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


@overload
def pipe(
    data: A,
    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],
    /,
) -> H: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> I: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> J: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> K: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> L: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> M: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> N: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> O: ...


@overload
def pipe(
    data: A,
    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],
    /,
) -> P: ...


def pipe(data: Any, *functions: Any) -> Any:
    """
    Performs left-to-right function composition, passing data through functions in sequence.

    Each function receives the output of the previous function.

    Parameters
    ----------
    data: Any
        The data to pass to the first function (positional-only).
    *functions : Callable
        The functions to compose (positional-only).

    Returns
    -------
    Any
        The result of the composed functions.

    See Also
    --------
    piped

    Examples
    --------
    Data first:
    >>> R.pipe({'a': 'x', 'b': 'y', 'c': 'z'}, R.values(), list)
    ['x', 'y', 'z']

    """
    for fn in functions:
        data = fn(data)
    return data
