from typing import Callable
from typing import Any
from typing import Tuple
import time


def time_fn(fn: Callable) -> Callable:
    """Decorator/wrapper for to measure the execution of a callable.
    A function using this decorator will return a tuple whose
    first item is the result of the function itself, and the
    second item is the measured execution time.

    Args:
        fn (Callable): a callable whose execution time will be measured,
        the function can also sepcify its own timer function, which
        will be used in place of time.monotonic

    Returns:
        Callable: a wrapper that returns the result of the wrapped
            function and the measured execution time
    """
    def wrapper(*args: Any,
                **kwargs: Any) -> Tuple[Any, float]:

        timer = kwargs.get("timer")
        if timer is None:
            timer = time.monotonic

        st = timer()
        res = fn(*args, **kwargs)
        elapsed = timer() - st

        return res, elapsed
    return wrapper