package com.njcn.prepare.harmonic.service.mysql.newalgorithm.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.njcn.harmonic.pojo.po.RMpBenchmarkLevelD;
import com.njcn.harmonic.pojo.po.RMpBenchmarkLevelM;
import com.njcn.prepare.harmonic.mapper.mysql.newalgorithm.RMpBenchmarkLevelMMapper;
import com.njcn.prepare.harmonic.pojo.bo.CalculatedParam;
import com.njcn.prepare.harmonic.service.mysql.newalgorithm.IRMpBenchmarkLevelDService;
import com.njcn.prepare.harmonic.service.mysql.newalgorithm.IRMpBenchmarkLevelMService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 类的介绍：监测点基准水平评估_月
 *
 * @author xuyang
 * @version 1.0.0
 * @createTime 2023/11/21 14:50
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class RMpBenchmarkLevelMServiceImpl extends MppServiceImpl<RMpBenchmarkLevelMMapper, RMpBenchmarkLevelM> implements IRMpBenchmarkLevelMService {

    private final IRMpBenchmarkLevelDService irMpBenchmarkLevelDService;

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void benchmarkLevelM(CalculatedParam calculatedParam) {
        log.info(LocalDateTime.now()+"===>监测点基准水平评估_月统计算法开始");
        List<RMpBenchmarkLevelM> result = new ArrayList<>();
        List<RMpBenchmarkLevelD> dList = new ArrayList<>();
        Map<String,List<RMpBenchmarkLevelD>> map = new HashMap<>();
        List<String> lineIds = calculatedParam.getIdList();
        DateTime beginMonth = DateUtil.beginOfMonth(DateUtil.parse(calculatedParam.getDataDate(), DatePattern.NORM_DATE_PATTERN));
        DateTime endMonth = DateUtil.endOfMonth(DateUtil.parse(calculatedParam.getDataDate(), DatePattern.NORM_DATE_PATTERN));
        //以尺寸100分片,查询数据
        List<List<String>> pendingIds =  ListUtils.partition(lineIds,5);
        for (List<String> pendingId : pendingIds) {
            LambdaQueryWrapper<RMpBenchmarkLevelD> lambdaQueryWrapper = new LambdaQueryWrapper<RMpBenchmarkLevelD>();
            lambdaQueryWrapper.in(RMpBenchmarkLevelD::getMeasurementPointId,pendingId)
                                .between(RMpBenchmarkLevelD::getDataDate,beginMonth,endMonth);
            dList.addAll(irMpBenchmarkLevelDService.list(lambdaQueryWrapper));
        }
        if (CollectionUtil.isNotEmpty(dList)){
            map = dList.stream().collect(Collectors.groupingBy(RMpBenchmarkLevelD::getMeasurementPointId));
        }
        for (String item : lineIds) {
            RMpBenchmarkLevelM rMpBenchmarkLevel = new RMpBenchmarkLevelM();
            rMpBenchmarkLevel.setMeasurementPointId(item);
            rMpBenchmarkLevel.setDataDate(beginMonth);
            //初始化数据
            rMpBenchmarkLevel.setVoltageAvg(0.0);
            rMpBenchmarkLevel.setVoltageSd(0.0);
            rMpBenchmarkLevel.setUnbalanceAvg(0.0);
            rMpBenchmarkLevel.setUnbalanceSd(0.0);
            rMpBenchmarkLevel.setVthdAvg(0.0);
            rMpBenchmarkLevel.setVthdSd(0.0);
            rMpBenchmarkLevel.setFlickerAvg(0.0);
            rMpBenchmarkLevel.setFlickerSd(0.0);
            rMpBenchmarkLevel.setEventAvg(0.0);
            rMpBenchmarkLevel.setEventSd(0.0);
            rMpBenchmarkLevel.setRiseAvg(0.0);
            rMpBenchmarkLevel.setRiseSd(0.0);
            rMpBenchmarkLevel.setInterruptAvg(0.0);
            rMpBenchmarkLevel.setInterruptSd(0.0);
            //稳态-有数据处理
            List<RMpBenchmarkLevelD> day = map.get(item);
            if (CollectionUtil.isNotEmpty(day)){
                //均值
                double d1 = day.stream().mapToDouble(RMpBenchmarkLevelD::getVoltageAvg).average().orElse(0.0);
                double d2 = day.stream().mapToDouble(RMpBenchmarkLevelD::getUnbalanceAvg).average().orElse(0.0);
                double d3 = day.stream().mapToDouble(RMpBenchmarkLevelD::getVthdAvg).average().orElse(0.0);
                double d4 = day.stream().mapToDouble(RMpBenchmarkLevelD::getFlickerAvg).average().orElse(0.0);
                rMpBenchmarkLevel.setVoltageAvg(d1);
                rMpBenchmarkLevel.setUnbalanceAvg(d2);
                rMpBenchmarkLevel.setVthdAvg(d3);
                rMpBenchmarkLevel.setFlickerAvg(d4);
                //标准差
                List<Double> l1 = day.stream().map(RMpBenchmarkLevelD::getVoltageAvg).collect(Collectors.toList());
                List<Double> l2 = day.stream().map(RMpBenchmarkLevelD::getUnbalanceAvg).collect(Collectors.toList());
                List<Double> l3 = day.stream().map(RMpBenchmarkLevelD::getVthdAvg).collect(Collectors.toList());
                List<Double> l4 = day.stream().map(RMpBenchmarkLevelD::getFlickerAvg).collect(Collectors.toList());
                rMpBenchmarkLevel.setVoltageSd(calculateStandardDeviation(l1,d1));
                rMpBenchmarkLevel.setUnbalanceSd(calculateStandardDeviation(l2,d2));
                rMpBenchmarkLevel.setVthdSd(calculateStandardDeviation(l3,d3));
                rMpBenchmarkLevel.setFlickerSd(calculateStandardDeviation(l4,d4));
            }
            //暂态-暂无算法计算,默认为0
            result.add(rMpBenchmarkLevel);
        }
        if (CollectionUtil.isNotEmpty(result)){
            this.saveOrUpdateBatchByMultiId(result,100);
        }
    }

    private static double calculateStandardDeviation(List<Double> data, double mean) {
        return Math.sqrt(calculateVariance(data, mean));
    }

    private static double calculateVariance(List<Double> data, double mean) {
        return data.stream()
                .mapToDouble(Double::doubleValue)
                .map(value -> Math.pow(value - mean, 2))
                .average()
                .orElse(0.0);
    }

}
