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

from .decorator import make_data_last

T = TypeVar('T')


@overload
def drop_while(iterable: Iterable[T], predicate: Callable[[T], bool], /) -> Iterable[T]: ...


@overload
def drop_while(predicate: Callable[[T], bool], /) -> Callable[[Iterable[T]], Iterable[T]]: ...


@make_data_last
def drop_while(iterable: Iterable[T], predicate: Callable[[T], bool], /) -> Iterable[T]:
    """
    Yields the elements of the iterable after encountering the element that does not satisfy the predicate.

    Yields the element that does not satisfy the predicate.

    Parameters
    ----------
    iterable : Iterable[T]
        Input iterable (positional-only).
    predicate: Callable[[T], bool]
        Predicate to check the elements of the iterable (positional-only).

    Returns
    -------
    Iterable[T]
        Elements of the iterable after encountering the element that does not satisfy the predicate.

    Examples
    --------
    Data first:
    >>> list(R.drop_while([1, 2, 3, 4, 3, 2, 1], R.lt(4)))
    [4, 3, 2, 1]

    Data last:
    >>> R.pipe([1, 2, 3, 4, 3, 2, 1], R.drop_while(R.lt(4)), list)
    [4, 3, 2, 1]

    """
    iterable = iter(iterable)
    for x in iterable:
        if predicate(x):
            continue
        else:
            yield x
            break
    yield from iterable
