from typing import Callable
from typing import Tuple


def find_upper_and_lower_integral_upper_bound(
    get_integral_value: Callable[[float], Tuple[float, float]],
    target_value: float,
    min_upper_bound: float,
    max_upper_bound: float,
) -> Tuple[float, float]:
    """
    This function finds approximate lower and upper integral bounds for the
    upper limit of integration
    """

    lower_test_upper_bound: float = min_upper_bound
    upper_test_upper_bound: float = min_upper_bound

    upper_test_value: float = 0

    while upper_test_upper_bound < max_upper_bound:
        result: Tuple[float, float] = get_integral_value(upper_test_upper_bound)
        (upper_test_value, _) = result

        if upper_test_value >= target_value:
            break

        lower_test_upper_bound = upper_test_upper_bound

        upper_test_upper_bound = (upper_test_upper_bound + 1) * 2

    # If we hit the maximum upper bound, then we assume that the true upper
    # bound is infinite
    if upper_test_value < target_value:
        raise RuntimeWarning("max_upper bound reached")

    return (lower_test_upper_bound, upper_test_upper_bound)