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

from remedapy.decorator import make_data_last

Key = TypeVar('Key', str, int)
T = TypeVar('T')


@overload
def path_or(data: dict[Key, Any], path: Iterable[str | int], default: T, /) -> T | Any: ...


@overload
def path_or(path: Iterable[str | int], default: T, /) -> Callable[[dict[Key, Any]], T | Any]: ...


@make_data_last
def path_or(data: dict[Key, Any], path: Iterable[str | int], default: T, /) -> T | Any:
    """
    Returns the value at the given path or the default value.

    Parameters
    ----------
    data: dict[K, V]
        The dict to get the value from.
    path: list[int | str]
        The path to get the value from.
    default: V
        The default value to return if the path is not found.

    Returns
    -------
    T | Any
        The value at the given path or the default value.

    Examples
    --------
    Data first:
    >>> R.path_or({'x': 10}, ['y'], 2)
    2
    >>> R.path_or({'y': 10}, ['y'], 2)
    10
    >>> R.path_or({'y': {'x': 10}}, ['y', 'x'], 2)
    10
    >>> R.path_or({'y': {'x': 10}}, ['y', 'y'], 2)
    2

    Data last:
    >>> R.pipe({'x': 10}, R.path_or(['y'], 2))
    2
    >>> R.pipe({'y': 10}, R.path_or(['y'], 2))
    10

    """
    current = data
    for i in path:
        try:
            current = current[i]  # pyright: ignore[reportArgumentType]
        except (KeyError, IndexError):
            return default
    return current
