package com.yeejoin.amos.boot.module.jxiop.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yeejoin.amos.boot.module.jxiop.biz.dto.HealthIndexDTO;
import com.yeejoin.amos.boot.module.jxiop.biz.entity.IdxBizFanWeight;
import com.yeejoin.amos.boot.module.jxiop.biz.entity.IdxBizPvWeight;
import com.yeejoin.amos.boot.module.jxiop.biz.mapper2.IdxBizFanWeightMapper;
import com.yeejoin.amos.boot.module.jxiop.biz.mapper2.IdxBizPvWeightMapper;
import com.yeejoin.amos.boot.module.jxiop.biz.service.IFanHealthIndexService;
import com.yeejoin.amos.boot.module.jxiop.biz.tdMapper2.FanHealthIndexMapper;
import com.yeejoin.amos.boot.module.jxiop.biz.tdMapper2.PvHealthIndexMapper;
import com.yeejoin.amos.boot.module.jxiop.biz.tdengine.FanHealthIndex;
import com.yeejoin.amos.boot.module.jxiop.biz.tdengine.PvHealthIndex;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 风电 - 按时刻生成子系统、设备、场站、区域 数据
 * <p>
 * ProjectName: amos-boot-zx-biz
 * PackageName: com.yeejoin.amos.boot.module.jxiop.biz.service.impl
 *
 * @author yangyang
 * @version v1.0
 * @date 2024/7/23 19:05
 */
@Component
@Slf4j
public class FanHealthIndexServiceImpl implements IFanHealthIndexService {

    @Autowired
    private FanHealthIndexMapper fanHealthIndexMapper;

    @Autowired
    private IdxBizFanWeightMapper idxBizFanWeightMapper;

    @Autowired
    private PvHealthIndexMapper pvHealthIndexMapper;

    @Autowired
    private IdxBizPvWeightMapper idxBizPvWeightMapper;

    @Value("${analysis.weightRounding:false}")
    private Boolean weightRounding;

    @Override
    public List<FanHealthIndex> getInfoListByGroupByCdFan(String startTime, String tableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndicesZxt = fanHealthIndexMapper.getInfoList(startTime, tableName, analysisObjectType);
        QueryWrapper<IdxBizFanWeight> idxBizFanWeightQueryWrapper = new QueryWrapper<>();
        idxBizFanWeightQueryWrapper.eq("type", "5");
        idxBizFanWeightQueryWrapper.isNotNull("value");
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(idxBizFanWeightQueryWrapper);
        Map<String, Float> weightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> o.getArae() + o.getStation() + o.getEquipmentName() + o.getSubarray() + o.getPointName(), IdxBizFanWeight::getValue));
        // 开始计算加权平均
        Map<String, List<FanHealthIndex>> fanHealthIndicesZxtMap = fanHealthIndicesZxt.stream().collect(Collectors.groupingBy(o -> o.getGatewayId() + o.getIndexAddress() + o.getStation() + o.getAnalysisObjType() + o.getAnalysisObjSeq() + o.getWeight() + o.getArea() + o.getSubSystem() + o.getEquipmentName() + o.getNumber() + o.getPointName() + o.getKks() + o.getOrgCode()));
        List<FanHealthIndex> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            FanHealthIndex fanHealthIndex = new FanHealthIndex();
            fanHealthIndex.setIndexAddress(v.get(0).getIndexAddress());
            fanHealthIndex.setGatewayId(v.get(0).getGatewayId());
            fanHealthIndex.setStation(v.get(0).getStation());
            fanHealthIndex.setAnalysisObjType(v.get(0).getAnalysisObjType());
            fanHealthIndex.setAnalysisObjSeq(v.get(0).getAnalysisObjSeq());
            fanHealthIndex.setWeight(v.get(0).getWeight());
            fanHealthIndex.setArea(v.get(0).getArea());
            fanHealthIndex.setSubSystem(v.get(0).getSubSystem());
            fanHealthIndex.setNumber(v.get(0).getNumber());
            fanHealthIndex.setEquipmentName(v.get(0).getEquipmentName());
            fanHealthIndex.setPointName(v.get(0).getPointName());
            fanHealthIndex.setKks(v.get(0).getKks());
            fanHealthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<FanHealthIndex, String> assembleKey = o -> o.getArea() + o.getStation() + o.getEquipmentName() + o.getSubSystem() + o.getPointName();
                this.weightedMean(assembleKey, fanHealthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(fanHealthIndex, v);
            }
            fanHealthIndicesZxtNews.add(fanHealthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    /**
     * 子系统加权平均
     * 加权平均数 = (w1 * x1 + w2 * x2 + … + wn * xn) / (w1 + w2 + … + wn)
     * w1, w2, …, wn 是各个数据点的权重；
     * x1, x2, …, xn 是各个数据点的数值；
     * n 是数据点的总数。
     *
     * @param startTime          startTime
     * @param tableName          tableName
     * @param analysisObjectType analysisObjectType
     * @return {@link  List< FanHealthIndex>}
     * @throws
     * @author yangyang
     * @date 2024/7/23 21:02
     */
    @Override
    public List<FanHealthIndex> getInfoListByGroupByZxtFan(String startTime, String tableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndicesZxt = fanHealthIndexMapper.getInfoList(startTime, tableName, analysisObjectType);
        QueryWrapper<IdxBizFanWeight> idxBizFanWeightQueryWrapper = new QueryWrapper<>();
        idxBizFanWeightQueryWrapper.eq("type", "5");
        idxBizFanWeightQueryWrapper.isNotNull("value");
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(idxBizFanWeightQueryWrapper);
        Map<String, Float> weightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> o.getArae() + o.getStation() + o.getEquipmentName() + o.getSubarray() + o.getPointName(), IdxBizFanWeight::getValue));
        // 开始计算加权平均
        Map<String, List<FanHealthIndex>> fanHealthIndicesZxtMap = fanHealthIndicesZxt.stream().collect(Collectors.groupingBy(o -> o.getGatewayId() + o.getStation() + o.getAnalysisObjType() + o.getArea() + o.getSubSystem() + o.getEquipmentName() + o.getNumber() + o.getOrgCode()));
        List<FanHealthIndex> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            FanHealthIndex fanHealthIndex = new FanHealthIndex();
            fanHealthIndex.setGatewayId(v.get(0).getGatewayId());
            fanHealthIndex.setStation(v.get(0).getStation());
            fanHealthIndex.setAnalysisObjType("子系统");
            fanHealthIndex.setArea(v.get(0).getArea());
            fanHealthIndex.setSubSystem(v.get(0).getSubSystem());
            fanHealthIndex.setEquipmentName(v.get(0).getEquipmentName());
            fanHealthIndex.setNumber(v.get(0).getNumber());
            fanHealthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<FanHealthIndex, String> assembleKey = o -> o.getArea() + o.getStation() + o.getEquipmentName() + o.getSubSystem() + o.getPointName();
                this.weightedMean(assembleKey, fanHealthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(fanHealthIndex, v);
            }
            fanHealthIndicesZxtNews.add(fanHealthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    /**
     * 设备加权平均
     * 加权平均数 = (w1 * x1 + w2 * x2 + … + wn * xn) / (w1 + w2 + … + wn)
     * w1, w2, …, wn 是各个数据点的权重；
     * x1, x2, …, xn 是各个数据点的数值；
     * n 是数据点的总数。
     *
     * @param startTime          startTime
     * @param tableName          tableName
     * @param analysisObjectType analysisObjectType
     * @return {@link  List< FanHealthIndex>}
     * @throws
     * @author yangyang
     * @date 2024/7/23 21:02
     */
    @Override
    public List<FanHealthIndex> getInfoListByGroupBySbFan(String startTime, String tableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndicesZxt = fanHealthIndexMapper.getInfoList(startTime, tableName, analysisObjectType);
        QueryWrapper<IdxBizFanWeight> idxBizFanWeightQueryWrapper = new QueryWrapper<>();
        idxBizFanWeightQueryWrapper.eq("type", "4");
        idxBizFanWeightQueryWrapper.isNotNull("value");
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(idxBizFanWeightQueryWrapper);
        Map<String, Float> weightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> o.getArae() + o.getStation() + o.getEquipmentName() + o.getSubarray(), IdxBizFanWeight::getValue));
        // 开始计算加权平均
        Map<String, List<FanHealthIndex>> fanHealthIndicesZxtMap = fanHealthIndicesZxt.stream().collect(Collectors.groupingBy(o -> o.getGatewayId() + o.getStation() + o.getAnalysisObjType() + o.getArea() + o.getNumber() + o.getEquipmentName() + o.getOrgCode()));
        List<FanHealthIndex> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            FanHealthIndex fanHealthIndex = new FanHealthIndex();
            fanHealthIndex.setGatewayId(v.get(0).getGatewayId());
            fanHealthIndex.setStation(v.get(0).getStation());
            fanHealthIndex.setAnalysisObjType("设备");
            fanHealthIndex.setArea(v.get(0).getArea());
            fanHealthIndex.setNumber(v.get(0).getNumber());
            fanHealthIndex.setEquipmentName(v.get(0).getEquipmentName());
            fanHealthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<FanHealthIndex, String> assembleKey = o -> o.getArea() + o.getStation() + o.getEquipmentName() + o.getSubSystem();
                this.weightedMean(assembleKey, fanHealthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(fanHealthIndex, v);
            }
            fanHealthIndicesZxtNews.add(fanHealthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    /**
     * 场站加权平均
     * 加权平均数 = (w1 * x1 + w2 * x2 + … + wn * xn) / (w1 + w2 + … + wn)
     * w1, w2, …, wn 是各个数据点的权重；
     * x1, x2, …, xn 是各个数据点的数值；
     * n 是数据点的总数。
     *
     * @param startTime          startTime
     * @param tableName          tableName
     * @param analysisObjectType analysisObjectType
     * @return {@link  List< FanHealthIndex>}
     * @throws
     * @author yangyang
     * @date 2024/7/23 21:02
     */
    @Override
    public List<FanHealthIndex> getInfoListByGroupByCzFan(String startTime, String tableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndicesZxt = fanHealthIndexMapper.getInfoList(startTime, tableName, analysisObjectType);
        QueryWrapper<IdxBizFanWeight> idxBizFanWeightQueryWrapper = new QueryWrapper<>();
        idxBizFanWeightQueryWrapper.eq("type", "3");
        idxBizFanWeightQueryWrapper.isNotNull("value");
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(idxBizFanWeightQueryWrapper);
        Map<String, Float> weightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> o.getArae() + o.getStation() + o.getEquipmentName(), IdxBizFanWeight::getValue));
        // 开始计算加权平均
        Map<String, List<FanHealthIndex>> fanHealthIndicesZxtMap = fanHealthIndicesZxt.stream().collect(Collectors.groupingBy(o -> o.getGatewayId() + o.getStation() + o.getAnalysisObjType() + o.getArea() + o.getOrgCode()));
        List<FanHealthIndex> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            FanHealthIndex fanHealthIndex = new FanHealthIndex();
            fanHealthIndex.setGatewayId(v.get(0).getGatewayId());
            fanHealthIndex.setStation(v.get(0).getStation());
            fanHealthIndex.setAnalysisObjType("场站");
            fanHealthIndex.setArea(v.get(0).getArea());
            fanHealthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<FanHealthIndex, String> assembleKey = o -> o.getArea() + o.getStation() + o.getEquipmentName();
                this.weightedMean(assembleKey, fanHealthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(fanHealthIndex, v);
            }
            fanHealthIndicesZxtNews.add(fanHealthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    /**
     * 区域加权平均
     * 加权平均数 = (w1 * x1 + w2 * x2 + … + wn * xn) / (w1 + w2 + … + wn)
     * w1, w2, …, wn 是各个数据点的权重；
     * x1, x2, …, xn 是各个数据点的数值；
     * n 是数据点的总数。
     *
     * @param startTime          startTime
     * @param tableName          tableName
     * @param analysisObjectType analysisObjectType
     * @return {@link  List< FanHealthIndex>}
     * @throws
     * @author yangyang
     * @date 2024/7/23 21:02
     */
    @Override
    @Deprecated
    public List<FanHealthIndex> getInfoListByGroupByQyFan(String startTime, String tableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndicesZxt = fanHealthIndexMapper.getInfoList(startTime, tableName, analysisObjectType);
        QueryWrapper<IdxBizFanWeight> idxBizFanWeightQueryWrapper = new QueryWrapper<>();
        idxBizFanWeightQueryWrapper.eq("type", "2");
        idxBizFanWeightQueryWrapper.isNotNull("value");
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(idxBizFanWeightQueryWrapper);
        Map<String, Float> weightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> o.getArae() + o.getStation(), IdxBizFanWeight::getValue));
        // 开始计算加权平均
        Map<String, List<FanHealthIndex>> fanHealthIndicesZxtMap = fanHealthIndicesZxt.stream().collect(Collectors.groupingBy(o -> o.getAnalysisObjType() + o.getArea() + o.getOrgCode()));
        List<FanHealthIndex> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            FanHealthIndex fanHealthIndex = new FanHealthIndex();
            fanHealthIndex.setAnalysisObjType("片区");
            fanHealthIndex.setArea(v.get(0).getArea());
            fanHealthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<FanHealthIndex, String> assembleKey = o -> o.getArea() + o.getStation();
                this.weightedMean(assembleKey, fanHealthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(fanHealthIndex, v);
            }
            fanHealthIndicesZxtNews.add(fanHealthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    /**
     * 全域【所有 / 全国】加权平均
     * 加权平均数 = (w1 * x1 + w2 * x2 + … + wn * xn) / (w1 + w2 + … + wn)
     * w1, w2, …, wn 是各个数据点的权重；
     * x1, x2, …, xn 是各个数据点的数值；
     * n 是数据点的总数。
     *
     * @param startTime          startTime
     * @param tableName          tableName
     * @param analysisObjectType analysisObjectType
     * @return {@link  List< FanHealthIndex>}
     * @throws
     * @author yangyang
     * @date 2024/7/23 21:02
     */
    @Override
    @Deprecated
    public List<FanHealthIndex> getInfoListByGroupByQgFan(String startTime, String tableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndicesZxt = fanHealthIndexMapper.getInfoList(startTime, tableName, analysisObjectType);
        QueryWrapper<IdxBizFanWeight> idxBizFanWeightQueryWrapper = new QueryWrapper<>();
        idxBizFanWeightQueryWrapper.eq("type", "1");
        idxBizFanWeightQueryWrapper.isNotNull("value");
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(idxBizFanWeightQueryWrapper);
        Map<String, Float> weightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> o.getArae(), IdxBizFanWeight::getValue));
        // 开始计算加权平均
        Map<String, List<FanHealthIndex>> fanHealthIndicesZxtMap = fanHealthIndicesZxt.stream().collect(Collectors.groupingBy(o -> o.getAnalysisObjType() + o.getOrgCode()));
        List<FanHealthIndex> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            FanHealthIndex fanHealthIndex = new FanHealthIndex();
            fanHealthIndex.setAnalysisObjType("全域");
            fanHealthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<FanHealthIndex, String> assembleKey = o -> o.getArea();
                this.weightedMean(assembleKey, fanHealthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(fanHealthIndex, v);
            }
            fanHealthIndicesZxtNews.add(fanHealthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    @Override
    public List<HealthIndexDTO> getInfoListByGroupByQy(String startTime, String fanTableName, String pvTableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndices = fanHealthIndexMapper.getInfoList(startTime, fanTableName, analysisObjectType);
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(new QueryWrapper<IdxBizFanWeight>().eq("type", "2").isNotNull("value"));
        Map<String, Float> fanWeightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> "fan" + o.getArae() + o.getStation(), IdxBizFanWeight::getValue));

        List<PvHealthIndex> pvHealthIndices = pvHealthIndexMapper.getInfoList(startTime, pvTableName, analysisObjectType);
        List<IdxBizPvWeight> pvIdxBizFanWeights = idxBizPvWeightMapper.selectList(new QueryWrapper<IdxBizPvWeight>().eq("type", "2").isNotNull("value"));
        Map<String, Float> pvWeightMap = pvIdxBizFanWeights.stream().collect(Collectors.toMap(o -> "pv" + o.getArae() + o.getStation(), IdxBizPvWeight::getValue));

        List<HealthIndexDTO> healthIndexDTOS = new ArrayList<>();
        healthIndexDTOS.addAll(fanHealthIndices.stream().map(this::toHealthIndexDTO).collect(Collectors.toList()));
        healthIndexDTOS.addAll(pvHealthIndices.stream().map(this::toHealthIndexDTO).collect(Collectors.toList()));

        Map<String, Float> weightMap = new HashMap<>();
        weightMap.putAll(fanWeightMap);
        weightMap.putAll(pvWeightMap);
        // 开始计算加权平均
        Map<String, List<HealthIndexDTO>> fanHealthIndicesZxtMap = healthIndexDTOS.stream().collect(Collectors.groupingBy(o -> o.getAnalysisObjType() + o.getArea()));
        List<HealthIndexDTO> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            HealthIndexDTO healthIndex = new HealthIndexDTO();
            healthIndex.setAnalysisObjType("片区");
            healthIndex.setArea(v.get(0).getArea());
            healthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<HealthIndexDTO, String> assembleKey = o -> o.getType() + o.getArea() + o.getStation();
                this.weightedMean(assembleKey, healthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(healthIndex, v);
            }
            fanHealthIndicesZxtNews.add(healthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    @Override
    public List<HealthIndexDTO> getInfoListByGroupByQg(String startTime, String fanTableName, String pvTableName, String analysisObjectType) {
        List<FanHealthIndex> fanHealthIndices = fanHealthIndexMapper.getInfoList(startTime, fanTableName, analysisObjectType);
        List<IdxBizFanWeight> idxBizFanWeights = idxBizFanWeightMapper.selectList(new QueryWrapper<IdxBizFanWeight>().eq("type", "1").isNotNull("value"));
        Map<String, Float> fanWeightMap = idxBizFanWeights.stream().collect(Collectors.toMap(o -> "fan" + o.getArae(), IdxBizFanWeight::getValue));

        List<PvHealthIndex> pvHealthIndices = pvHealthIndexMapper.getInfoList(startTime, pvTableName, analysisObjectType);
        List<IdxBizPvWeight> pvIdxBizFanWeights = idxBizPvWeightMapper.selectList(new QueryWrapper<IdxBizPvWeight>().eq("type", "1").isNotNull("value"));
        Map<String, Float> pvWeightMap = pvIdxBizFanWeights.stream().collect(Collectors.toMap(o -> "pv" + o.getArae(), IdxBizPvWeight::getValue));

        List<HealthIndexDTO> healthIndexDTOS = new ArrayList<>();
        healthIndexDTOS.addAll(fanHealthIndices.stream().map(this::toHealthIndexDTO).collect(Collectors.toList()));
        healthIndexDTOS.addAll(pvHealthIndices.stream().map(this::toHealthIndexDTO).collect(Collectors.toList()));

        Map<String, Float> weightMap = new HashMap<>();
        weightMap.putAll(fanWeightMap);
        weightMap.putAll(pvWeightMap);

        // 开始计算加权平均
        Map<String, List<HealthIndexDTO>> fanHealthIndicesZxtMap = healthIndexDTOS.stream().collect(Collectors.groupingBy(o -> o.getAnalysisObjType()));
        List<HealthIndexDTO> fanHealthIndicesZxtNews = new ArrayList<>();
        fanHealthIndicesZxtMap.forEach((k, v) -> {
            HealthIndexDTO healthIndex = new HealthIndexDTO();
            healthIndex.setAnalysisObjType("全域");
            healthIndex.setOrgCode(v.get(0).getOrgCode());
            // 例如 子系统 = (测点1 * 测点1权重 + 测点2 * 测点2权重 + .... 测点n权重) /  (测点1权重 + 测点2权重 + .... 测点n权重)
            // 但是测点是没有权重的，所以子系统无法计算加权平均
            // 设备 = (子系统1 * 子系统1权重 + 子系统2 * 子系统2权重 + .... 子系统n权重) /  (子系统1权重 + 子系统2权重 + .... 子系统n权重)
            // 但如果没有配置子系统的权重，如何计算？
            try {
                // 加权平均
                Function<HealthIndexDTO, String> assembleKey = o -> o.getType() + o.getArea();
                this.weightedMean(assembleKey, healthIndex, v, weightMap);
            } catch (Exception e) {
                // 普通平均
                this.calculateAvg(healthIndex, v);
            }
            fanHealthIndicesZxtNews.add(healthIndex);
        });
        return fanHealthIndicesZxtNews;
    }

    public void weightedMean(Function<HealthIndexDTO, String> assembleKey, HealthIndexDTO healthIndex, List<HealthIndexDTO> v, Map<String, Float> weightMap) {
        Double totalHealthIndex = v.stream().mapToDouble(o -> getWeight(() -> assembleKey.apply(o), weightMap) * o.getHealthIndex()).sum();
        Double totalAnomaly = v.stream().mapToDouble(o -> getWeight(() -> assembleKey.apply(o), weightMap) * o.getAnomaly()).sum();
        Double totalWeight = v.stream().mapToDouble(o -> getWeight(() -> assembleKey.apply(o), weightMap)).sum();
        healthIndex.setAnomaly(division(totalAnomaly, totalWeight));
        healthIndex.setHealthIndex(division(totalHealthIndex, totalWeight));
    }

    public void weightedMean(Function<FanHealthIndex, String> assembleKey, FanHealthIndex healthIndex, List<FanHealthIndex> v, Map<String, Float> weightMap) {
        Double totalHealthIndex = v.stream().mapToDouble(o -> getWeight(() -> assembleKey.apply(o), weightMap) * o.getHealthIndex()).sum();
        Double totalAnomaly = v.stream().mapToDouble(o -> getWeight(() -> assembleKey.apply(o), weightMap) * o.getAnomaly()).sum();
        Double totalWeight = v.stream().mapToDouble(o -> getWeight(() -> assembleKey.apply(o), weightMap)).sum();
        healthIndex.setAnomaly(division(totalAnomaly, totalWeight));
        healthIndex.setHealthIndex(division(totalHealthIndex, totalWeight));
    }

    public void calculateAvg(FanHealthIndex healthIndex, List<FanHealthIndex> v) {
        // 普通平均
        Double avgHealthIndex = v.stream().mapToDouble(o -> o.getHealthIndex()).sum();
        Double avgAnomaly = v.stream().mapToDouble(o -> o.getAnomaly()).sum();
        Long totalHealthIndex = v.stream().filter(o -> o.getHealthIndex() != null).mapToDouble(o -> o.getHealthIndex()).count();
        Long totalAnomaly = v.stream().filter(o -> o.getAnomaly() != null).mapToDouble(o -> o.getAnomaly()).count();
        healthIndex.setAnomaly(division(avgAnomaly, totalAnomaly.doubleValue()));
        healthIndex.setHealthIndex(division(avgHealthIndex, totalHealthIndex.doubleValue()));
    }

    public void calculateAvg(HealthIndexDTO healthIndex, List<HealthIndexDTO> v) {
        // 普通平均
        Double avgHealthIndex = v.stream().mapToDouble(o -> o.getHealthIndex()).sum();
        Double avgAnomaly = v.stream().mapToDouble(o -> o.getAnomaly()).sum();
        Long totalHealthIndex = v.stream().filter(o -> o.getHealthIndex() != null).mapToDouble(o -> o.getHealthIndex()).count();
        Long totalAnomaly = v.stream().filter(o -> o.getAnomaly() != null).mapToDouble(o -> o.getAnomaly()).count();
        healthIndex.setAnomaly(division(avgAnomaly, totalAnomaly.doubleValue()));
        healthIndex.setHealthIndex(division(avgHealthIndex, totalHealthIndex.doubleValue()));
    }

    public Double getWeight(Supplier<String> key, Map<String, Float> weightMap) {
        Float weight = weightMap.get(key.get());
        if (weight == null) {
            log.error("计算加权平均异常【" + key.get() + "】未配置权重");
            throw new RuntimeException("【" + key.get() + "】未配置权重");
        }
        return weight.doubleValue();
    }

    public HealthIndexDTO toHealthIndexDTO(FanHealthIndex healthIndex) {
        HealthIndexDTO healthIndexDTO = new HealthIndexDTO();
        BeanUtils.copyProperties(healthIndex, healthIndexDTO);
        healthIndexDTO.setSubSystem(healthIndex.getSubSystem());
        healthIndexDTO.setType("fan");
        return healthIndexDTO;
    }

    public HealthIndexDTO toHealthIndexDTO(PvHealthIndex healthIndex) {
        HealthIndexDTO healthIndexDTO = new HealthIndexDTO();
        BeanUtils.copyProperties(healthIndex, healthIndexDTO);
        healthIndexDTO.setSubSystem(healthIndex.getSubarray());
        healthIndexDTO.setType("pv");
        return healthIndexDTO;
    }

    @Override
    public FanHealthIndex toFanHealthIndex(HealthIndexDTO healthIndex) {
        FanHealthIndex fanHealthIndex = new FanHealthIndex();
        BeanUtils.copyProperties(healthIndex, fanHealthIndex);
        fanHealthIndex.setSubSystem(healthIndex.getSubSystem());
        return fanHealthIndex;
    }

    @Override
    public PvHealthIndex toPvHealthIndex(HealthIndexDTO healthIndex) {
        PvHealthIndex pvHealthIndex = new PvHealthIndex();
        BeanUtils.copyProperties(healthIndex, pvHealthIndex);
        pvHealthIndex.setSubarray(healthIndex.getSubSystem());
        return pvHealthIndex;
    }

    /**
     * 计算的时候，会使用原始数据计算，页面显示数据会四舍五入到1位小数
     *
     * 启用weightRounding 配置则会四舍五入到小数点后1位
     *
     * @param a a
     * @param b b
     * @return {@link  Double}
     * @throws
     * @author yangyang
     * @date 2024/7/25 17:28
     */
    private Double division(Double a, Double b) {
        if (weightRounding) {
            BigDecimal c = new BigDecimal(a).divide(new BigDecimal(b), 1, BigDecimal.ROUND_HALF_UP);
            return c.doubleValue();
        }
        return a / b;
    }

}
