from typing import Tuple
from typing import List


def get_increasing_thresholds_for_bin_splitting(
    range_min: float, range_max: float, bin_thresh_increase: float, bin_count: int
) -> Tuple[List[float], List[float]]:
    """
    This splits the interval [range_min, range_max] in bins that increase by
    range_increase. So it returns the thresholds computed as:
    '''
    bin[i] = range_increase * bin[i-1]
    threshold[i] = threshold[i-1] + bin[i]
    '''
    The bin[0] is computed so that the final number of bins (following that rule)
    is 'bin_count' and it covers the whole range following the rules above.

    Parameters
    ----------
    range_min: float
        Minimum value of the range to split
    range_max: float
        Maximum value of the range to split
    bin_thresh_increase: float
        How much the next bin is increased w.r.t the previous bin
        (bin[i] = range_increase * bin[i-1])
    bin_count:
        Number of bins that you want to create

    Returns
    -------
    thresh_list: List
        List of thresholds that split the range between range_min and range_max
    bin_size_list: List
        List of bin sizes (i.e. threshold[i+1] - threshold[i]). It can be useful if
        reused in later computations (without recalculating)

    """
    tot_range = range_max - range_min
    # Set the first threshold as the range_min (minus small value so that range_min
    # is included in further computation)
    thresh_list = [
        range_min - range_min * 1e-10,
    ]
    # Check if the bins are supposed to be the same size, or not
    if bin_thresh_increase == 1:
        thresh_list.extend(
            [tot_range / bin_count * (i + 1) + range_min for i in range(bin_count - 1)]
        )
        bin_size_list = [tot_range / bin_count] * bin_count
    else:
        # Calculate the starting bin so that the bin_count can fit in range
        geometric_serie_sum = (1 - bin_thresh_increase ** bin_count) / (
            1 - bin_thresh_increase
        )
        new_bin_range = tot_range / geometric_serie_sum
        bin_size_list = [
            new_bin_range,
        ]
        # 'bin_count - 1' because the last threshold must correspond to 'range_max'
        for _ in range(bin_count - 1):
            # New threshold
            new_bin_thresh = new_bin_range + thresh_list[-1]
            thresh_list.append(new_bin_thresh)
            # Compute new bin_size by increasing previous one
            new_bin_range = bin_thresh_increase * bin_size_list[-1]
            bin_size_list.append(new_bin_range)
    # Overwrite the last bin so it ends at range_max
    bin_size_list[-1] = range_max - thresh_list[-1]
    thresh_list.append(range_max)

    return thresh_list, bin_size_list