import numpy as np
import mobspy.simulation_logging.log_scripts as simlog


def time_series_average(species_string, mobspy_ts):
    """
    Badly named function - Average between all RUNS inside a single time-series

    :param species_string: (str) species string to perform the average upon
    :param mobspy_ts: (MobsPy TimeSeries) MobsPy time series object
    :return: average_series (list) a list with the average values from all runs
    """

    list_series = []
    for series in mobspy_ts:
        if species_string in series.keys():
            list_series.append(series)

    war_1, war_2 = (True, True)
    for s1 in list_series:
        for s2 in list_series:
            if s1 == s2:
                continue

            if len(s1) != len(s2) and war_1:
                simlog.warning(
                    "Time Series length is different. \n"
                    "MobsPy disregards time-series that have already finished during calculations"
                )
                war_1 = False

            for t1, t2 in zip(s1["Time"], s2["Time"]):
                if t1 != t2 and war_2:
                    simlog.warning(
                        "Times in Time Series Objects are different. \n"
                        "MobsPy calculates the average by index position. Please be careful."
                    )
                war_2 = False

    average_series = []
    for j in range(len(mobspy_ts.get_max_time_for_species(species_string))):
        add = 0
        size = 0
        for series in list_series:
            try:
                add = add + series[species_string][j]
                size += 1
            except IndexError:
                pass
            except KeyError:
                pass

        average_series.append(add / size)

    return average_series


def standard_deviation(species_string, mobspy_ts, average_series=None):
    """
    Standard deviation between all RUNS inside a single time-series

    :param species_string: (str) Species string
    :param mobspy_ts: (MobsPy TimeSeries) MobsPy time series object
    :param average_series: (list) if the average series is given it is not recalculated
    :return: deviation_series (list) a list with the standard deviation values from all runs
    """
    if average_series is None:
        average_series = time_series_average(species_string, mobspy_ts)
    deviation_series = []

    for j in range(len(mobspy_ts.get_max_time_for_species(species_string))):
        add = 0
        size = 0
        for series in mobspy_ts:
            try:
                add = add + (average_series[j] - series[species_string][j]) ** 2
                size += 1
            except IndexError:
                pass
            except KeyError:
                pass

        deviation_series.append(np.sqrt(add / size))

    return deviation_series


def average_plus_standard_deviation(
    species_string, mobspy_ts, average_series=None, deviation_series=None
):
    """
    Standard deviation between all RUNS inside a single time-series

    :param species_string: (str) Species string
    :param mobspy_ts: (MobsPy TimeSeries) MobsPy time series object
    :param average_series: (list) if the average series is given it is not recalculated
    :param deviation_series: (list) if the deviation is given it is not recalculated

    :return: series_average (list) = average value of the run,  plus (list) = average + deviation,
        minus (list) = average - deviation,
    """
    if average_series is None:
        series_average = time_series_average(species_string, mobspy_ts)
    if deviation_series is None:
        series_deviation = standard_deviation(species_string, mobspy_ts)

    plus = []
    minus = []
    for average, deviation in zip(series_average, series_deviation):
        plus.append(average + deviation)
        minus.append(average - deviation)

    return series_average, plus, minus
