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

from remedapy.ceil import NonPositiveInt
from remedapy.decorator import make_data_last

TNum = TypeVar('TNum', int, float)


@overload
def floor(precision: NonPositiveInt, /) -> Callable[[int | float], int]: ...
@overload
@overload
def floor(precision: int, /) -> Callable[[TNum], TNum]: ...


@overload
def floor(value: int | float, precision: NonPositiveInt, /) -> int: ...


@overload
def floor(value: TNum, precision: int, /) -> TNum: ...


@make_data_last
def floor(
    value: int | float,
    precision: int,
    /,
) -> int | float:
    """
    Rounds down a given number to a specific precision.

    Parameters
    ----------
    value : int | float
        Number to round down (positional-only).
    precision : int
        Desired precision (positional-only).

    Returns
    -------
    int | float
        rounded value, int if precision is non-positive, otherwise float.

    Examples
    --------
    Data first:
    >>> R.floor(123.9876, 3)
    123.987
    >>> R.floor(8541.1, -1)
    8540

    Data last:
    >>> R.floor(1)(483.22243)
    483.2
    >>> R.floor(-3)(456789)
    456000

    """
    if precision == 0:
        return math.floor(value)
    factor = 10**precision
    result = math.floor(value * factor) / factor
    if precision > 0:
        return result
    return int(result)
