package com.njcn.csharmonic.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.csdevice.api.CsCommTerminalFeignClient;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.pojo.dto.DevDetailDTO;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.csharmonic.api.PqGovernPlanFeignClient;
import com.njcn.csharmonic.mapper.RStatLimitRateDMapper;
import com.njcn.csharmonic.pojo.param.MainLineQueryParam;
import com.njcn.csharmonic.pojo.param.MainLineStatLimitRateDetailsQueryParam;
import com.njcn.csharmonic.pojo.param.TotalLimitStatisticsDetailsQueryParam;
import com.njcn.csharmonic.pojo.param.TotalLimitStatisticsParam;
import com.njcn.csharmonic.pojo.po.PqGovernPlan;
import com.njcn.csharmonic.pojo.po.RStatLimitRateDPO;
import com.njcn.csharmonic.pojo.vo.*;
import com.njcn.csharmonic.service.IRStatLimitRateDService;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.pojo.po.DictData;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 合格率统计日表(越限次数) 服务实现类
 * </p>
 *
 * @author wr
 * @since 2023-04-03
 */
@DS("sjzx")
@RequiredArgsConstructor
@Service
public class RStatLimitRateDServiceImpl extends ServiceImpl<RStatLimitRateDMapper, RStatLimitRateDPO> implements IRStatLimitRateDService {

    private final CsLineFeignClient csLineFeignClient;
    private final DicDataFeignClient dicDataFeignClient;
    private final EquipmentFeignClient equipmentFeignClient;
    private final DecimalFormat df = new DecimalFormat("#0.00");
    private final String GRID_SIDE_DICT_CODE = "Grid_Side";
    private final CsCommTerminalFeignClient csCommTerminalFeignClient;
    private final CsCommTerminalFeignClient csCommTerminal;
    private final PqGovernPlanFeignClient pqGovernPlanFeignClient;

    @Override
    public List<RStatLimitRateDPO> monitorIdsGetLimitRateInfo(String date, List<String> monitorIds) {
        return this.baseMapper.selectList(new LambdaQueryWrapper<RStatLimitRateDPO>()
                .in(RStatLimitRateDPO::getLineId, monitorIds).eq(RStatLimitRateDPO::getTime, date).eq(RStatLimitRateDPO::getPhasicType, "T"));
    }


    @Override
    public List<RStatLimitRateDPO> getOverData(String lineId, String startTime, String endTime, Integer type) {
        QueryWrapper<RStatLimitRateDPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(RStatLimitRateDPO::getLineId, lineId)
                .between(RStatLimitRateDPO::getTime, startTime, endTime)
                .groupBy(RStatLimitRateDPO::getTime);
        //频率偏差
        if (type == 1) {
            queryWrapper.select("time_id time,max(freq_dev_overtime) freq_dev_overtime");
            queryWrapper.lambda().gt(RStatLimitRateDPO::getFreqDevOvertime, 0);
        }
        //电压偏差
        else if (type == 2) {
            queryWrapper.select("time_id time,max(voltage_dev_overtime) voltage_dev_overtime");
            queryWrapper.lambda().gt(RStatLimitRateDPO::getVoltageDevOvertime, 0);
        }
        //长时闪变
        else if (type == 3) {
            queryWrapper.select("time_id time,max(flicker_overtime) flicker_overtime");
            queryWrapper.lambda().gt(RStatLimitRateDPO::getFlickerOvertime, 0);
        }
        //电压总谐波畸变率
        else if (type == 4) {
            queryWrapper.select("time_id time,max(uaberrance_overtime) uaberrance_overtime");
            queryWrapper.lambda().gt(RStatLimitRateDPO::getUaberranceOvertime, 0);
        }
        //负序电压不平衡度
        else if (type == 5) {
            queryWrapper.select("time_id time,max(ubalance_overtime) ubalance_overtime");
            queryWrapper.lambda().gt(RStatLimitRateDPO::getUbalanceOvertime, 0);
        }
        //负序电流
        else if (type == 6) {
            queryWrapper.select("time_id time,max(i_neg_overtime) i_neg_overtime");
            queryWrapper.lambda().gt(RStatLimitRateDPO::getINegOvertime, 0);
        }
        //谐波电压含有率
        else if (type == 7) {
            StringBuilder selectSql = new StringBuilder();
            StringBuilder havingSql = new StringBuilder();
            for (int i = 2; i <= 25; i++) {
                selectSql.append("max(uharm_").append(i).append("_overtime) uharm_").append(i).append("_overtime,");
                if (i == 25) {
                    havingSql.append("uharm_").append(i).append("_overtime");
                } else {
                    havingSql.append("uharm_").append(i).append("_overtime + ");
                }
            }
            selectSql.append("time_id time");
            havingSql = new StringBuilder("sum(" + havingSql + ")");
            queryWrapper.select(selectSql.toString()).having(havingSql.toString(), 0);
        }
        //谐波电流
        else if (type == 8) {
            StringBuilder selectSql = new StringBuilder();
            StringBuilder havingSql = new StringBuilder();
            for (int i = 2; i <= 25; i++) {
                selectSql.append("max(iharm_").append(i).append("_overtime) iharm_").append(i).append("_overtime,");
                if (i == 25) {
                    havingSql.append("iharm_").append(i).append("_overtime");
                } else {
                    havingSql.append("iharm_").append(i).append("_overtime + ");
                }
            }
            selectSql.append("time_id time");
            havingSql = new StringBuilder("sum(" + havingSql + ")");
            queryWrapper.select(selectSql.toString()).having(havingSql.toString(), 0);
        }
        //间谐波电压
        else if (type == 9) {
            StringBuilder selectSql = new StringBuilder();
            StringBuilder havingSql = new StringBuilder();
            for (int i = 1; i <= 16; i++) {
                selectSql.append("max(inuharm_").append(i).append("_overtime) inuharm_").append(i).append("_overtime,");
                if (i == 16) {
                    havingSql.append("inuharm_").append(i).append("_overtime");
                } else {
                    havingSql.append("inuharm_").append(i).append("_overtime + ");
                }
            }
            selectSql.append("time_id time");
            havingSql = new StringBuilder("sum(" + havingSql + ")");
            queryWrapper.select(selectSql.toString()).having(havingSql.toString(), 0);
        }
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    public Page<MainLineVO> mainLineList(MainLineQueryParam param) {
        Page<MainLineVO> result = new Page<>();
        result.setCurrent(param.getPageNum());
        result.setSize(param.getPageSize());
        String keywords = param.getKeywords();
        List<String> keywordsLineIds = new ArrayList<>();
        if (StrUtil.isNotBlank(keywords)) {
            List<CsLinePO> lineList = csLineFeignClient.getLineByName(keywords).getData();
            if (CollUtil.isEmpty(lineList)) {
                return result;
            }
            keywordsLineIds = lineList.stream().filter(po -> po.getIsImportant() != null && po.getIsImportant() == 1).map(CsLinePO::getLineId).collect(Collectors.toList());
        } else {
            List<CsLinePO> poList = csLineFeignClient.getSimpleLine().getData();
            if (CollUtil.isNotEmpty(poList)) {
                keywordsLineIds = poList.stream().filter(po -> po.getIsImportant() != null && po.getIsImportant() == 1).map(CsLinePO::getLineId).collect(Collectors.toList());
            }
        }
        if (CollUtil.isEmpty(keywordsLineIds)) {
            return result;
        }
        // 按监测点总数手动分页，确保没有数据的监测点也能展示
        result.setTotal(keywordsLineIds.size());
        int fromIndex = (param.getPageNum() - 1) * param.getPageSize();
        if (fromIndex >= keywordsLineIds.size()) {
            return result;
        }
        int toIndex = Math.min(fromIndex + param.getPageSize(), keywordsLineIds.size());
        List<String> pageLineIds = new ArrayList<>(keywordsLineIds.subList(fromIndex, toIndex));

        List<MainLineVO> list = new ArrayList<>();
        MainLineVO mainLineVO;
        List<DevDetailDTO> devDetailDTOList = csCommTerminalFeignClient.getLedgerByLineId(pageLineIds).getData();
        Map<String, DevDetailDTO> devDetailDTOMap = CollUtil.isEmpty(devDetailDTOList)
                ? Collections.emptyMap()
                : devDetailDTOList.stream().collect(Collectors.toMap(DevDetailDTO::getLineId, item -> item));
        //根据监测点获取治理方案
        List<PqGovernPlan> pqGovernPlans = pqGovernPlanFeignClient.getListByMonitorPoint(pageLineIds).getData();
        Map<String, PqGovernPlan> pqGovernPlanMap1 = Collections.emptyMap();
        Map<String, PqGovernPlan> pqGovernPlanMap2 = Collections.emptyMap();
        if (CollUtil.isNotEmpty(pqGovernPlans)) {
            pqGovernPlanMap1 = pqGovernPlans.stream().collect(Collectors.toMap(PqGovernPlan::getGovernBefore, item -> item));
            pqGovernPlanMap2 = pqGovernPlans.stream().collect(Collectors.toMap(PqGovernPlan::getGovernAfter, item -> item));
        }

        for (String lineId : pageLineIds) {
            mainLineVO = new MainLineVO();
            mainLineVO.setLineId(lineId);
            DevDetailDTO devDetailDTO = devDetailDTOMap.get(lineId);
            if (devDetailDTO != null) {
                mainLineVO.setEngineeringName(devDetailDTO.getEngineeringName());
                mainLineVO.setProjectName(devDetailDTO.getProjectName());
                mainLineVO.setDevName(devDetailDTO.getEquipmentName());
                mainLineVO.setLineName(devDetailDTO.getLineName());
                mainLineVO.setObjType(devDetailDTO.getObjType());
                if (ObjectUtil.isNotNull(devDetailDTO.getObjType())) {
                    DictData dictData = dicDataFeignClient.getDicDataById(devDetailDTO.getObjType()).getData();
                    if (dictData != null) {
                        mainLineVO.setObjType(dictData.getName());
                    }
                }
            }
            PqGovernPlan plan1 = pqGovernPlanMap1.get(lineId);
            if (!Objects.isNull(plan1)) {
                mainLineVO.setGovern(Objects.isNull(plan1.getGovernMethod()) ? "未治理" : plan1.getGovernMethod());
            }
            PqGovernPlan plan2 = pqGovernPlanMap2.get(lineId);
            if (!Objects.isNull(plan2)) {
                mainLineVO.setGovern(Objects.isNull(plan2.getGovernMethod()) ? "未治理" : plan2.getGovernMethod());
            }
            MainLineStatLimitRateDetailsQueryParam detailsQueryParam = new MainLineStatLimitRateDetailsQueryParam();
            detailsQueryParam.setLineId(lineId);
            detailsQueryParam.setSearchBeginTime(param.getSearchBeginTime());
            detailsQueryParam.setSearchEndTime(param.getSearchEndTime());
            List<MainLineStatLimitRateDetailsVO> detailsList = this.mainLineStatLimitRateDetails(detailsQueryParam);
            List<String> problemList = new ArrayList<>();
            for (MainLineStatLimitRateDetailsVO details : detailsList) {
                JSONObject entries = JSONUtil.parseObj(details);
                for (Map.Entry<String, Object> entry : entries.entrySet()) {
                    String key = entry.getKey();
                    if (key.endsWith("Overtime")) {
                        String value = entry.getValue().toString();
                        // 值 >0 则表示该电能质量指标有问题
                        Integer intValue = new Integer(value);
                        if (intValue > 0) {
                            String description = getDescription(key);
                            if (StrUtil.isNotBlank(description)) {
                                if (!problemList.contains(description)) {
                                    problemList.add(description);
                                }
                            }
                        }
                    }
                }
            }
            if (CollUtil.isEmpty(detailsList)) {
                mainLineVO.setProblems("暂无数据");
            } else if (CollUtil.isEmpty(problemList)) {
                mainLineVO.setProblems("所有指标都合格");
            } else {
                mainLineVO.setProblems(CollUtil.join(problemList, "、"));
            }
            list.add(mainLineVO);
        }
        result.setRecords(list);
        return result;
    }

    @Override
    public List<MainLineStatLimitRateDetailsVO> mainLineStatLimitRateDetails(MainLineStatLimitRateDetailsQueryParam param) {
        HttpResult<CsLinePO> lineResult = csLineFeignClient.getById(param.getLineId());
        CsLinePO linePO = lineResult.getData();
        if (linePO == null) {
            return Collections.emptyList();
        }
        List<RStatLimitRateDPO> list = this.list(new LambdaQueryWrapper<RStatLimitRateDPO>()
                .eq(RStatLimitRateDPO::getPhasicType, "T")
                .eq(RStatLimitRateDPO::getLineId, param.getLineId())
                .ge(StrUtil.isNotBlank(param.getSearchBeginTime()), RStatLimitRateDPO::getTime, param.getSearchBeginTime())
                .le(StrUtil.isNotBlank(param.getSearchEndTime()), RStatLimitRateDPO::getTime, param.getSearchEndTime())
                .orderByAsc(RStatLimitRateDPO::getTime)
        );

        return list.stream().map(item -> {
            MainLineStatLimitRateDetailsVO vo = BeanUtil.copyProperties(item, MainLineStatLimitRateDetailsVO.class);
            vo.setLineName(linePO.getName());
            Integer lineInterval = linePO.getLineInterval();
            JSONObject entries = JSONUtil.parseObj(vo);
            for (Map.Entry<String, Object> entry : entries.entrySet()) {
                String key = entry.getKey();
                if (key.endsWith("Overtime")) {
                    String value = entry.getValue().toString();
                    Integer intValue = new Integer(value);
                    // 总分钟 = 越限次数 * 间隔时间
                    int minutes = intValue * lineInterval;
                    entries.putOpt(key, minutes);
                }
            }
            return BeanUtil.copyProperties(entries, MainLineStatLimitRateDetailsVO.class);
        }).collect(Collectors.toList());
    }



    @Override
    public TotalLimitTotalStatisticsVO totalLimitTotalStatisticsData(TotalLimitStatisticsParam param) {
        TotalLimitTotalStatisticsVO statisticsVO = new TotalLimitTotalStatisticsVO();
        //获取用户监测点
        List<String> keywordsLineIds = new ArrayList<>();
        List<CsLinePO> poList = csLineFeignClient.getSimpleLine().getData();
        if (CollUtil.isNotEmpty(poList)) {
            keywordsLineIds = poList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(keywordsLineIds)) {
            return statisticsVO;
        }
        List<RStatLimitRateDPO> rateList = this.list(new LambdaQueryWrapper<RStatLimitRateDPO>()
                .eq(RStatLimitRateDPO::getPhasicType, "T")
                .ge(StrUtil.isNotBlank(param.getSearchBeginTime()), RStatLimitRateDPO::getTime, param.getSearchBeginTime())
                .le(StrUtil.isNotBlank(param.getSearchEndTime()), RStatLimitRateDPO::getTime, param.getSearchEndTime())
                .in(RStatLimitRateDPO::getLineId, keywordsLineIds)
                .orderByAsc(RStatLimitRateDPO::getTime)
        );

        int flickerTotalTime = rateList.stream().mapToInt(RStatLimitRateDPO::getFlickerOvertime).sum();
        int voltageDevTotalTime = rateList.stream().mapToInt(RStatLimitRateDPO::getVoltageDevOvertime).sum();
        int ubalanceTotalTime = rateList.stream().mapToInt(RStatLimitRateDPO::getUbalanceOvertime).sum();
        int iharmTotalTime = 0;
        int uharmTotalTime = 0;
        for (RStatLimitRateDPO rate : rateList) {
            JSONObject entries = JSONUtil.parseObj(rate);
            for (Map.Entry<String, Object> entry : entries.entrySet()) {
                String key = entry.getKey();
                if (key.endsWith("Overtime")) {
                    String value = entry.getValue().toString();
                    int intValue = new Integer(value);
                    if (key.startsWith("uharm")) {
                        uharmTotalTime += intValue;
                    }
                    if (key.startsWith("iharm")) {
                        iharmTotalTime += intValue;
                    }
                }
            }

        }
        int totalTime = flickerTotalTime + voltageDevTotalTime + ubalanceTotalTime + iharmTotalTime + uharmTotalTime;
        if (totalTime == 0) {
            return statisticsVO;
        }
        statisticsVO.setFlicker(calculatePercentage(flickerTotalTime, totalTime));
        statisticsVO.setUharm(calculatePercentage(uharmTotalTime, totalTime));
        statisticsVO.setIharm(calculatePercentage(iharmTotalTime, totalTime));
        statisticsVO.setVoltageDev(calculatePercentage(voltageDevTotalTime, totalTime));
        statisticsVO.setUbalance(calculatePercentage(ubalanceTotalTime, totalTime));
        return statisticsVO;
    }

    @Override
    public List<TotalLimitStatisticsVO> totalLimitStatisticsList(TotalLimitStatisticsParam param) {
        List<TotalLimitStatisticsVO> result = new ArrayList<>();
        //获取用户监测点
        List<String> keywordsLineIds = new ArrayList<>();
        List<CsLinePO> poList = csLineFeignClient.getSimpleLine().getData();
        if (CollUtil.isNotEmpty(poList)) {
            keywordsLineIds = poList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        }
        if (CollUtil.isEmpty(keywordsLineIds)) {
            return result;
        }
        List<RStatLimitRateDPO> rateList = this.list(new LambdaQueryWrapper<RStatLimitRateDPO>()
                .eq(RStatLimitRateDPO::getPhasicType, "T")
                .ge(StrUtil.isNotBlank(param.getSearchBeginTime()), RStatLimitRateDPO::getTime, param.getSearchBeginTime())
                .le(StrUtil.isNotBlank(param.getSearchEndTime()), RStatLimitRateDPO::getTime, param.getSearchEndTime())
                .in(RStatLimitRateDPO::getLineId, keywordsLineIds)
                .orderByAsc(RStatLimitRateDPO::getTime)
        );
        if (CollUtil.isEmpty(rateList)) {
            return result;
        }
        Map<String, List<RStatLimitRateDPO>> lineMap = rateList.stream().collect(Collectors.groupingBy(RStatLimitRateDPO::getLineId));

        List<CsLinePO> linePOList = csLineFeignClient.queryLineById(new ArrayList<>(lineMap.keySet())).getData();
        if (CollUtil.isEmpty(linePOList)) {
            return result;
        }

        List<DevDetailDTO> devDetailDTOList = csCommTerminal.getLedgerByLineId(keywordsLineIds).getData();
        Map<String, DevDetailDTO> devDetailDTOMap = devDetailDTOList.stream().collect(Collectors.toMap(DevDetailDTO::getLineId, item -> item));

        TotalLimitStatisticsVO statisticsVO;
        for (CsLinePO linePO : linePOList) {
            statisticsVO = new TotalLimitStatisticsVO();
            statisticsVO.setEngineeringName(devDetailDTOMap.get(linePO.getLineId()).getEngineeringName());
            statisticsVO.setProjectName(devDetailDTOMap.get(linePO.getLineId()).getProjectName());
            statisticsVO.setDevName(devDetailDTOMap.get(linePO.getLineId()).getEquipmentName()      );
            statisticsVO.setLineId(linePO.getLineId());
            statisticsVO.setLineName(linePO.getName());
            List<RStatLimitRateDPO> lineRateList = lineMap.get(linePO.getLineId());
            int totalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getAllTime).sum();
            int flickerTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getFlickerAllTime).sum();
            int flickerTotalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getFlickerOvertime).sum();
            int voltageDevTotalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getVoltageDevOvertime).sum();
            int ubalanceTotalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getUbalanceOvertime).sum();
            int uharm = 0;
            int iharm = 0;
            for (RStatLimitRateDPO item : lineRateList) {
                JSONObject entries = JSONUtil.parseObj(item);
                List<Integer> uharmList = new ArrayList<>();
                List<Integer> iharmList = new ArrayList<>();
                for (Map.Entry<String, Object> entry : entries.entrySet()) {
                    String key = entry.getKey();
                    if (key.endsWith("Overtime")) {
                        if (key.startsWith("uharm")) {
                            String value = entry.getValue().toString();
                            Integer intValue = new Integer(value);
                            uharmList.add(intValue);
                        }
                        if (key.startsWith("iharm")) {
                            String value = entry.getValue().toString();
                            Integer intValue = new Integer(value);
                            iharmList.add(intValue);
                        }
                    }
                }
                // 取最大值
                uharm += uharmList.stream().max(Integer::compareTo).orElse(0);
                iharm += iharmList.stream().max(Integer::compareTo).orElse(0);
            }
            if (totalTime == 0) {
                statisticsVO.setFlicker(0.0);
                statisticsVO.setVoltageDev(0.0);
                statisticsVO.setUbalance(0.0);
                statisticsVO.setUharm(0.0);
                statisticsVO.setIharm(0.0);
            } else {
                statisticsVO.setFlicker(calculatePercentage(flickerTotalTime, flickerTime));
                statisticsVO.setVoltageDev(calculatePercentage(voltageDevTotalTime, totalTime));
                statisticsVO.setUbalance(calculatePercentage(ubalanceTotalTime, totalTime));
                statisticsVO.setUharm(calculatePercentage(uharm, totalTime));
                statisticsVO.setIharm(calculatePercentage(iharm, totalTime));
            }
            result.add(statisticsVO);

        }
        return result;
    }

    @Override
    public List<TotalLimitStatisticsDetailsVO> totalLimitStatisticsDetails(TotalLimitStatisticsDetailsQueryParam param) {

        HttpResult<CsLinePO> lineResult = csLineFeignClient.getById(param.getLineId());
        CsLinePO linePO = lineResult.getData();
        if (linePO == null) {
            return Collections.emptyList();
        }
        List<RStatLimitRateDPO> list = this.list(new LambdaQueryWrapper<RStatLimitRateDPO>()
                .eq(RStatLimitRateDPO::getLineId, param.getLineId())
                .eq(RStatLimitRateDPO::getPhasicType, "T")
                .ge(StrUtil.isNotBlank(param.getSearchBeginTime()), RStatLimitRateDPO::getTime, param.getSearchBeginTime())
                .le(StrUtil.isNotBlank(param.getSearchEndTime()), RStatLimitRateDPO::getTime, param.getSearchEndTime())
                .orderByAsc(RStatLimitRateDPO::getTime)
        );

        List<DevDetailDTO> devDetailDTOList = csCommTerminal.getLedgerByLineId(Collections.singletonList(param.getLineId())).getData();
        Map<String, DevDetailDTO> devDetailDTOMap = devDetailDTOList.stream().collect(Collectors.toMap(DevDetailDTO::getLineId, item -> item));

        return list.stream().map(item -> {
            MainLineStatLimitRateDetailsVO vo = BeanUtil.copyProperties(item, MainLineStatLimitRateDetailsVO.class);
            vo.setEngineeringName(devDetailDTOMap.get(param.getLineId()).getEngineeringName());
            vo.setProjectName(devDetailDTOMap.get(param.getLineId()).getProjectName());
            vo.setDevName(devDetailDTOMap.get(param.getLineId()).getEquipmentName());
            vo.setLineName(linePO.getName());
            Integer allTime = item.getAllTime();
            Integer flickerTime = item.getFlickerAllTime();
            JSONObject entries = JSONUtil.parseObj(vo);
            for (Map.Entry<String, Object> entry : entries.entrySet()) {
                String key = entry.getKey();
                if (key.endsWith("Overtime") && allTime != 0 && !Objects.equals("flickerOvertime", key)) {
                    String value = entry.getValue().toString();
                    int intValue = new Integer(value);
                    // 占比 = 越限次数 / 总次数 * 100
                    double proportion = calculatePercentage(intValue, allTime);
                    entries.putOpt(key, proportion);
                } else if (Objects.equals("flickerOvertime", key)) {
                    String value = entry.getValue().toString();
                    int intValue = new Integer(value);
                    // 占比 = 越限次数 / 总次数 * 100
                    double proportion = calculatePercentage(intValue, flickerTime);
                    entries.putOpt(key, proportion);
                }
            }
            return BeanUtil.copyProperties(entries, TotalLimitStatisticsDetailsVO.class);
        }).collect(Collectors.toList());
    }

    @Override
    public TotalLimitTotalStatisticsVO gridSideLimitTotalStatisticsData(TotalLimitStatisticsParam param) {
        TotalLimitTotalStatisticsVO statisticsVO = new TotalLimitTotalStatisticsVO();
        // 获取电网侧监测点
        DictData dictData = dicDataFeignClient.getDicDataByCode(GRID_SIDE_DICT_CODE).getData();
        CsLinePO queryParam = new CsLinePO();
        queryParam.setPosition(dictData.getId());
        List<CsLinePO> linePOList = csLineFeignClient.list(queryParam).getData();
        List<String> lineIds = linePOList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        if (CollUtil.isEmpty(lineIds)) {
            return statisticsVO;
        }
        List<RStatLimitRateDPO> rateList = this.list(new LambdaQueryWrapper<RStatLimitRateDPO>()
                .in(RStatLimitRateDPO::getLineId, lineIds)
                .eq(RStatLimitRateDPO::getPhasicType, "T")
                .ge(StrUtil.isNotBlank(param.getSearchBeginTime()), RStatLimitRateDPO::getTime, param.getSearchBeginTime())
                .le(StrUtil.isNotBlank(param.getSearchEndTime()), RStatLimitRateDPO::getTime, param.getSearchEndTime())
                .orderByAsc(RStatLimitRateDPO::getTime)
        );


        int flickerTotalTime = rateList.stream().mapToInt(RStatLimitRateDPO::getFlickerOvertime).sum();
        int voltageDevTotalTime = rateList.stream().mapToInt(RStatLimitRateDPO::getVoltageDevOvertime).sum();
        int ubalanceTotalTime = rateList.stream().mapToInt(RStatLimitRateDPO::getUbalanceOvertime).sum();
        int iharmTotalTime = 0;
        int uharmTotalTime = 0;
        for (RStatLimitRateDPO rate : rateList) {
            JSONObject entries = JSONUtil.parseObj(rate);
            for (Map.Entry<String, Object> entry : entries.entrySet()) {
                String key = entry.getKey();
                if (key.endsWith("Overtime")) {
                    String value = entry.getValue().toString();
                    int intValue = new Integer(value);
                    if (key.startsWith("uharm")) {
                        uharmTotalTime += intValue;
                    }
                    if (key.startsWith("iharm")) {
                        iharmTotalTime += intValue;
                    }
                }
            }

        }
        int totalTime = flickerTotalTime + voltageDevTotalTime + ubalanceTotalTime + iharmTotalTime + uharmTotalTime;
        if (totalTime == 0) {
            return statisticsVO;
        }
        statisticsVO.setFlicker(calculatePercentage(flickerTotalTime, totalTime));
        statisticsVO.setUharm(calculatePercentage(uharmTotalTime, totalTime));
        statisticsVO.setIharm(calculatePercentage(iharmTotalTime, totalTime));
        statisticsVO.setVoltageDev(calculatePercentage(voltageDevTotalTime, totalTime));
        statisticsVO.setUbalance(calculatePercentage(ubalanceTotalTime, totalTime));
        return statisticsVO;
    }

    @Override
    public List<TotalLimitStatisticsVO> gridSideLimitStatisticsList(TotalLimitStatisticsParam param) {
        List<TotalLimitStatisticsVO> result = new ArrayList<>();
        // 获取电网侧监测点
        DictData dictData = dicDataFeignClient.getDicDataByCode(GRID_SIDE_DICT_CODE).getData();
        CsLinePO queryParam = new CsLinePO();
        queryParam.setPosition(dictData.getId());
        List<CsLinePO> linePOList = csLineFeignClient.list(queryParam).getData();
        List<String> lineIds = linePOList.stream().map(CsLinePO::getLineId).collect(Collectors.toList());
        if (CollUtil.isEmpty(lineIds)) {
            return result;
        }
        List<RStatLimitRateDPO> rateList = this.list(new LambdaQueryWrapper<RStatLimitRateDPO>()
                .in(RStatLimitRateDPO::getLineId, lineIds)
                .eq(RStatLimitRateDPO::getPhasicType, "T")
                .ge(StrUtil.isNotBlank(param.getSearchBeginTime()), RStatLimitRateDPO::getTime, param.getSearchBeginTime())
                .le(StrUtil.isNotBlank(param.getSearchEndTime()), RStatLimitRateDPO::getTime, param.getSearchEndTime())
                .orderByAsc(RStatLimitRateDPO::getTime)
        );
        if (CollUtil.isEmpty(rateList)) {
            return result;
        }
        Map<String, List<RStatLimitRateDPO>> lineMap = rateList.stream().collect(Collectors.groupingBy(RStatLimitRateDPO::getLineId));
        Map<String, CsLinePO> linePOMap = linePOList.stream().collect(Collectors.toMap(CsLinePO::getLineId, csLinePO -> csLinePO));
        List<CsLinePO> lineList = new ArrayList<>();
        for (String lineId : lineMap.keySet()) {
            CsLinePO linePO = linePOMap.getOrDefault(lineId, null);
            if (linePO != null) {
                lineList.add(linePO);
            }
        }
        if (CollUtil.isEmpty(lineList)) {
            return result;
        }
        TotalLimitStatisticsVO statisticsVO;

        List<DevDetailDTO> devDetailDTOList = csCommTerminal.getLedgerByLineId(lineIds).getData();
        Map<String, DevDetailDTO> devDetailDTOMap = devDetailDTOList.stream().collect(Collectors.toMap(DevDetailDTO::getLineId, item -> item));

        for (CsLinePO linePO : lineList) {
            statisticsVO = new TotalLimitStatisticsVO();
            statisticsVO.setEngineeringName(devDetailDTOMap.get(linePO.getLineId()).getEngineeringName());
            statisticsVO.setProjectName(devDetailDTOMap.get(linePO.getLineId()).getProjectName());
            statisticsVO.setDevName(devDetailDTOMap.get(linePO.getLineId()).getEquipmentName());
            statisticsVO.setLineId(linePO.getLineId());
            statisticsVO.setLineName(linePO.getName());
            List<RStatLimitRateDPO> lineRateList = lineMap.get(linePO.getLineId());
            int totalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getAllTime).sum();
            int flickerTotalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getFlickerOvertime).sum();
            int voltageDevTotalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getVoltageDevOvertime).sum();
            int ubalanceTotalTime = lineRateList.stream().mapToInt(RStatLimitRateDPO::getUbalanceOvertime).sum();
            int uharm = 0;
            int iharm = 0;
            for (RStatLimitRateDPO item : lineRateList) {
                JSONObject entries = JSONUtil.parseObj(item);
                List<Integer> uharmList = new ArrayList<>();
                List<Integer> iharmList = new ArrayList<>();
                for (Map.Entry<String, Object> entry : entries.entrySet()) {
                    String key = entry.getKey();
                    if (key.endsWith("Overtime")) {
                        if (key.startsWith("uharm")) {
                            String value = entry.getValue().toString();
                            Integer intValue = new Integer(value);
                            uharmList.add(intValue);
                        }
                        if (key.startsWith("iharm")) {
                            String value = entry.getValue().toString();
                            Integer intValue = new Integer(value);
                            iharmList.add(intValue);
                        }
                    }
                }
                // 取最大值
                uharm += uharmList.stream().max(Integer::compareTo).orElse(0);
                iharm += iharmList.stream().max(Integer::compareTo).orElse(0);
            }
            if (totalTime == 0) {
                statisticsVO.setFlicker(0.0);
                statisticsVO.setVoltageDev(0.0);
                statisticsVO.setUbalance(0.0);
                statisticsVO.setUharm(0.0);
                statisticsVO.setIharm(0.0);
            } else {
                statisticsVO.setFlicker(calculatePercentage(flickerTotalTime, totalTime));
                statisticsVO.setVoltageDev(calculatePercentage(voltageDevTotalTime, totalTime));
                statisticsVO.setUbalance(calculatePercentage(ubalanceTotalTime, totalTime));
                statisticsVO.setUharm(calculatePercentage(uharm, totalTime));
                statisticsVO.setIharm(calculatePercentage(iharm, totalTime));
            }
            result.add(statisticsVO);

        }
        return result;
    }

    private String getDescription(String key) {
        if (StrUtil.equals(key, "flickerOvertime")) {
            return "闪变越限超标";
        }
        if (StrUtil.equals(key, "freqDevOvertime")) {
            return "频率偏差超标";
        }
        if (StrUtil.equals(key, "voltageDevOvertime")) {
            return "电压偏差超标";
        }
        if (StrUtil.equals(key, "ubalanceOvertime")) {
            return "三相电压不平衡超标";
        }
        // 电压
        if (StrUtil.startWith(key, "uharm")) {
            // 从 key 中提取数字 2
            String number = key.substring(5, key.indexOf("Overtime"));
            return number + "次谐波电压";
        }
        // 电流
        if (StrUtil.startWith(key, "iharm")) {
            // 从 key 中提取数字
            String number = key.substring(5, key.indexOf("Overtime"));
            return number + "次谐波电流";
        }
        return null;
    }


    private double calculatePercentage(double part, double total) {
        if (total == 0) {
            return 0.0;
        }
        return Double.parseDouble(df.format(BigDecimal.valueOf(part / total * 100.0)
                .setScale(2, RoundingMode.HALF_UP).doubleValue()));
    }

}
