package com.syjy.calculate.function;

import cn.hutool.json.JSONObject;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.type.*;
import com.syjy.calculate.entity.FormulaParam;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 将list 中的数据是按日期分组，list的格式是List<List<Map<String, Object>>>，最外层list的每一条是一天的数据
 *
 * @author zcl
 * @version 1.0
 * @since 2023/7/6 9:30
 */
@Slf4j
public class ManyDayThreeDayDeviationElectricity extends AbstractFunction {
    /**
     * @param env  参数集合
     * @param arg1 list 待计算数据
     * @param arg2 偏差带阈值 0.2/0.15
     * @param arg3 计算单点还是一段时间
     * @return
     */
    @Override
    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
        // 获取参数
        FormulaParam formulaParam = CommonUtil.getFormulaParam(env, arg1, arg2, arg3, null, null);
        // 获取list
        Object first = arg1.getValue(env);
        // 将参数转为集合
        Sequence seq = CommonUtil.getSeq(first, env);
        // 获取传入的数据
        List<List<Map<String, Object>>> list = new ArrayList<>();
        for (Object obj : seq) {
            List<Map<String, Object>> listData = (List<Map<String, Object>>) obj;
            list.add(listData);
        }

        // 数据校验
        if (list == null || list.size() == 0) {
            log.warn("入参列表为空");
            return new AviatorString("入参列表为空");
        }

        // 判断是否传入的是三天数据
        if (list.size() != 3) {
            log.warn("入参数据不是三天的数据");
            return new AviatorString("入参数据不是三天的数据,东北新短期准确率需前三日的预测数据");
        }
        int sum = 0;
        // 循环求一共有多少条数据
        for (List<Map<String, Object>> listMap : list) {
            sum = sum + listMap.size();
        }
        // 如果数据总数!= 第一天数据*一共几天，则证明各天数据个数不一致
        if (!(list.get(0).size() == list.get(1).size() && list.get(1).size() == list.get(2).size())) {
            log.warn("各天数据个数不一致，需要每天96条完整数据");
            return new AviatorString("各天数据个数不一致，需要每天96条完整数据");
        }

        BigDecimal agoOneRateResult;
        BigDecimal agoTwoRateResult;
        BigDecimal agoThreeRateResult;
        BigDecimal deviationElectricityAvg;
        // 偏差电量总和
        BigDecimal sumDeviationElectricity = BigDecimal.ZERO;
        BigDecimal deviationThreshold = new BigDecimal(formulaParam.getSecond());
        String exp = formulaParam.getThird();
        BigDecimal pointDeviationAvg = BigDecimal.ZERO;
        // 循环列表中3天的数据
        for (int i = 0; i < list.get(0).size(); i++) {
            Map<String, Object> agoOneMap = list.get(0).get(i);
            agoOneMap.put("deviationThreshold", deviationThreshold);
            Map<String, Object> agoTwoMap = list.get(1).get(i);
            agoTwoMap.put("deviationThreshold", deviationThreshold);
            Map<String, Object> agoThreeMap = list.get(2).get(i);
            agoThreeMap.put("deviationThreshold", deviationThreshold);

            agoOneRateResult = getPointDeviation(exp, agoOneMap);
            agoTwoRateResult = getPointDeviation(exp, agoTwoMap);
            agoThreeRateResult = getPointDeviation(exp, agoThreeMap);

            deviationElectricityAvg = (agoOneRateResult.add(agoTwoRateResult).add(agoThreeRateResult)).divide(new BigDecimal(3), 4, BigDecimal.ROUND_HALF_UP);
            // 偏差电量求和
            sumDeviationElectricity = sumDeviationElectricity.add(deviationElectricityAvg);
            // 获取最后一条的点偏差均值
            if (i == list.get(0).size() - 1) {
                pointDeviationAvg = deviationElectricityAvg;
            }
        }
        JSONObject resultJson = new JSONObject();
        resultJson.set("pointDeviation", (BigDecimal.ONE.subtract(pointDeviationAvg).multiply(new BigDecimal(100))) + "%");
        resultJson.set("sumDeviationElectricity", sumDeviationElectricity);
        return new AviatorString(resultJson.toString());
    }


    /**
     * 获取单点偏差电量
     *
     * @param exp
     * @param dataInfo
     * @return
     */
    public BigDecimal getPointDeviation(String exp, Map<String, Object> dataInfo) {
        BigDecimal result;
        result = new BigDecimal(String.valueOf(AviatorEvaluator.execute(exp, dataInfo)));
        return result;
    }

    @Override
    public String getName() {
        return "manyDayThreeDayDeviationElectricity";
    }

}
