import math


def calc_weighted_mean_and_sd(values_list, weights_list):
    """
    Textbook implementation following ref [Dataplot1] (identical to standard statistics definition)
    Simplified here from data format specific version in ASL project handling data tensors
    and calculating lists of means / sds
    :param values_list:
    :param weights_list: weights must be >= 0.0; typically > 0.0; both lists must have equal length
    :return: weighted_mean (float), weighted_sd (float), n (int), non_zero_n (int)
    """
    n = len(values_list)
    if n == 0:
        return 0.0, 0.0, 0, 0

    non_zero_n = 0
    sum = 0.0
    weight_sum = 0.0
    for i, v in enumerate(values_list):
        v = float(v)
        w = float(weights_list[i])
        if w <= 0.0:
            if w < 0.0:
                print('ERROR: calc_weighted_mean(): negative weight detected')
            continue
        non_zero_n += 1
        sum += w * v
        weight_sum += w

    if non_zero_n == 0 or weight_sum == 0.0:
        return 0.0, 0.0, n, non_zero_n

    weighted_mean = sum / weight_sum

    if n == 1:
        return weighted_mean, 0.0, n, non_zero_n

    sum = 0.0
    for i, v in enumerate(values_list):
        v = float(v)
        w = float(weights_list[i])
        delta = v - weighted_mean
        sum += w * delta * delta

    weighted_variance = (sum / weight_sum) * (non_zero_n / (non_zero_n - 1))

    return weighted_mean, math.sqrt(weighted_variance), n, non_zero_n