import pendulum
from unify_api.modules.load_analysis.components.load_forecast_cps import (
    ForecastResp, LoadValue,
)
from unify_api.utils.common_utils import choose_list
from unify_api.modules.load_analysis.dao.load_forecast_dao import \
    get_kwh_p_dao, get_pred_p_dao


async def load_forecast_srv(cids, s_time, e_time, interval, slots):
    if interval == 15 * 60:
        # 按日
        time_fmt = "%%Y-%%m-%%d %%H:%%i"
        now_time_fmt = "YYYY-MM-DD HH:mm"
        tbl_name = "company_15min_power"
    elif interval == 86400:
        # 按月
        time_fmt = "%%Y-%%m-%%d"
        now_time_fmt = "YYYY-MM-DD"
        tbl_name = "company_1day_power"
    else:
        # 按年
        time_fmt = "%%Y-%%m"
        now_time_fmt = "YYYY-MM"
        tbl_name = "company_1day_power"

    now_time = pendulum.now().format(now_time_fmt)
    now_month = pendulum.now().format("YYYY-MM")

    # 1,获取实际数据
    real_result = await get_kwh_p_dao(cids, s_time, e_time, tbl_name, time_fmt)
    # if not real_result:
    #     return [], [], [], [], [], [], [], 0, "", 0, "", 0, 0

    real_data = {i["cal_time"]: i for i in real_result}
    real_list, real_power_list = [], []
    for slot in slots:
        if slot in real_data:
            p = real_data[slot]["p"]
            kwh = real_data[slot]["kwh"]
            if slot > now_time:
                value, kwh = "", ""
            elif p in [0, 0.0]:
                value, kwh = 0.0, 0.0
            elif p:
                value = round(p, 2)
                kwh = round(kwh, 2)
            else:
                value, kwh = "", ""
        else:
            value, kwh = "", ""
        real_list.append(value)
        real_power_list.append(kwh)

    # 2,获取预测数据
    forecast_result = await get_pred_p_dao(cids, s_time, e_time, time_fmt)
    # if not forecast_result:
    #     return [], [], [], [], [], [], [], 0, "", 0, "", 0, 0
    forecast_data = {i["cal_time"]: i for i in forecast_result}
    forecast_list, forecast_power_list = [], []
    for slot in slots:
        if slot in forecast_data:
            p = forecast_data[slot]["p"]
            if p in [0, 0.0]:
                value = 0.0
            elif p:
                value = round(p, 2)
            else:
                value = ""
        else:
            value = ""
        forecast_list.append(value)
        if value or value == 0.0:
            p_count = forecast_data[slot]["p_count"]
            power_value = round(value * 0.25 * p_count, 2)
        else:
            power_value = ""
        forecast_power_list.append(power_value)

    # 3.求偏差数据
    deviation_list, deviation_power_list = [], []  # 偏差取绝对值, 最大/最小/平均偏差都是绝对值后数据
    for num, value in enumerate(real_list):
        if not value or not forecast_list[num]:
            deviation_list.append("")
        else:
            # (预测-实际)/实际 * 100%
            deviation = (forecast_list[num] - value) / value
            deviation_list.append(abs(round(deviation, 4)))

    for num, value in enumerate(real_power_list):
        if not value or not forecast_power_list[num]:
            deviation_power = ""
        else:
            # (预测-实际)/实际 * 100%
            deviation_power = (forecast_power_list[num] - value) / value
            deviation_power = abs(round(deviation_power, 4))
        # 如果是本月的,那么当天的电量偏差没有意义, 置为空
        if interval == 86400 and now_month == s_time[:7] and \
                num == slots.index(now_time):
            deviation_power = ""
        deviation_power_list.append(deviation_power)

    # 4,求偏差统计值
    deviation_list_tmp = [i for i in deviation_list if i != ""]

    if deviation_list_tmp:
        count, max_deviation, min_deviation, average, max_index, min_index = \
            choose_list(deviation_list_tmp, 4)
        # 求最大偏差和最小偏差时间
        max_time = slots[max_index]
        min_time = slots[min_index]
        # 平均偏差
        avg_deviation = average
        # 总量偏差 = | (预测(总) - 实际(总)) / 实际(总) | * 100%
        real_tmp = [i for i in real_list if i != ""]
        pred_tmp = forecast_list[: len(real_tmp)]
        pred_tmp = [i for i in pred_tmp if i != ""]
        total_deviation = abs((sum(pred_tmp) - sum(real_tmp)) / sum(real_tmp))
        total_deviation = round(total_deviation, 4)
    else:
        max_deviation, max_time, min_deviation, min_time = 0, "", 0, ""
        avg_deviation, total_deviation = 0, 0

    # 重置 slots
    if interval == 15 * 60:
        for num, slot in enumerate(slots):
            slot = pendulum.parse(slot).format("HH:mm")
            slots[num] = slot

    return ForecastResp(
        pred_data=LoadValue(slots=slots, value=forecast_list),
        real_data=LoadValue(slots=slots, value=real_list),
        deviation_list=deviation_list,
        max_deviation=max_deviation,
        min_deviation=min_deviation,
        avg_deviation=avg_deviation,
        total_deviation=total_deviation,
        real_power_list=LoadValue(slots=slots, value=real_power_list),
        pred_power_list=LoadValue(slots=slots, value=forecast_power_list),
        deviation_power_list=deviation_power_list,
    )
