# -*- coding: utf-8 -*-

from functools import wraps
from logging import Logger
from time import sleep
from typing import Tuple, Callable


def retry(
        fcn: Callable = None, tries: int = 3, delay: int = 1, backoff: int = 2,
        exceptions: Tuple = (Exception,), logger: Logger = None):

    """ Retry calling the decorated function using an exponential backoff """

    def decorator_retry(_fcn):
        @wraps(_fcn)
        def function_retry(*args, **kwargs):
            _tries, _delay = tries, delay
            while _tries > 1:
                try:
                    return _fcn(*args, **kwargs)

                except exceptions as error:
                    if logger:
                        logger.warning(f"Retrying in {_delay}. Because: {error}")

                    sleep(delay)
                    _tries -= 1
                    _delay *= backoff

            return _fcn(*args, **kwargs)

        return function_retry

    if not fcn:
        return decorator_retry

    return decorator_retry(fcn)
