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

from remedapy.decorator import make_data_last

T = TypeVar('T')
K = TypeVar('K')
V = TypeVar('V')


@overload
def map_to_obj(data: Iterable[T], fn: Callable[[T], tuple[K, V]], /) -> dict[K, V]: ...


@overload
def map_to_obj(fn: Callable[[T], tuple[K, V]], /) -> Callable[[Iterable[T]], dict[K, V]]: ...


@make_data_last
def map_to_obj(
    iterable: Iterable[T],
    function: Callable[[T], tuple[K, V]],
    /,
) -> dict[K, V]:
    """
    Given an iterable and a function returning key-value pairs returns a dict.

    Parameters
    ----------
    iterable : iterable
        Iterable to sum (positional-only).
    function: Callable[[T], tuple[K, V]]
        The function to apply to each element of the iterable (positional-only).

    Returns
    -------
    dict[K, V]
        The dict.

    See Also
    --------
    index_by

    Examples
    --------
    Data first:
    >>> R.map_to_obj([1, 2, 3], lambda x: (str(x), x * 2))
    {'1': 2, '2': 4, '3': 6}

    Data last:
    >>> R.pipe([1, 2, 3], R.map_to_obj(lambda x: (str(x), x * 2)))
    {'1': 2, '2': 4, '3': 6}

    """
    return dict(function(x) for x in iterable)
