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

from remedapy.decorator import make_data_last

T = TypeVar('T')


@overload
def first() -> Callable[[Iterable[T]], T | None]: ...


@overload
def first(iterable: Iterable[T], /) -> T | None: ...


@make_data_last
def first(iterable: Iterable[T], /) -> T | None:
    """
    Returns the first element of the iterable.

    If the iterable is empty, returns `None`.

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

    Returns
    -------
    T | None
        First element of the iterable or `None` if the iterable is empty.

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

    Data last:
    >>> R.pipe([1, 2, 4, 8, 16], R.filter(R.gt(3)), R.first(), R.default_to(0), R.add(1))
    5

    """
    x = next(iter(iterable), None)
    return x
