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

from .decorator import make_data_last
from .find_last_index import find_last_index

T = TypeVar('T')


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


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


@make_data_last
def drop_last_while(iterable: Iterable[T], predicate: Callable[[T], bool], /) -> list[T]:
    """
    Returns the elements of the iterable until the last one that does not satisfy the predicate.

    Does return that last element that does not satisfy the predicate.

    Tantamount to skipping all the elements of the iterable from the end
    until the first element that does not satisfy the predicate,
    but the elements are returned in the original order.

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

    Returns
    -------
    list[T]
        Elements of the iterable from the last one that does not satisfy the predicate.

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

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

    """
    list_ = list(iterable)
    index = find_last_index(list_, lambda x: not predicate(x))
    return list_[: index + 1]
