from typing import Callable
import time
import shutil


def timeitprint(func: Callable) -> Callable:
    """A decorator for functions, prints execution time of a function as the side effect.

    Use as @timeitprint just above your function definition.

    Args:
        func: A callable, could be any function.

    Returns:
        A wrapped function (callable) that is identicial to the origial function
        with additional side effect: it prints the execution time to stdout.

    Raises:
        None
    """

    def wrapped_function(*args, **kwargs):
        time_start = time.time()
        result = func(*args, **kwargs)
        time_elapsed = time.time() - time_start

        hours, minutes = 0, 0

        if time_elapsed >= 3600:
            hours = int(time_elapsed // 3600)
            time_elapsed = time_elapsed - hours * 3600
        if time_elapsed >= 60:
            minutes = int(time_elapsed // 60)
            time_elapsed = time_elapsed - minutes * 60
        seconds = round(time_elapsed, 3)
        func_name = func.__name__
        try:
            terminal_width = shutil.get_terminal_size().columns
        except:
            terminal_width = 50

        if hours:
            msg = f" Func '{func_name}' finished in {hours} hrs, {minutes} mins, {int(seconds)} secs "
            print("{:=^{width}}\n".format(msg, width=terminal_width))
        elif minutes:
            msg = " Func '{}' finished in {} mins, {:.2f} secs ".format(
                func_name, minutes, seconds
            )
            print("{:=^{width}}\n".format(msg, width=terminal_width))
        else:
            msg = " Func '{}' finished in {:.10f} secs ".format(func_name, seconds)
            print("{:=^{width}}\n".format(msg, width=terminal_width))

        return result

    return wrapped_function