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

from .decorator import make_data_last

T = TypeVar('T')


@overload
def unique(it: Iterable[T], /) -> Iterable[T]: ...


@overload
def unique() -> Callable[[Iterable[T]], Iterable[T]]: ...


@make_data_last
def unique(iterable: Iterable[T], /) -> Iterable[T]:
    """
    Yields elements of the iterable without duplicates in the order they appear.

    Parameters
    ----------
    iterable: Iterable[T]
        Iterable (positional-only).

    Returns
    -------
    Iterable[T]
        Unique elements from the iterable.

    Examples
    --------
    Data first:
    >>> list(R.unique(['1', '2', '3', '2', '1']))
    ['1', '2', '3']

    Data last:
    >>> R.pipe(['1', '2', '3', '2', '1'], R.unique, list)
    ['1', '2', '3']

    """
    seen = set[T]()
    for x in iterable:
        if x not in seen:
            seen.add(x)
            yield x
