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

from remedapy.decorator import make_data_last

T = TypeVar('T')
U = TypeVar('U')


@overload
def concat(data: Iterable[T], other: Iterable[U], /) -> Iterable[T | U]: ...


@overload
def concat(other: Iterable[U], /) -> Callable[[Iterable[T]], Iterable[T | U]]: ...


# TODO: variadic
@make_data_last
def concat(
    iterable1: Iterable[T],
    iterable2: Iterable[U],
    /,
) -> Iterable[T | U]:
    """
    Yields from one iterable and then from the other.

    Parameters
    ----------
    iterable1: Iterable[T]
        First iterable.
    iterable2: Iterable[U]
        Second iterable.

    Returns
    -------
    result: Iterable[T | U]
        Iterable being the result of concatenation.

    Examples
    --------
    Data first:
    >>> list(R.concat([1,2,3], [4,5,6]))
    [1, 2, 3, 4, 5, 6]

    Data last:
    >>> list(R.concat([4,5,6])([1,2,3]))
    [1, 2, 3, 4, 5, 6]

    """
    yield from iterable1
    yield from iterable2
