package com.njcn.advance.service.carrycapacity.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.njcn.advance.enums.AdvanceResponseEnum;
import com.njcn.advance.enums.CarryingCapacityEnum;
import com.njcn.advance.pojo.carrycapacity.excel.*;
import com.njcn.advance.pojo.carrycapacity.param.CarryCapacityCalParam;
import com.njcn.advance.pojo.carrycapacity.param.CarryCapacityEvaluateParam;
import com.njcn.advance.pojo.carrycapacity.param.CarryCapacityQueryDataParam;
import com.njcn.advance.pojo.carrycapacity.param.ExcelDataParam;
import com.njcn.advance.pojo.carrycapacity.po.CarryCapacityDataPO;
import com.njcn.advance.pojo.carrycapacity.po.CarryCapacityDevicePO;
import com.njcn.advance.pojo.carrycapacity.po.CarryCapacityResultPO;
import com.njcn.advance.pojo.carrycapacity.po.CarryCapacityUserPO;
import com.njcn.advance.pojo.carrycapacity.vo.*;
import com.njcn.advance.service.carrycapacity.*;
import com.njcn.advance.utils.CZNLPG;
import com.njcn.advance.utils.EasyExcelUtil;
import com.njcn.advance.utils.Utils;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.utils.PubUtils;
import com.njcn.device.biz.pojo.po.Overlimit;
import com.njcn.device.biz.utils.COverlimitUtil;
import com.njcn.device.pq.api.DeviceTreeClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.pojo.vo.LineDetailDataVO;
import com.njcn.device.pq.pojo.vo.TerminalTree;
import com.njcn.influx.constant.InfluxDbSqlConstant;
import com.njcn.influx.imapper.DataHarmPowerPMapper;
import com.njcn.influx.imapper.DataHarmPowerQMapper;
import com.njcn.influx.imapper.DataVMapper;
import com.njcn.influx.imapper.DataIMapper;
import com.njcn.influx.pojo.bo.CarryCapcityData;
import com.njcn.influx.pojo.constant.InfluxDBTableConstant;
import com.njcn.influx.pojo.po.DataI;
import com.njcn.oss.constant.OssPath;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.DictData;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.njcn.advance.pojo.carrycapacity.vo.CarryCapacityStrategyVO.CarryCapacityStrategysingleVO;

/**
 * Description:
 * Date: 2024/1/31  14:42【需求编号】
 *
 * @author clam
 * @version V1.0.0
 */
@Service
@RequiredArgsConstructor
public class CarryCapacityServiceImpl implements CarryCapacityService {

    private final LineFeignClient lineFeignClient;
    private final DeviceTreeClient deviceTreeClient;

    private final DataHarmPowerQMapper dataHarmPowerqMapper;

    private final DataHarmPowerPMapper dataHarmPowerpMapper;
    private final DataVMapper datavMapper;

    private final DataIMapper dataiMapper;

    private final CarryCapacityStrategyPOService carryCapacityStrategyPOService;
    private final CarryCapacityDataPOService carryCapacityDataPOService;
    private final RedisUtil redisUtil;
    private final CarryCapacityResultPOService carryCapacityResultPOService;
    private final CarryCapacityUserPOService carryCapacityUserPOService;
    private static final double DEFAULTVALUE = 3.1415926;

    private final FileStorageUtil fileStorageUtil;

    private final DicDataFeignClient dicDataFeignClient;


    @Override
    public CarryCapacityDataVO queryCarryCapacityData(CarryCapacityQueryDataParam queryParam) {

        //前一周数据
        List<CarryCapcityData> dataHarmPowerpList;
        List<CarryCapcityData> dataHarmPowerqList;
        //前2周的数据
        List<CarryCapcityData> dataHarmPowerP2List;
        List<CarryCapcityData> dataHarmPowerQ2List;
        List<CarryCapcityData> dataHarmPowerU2List;

        CarryCapacityDataVO carryCapacityDataVO = new CarryCapacityDataVO();
        String lineId = queryParam.getLineId();
        LineDetailDataVO data = lineFeignClient.getLineDetailData(lineId).getData();
//        //时间间隔
        Integer timeInterval = data.getTimeInterval();

        LocalDate startDate = queryParam.getStartTime();
        LocalDate endDate = queryParam.getEndTime();
        //前2周的时间
        LocalDate startDate2 = startDate.plusWeeks(-1);
        LocalDate endDate2 = endDate.plusWeeks(-1);


        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String startTime = LocalDateTimeUtil.format(queryParam.getStartTime(), formatter) + " 00:00:00";
        String endTime = LocalDateTimeUtil.format(queryParam.getEndTime(), formatter) + " 23:59:00";

        //先重redis读取数据，无数据，查看是否存在文件，不存在文件查数据库，数据校验补通过上传文件
        dataHarmPowerpList = (List<CarryCapcityData>) redisUtil.getObjectByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "P");
        dataHarmPowerP2List = (List<CarryCapcityData>) redisUtil.getObjectByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "P");
        dataHarmPowerQ2List = (List<CarryCapcityData>) redisUtil.getObjectByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "Q");
        dataHarmPowerU2List = (List<CarryCapcityData>) redisUtil.getObjectByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "U");

        if (CollectionUtil.isEmpty(dataHarmPowerpList) ||
                CollectionUtil.isEmpty(dataHarmPowerP2List) ||
                CollectionUtil.isEmpty(dataHarmPowerQ2List) ||
                CollectionUtil.isEmpty(dataHarmPowerU2List)) {
            CarryCapacityDataPO one = carryCapacityDataPOService.lambdaQuery().eq(CarryCapacityDataPO::getLineId, lineId)
                    .eq(CarryCapacityDataPO::getStartTime, queryParam.getStartTime())
                    .eq(CarryCapacityDataPO::getEndTime, queryParam.getEndTime()).one();
            if (Objects.nonNull(one)) {
                //todo 调用查询文件
                InputStream fileStream = fileStorageUtil.getFileStream(one.getDateList());
                ExcelDataDTO excelDataDTO = parsingFile(one.getStartTime(), one.getEndTime(), fileStream);
                dataHarmPowerpList = excelDataDTO.getDataHarmPowerPList();
                dataHarmPowerP2List = excelDataDTO.getDataHarmPowerP2List();
                dataHarmPowerQ2List = excelDataDTO.getDataHarmPowerQ2List();
                dataHarmPowerU2List = excelDataDTO.getDataHarmPowerU2List();


            } else {
                  /* 近一周的数据包括电流,电压，有功功率，无功功率，数据完整性校验就取有功功率一组数据校验，因为，要有都有要没有都没有，数据查询按时间间隔和tag分组，
                        缺失布置3.1415926，后边更具3.1415926个数来判断数据完整性，及进行数据补充*/
                //有功功率
                String sqlP1 = "select mean(p)*1000 as value from data_harmpower_p where  value_type='CP95' and phasic_type!='T' and line_id='" + lineId +
                        "'  and  time >= '" + startTime + "'and time <= '" + endTime + "'" + "group by time(" + timeInterval + "m) ,* fill(0.0031415926)" + InfluxDbSqlConstant.TZ;
                dataHarmPowerpList = dataHarmPowerpMapper.getSqlResult(sqlP1);

                //数据校验
                if (CollectionUtil.isEmpty(dataHarmPowerpList)) {
                    throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                } else {

                    if (checkData(dataHarmPowerpList, startDate, endDate, timeInterval)) {

                        throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                    }
                }
                //数据缺失填补
                linearInterpolation(dataHarmPowerpList);
//                redisUtil.saveByKey(lineId+"#"+LocalDateTimeUtil.format(startDate, formatter)+"#"+LocalDateTimeUtil.format(endDate, formatter)+"#"+"P",
//                        dataHarmPowerPList);

                //无功功率
                String sqlQ1 = "select mean(q)*1000 as value from data_harmpower_q where  value_type='CP95' and phasic_type!='T' and line_id='" + lineId +
                        "'  and  time >= '" + startTime + "'and time <= '" + endTime + "'" + "group by time(" + timeInterval + "m) ,* fill(0.0031415926)" + InfluxDbSqlConstant.TZ;
                dataHarmPowerqList = dataHarmPowerqMapper.getSqlResult(sqlQ1);
                //数据缺失填补
                //数据校验
                if (CollectionUtil.isEmpty(dataHarmPowerqList)) {
                    throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                } else {

                    if (checkData(dataHarmPowerqList, startDate, endDate, timeInterval)) {

                        throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                    }
                }

                linearInterpolation(dataHarmPowerqList);
//                redisUtil.saveByKey(lineId+"#"+LocalDateTimeUtil.format(startDate, formatter)+"#"+LocalDateTimeUtil.format(endDate, formatter)+"#"+"Q",
//                        dataHarmPowerqList);


                //前2周的数据用于计算首端电流模型参数
                String forwardStartTime = LocalDateTimeUtil.format(queryParam.getStartTime()
                                .plusWeeks(-1)
                        , formatter) + " 00:00:00";
                String forwardEndTime = LocalDateTimeUtil.format(queryParam.getEndTime()
                                .plusWeeks(-1)
                        , formatter) + " 23:59:00";

                String sqlP2 = "select mean(p)*1000 as value from data_harmpower_p where  value_type='CP95' and phasic_type!='T' and line_id='" + lineId +
                        "'  and  time >= '" + forwardStartTime + "'and time <= '" + forwardEndTime + "'" + "group by time(" + timeInterval + "m) ,* fill(0.0031415926)" + InfluxDbSqlConstant.TZ;
                dataHarmPowerP2List = dataHarmPowerpMapper.getSqlResult(sqlP2);
                //数据校验
                if (CollectionUtil.isEmpty(dataHarmPowerP2List)) {
                    throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                } else {

                    if (checkData(dataHarmPowerP2List, startDate2, endDate2, timeInterval)) {

                        throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                    }
                }

                //数据缺失填补
                linearInterpolation(dataHarmPowerP2List);


                //无功功率
                String sqlQ2 = "select mean(q)*1000 as value from data_harmpower_q where  value_type='CP95' and phasic_type!='T' and line_id='" + lineId +
                        "'  and  time >= '" + forwardStartTime + "'and time <= '" + forwardEndTime + "'" + "group by time(" + timeInterval + "m) ,* fill(0.0031415926)" + InfluxDbSqlConstant.TZ;
                dataHarmPowerQ2List = dataHarmPowerqMapper.getSqlResult(sqlQ2);
                //数据校验
                //数据校验
                if (CollectionUtil.isEmpty(dataHarmPowerQ2List)) {
                    throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                } else {

                    if (checkData(dataHarmPowerQ2List, startDate2, endDate2, timeInterval)) {

                        throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                    }
                }

                //数据缺失填补
                linearInterpolation(dataHarmPowerQ2List);


                //电压
                String sqlU2 = "select mean(rms)*1000 as value from data_v where  value_type='CP95' and phasic_type!='T' and line_id='" + lineId +
                        "'  and  time >= '" + forwardStartTime + "'and time <= '" + forwardEndTime + "'" + "group by time(" + timeInterval + "m) ,* fill(0.0031415926)" + InfluxDbSqlConstant.TZ;
                dataHarmPowerU2List = datavMapper.getSqlResult(sqlU2);
                //数据校验
                //数据校验
                if (CollectionUtil.isEmpty(dataHarmPowerU2List)) {
                    throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                } else {

                    if (checkData(dataHarmPowerU2List, startDate2, endDate2, timeInterval)) {

                        throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                    }
                }
                //数据缺失填补
                linearInterpolation(dataHarmPowerU2List);
                redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "P",
                        dataHarmPowerpList);
                redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "P",
                        dataHarmPowerP2List);
                redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "Q",
                        dataHarmPowerQ2List);
                redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "U",
                        dataHarmPowerU2List);


            }


        }
//        dataHarmPowerpList = dataHarmPowerpList.stream().map(temp -> {
//            temp.setTime(temp.getTime().plusMillis(TimeUnit.HOURS.toMillis(8)));
//            return temp;
//        }).collect(Collectors.toList());
        carryCapacityDataVO.setData(dataHarmPowerpList);


        List<String> phaseType = Stream.of("A", "B", "C").collect(Collectors.toList());

        Map<String, Double> results = new HashMap<>(4);
        //计算最小Cp95值用于评估
        List<CarryCapcityData> finalDataHarmPowerpList = dataHarmPowerpList;
        phaseType.forEach(phase -> {
            List<Double> listP = finalDataHarmPowerpList.stream().filter(temp -> Utils.isTimeInRange(temp.getTime(), LocalTime.of(9, 0), LocalTime.of(15, 0)))
                    .filter(temp -> temp.getValue() != DEFAULTVALUE && Objects.nonNull(temp.getValue()))
                    .filter(temp -> Objects.equals(temp.getPhaseType(), phase))
                    .map(CarryCapcityData::getValue)
                    .collect(Collectors.toList());
            double pMin = CZNLPG.calculatePercentile(listP, 1);
            results.put(phase, pMin);
        });

        carryCapacityDataVO.setP_βminMap(results);

        try {
            //用前2周的数据计算C,a,b
            Map<String, Double[]> stringMap = caluParam(dataHarmPowerP2List, dataHarmPowerQ2List, dataHarmPowerU2List);
            carryCapacityDataVO.setStringMap(stringMap);
            return carryCapacityDataVO;
        }catch (Exception e){
            return carryCapacityDataVO;
        }

    }

    @Override
    public CarryCapacityDataQVO queryCarryCapacityqData(CarryCapacityQueryDataParam queryParam) {

        CarryCapacityDataQVO carryCapacityDataqVO = new CarryCapacityDataQVO();
        String lineId = queryParam.getLineId();
        LineDetailDataVO data = lineFeignClient.getLineDetailData(lineId).getData();
        //时间间隔
        Integer timeInterval = data.getTimeInterval();
//        Integer timeInterval =10;

        //根据时间间隔算出最低数据量 7天*6小时*60分钟*3项*90%/时间间隔
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startDate = queryParam.getStartTime();
        LocalDate endDate = queryParam.getEndTime();

        String startTime = LocalDateTimeUtil.format(queryParam.getStartTime(), formatter) + " 00:00:00";
        String endTime = LocalDateTimeUtil.format(queryParam.getEndTime(), formatter) + " 23:59:00";
        List<CarryCapcityData> dataHarmPowerqList = new ArrayList<>();
        dataHarmPowerqList = (List<CarryCapcityData>) redisUtil.getObjectByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "Q");
        if (CollectionUtil.isEmpty(dataHarmPowerqList)) {
            //无功功率
            String sqlQ1 = "select mean(q)*1000 as value from data_harmpower_q where  value_type='CP95' and phasic_type!='T' and line_id='" + lineId +
                    "'  and  time >= '" + startTime + "'and time <= '" + endTime + "'" + "group by time(" + timeInterval + "m) ,* fill(0.0031415926)" + InfluxDbSqlConstant.TZ;
            dataHarmPowerqList = dataHarmPowerqMapper.getSqlResult(sqlQ1);
            if (CollectionUtil.isEmpty(dataHarmPowerqList)) {
                throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
            } else {

                if (checkData(dataHarmPowerqList, startDate, endDate, timeInterval)) {

                    throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                }
            }
            //数据缺失填补
            linearInterpolation(dataHarmPowerqList);
            redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "Q",
                    dataHarmPowerqList);
        }
//        dataHarmPowerqList = dataHarmPowerqList.stream().map(temp -> {
//            temp.setTime(temp.getTime().plusMillis(TimeUnit.HOURS.toMillis(8)));
//            return temp;
//        }).collect(Collectors.toList());

        carryCapacityDataqVO.setData(dataHarmPowerqList);


        List<String> phaseType = Stream.of("A", "B", "C").collect(Collectors.toList());

        Map<String, Double> results = new HashMap<>(4);
        //计算最小Cp95值用于评估
        List<CarryCapcityData> finalDataHarmPowerqList = dataHarmPowerqList;
        phaseType.forEach(phase -> {
            List<Double> listQ = finalDataHarmPowerqList.stream().filter(temp -> Utils.isTimeInRange(temp.getTime(), LocalTime.of(9, 0), LocalTime.of(15, 0)))
                    .filter(temp -> temp.getValue() != DEFAULTVALUE && Objects.nonNull(temp.getValue()))
                    .filter(temp -> Objects.equals(temp.getPhaseType(), phase))
                    .map(CarryCapcityData::getValue)
                    .collect(Collectors.toList());
            double qMin = CZNLPG.calculatePercentile(listQ, 1);
            results.put(phase, qMin);
        });

        carryCapacityDataqVO.setQ_βminMap(results);
        return carryCapacityDataqVO;
    }

    @Override
    public CarryCapacityDataIVO queryCarryCapacityiData(CarryCapacityQueryDataParam queryParam) {
        CarryCapacityDataIVO carryCapacityDataiVO = new CarryCapacityDataIVO();
        String lineId = queryParam.getLineId();
        LineDetailDataVO data = lineFeignClient.getLineDetailData(lineId).getData();
        //时间间隔
        Integer timeInterval = data.getTimeInterval();
        LocalDate startDate = queryParam.getStartTime();
        LocalDate endDate = queryParam.getEndTime();

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String startTime = LocalDateTimeUtil.format(startDate, formatter) + " 00:00:00";
        String endTime = LocalDateTimeUtil.format(endDate, formatter) + " 23:59:00";

        List<DataI> dataI = new ArrayList<>();
        dataI = (List<DataI>) redisUtil.getObjectByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "I");

        if (CollectionUtil.isEmpty(dataI)) {
            //电流
            StringBuilder stringBuilder1 = new StringBuilder();
            StringBuilder stringBuilder2 = new StringBuilder();
            for (int i = 2; i <= 25; i++) {
                if (i == 25) {
                    stringBuilder1.append("mean(i_").append(i).append(") AS i_").append(i);
                } else {
                    stringBuilder1.append("mean(i_").append(i).append(") AS i_").append(i).append(",");
                }
            }
            stringBuilder2.append("line_id='").append(lineId).append("' and ").append(InfluxDbSqlConstant.TIME + " >= '").append(startTime).append("' and ").append(InfluxDbSqlConstant.TIME).append(" <= '").append(endTime).append("'  group by time(").append(timeInterval).append("m),* fill(3.1415926) ").append(InfluxDbSqlConstant.TZ);
            String sqlI1 = "select " + stringBuilder1 + " from " + InfluxDBTableConstant.DATA_I + " where value_type='CP95' and phasic_type!='T' and  " + stringBuilder2;
            dataI = dataiMapper.getSqlResult(sqlI1);
            //此处查询influxdb少8个小时
            dataI = dataI.stream().map(temp -> {
                temp.setTime(temp.getTime().plusMillis(TimeUnit.HOURS.toMillis(8)));
                return temp;
            }).collect(Collectors.toList());
            if (CollectionUtil.isEmpty(dataI)) {
                throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
            } else {
                List<CarryCapcityData> iList = dataI.stream().map(temp -> {
                    CarryCapcityData carryCapcityData = new CarryCapcityData();
                    BeanUtils.copyProperties(temp, carryCapcityData);
                    carryCapcityData.setValue(temp.getI2());
                    return carryCapcityData;
                }).collect(Collectors.toList());
                if (checkData(iList, startDate, endDate, timeInterval)) {

                    throw new BusinessException(AdvanceResponseEnum.DATA_NOT_FOUND);
                }
            }
            //数据缺失填补
            linearInterpolationI(dataI);
            redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "I",
                    dataI);

        }

        List<CarryCapcityData> iList = dataI.stream().map(temp -> {
            CarryCapcityData carryCapcityData = new CarryCapcityData();
            BeanUtils.copyProperties(temp, carryCapcityData);
            carryCapcityData.setValue(Utils.getAttributeValueByPropertyName(temp, "i" + queryParam.getTime()));
            return carryCapcityData;
        }).collect(Collectors.toList());
        carryCapacityDataiVO.setData(iList);

        List<Double> iMaxList = new ArrayList<>();
        List<Integer> integerList = Stream.of(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25).collect(Collectors.toList());
        List<String> phaseType = Stream.of("A", "B", "C").collect(Collectors.toList());
        List<DataI> finalDataI = dataI;
        integerList.forEach(temp -> {
            List<Double> tempList = new ArrayList<>();
            phaseType.forEach(phase -> {

                List<DataI> tempDataiList = finalDataI.stream().filter(temp1 -> Utils.isTimeInRange(temp1.getTime(), LocalTime.of(9, 0), LocalTime.of(15, 0)))
                        .filter(temp1 -> temp1.getPhaseType().equals(phase))
                        .collect(Collectors.toList());

                List<Double> attributeValueByPropertyName = Utils.getAttributeValueByPropertyName(tempDataiList, "i" + temp);
                double iCp95 = CZNLPG.calculatePercentile(attributeValueByPropertyName, 0);
                tempList.add(iCp95);
            });
            //取uList最大值
            double iMax = tempList.stream().mapToDouble(Double::doubleValue)
                    .max()
                    .getAsDouble();
            iMaxList.add(iMax);
        });
        carryCapacityDataiVO.setI_βmax(iMaxList);

        return carryCapacityDataiVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CarryCapacityDResultVO carryCapacityCal(CarryCapacityCalParam calParam) {
        CarryCapacityDResultVO carryCapacitydResultVO = new CarryCapacityDResultVO();
        if(CollectionUtil.isEmpty(calParam.getStringMap())){
            throw new BusinessException("数据有误,模型训练失败");
        }

        String scale = calParam.getScale();
        String scaleValue = dicDataFeignClient.getDicDataById(scale).getData().getValue();

        //todo S_T查询监测点的容量
        Double sT = calParam.getS_T();
        Double sPv = calParam.getS_pv();
        Double pPv = calParam.getS_pv() * Double.valueOf(CarryingCapacityEnum.K.getValue());
        List<String> phaseType = Stream.of("A", "B", "C").collect(Collectors.toList());
        List<Double> uList = new ArrayList<>();
        List<Double> pftList = new ArrayList<>();
        List<Double> btList = new ArrayList<>();

        for (String phase : phaseType) {
            Double pMin = calParam.getP_βminMap().get(phase)/1000;
            Double qMin = calParam.getQ_βminMap().get(phase)/1000;
            Double[] res = calParam.getStringMap().get(phase);
            double bt = CZNLPG.calculateB(pMin, qMin, Double.parseDouble(CarryingCapacityEnum.K.getValue()), sT, sPv, pPv);
            btList.add(bt);
            double pft = CZNLPG.calculatePF_T(pMin, qMin, Double.parseDouble(CarryingCapacityEnum.K.getValue()), sPv);
            pftList.add(pft);
            double u = CZNLPG.calculateU(res[0], res[1], res[2], pMin, Double.parseDouble(CarryingCapacityEnum.K.getValue()), qMin, sPv, Double.parseDouble(scaleValue));
            uList.add(u);
        }
        //取uList最大值
        double utMax = uList.stream().mapToDouble(Double::doubleValue)
                .max()
                .getAsDouble();


        double btMax = btList.stream().mapToDouble(Double::doubleValue)
                .max()
                .getAsDouble();

        double pftMax = pftList.stream().mapToDouble(Double::doubleValue)
                .max()
                .getAsDouble();
        Integer utLevel = CZNLPG.evaluateVoltageLevel(utMax);
        carryCapacitydResultVO.setUTLevel(utLevel);

        Integer pftLevel = CZNLPG.evaluatePowerFactorLevel(pftMax);
        carryCapacitydResultVO.setPfTLevel(pftLevel);

        Integer btLevel = CZNLPG.evaluateEquivalentLoadRateLevel(btMax);
        carryCapacitydResultVO.setBTLevel(btLevel);
        //谐波电流幅值判断
        //获取限值
        Overlimit overlimit = lineFeignClient.getOverLimitData(calParam.getLineId()).getData();

        //各次谐波电流 均小于国标限值 返回1	存在某次谐波电流幅值 超出限值，但在1.25倍限值内  返回2		存在某次谐波电流幅值超出限值1.25倍以上 返回3	存在多次谐波电流幅值均超出限值1.25倍以上 返回4
        //i_count1小于国标限值的个数，i_count2>=国标限值<=1.25倍的国标限值，i_count3>1.25倍的国标限值
        int iCount1 = 0, iCount2 = 0, iCount3 = 0;
        for (int i = 0; i < calParam.getI_βmax().size(); i++) {
            double itm = CZNLPG.calculateITm(calParam.getI_βmax().get(i), Double.parseDouble(CarryingCapacityEnum.K.getValue()),
                    Double.parseDouble(scaleValue), sPv, Double.parseDouble(Objects.requireNonNull(CarryingCapacityEnum.getValueByCode("K_H_" + (i + 2)))),
                    Double.parseDouble(Objects.requireNonNull(CarryingCapacityEnum.getValueByCode("I_INV_" + (i + 2)))));
            double getUharm = PubUtils.getValueByMethod(overlimit, "getIharm", i + 2);
            if (itm < getUharm) {
                iCount1++;
            } else if (itm >= getUharm && itm <= 1.25 * getUharm) {
                iCount2++;
            } else if (itm > 1.25 * getUharm) {
                iCount3++;
            }

        }
        int iLevel = 1;
        if (iCount3 > 1) {
            iLevel = 4;
        } else if (iCount3 == 1) {
            iLevel = 3;
        } else if (iCount2 == 1) {
            iLevel = 2;
        }
        carryCapacitydResultVO.setILevel(iLevel);
        //统计安全，3级预警，2级预警1级预警个数
        List<Integer> list = Stream.of(utLevel, pftLevel, btLevel, iLevel).collect(Collectors.toList());
        int safeCount, warnCount3, warnCount2, warnCount1;
        safeCount = (int) list.stream()
                .filter(temp -> temp == 1)
                .count();
        warnCount3 = (int) list.stream()
                .filter(temp -> temp == 2)
                .count();
        warnCount2 = (int) list.stream()
                .filter(temp -> temp == 3)
                .count();
        warnCount1 = (int) list.stream()
                .filter(temp -> temp == 4)
                .count();


        List<CarryCapacityStrategyVO> carryCapacityStrategyVOList = carryCapacityStrategyPOService.queyDetail();
        carryCapacitydResultVO.setReslutLevel(5);
        //1-安全，2-III级预警，3-II级预警，4-I 级预警,依次执行策略看是否符合
        for (int i = 1; i < 5; i++) {
            boolean b = strategyReslut(carryCapacityStrategyVOList, i, safeCount, warnCount1, warnCount2, warnCount3);

            if (b) {
                carryCapacitydResultVO.setReslutLevel(i);
                break;
            }
        }
        CarryCapacityResultPO carryCapacityResult = new CarryCapacityResultPO();
        List<CarryCapacityResultPO> list1 = carryCapacityResultPOService.lambdaQuery().eq(CarryCapacityResultPO::getLineId, calParam.getLineId())
                .eq(CarryCapacityResultPO::getUserId, calParam.getUserId())
                .eq(CarryCapacityResultPO::getStartTime, calParam.getStartTime())
                .eq(CarryCapacityResultPO::getEndTime, calParam.getEndTime())
                .eq(CarryCapacityResultPO::getStatus, 1).list();
        if (CollectionUtil.isNotEmpty(list1)) {
            throw new BusinessException(AdvanceResponseEnum.EXISTENCE_EVALUATION_RESULT);

        }

        carryCapacityResult.setLineId(calParam.getLineId());
        carryCapacityResult.setUserId(calParam.getUserId());
        //
        CarryCapacityUserPO carryCapacityUser = carryCapacityUserPOService.queyDetailUserById(calParam.getUserId());
        carryCapacityResult.setEvaluateType(carryCapacityUser.getUserType());

        carryCapacityResult.setStartTime(calParam.getStartTime());
        carryCapacityResult.setEndTime(calParam.getEndTime());
        carryCapacityResult.setUTLevel(carryCapacitydResultVO.getUTLevel());
        carryCapacityResult.setPfTLevel(carryCapacitydResultVO.getPfTLevel());
        carryCapacityResult.setBTLevel(carryCapacitydResultVO.getBTLevel());
        carryCapacityResult.setILevel(carryCapacitydResultVO.getILevel());
        carryCapacityResult.setReslutLevel(carryCapacitydResultVO.getReslutLevel());
        carryCapacityResult.setEvaluateDate(LocalDate.now());
        carryCapacityResult.setStatus(1);
        carryCapacityResultPOService.save(carryCapacityResult);

        return carryCapacitydResultVO;
    }

    @Override
    public List<TerminalTree> carryCapacityTree() {
        List<TerminalTree> data = deviceTreeClient.getTerminalTree().getData();
        data.forEach(temp -> temp.getChildren().forEach(temp1 -> temp1.getChildren().forEach(temp2 -> temp2.getChildren().forEach(temp3 -> temp3.getChildren().forEach(temp4 -> {
            List<TerminalTree> collect = temp4.getChildren().stream()
                    .map(TerminalTree::getChildren).flatMap(Collection::stream)
                    .map(TerminalTree::getChildren).flatMap(Collection::stream)
                    .collect(Collectors.toList());
            temp4.setChildren(collect);

        })))));
        return data;
    }

    @SneakyThrows
    @Override
    public boolean uploadExcel(ExcelDataParam excelDataParam) {

        String lineId = excelDataParam.getLineId();
        LineDetailDataVO data = lineFeignClient.getLineDetailData(lineId).getData();
        //时间间隔
        Integer timeInterval = data.getTimeInterval();


        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate startDate = LocalDate.parse(excelDataParam.getStartTime(), formatter);
        LocalDate endDate = LocalDate.parse(excelDataParam.getEndTime(), formatter);
        //前2周的时间
        LocalDate startDate2 = startDate.plusWeeks(-1);
        LocalDate endDate2 = endDate.plusWeeks(-1);


        //前一周的数据
        ExcelDataDTO excelDataDTO = parsingFile(startDate, endDate, excelDataParam.getFile().getInputStream());
        List<CarryCapcityData> dataHarmPowerpList = excelDataDTO.getDataHarmPowerPList();
        List<CarryCapcityData> dataHarmPowerqList = excelDataDTO.getDataHarmPowerQList();
        List<DataI> dataiList = excelDataDTO.getDataIList();
        ////前2周的数据
        List<CarryCapcityData> dataHarmPowerp2List = excelDataDTO.getDataHarmPowerP2List();
        List<CarryCapcityData> dataHarmPowerq2List = excelDataDTO.getDataHarmPowerQ2List();
        List<CarryCapcityData> dataHarmPoweruList = excelDataDTO.getDataHarmPowerU2List();

        //数据校验
        if (CollectionUtil.isEmpty(dataHarmPowerpList)) {
            throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据及其上周是否充足");
        } else {

            if (checkData(dataHarmPowerpList, startDate, endDate, timeInterval)) {

                throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据是否充足");
            }
        }
        linearInterpolation(dataHarmPowerpList);

        //数据校验
        if (CollectionUtil.isEmpty(dataHarmPowerp2List)) {
            throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据及其上周是否充足");
        } else {

            if (checkData(dataHarmPowerp2List, startDate2, endDate2, timeInterval)) {

                throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的前一周数据量是否充足");
            }
        }
        linearInterpolation(dataHarmPowerp2List);

        //数据校验
        if (CollectionUtil.isEmpty(dataHarmPowerqList)) {
            throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据及其上周是否充足");
        } else {

            if (checkData(dataHarmPowerqList, startDate, endDate, timeInterval)) {

                throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据是否充足");
            }
        }
        linearInterpolation(dataHarmPowerqList);

        //数据校验
        if (CollectionUtil.isEmpty(dataHarmPowerq2List)) {
            throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据及其上周是否充足");
        } else {

            if (checkData(dataHarmPowerq2List, startDate2, endDate2, timeInterval)) {

                throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的前一周数据量是否充足");
            }
        }
        linearInterpolation(dataHarmPowerq2List);

        //数据校验
        if (CollectionUtil.isEmpty(dataHarmPoweruList)) {
            throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据及其上周是否充足");
        } else {

            if (checkData(dataHarmPoweruList, startDate2, endDate2, timeInterval)) {

                throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的前一周数据量是否充足");
            }
        }
        linearInterpolation(dataHarmPoweruList);

        if (CollectionUtil.isEmpty(dataiList)) {
            throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据及其上周是否充足");
        } else {
            List<CarryCapcityData> iList = dataiList.stream().map(temp -> {
                CarryCapcityData carryCapcityData = new CarryCapcityData();
                BeanUtils.copyProperties(temp, carryCapcityData);
                carryCapcityData.setValue(temp.getI2());
                return carryCapcityData;
            }).collect(Collectors.toList());
            if (checkData(iList, startDate, endDate, timeInterval)) {

                throw new BusinessException("数据量过少，请查看上传数据集的数据集时间与页面选择时间"+startDate+"-"+endDate+"的本周数据量是否充足");
            }
        }
        linearInterpolationI(dataiList);

//        存入redis
        redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "P",
                dataHarmPowerpList);
        redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "P",
                dataHarmPowerp2List);
        redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "Q",
                dataHarmPowerqList);
        redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "Q",
                dataHarmPowerq2List);
        redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate2, formatter) + "#" + LocalDateTimeUtil.format(endDate2, formatter) + "#" + "U",
                dataHarmPoweruList);
        redisUtil.saveByKey(lineId + "#" + LocalDateTimeUtil.format(startDate, formatter) + "#" + LocalDateTimeUtil.format(endDate, formatter) + "#" + "I",
                dataiList);
        //todo 将文件存入文件服务器获取url
        String filePath = fileStorageUtil.uploadMultipart(excelDataParam.getFile(), OssPath.CARRY_CAPCITY_DATA);
//        String url = "temp";
        CarryCapacityDataPO carryCapacityData = new CarryCapacityDataPO(lineId, startDate, endDate, filePath);
        carryCapacityDataPOService.saveOrUpdateByMultiId(carryCapacityData);


        return true;
    }


    @Override
    public CarryCapacityDResultVO carryCapacityEvaluate(CarryCapacityEvaluateParam calParam) {
        CarryCapacityDResultVO vo = new CarryCapacityDResultVO();
        List<CarryCapacityDResultVO.CarryCapacityIResult> carryCapacityiResultList = new ArrayList<>();

        List<CarryCapacityDevicePO> devList = calParam.getDevList();
        if (CollectionUtil.isEmpty(devList)) {
            throw new BusinessException(AdvanceResponseEnum.DEVICE_LOST);
        }
        String userId = devList.get(0).getUserId();
        CarryCapacityUserPO carryCapacityUser = carryCapacityUserPOService.queyDetailUserById(userId);
        String userType = carryCapacityUser.getUserType();
        String code = dicDataFeignClient.getDicDataById(userType).getData().getCode();
        //用户协议容量
        double sumCapacity = carryCapacityUser.getProtocolCapacity();

        double rate = sumCapacity / calParam.getShortCapacity();
        vo.setFirstResult(rate * 100);

        CarryCapacityResultPO carryCapacityResult = new CarryCapacityResultPO();
        carryCapacityResult.setFirstResult(rate * 100);
        carryCapacityResult.setUserId(userId);
        carryCapacityResult.setEvaluateDate(LocalDate.now());
        carryCapacityResult.setEvaluateType(userType);
        carryCapacityResult.setStatus(1);
        carryCapacityResult.setPtType(calParam.getPtType());
        carryCapacityResult.setConnectionMode(calParam.getConnectionMode());
        carryCapacityResult.setK(calParam.getK());
        carryCapacityResult.setUserMode(calParam.getUserMode());
        carryCapacityResult.setScale(calParam.getScale());
        carryCapacityResult.setShortCapacity(calParam.getShortCapacity());
        carryCapacityResult.setDeviceCapacity(calParam.getDeviceCapacity());


        carryCapacityResult.setStatus(1);
        if (rate < 0.001) {
            carryCapacityResult.setReslutLevel(6);
            carryCapacityResultPOService.save(carryCapacityResult);
            return vo;
        }

        /*二次评估充电桩、电气化铁路如果经过变压器并网的是需要的，像电弧炉他是要经过一个电弧炉专用变压器并网的
        正常如果是专变用户的话是经过变压器的高压侧进行考核，公变用户的正常是在低压侧进行考核,
        当变压器连接方式为YNyn零序电流可以流通计算变压器高压侧的谐波电流（零序电流次数为3、6、9、12、）否则为0
        */
        //设备电压等级单位KV
        String sacaleValue = dicDataFeignClient.getDicDataById(calParam.getScale()).getData().getValue();

//        //用户电压等级
        DictData data = dicDataFeignClient.getDicDataById(carryCapacityUser.getVoltage()).getData();

        float userSacaleValue = Float.parseFloat(data.getValue()) * (data.getCode().contains("k") ? 1000 : 1);
        //用户模式专变用户,公变用户
        String userMode = dicDataFeignClient.getDicDataById(calParam.getUserMode()).getData().getCode();
        //变压器连接方式接线方式
        String connectionMode;
        if (Objects.nonNull(calParam.getConnectionMode()) && !"".equals(calParam.getConnectionMode())) {
            connectionMode = dicDataFeignClient.getDicDataById(calParam.getConnectionMode()).getData().getCode();

        } else {
            connectionMode = "";
        }

        List<Integer> integerList = Stream.of(3, 5, 7, 9, 11, 13, 15, 17, 19).collect(Collectors.toList());


        Overlimit overlimit = new Overlimit();
        COverlimitUtil.iHarm(overlimit, Float.valueOf(sacaleValue), (float) sumCapacity, calParam.getDeviceCapacity(), calParam.getShortCapacity());


        if (DicDataEnum.Charging_Station_Users.getCode().equals(code)) {

            integerList.forEach(temp -> {
                CarryCapacityDResultVO.CarryCapacityIResult carryCapacityiResultVO = new CarryCapacityDResultVO.CarryCapacityIResult();
                List<Double> ilist = new ArrayList<>();
                devList.forEach(dev -> {
                    DictData devScaledata = dicDataFeignClient.getDicDataById(dev.getDevScale()).getData();
                    double devScaleValue = Float.parseFloat(devScaledata.getValue()) * (devScaledata.getCode().contains("k") ? 1 : 0.0001);
                    //基波电流I_1:设备容量(转成KVA*1000)*K（功率因数）（转成kW）/更号3*电压等级（转成Kv）

                    double i1 = dev.getProtocolCapacity() * 1000 * calParam.getK() / (Math.sqrt(3) * devScaleValue);
                    //低压侧
                    double iH = i1 * (Double.parseDouble(Objects.requireNonNull(CarryingCapacityEnum.getValueByCode("CP_I_" + temp)))) / 100;
                    //当变压器连接方式为YNyn零序电流可以流通计算变压器高压侧的谐波电流（零序电流次数为3、6、9、12、）否则为0
                    if (!DicDataEnum.YNyn.getCode().equals(connectionMode) && temp % 3 == 0) {
                        iH = 0.00;
                    }
                    ilist.add(iH);

                });
                //将变压器下多个设备电流合并
                Double mergeI = mergeiList(ilist);


                //专变用户的话是经过变压器的高压侧进行考核，公变用户的正常是在低压侧进行考核
                if (DicDataEnum.SPECIAL_USER.getCode().equals(userMode)) {
                    mergeI = mergeI / (Double.parseDouble(sacaleValue) * 1000 / userSacaleValue);
                }

                carryCapacityiResultVO.setTime(temp);
                carryCapacityiResultVO.setI(mergeI);
                double getUharm = PubUtils.getValueByMethod(overlimit, "getIharm", temp);
                carryCapacityiResultVO.setI_limit(getUharm);
                carryCapacityiResultList.add(carryCapacityiResultVO);
            });

        } else if (DicDataEnum.Electric_Heating_Load_Users.getCode().equals(code)) {

            integerList.forEach(temp -> {
                CarryCapacityDResultVO.CarryCapacityIResult carryCapacityiResultVO = new CarryCapacityDResultVO.CarryCapacityIResult();
                List<Double> ilist = new ArrayList<>();
                devList.forEach(dev -> {
                    DictData devScaledata = dicDataFeignClient.getDicDataById(dev.getDevScale()).getData();
                    double devScaleValue = Float.parseFloat(devScaledata.getValue()) * (devScaledata.getCode().contains("k") ? 1 : 0.0001);
                    //基波电流I_1:设备容量(转成KVA*1000)*K（功率因数）（转成kW）/更号3*电压等级（转成Kv）
                    double i1 = dev.getProtocolCapacity() * 1000 * calParam.getK() / (Math.sqrt(3) * devScaleValue);
                    //低压侧
                    double iH = i1 * (Double.parseDouble(Objects.requireNonNull(CarryingCapacityEnum.getValueByCode("EAF_I_" + temp)))) / 100;
                    //当变压器连接方式为YNyn零序电流可以流通计算变压器高压侧的谐波电流（零序电流次数为3、6、9、12、）否则为0
                    if (!DicDataEnum.YNyn.getCode().equals(connectionMode) && temp % 3 == 0) {
                        iH = 0.00;
                    }
                    ilist.add(iH);

                });
                //将变压器下多个设备电流合并
                Double mergeI = mergeiList(ilist);


                //专变用户的话是经过变压器的高压侧进行考核，公变用户的正常是在低压侧进行考核
                if (DicDataEnum.SPECIAL_USER.getCode().equals(userMode)) {
                    mergeI = mergeI / (Double.parseDouble(sacaleValue) * 1000 / userSacaleValue);
                }

                carryCapacityiResultVO.setTime(temp);
                carryCapacityiResultVO.setI(mergeI);
                double getUharm = PubUtils.getValueByMethod(overlimit, "getIharm", temp);
                carryCapacityiResultVO.setI_limit(getUharm);
                carryCapacityiResultList.add(carryCapacityiResultVO);
            });

        } else if (DicDataEnum.Electrified_Rail_Users.getCode().equals(code)) {
            integerList.forEach(temp -> {
                CarryCapacityDResultVO.CarryCapacityIResult carryCapacityiResult = new CarryCapacityDResultVO.CarryCapacityIResult();
                List<Double> ilist = new ArrayList<>();
                devList.forEach(dev -> {
                    DictData devScaledata = dicDataFeignClient.getDicDataById(dev.getDevScale()).getData();
                    double devScaleValue = Float.parseFloat(devScaledata.getValue()) * (devScaledata.getCode().contains("k") ? 1 : 0.0001);
                    //基波电流I_1:设备容量(转成KVA*1000)*K（功率因数）（转成kW）/更号3*电压等级（转成Kv）
                    double i1 = dev.getProtocolCapacity() * 1000 * calParam.getK() / (Math.sqrt(3) * devScaleValue);
                    //低压侧
                    double iH = i1 * (Double.parseDouble(Objects.requireNonNull(CarryingCapacityEnum.getValueByCode("ER_I_" + temp)))) / 100;
                    //当变压器连接方式为YNyn零序电流可以流通计算变压器高压侧的谐波电流（零序电流次数为3、6、9、12、）否则为0
                    if (!DicDataEnum.YNyn.getCode().equals(connectionMode) && temp % 3 == 0) {
                        iH = 0.00;
                    }
                    ilist.add(iH);

                });
                //将变压器下多个设备电流合并
                Double mergeI = mergeiList(ilist);


                //专变用户的话是经过变压器的高压侧进行考核，公变用户的正常是在低压侧进行考核
                if (DicDataEnum.SPECIAL_USER.getCode().equals(userMode)) {
                    mergeI = mergeI / (Double.parseDouble(sacaleValue) * 1000 / userSacaleValue);
                }

                carryCapacityiResult.setTime(temp);
                carryCapacityiResult.setI(mergeI);
                double getUharm = PubUtils.getValueByMethod(overlimit, "getIharm", temp);
                carryCapacityiResult.setI_limit(getUharm);
                carryCapacityiResultList.add(carryCapacityiResult);
            });
        }
        vo.setIResultList(carryCapacityiResultList);
        carryCapacityResult.setIResultList(JSONUtil.toJsonStr(carryCapacityiResultList));
        long count = carryCapacityiResultList.stream().filter(temp -> temp.getI() > temp.getI_limit()).count();
        carryCapacityResult.setReslutLevel(count == 0 ? 6 : 5);
        vo.setReslutLevel(count == 0 ? 6 : 5);
        carryCapacityResultPOService.save(carryCapacityResult);

        return vo;
    }

    private Double mergeiList(List<Double> ilist) {
        Double result;

        if (ilist.size() == 1) {
            return ilist.get(0);
        } else {
            result = ilist.get(0);
            for (int i = 1; i < ilist.size(); i++) {
                double sum = result * result + ilist.get(i) * ilist.get(i) + Double.parseDouble(Objects.requireNonNull(CarryingCapacityEnum.getValueByCode("K_H_" + (i + 2)))) * result * ilist.get(i);
                result = Math.sqrt(sum);
            }

        }


        return result;
    }


    public static ExcelDataDTO parsingFile(LocalDate startDate, LocalDate endDate, InputStream is) {
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        List<CarryCapcityData> dataHarmPowerpList;
        List<CarryCapcityData> dataHarmPowerqList;
        List<DataI> dataiList;

        //前2周的时间
        LocalDate startDate2 = startDate.plusWeeks(-1);
        LocalDate endDate2 = endDate.plusWeeks(-1);

        //前一周的数据
        List<CarryCapcityData> dataHarmPowerP2List;
        List<CarryCapcityData> dataHarmPowerQ2List;
        List<CarryCapcityData> dataHarmPowerU2List;

        try {
            List<CarryCapcityDataEexcel> objects = EasyExcelUtil.syncReadModel(is, CarryCapcityDataEexcel.class, 0, 3);
            objects = objects.stream().filter(temp -> Objects.nonNull(temp.getTime())).collect(Collectors.toList());
            List<CarryCapcityDataIEexcel> iEexcelList = new ArrayList<>();
            List<CarryCapcityDataVEexcel> vEexcelList = new ArrayList<>();
            List<CarryCapcityDataPEexcel> pEexcelList = new ArrayList<>();
            List<CarryCapcityDataQEexcel> qEexcelList = new ArrayList<>();
            objects.forEach(temp -> {
                CarryCapcityDataIEexcel carryCapcityDataiEexcel = new CarryCapcityDataIEexcel();
                CarryCapcityDataVEexcel carryCapcityDatavEexcel = new CarryCapcityDataVEexcel();
                CarryCapcityDataPEexcel carryCapcityDatapEexcel = new CarryCapcityDataPEexcel();
                CarryCapcityDataQEexcel carryCapcityDataqEexcel = new CarryCapcityDataQEexcel();

                BeanUtils.copyProperties(temp, carryCapcityDataiEexcel);
                carryCapcityDataiEexcel.setTime(temp.getTime().atZone(ZoneId.systemDefault()).toInstant());
                carryCapcityDataiEexcel.setValueType("CP95");

                carryCapcityDatavEexcel.setTime(temp.getTime().atZone(ZoneId.systemDefault()).toInstant());
                carryCapcityDatavEexcel.setValueType("CP95");
                carryCapcityDatavEexcel.setValue_a(temp.getU_a());
                carryCapcityDatavEexcel.setValue_b(temp.getU_b());
                carryCapcityDatavEexcel.setValue_c(temp.getU_c());


                carryCapcityDatapEexcel.setTime(temp.getTime().atZone(ZoneId.systemDefault()).toInstant());
                carryCapcityDatapEexcel.setValueType("CP95");
                carryCapcityDatapEexcel.setValue_a(temp.getP_a());
                carryCapcityDatapEexcel.setValue_b(temp.getP_b());
                carryCapcityDatapEexcel.setValue_c(temp.getP_c());

                carryCapcityDataqEexcel.setTime(temp.getTime().atZone(ZoneId.systemDefault()).toInstant());
                carryCapcityDataqEexcel.setValueType("CP95");
                carryCapcityDataqEexcel.setValue_a(temp.getQ_a());
                carryCapcityDataqEexcel.setValue_b(temp.getQ_b());
                carryCapcityDataqEexcel.setValue_c(temp.getQ_c());
                iEexcelList.add(carryCapcityDataiEexcel);
                vEexcelList.add(carryCapcityDatavEexcel);
                pEexcelList.add(carryCapcityDatapEexcel);
                qEexcelList.add(carryCapcityDataqEexcel);

            });


            List<DataI> collect = iEexcelList.stream().map(CarryCapcityDataIEexcel::excelToPO).filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
            dataiList = collect.stream().filter(
                    item -> Utils.isTimeInRange(item.getTime(), startDate, endDate)
            ).collect(Collectors.toList());


            // 校验合格的数据
            List<CarryCapcityData> collect2 = vEexcelList.stream().map(CarryCapcityDataVEexcel::excelToPO).filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
            // 业务逻辑
            dataHarmPowerU2List = collect2.stream().filter(
                    item -> Utils.isTimeInRange(item.getTime(), startDate2, endDate2)
            ).collect(Collectors.toList());


            // 校验合格的数据
            List<CarryCapcityData> collect3 = pEexcelList.stream().map(CarryCapcityDataPEexcel::excelToPO).filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
            dataHarmPowerpList = collect3.stream().filter(
                    item -> Utils.isTimeInRange(item.getTime(), startDate, endDate)
            ).collect(Collectors.toList());
            dataHarmPowerP2List = collect3.stream().filter(
                    item -> Utils.isTimeInRange(item.getTime(), startDate2, endDate2)
            ).collect(Collectors.toList());


            List<CarryCapcityData> collect4 = qEexcelList.stream().map(CarryCapcityDataQEexcel::excelToPO).filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
            dataHarmPowerqList = collect4.stream().filter(
                    item -> Utils.isTimeInRange(item.getTime(), startDate, endDate)
            ).collect(Collectors.toList());
            dataHarmPowerQ2List = collect4.stream().filter(
                    item -> Utils.isTimeInRange(item.getTime(), startDate2, endDate2)
            ).collect(Collectors.toList());

        } catch (Exception e) {
            throw new BusinessException(AdvanceResponseEnum.DOCUMENT_FORMAT_ERROR);
        }
        ExcelDataDTO dto = new ExcelDataDTO();
        dto.setDataHarmPowerPList(dataHarmPowerpList);
        dto.setDataHarmPowerQList(dataHarmPowerqList);
        dto.setDataIList(dataiList);
        dto.setDataHarmPowerP2List(dataHarmPowerP2List);
        dto.setDataHarmPowerQ2List(dataHarmPowerQ2List);
        dto.setDataHarmPowerU2List(dataHarmPowerU2List);

        return dto;
    }

    /**
     * @Description: 首先，找到缺失值的前一个和后一个非缺失值。
     * 计算两个非缺失值之间的差值。
     * 将差值除以两个非缺失值之间的距离，得到斜率。
     * 使用斜率和前一个非缺失值计算缺失值的近似值。
     * @Param:
     * @Author: clam
     * @Date: 2024/2/28
     */
    public static void linearInterpolation(List<CarryCapcityData> data) {


        data.stream().collect(Collectors.groupingBy(CarryCapcityData::getPhaseType)).forEach((k, v) -> {

            for (int i = 0; i < v.size(); i++) {
                if (v.get(i).getValue() == DEFAULTVALUE || Objects.isNull(v.get(i).getValue())) {
                    int prevIndex = i - 1;
                    int nextIndex = i + 1;
                    while (prevIndex >= 0 && (v.get(prevIndex).getValue() == DEFAULTVALUE || Objects.isNull(v.get(prevIndex).getValue()))) {
                        prevIndex--;
                    }
                    while (nextIndex < v.size() && (v.get(nextIndex).getValue() == DEFAULTVALUE || Objects.isNull(v.get(nextIndex).getValue()))) {
                        nextIndex++;
                    }
                    if (prevIndex >= 0 && nextIndex < v.size()) {
                        double slope = (v.get(nextIndex).getValue() - v.get(prevIndex).getValue()) / (nextIndex - prevIndex);
                        v.get(i).setValue(v.get(prevIndex).getValue() + slope * (i - prevIndex));
                    } else {
                        v.get(i).setValue(DEFAULTVALUE);
                    }
                }
            }
        });


    }

    /**
     * @Description: linearInterpolationI 电流数据缺失填补
     * @Param:
     * @return: void
     * @Author: clam
     * @Date: 2024/2/28
     */
    public static void linearInterpolationI(List<DataI> data) {

        data.stream().collect(Collectors.groupingBy(DataI::getPhaseType)).forEach((k, v) -> {
            for (int i = 0; i < v.size(); i++) {
                if (v.get(i).getI2() == DEFAULTVALUE || Objects.isNull(v.get(i).getI2())) {
                    int prevIndex = i - 1;
                    int nextIndex = i + 1;
                    while (prevIndex >= 0 && (v.get(prevIndex).getI2() == DEFAULTVALUE || Objects.isNull(v.get(prevIndex).getI2()))) {
                        prevIndex--;
                    }
                    while (nextIndex < v.size() && (v.get(nextIndex).getI2() == DEFAULTVALUE || Objects.isNull(v.get(nextIndex).getI2()))) {
                        nextIndex++;
                    }
                    if (prevIndex >= 0 && nextIndex < v.size()) {
                        double slope = (v.get(nextIndex).getI2() - v.get(prevIndex).getI2()) / (nextIndex - prevIndex);
                        v.get(i).setI2(v.get(prevIndex).getI2() + slope * (i - prevIndex));
                        v.get(i).setI3(v.get(prevIndex).getI3() + slope * (i - prevIndex));
                        v.get(i).setI4(v.get(prevIndex).getI4() + slope * (i - prevIndex));
                        v.get(i).setI5(v.get(prevIndex).getI5() + slope * (i - prevIndex));
                        v.get(i).setI6(v.get(prevIndex).getI6() + slope * (i - prevIndex));
                        v.get(i).setI7(v.get(prevIndex).getI7() + slope * (i - prevIndex));
                        v.get(i).setI8(v.get(prevIndex).getI8() + slope * (i - prevIndex));
                        v.get(i).setI9(v.get(prevIndex).getI9() + slope * (i - prevIndex));
                        v.get(i).setI10(v.get(prevIndex).getI10() + slope * (i - prevIndex));
                        v.get(i).setI11(v.get(prevIndex).getI11() + slope * (i - prevIndex));
                        v.get(i).setI12(v.get(prevIndex).getI12() + slope * (i - prevIndex));
                        v.get(i).setI13(v.get(prevIndex).getI13() + slope * (i - prevIndex));
                        v.get(i).setI14(v.get(prevIndex).getI14() + slope * (i - prevIndex));
                        v.get(i).setI15(v.get(prevIndex).getI15() + slope * (i - prevIndex));
                        v.get(i).setI16(v.get(prevIndex).getI16() + slope * (i - prevIndex));
                        v.get(i).setI17(v.get(prevIndex).getI17() + slope * (i - prevIndex));
                        v.get(i).setI18(v.get(prevIndex).getI18() + slope * (i - prevIndex));
                        v.get(i).setI19(v.get(prevIndex).getI19() + slope * (i - prevIndex));
                        v.get(i).setI20(v.get(prevIndex).getI20() + slope * (i - prevIndex));
                        v.get(i).setI21(v.get(prevIndex).getI21() + slope * (i - prevIndex));
                        v.get(i).setI22(v.get(prevIndex).getI22() + slope * (i - prevIndex));
                        v.get(i).setI23(v.get(prevIndex).getI23() + slope * (i - prevIndex));
                        v.get(i).setI24(v.get(prevIndex).getI24() + slope * (i - prevIndex));
                        v.get(i).setI25(v.get(prevIndex).getI25() + slope * (i - prevIndex));

                    } else {
                        v.get(i).setI2(DEFAULTVALUE);
                        v.get(i).setI3(DEFAULTVALUE);
                        v.get(i).setI4(DEFAULTVALUE);
                        v.get(i).setI5(DEFAULTVALUE);
                        v.get(i).setI6(DEFAULTVALUE);
                        v.get(i).setI7(DEFAULTVALUE);
                        v.get(i).setI8(DEFAULTVALUE);
                        v.get(i).setI9(DEFAULTVALUE);
                        v.get(i).setI10(DEFAULTVALUE);
                        v.get(i).setI11(DEFAULTVALUE);
                        v.get(i).setI12(DEFAULTVALUE);
                        v.get(i).setI13(DEFAULTVALUE);
                        v.get(i).setI14(DEFAULTVALUE);
                        v.get(i).setI15(DEFAULTVALUE);
                        v.get(i).setI16(DEFAULTVALUE);
                        v.get(i).setI17(DEFAULTVALUE);
                        v.get(i).setI18(DEFAULTVALUE);
                        v.get(i).setI19(DEFAULTVALUE);
                        v.get(i).setI20(DEFAULTVALUE);
                        v.get(i).setI21(DEFAULTVALUE);
                        v.get(i).setI22(DEFAULTVALUE);
                        v.get(i).setI23(DEFAULTVALUE);
                        v.get(i).setI24(DEFAULTVALUE);
                        v.get(i).setI25(DEFAULTVALUE);

                    }
                }
            }
        });


    }

    /**
     * @Description: calUParam 首端电压模型训练获取A,B,C三项C,a，b参数
     * @Param:
     * @return: java.util.Map<java.lang.String, java.lang.Double [ ]>
     * @Author: clam
     * @Date: 2024/2/29
     */
    public static Map<String, Double[]> caluParam(List<CarryCapcityData> dataHarmPowerpList2, List<CarryCapcityData> dataHarmPowerqList2, List<CarryCapcityData> datavList2) {
        Map<String, Double[]> results = new HashMap<>(4);
        List<String> phaseType = Stream.of("A", "B", "C").collect(Collectors.toList());


        phaseType.forEach(phase -> {
            List<Double> listP2 = dataHarmPowerpList2.stream().filter(temp -> Utils.isTimeInRange(temp.getTime(), LocalTime.of(9, 0), LocalTime.of(15, 0)))
                    .filter(temp -> temp.getPhaseType().equals(phase))
                    .map(CarryCapcityData::getValue)
                    .collect(Collectors.toList());

            List<Double> listQ2 = dataHarmPowerqList2.stream().filter(temp -> Utils.isTimeInRange(temp.getTime(), LocalTime.of(9, 0), LocalTime.of(15, 0)))
                    .filter(temp -> temp.getPhaseType().equals(phase))
                    .map(CarryCapcityData::getValue)
                    .collect(Collectors.toList());

            List<Double> listV2 = datavList2.stream().filter(temp -> Utils.isTimeInRange(temp.getTime(), LocalTime.of(9, 0), LocalTime.of(15, 0)))
                    .filter(temp -> temp.getPhaseType().equals(phase))
                    .map(CarryCapcityData::getValue)
                    .collect(Collectors.toList());
            //todo 抽取5000条数据（抽取方式待确定)
            Double[] res = new Double[3];
            CZNLPG.cznlpgDataTrain(listV2, listP2, listQ2, listV2.size(), res);
            results.put(phase, res);

        });

        return results;
    }

    private static boolean compareNumbers(int num1, int num2, String operator) {
        if ("/".equals(operator)) {
            return true;
        } else if ("<".equals(operator)) {
            return num1 < num2;
        } else if (">".equals(operator)) {
            return num1 > num2;
        } else if ("<=".equals(operator)) {
            return num1 <= num2;
        } else if (">=".equals(operator)) {
            return num1 >= num2;
        } else if ("==".equals(operator)) {
            return num1 == num2;
        } else if ("!=".equals(operator)) {
            return num1 != num2;
        } else {
            throw new IllegalArgumentException("无效的操作符");
        }
    }

    private static boolean strategyReslut(List<CarryCapacityStrategyVO> carryCapacityStrategyVOList, int resultLevel, int safeCount, int warnCount1, int warnCount2, int warnCount3) {

        CarryCapacityStrategyVO carryCapacityStrategyVO = carryCapacityStrategyVOList.stream()
                .filter(temp -> temp.getResult() == resultLevel)
                .collect(Collectors.toList()).get(0);
        //每个策略组结果
        List<Boolean> list = new ArrayList<>();
        List<CarryCapacityStrategysingleVO> capacityStrategysingleVOList = carryCapacityStrategyVO.getCapacityStrategysingleVOList();
        capacityStrategysingleVOList.forEach(temp -> {
            CarryCapacityStrategysingleVO.CarryCapacityStrategyIndexVO carryCapacityStrategyIndexVO = temp.getCarryCapacityStrategyIndexVOList().stream()
                    .filter(temp1 -> temp1.getIndexResult() == 1)
                    .collect(Collectors.toList()).get(0);
            boolean b1 = compareNumbers(safeCount, carryCapacityStrategyIndexVO.getCount(), carryCapacityStrategyIndexVO.getComparisonOperators());
            CarryCapacityStrategysingleVO.CarryCapacityStrategyIndexVO vo2 = temp.getCarryCapacityStrategyIndexVOList().stream()
                    .filter(temp1 -> temp1.getIndexResult() == 2)
                    .collect(Collectors.toList()).get(0);
            boolean b2 = compareNumbers(warnCount3, vo2.getCount(), vo2.getComparisonOperators());

            CarryCapacityStrategysingleVO.CarryCapacityStrategyIndexVO vo3 = temp.getCarryCapacityStrategyIndexVOList().stream()
                    .filter(temp1 -> temp1.getIndexResult() == 3)
                    .collect(Collectors.toList()).get(0);
            boolean b3 = compareNumbers(warnCount2, vo3.getCount(), vo3.getComparisonOperators());


            CarryCapacityStrategysingleVO.CarryCapacityStrategyIndexVO vo4 = temp.getCarryCapacityStrategyIndexVOList().stream()
                    .filter(temp1 -> temp1.getIndexResult() == 4)
                    .collect(Collectors.toList()).get(0);
            boolean b4 = compareNumbers(warnCount1, vo4.getCount(), vo4.getComparisonOperators());
            Boolean flag = b1 && b2 && b3 && b4;
            list.add(flag);
        });
        long count = list.stream().filter(temp -> temp).count();
        return count > 0;
    }

    private static boolean checkData(List<CarryCapcityData> list, LocalDate startTime, LocalDate endTime, int timeInterval) {
        boolean flag = false;
        long daysBetween = ChronoUnit.DAYS.between(startTime, endTime);
        //根据时间间隔算出最低数据量 1天*6小时*60分钟*90%/时间间隔算出一天一个的数据
        int minDataNum = 6 * 60 * 3 * 80 / (100 * timeInterval);
        //合格天数》=3通过
        int days = 0;

        for (long i = 0; i <= daysBetween; i++) {
            LocalDate currentDay = startTime.plusDays(i);
            long count = list.stream()
                    .filter(temp -> Utils.isTimeInRange(temp.getTime(), LocalTime.of(9, 0), LocalTime.of(15, 0)))
                    .filter(temp -> temp.getValue() != DEFAULTVALUE && Objects.nonNull(temp.getValue()))
                    .filter(temp -> temp.getTime().atZone(ZoneId.systemDefault()).toLocalDate().equals(currentDay)).count();
            if (count >= minDataNum) {
                days++;
            }

        }
        if (days >= 3) {
            flag = true;
        }

        return !flag;
    }


}
