package com.njcn.csdevice.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.constant.DataParam;
import com.njcn.csdevice.enums.LineBaseEnum;
import com.njcn.csdevice.mapper.CsDataSetMapper;
import com.njcn.csdevice.mapper.WlRecordMapper;
import com.njcn.csdevice.param.WlRecordPageParam;
import com.njcn.csdevice.pojo.dto.CsEquipmentDeliveryDTO;
import com.njcn.csdevice.pojo.param.WlRecordParam;
import com.njcn.csdevice.pojo.po.CsDataSet;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.csdevice.pojo.po.WlRecord;
import com.njcn.csdevice.pojo.vo.RecordAllDevTreeVo;
import com.njcn.csdevice.pojo.vo.RecordTreeVo;
import com.njcn.csdevice.pojo.vo.RecordVo;
import com.njcn.csdevice.service.IOverLimitService;
import com.njcn.csdevice.service.IWlRecordService;
import com.njcn.csdevice.util.InfluxDbParamUtil;
import com.njcn.csdevice.utils.StringUtil;
import com.njcn.csharmonic.param.CommonStatisticalQueryParam;
import com.njcn.csharmonic.pojo.vo.ThdDataVO;
import com.njcn.device.biz.pojo.po.Overlimit;
import com.njcn.device.biz.utils.COverlimitUtil;
import com.njcn.influx.imapper.CommonMapper;
import com.njcn.influx.pojo.bo.CommonQueryParam;
import com.njcn.influx.pojo.constant.InfluxDBTableConstant;
import com.njcn.influx.pojo.dto.StatisticalDataDTO;
import com.njcn.influx.query.InfluxQueryWrapper;
import com.njcn.influx.service.CommonService;
import com.njcn.system.api.CsStatisticalSetFeignClient;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.pojo.po.DictData;
import com.njcn.system.pojo.po.EleEpdPqd;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.DecimalFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 方案、测试项表 服务实现类
 * </p>
 *
 * @author xuyang
 * @since 2024-04-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WlRecordServiceImpl extends ServiceImpl<WlRecordMapper, WlRecord> implements IWlRecordService {

    private final EquipmentFeignClient equipmentFeignClient;

    private final CsStatisticalSetFeignClient csStatisticalSetFeignClient;

    private final CsLineFeignClient csLineFeignClient;

    private final CommonService commonService;

    private final CommonMapper commonMapper;

    private final CsDataSetMapper csDataSetMapper;

    private final InfluxDbParamUtil influxDbParamUtil;

    private final IOverLimitService overlimitService;
    private final DicDataFeignClient dicDataFeignClient;

    private final DecimalFormat df = new DecimalFormat(DataParam.DecimalFormatStr);

    @Override
//    @Transactional(rollbackFor = Exception.class)
    public void addRecord(WlRecordParam.AddRecord records) {
        checkRecord(records);
        //整理的方案下测试项集合(可能添加多个测试项)
        List<WlRecord> insertList = new ArrayList<>();
        //校验方案ID是否存在
        LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
        qw.eq(WlRecord::getId,records.getId()).eq(WlRecord::getType,0).eq(WlRecord::getState,1);
        List<WlRecord> wlRecordList = this.baseMapper.selectList(qw);
        if(wlRecordList.isEmpty() && wlRecordList.get(0).getPId()!=null){
            throw new BusinessException(LineBaseEnum.NOWLRECORD_FAIL.getMessage());
        }
        //便利测试项
        records.getRecords().forEach(item->{
            String id = IdUtil.simpleUUID();
            WlRecord record = new WlRecord();
            BeanUtils.copyProperties(item, record);
            record.setId(id);
            //当前测试项绑定当前方案
            record.setPId(records.getId());
            record.setType(0);
            record.setState(1);
            insertList.add(record);
            //绑定测试项的基础数据
            WlRecordParam.UpdateRecord updateRecord = new WlRecordParam.UpdateRecord();
            updateRecord.setId(record.getId());
            updateRecord.setList(item.getList());
            saveDataRecord(updateRecord);
            //生成测试项限值，用于报表
            DictData scaleResult = dicDataFeignClient.getDicDataById(record.getVoltageLevel()).getData();
            if (Objects.isNull(scaleResult)) {
                throw new BusinessException(CommonResponseEnum.DIC_DATA);
            }


            float voltageLevel = Float.parseFloat(scaleResult.getValue());
            Overlimit overlimit = COverlimitUtil.globalAssemble(voltageLevel, record.getCapacitySi(), record.getCapacitySt(), record.getCapacitySscmin(), 1, 0);
            overlimit.setId(id);
            overlimitService.saveOrUpdate(overlimit);
        });
        this.saveBatch(insertList);
    }

    private void checkRecord(WlRecordParam record) {
        if (record instanceof WlRecordParam.AddRecord) {
            WlRecordParam.AddRecord temp =( WlRecordParam.AddRecord) record;
            String itemName = temp.getRecords().get(0).getItemName();
            StringUtil.containsSpecialCharacters(itemName);
            if(StrUtil.isBlank(itemName)){
                throw new BusinessException("测试项名称不能为空或空格");
            }
            List<WlRecord> list = this.lambdaQuery().eq(WlRecord::getPId, temp.getId()).eq(WlRecord::getState, 1).eq(WlRecord::getItemName, itemName).list();
            if(!CollectionUtils.isEmpty(list)){
                throw new BusinessException("数据列表中存在同名测试项");
            }
        }else if (record instanceof WlRecordParam.UpdateRecord) {
            WlRecordParam.UpdateRecord temp =( WlRecordParam.UpdateRecord) record;
            String itemName = temp.getItemName();
            StringUtil.containsSpecialCharacters(itemName);
            if(StrUtil.isBlank(itemName)){
                throw new BusinessException("测试项名称不能为空或空格");
            }
            WlRecord one = this.lambdaQuery().eq(WlRecord::getId, temp.getId()).one();
            List<WlRecord> list = this.lambdaQuery().eq(WlRecord::getPId, one.getPId()).ne(WlRecord::getId, temp.getId()).eq(WlRecord::getState, 1).eq(WlRecord::getItemName, itemName).list();
            if(!CollectionUtils.isEmpty(list)){
                throw new BusinessException("数据列表中存在同名测试项");
            }
        }

    }

    @Override
    public void addBaseData(WlRecord wlRecord) {
        this.save(wlRecord);
    }

    @Override
    public void addBaseDataList(List<WlRecord> wlRecord) {
        this.saveBatch(wlRecord);
    }

    @Override
//    @Transactional(rollbackFor = Exception.class)
    public void updateTestRecord(WlRecordParam.UpdateRecord record) {
        checkRecord(record);
        WlRecord wlRecord = new WlRecord();
        BeanUtils.copyProperties(record, wlRecord);
        wlRecord.setStartTime(record.getProStartTime());
        wlRecord.setEndTime(record.getProEndTime());
        this.updateById(wlRecord);
        saveDataRecord(record);
        //修改测试项限值，用于报表
        DictData scaleResult = dicDataFeignClient.getDicDataById(record.getVoltageLevel()).getData();
        if (Objects.isNull(scaleResult)) {
            throw new BusinessException(CommonResponseEnum.DIC_DATA);
        }


        float voltageLevel = Float.parseFloat(scaleResult.getValue());
        Overlimit overlimit = COverlimitUtil.globalAssemble(voltageLevel, record.getCapacitySi(), record.getCapacitySt(), record.getCapacitySscmin(), 1, 0);
        overlimit.setId(record.getId());
        overlimitService.saveOrUpdate(overlimit);
    }

    @Override
    public void updateRecordData(WlRecordParam.UpdateRecord record) {
        LambdaQueryWrapper<WlRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WlRecord::getId, record.getId());
        WlRecord wlRecord = this.getOne(queryWrapper);
        if (Objects.isNull(wlRecord)) {
            throw new BusinessException("测试项缺失!");
        } else {
            wlRecord.setStartTime(record.getProStartTime());
            wlRecord.setEndTime(record.getProEndTime());
        }
        this.updateById(wlRecord);
    }

    @Override
    public void updateSchemeRecord(WlRecordParam.UpdateRecord record) {
        WlRecord wlRecord = new WlRecord();
        checkString(record.getItemName());
        if(record.getId()!=null){
            BeanUtils.copyProperties(record, wlRecord);
            LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
            qw.eq(WlRecord::getItemName,record.getItemName()).isNull(WlRecord::getPId).eq(WlRecord::getType,0).eq(WlRecord::getState,1).ne(WlRecord::getId,record.getId());
            List<WlRecord> wlRecordList = this.baseMapper.selectList(qw);
            //方案名称重复校验
            if(!wlRecordList.isEmpty()){
                throw new BusinessException(LineBaseEnum.EXISTWLRECORD_FAIL.getMessage());
            }
            this.updateById(wlRecord);
        }else{
            LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
            qw.eq(WlRecord::getItemName,record.getItemName()).isNull(WlRecord::getPId).eq(WlRecord::getType,0).eq(WlRecord::getState,1);
            List<WlRecord> wlRecordList = this.baseMapper.selectList(qw);
            //方案名称重复校验
            if(!wlRecordList.isEmpty()){
                throw new BusinessException(LineBaseEnum.EXISTWLRECORD_FAIL.getMessage());
            }
            BeanUtils.copyProperties(record, wlRecord);
            wlRecord.setId(IdUtil.simpleUUID());
            wlRecord.setType(0);
            wlRecord.setState(1);
            this.save(wlRecord);
        }
    }

    private void checkString(String itemName) {
        StringUtil.containsSpecialCharacters(itemName);
        if(StrUtil.isBlank(itemName)){
            throw new BusinessException("测试项名称不能为空或空格");
        }
    }

    @Override
    public RecordVo.RecordItemVo getTestRecordById(String testRecordId) {
        RecordVo.RecordItemVo recordItemVo = new RecordVo.RecordItemVo();
        List<RecordVo> recordVoList = new ArrayList<>();
        LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper<>();
        qw.eq(WlRecord::getId,testRecordId).eq(WlRecord::getType,0).eq(WlRecord::getState,1);
        List<WlRecord> list = this.baseMapper.selectList(qw);
        WlRecord wlRecord = list.get(0);
        //当前ID就是测试项ID直接返回
        if(wlRecord.getPId()!=null){
            qw.clear();
            qw.eq(WlRecord::getId,wlRecord.getPId()).eq(WlRecord::getType,0).eq(WlRecord::getState,1);
            List<WlRecord> wlRecordList = this.baseMapper.selectList(qw);
            recordItemVo.setDescribe(wlRecordList.get(0).getDescribe());
            recordItemVo.setItemName(wlRecordList.get(0).getItemName());
            RecordVo recordVo = new RecordVo();
            wlRecord.setStartTime(getFirstTimeById(wlRecord.getId()));
            wlRecord.setEndTime(getLastTimeById(wlRecord.getId()));
            BeanUtils.copyProperties(wlRecord, recordVo);
            recordVo.setList(this.baseMapper.getDataRecordBytestId(wlRecord.getId()));
            recordVoList.add(recordVo);
        }else{
            //反之则是方案ID 则返回该方案下所有的测试项信息
            recordItemVo.setDescribe(wlRecord.getDescribe());
            recordItemVo.setItemName(wlRecord.getItemName());
            qw.clear();
            qw.eq(WlRecord::getPId,testRecordId).eq(WlRecord::getType,0).eq(WlRecord::getState,1).orderByAsc(WlRecord::getCreateTime);;
            List<WlRecord> wlRecordList = this.baseMapper.selectList(qw);
            for (WlRecord wl : wlRecordList){
                RecordVo recordVo = new RecordVo();
                wl.setStartTime(getFirstTimeById(wl.getId()));
                wl.setEndTime(getLastTimeById(wl.getId()));
                BeanUtils.copyProperties(wl, recordVo);
                recordVo.setList(this.baseMapper.getDataRecordBytestId(wl.getId()));
                recordVoList.add(recordVo);
            }
        }
        recordItemVo.setRecords(recordVoList);
        return recordItemVo;
    }

    @Override
    public Object queryPage(WlRecordPageParam wlRecordPageParam) {
        //组装tree用于测试项绑定数据页面左侧的搜索树
 /*       List<RecordAllDevTreeVo> devList = new ArrayList<>();
        if(wlRecordPageParam.getIsTrueFlag() == 0){
            LambdaQueryWrapper<WlRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(WlRecord::getType,1).eq(WlRecord::getState, DataStateEnum.ENABLE.getCode());
            List<WlRecord> wlRecordList = this.list(lambdaQueryWrapper);



            if(CollUtil.isNotEmpty(wlRecordList)){
                List<String> devIds = wlRecordList.stream().map(WlRecord::getDevId).distinct().collect(Collectors.toList());
                List<String> lineIds = wlRecordList.stream().map(WlRecord::getLineId).distinct().collect(Collectors.toList());
                List<CsLinePO> csLinePOList = csLinePOMapper.selectBatchIds(lineIds);
                Map<String,CsLinePO> csLinePOMap = csLinePOList.stream().collect(Collectors.toMap(CsLinePO::getLineId, Function.identity()));
                List<CsEquipmentDeliveryPO> csDevPOList = csEquipmentDeliveryMapper.selectList(new LambdaQueryWrapper<CsEquipmentDeliveryPO>().in(CsEquipmentDeliveryPO::getId,devIds));
                Map<String,CsEquipmentDeliveryPO> csDevPOMap = csDevPOList.stream().collect(Collectors.toMap(CsEquipmentDeliveryPO::getId, Function.identity()));

                Map<String,List<WlRecord>> devMap = wlRecordList.stream().collect(Collectors.groupingBy(WlRecord::getDevId));

                devMap.forEach((devId,list)->{
                    RecordAllDevTreeVo devTree = new RecordAllDevTreeVo();
                    devTree.setId(devId);
                    devTree.setName(csDevPOMap.get(list.get(0).getDevId()).getName());
                    devTree.setPid("0");

                    Map<String,List<WlRecord>> lineMap = list.stream().collect(Collectors.groupingBy(WlRecord::getLineId));
                    List<RecordAllDevTreeVo> csLineList = new ArrayList<>();
                    lineMap.forEach((lineId,lineList)->{
                        RecordAllDevTreeVo recordAllDevTreeVo = new RecordAllDevTreeVo();
                        recordAllDevTreeVo.setId(lineId);
                        recordAllDevTreeVo.setName(csLinePOMap.get(lineList.get(0).getLineId()).getName());
                        recordAllDevTreeVo.setPid(devId);
                        List<RecordAllDevTreeVo> iiList = new ArrayList<>();
                        lineList.forEach(it->{
                            RecordAllDevTreeVo ii = new RecordAllDevTreeVo();
                            ii.setId(it.getId());
                            ii.setName(it.getStartTime()+"-"+it.getEndTime());
                            ii.setPid(lineId);
                            iiList.add(ii);
                        });
                        recordAllDevTreeVo.setChildren(iiList);
                        csLineList.add(recordAllDevTreeVo);
                    });
                    devTree.setChildren(csLineList);
                    devList.add(devTree);
                });
            }

        }*/

        List<RecordAllDevTreeVo> recordAllDevTreeVos = this.baseMapper.getRecordAll(wlRecordPageParam);
        for (RecordAllDevTreeVo recordAllDevTreeVo : recordAllDevTreeVos){
            wlRecordPageParam.setDevId(recordAllDevTreeVo.getId());
            List<RecordAllDevTreeVo.RecordAllLineTreeVo> recordAllLineTreeVos = this.baseMapper.getRecordAllLine(wlRecordPageParam);
            for(RecordAllDevTreeVo.RecordAllLineTreeVo recordAllLineTreeVo : recordAllLineTreeVos){
                wlRecordPageParam.setLineId(recordAllLineTreeVo.getId().split("-")[0]);
                recordAllLineTreeVo.setChildren(this.baseMapper.getRecordAllTime(wlRecordPageParam));
            }
            recordAllDevTreeVo.setChildren(recordAllLineTreeVos);
        }
        return recordAllDevTreeVos;
    }

    @Override
    public List<RecordTreeVo> getSchemeTree() {
        List<RecordTreeVo> result = new ArrayList<>();
        LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
        qw.eq(WlRecord::getState,"1").eq(WlRecord::getType,"0").orderByAsc(WlRecord::getCreateTime);
        List<WlRecord> list = this.baseMapper.selectList(qw);
        // 过滤出方案数据和测试项数据(组装成tree)
        List<WlRecord> schemes = list.stream().filter(item -> item.getPId() == null).collect(Collectors.toList());
        List<WlRecord> testItems = list.stream().filter(item -> item.getPId() != null).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(schemes)){
            // 遍历方案数据
            for (WlRecord scheme : schemes) {
                RecordTreeVo vo = new RecordTreeVo();
                vo.setId(scheme.getId());
                vo.setName(scheme.getItemName());
                List<RecordTreeVo.Children> childrens = new ArrayList<>();
                //遍历测试项 并且绑定对应的父级方案节点
                for(WlRecord testItem : testItems.stream().filter(e->e.getPId() .equals( scheme.getId())).collect(Collectors.toList())){
                    RecordTreeVo.Children children = new RecordTreeVo.Children();
                    children.setId(testItem.getId());
                    children.setName(testItem.getItemName());
                    children.setPId(testItem.getPId());
                    children.setStartTime(LocalDateTimeUtil.format(getFirstTimeById(testItem.getId()), DateTimeFormatter.ofPattern(DataParam.timeFormat)));
                    children.setEndTime(LocalDateTimeUtil.format(getLastTimeById(testItem.getId()), DateTimeFormatter.ofPattern(DataParam.timeFormat)));
                    childrens.add(children);
                }
                vo.setChildren(childrens);
                result.add(vo);
            }
        }
        return result;
    }

    @Override
//    @Transactional(rollbackFor = Exception.class)
    public void deleteRecord(String id) {
        LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
        qw.eq(WlRecord::getId,id).eq(WlRecord::getState,"1").eq(WlRecord::getType,"0");
        List<WlRecord> wlRecordList = this.baseMapper.selectList(qw);
        if(!wlRecordList.isEmpty()){
            //首先先删除本条数据
            LambdaUpdateWrapper<WlRecord> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.set(WlRecord::getState,0)
                    .eq(WlRecord::getId, id)
                    .eq(WlRecord::getType, 0);
            this.update(lambdaUpdateWrapper);
            WlRecord wlRecord = wlRecordList.get(0);
            //如果删除的是测试项
            if(wlRecord.getPId() != null){
                //方案关联的设备基础数据也删除
                this.baseMapper.deleteDataRecord(id,null);
                overlimitService.removeById(id);
            }else{
                //如果删除的是方案 那么连带方案下的所有测试项也要删除
                qw = new LambdaQueryWrapper();
                qw.eq(WlRecord::getPId,id).eq(WlRecord::getState,"1").eq(WlRecord::getType,"0");
                for (WlRecord wl : this.baseMapper.selectList(qw)){
                    LambdaUpdateWrapper<WlRecord> uw = new LambdaUpdateWrapper<>();
                    uw.set(WlRecord::getState,0)
                            .eq(WlRecord::getId, wl.getId());
                    this.update(uw);
                    //方案关联的设备基础数据也删除
                    this.baseMapper.deleteDataRecord(wl.getId(),null);
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveDataRecord(WlRecordParam.UpdateRecord record) {
        this.baseMapper.deleteDataRecord(record.getId(),null);
        if(record.getList()!=null && !record.getList().isEmpty()){
            for(String dataRecordId : record.getList()){
                this.baseMapper.saveDataRecord(record.getId(),dataRecordId);
            }
        }
    }

    @Override
    public List<ThdDataVO> queryCommonStatisticalByTest(CommonStatisticalQueryParam commonStatisticalQueryParam) {
        List<ThdDataVO> result = new ArrayList();
        LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
        //注意:此DevId为方案或测试项ID
        qw.eq(WlRecord::getId,commonStatisticalQueryParam.getDevId()).eq(WlRecord::getState,"1").eq(WlRecord::getType,"0");
        List<WlRecord> wlRecordList = this.baseMapper.selectList(qw);
        if(wlRecordList.isEmpty()){
            throw new BusinessException(LineBaseEnum.DEVID_FAIL.getMessage());
        }
        WlRecord wlRecord = wlRecordList.get(0);
        List<WlRecord> data = new ArrayList<>();
        if(wlRecord.getPId() == null){
            //如果查询的是方案 则查询该方案下所有的测试项关联的设备基础数据
            return null;
//            data = this.baseMapper.getDataRecordByTestId(wlRecord.getId(),1);
        }else{
            //如果查询的是测试项 则查询该测试项下所有的关联的设备基础数据
            data = this.baseMapper.getDataRecordByTestId(wlRecord.getId(),0);
        }
        //进行时间覆盖(查询的基础数据必须两个以上)
        if(data.size()>1){
            data = fuseWlRecordTime(data,0);
        }
        //格式化前端参数
        formatQueryParamList(commonStatisticalQueryParam);
        if(commonStatisticalQueryParam.getList() != null && !commonStatisticalQueryParam.getList().isEmpty()){
            for (CommonStatisticalQueryParam param : commonStatisticalQueryParam.getList()){
                if(param.getStatisticalId() == null){
                    continue;
                }
                List<EleEpdPqd> eleEpdPqds = csStatisticalSetFeignClient.queryStatisticalSelect(Collections.singletonList(param.getStatisticalId())).getData();
                for(WlRecord wl : data){
                    List<CsLinePO> finalCsLinePOList = csLineFeignClient.queryLineById(Arrays.asList(wl.getLineId())).getData();
                    CsDataSet csDataSet = csDataSetMapper.selectOne(new LambdaQueryWrapper<CsDataSet>().eq(CsDataSet::getId,finalCsLinePOList.get(0).getDataSetId()));
                    if(StrUtil.isBlank(csDataSet.getDataLevel())){
                        throw new BusinessException("当前测点数据集主要信息缺失,请联系管理员排查(测点表里面数据集id缺失)");
                    }
                    Double ct = Double.valueOf(wlRecord.getCt())/wlRecord.getCt1();
                    Double pt =Double.valueOf(wlRecord.getPt())/wlRecord.getPt1();

                    List<CsEquipmentDeliveryDTO> data1 = equipmentFeignClient.queryDeviceById(Stream.of(wl.getDevId()).collect(Collectors.toList())).getData();
                    eleEpdPqds.forEach(epdPqd->{
                        List<CommonQueryParam> commonQueryParams = finalCsLinePOList.stream().map(temp -> {
                            CommonQueryParam commonQueryParam = new CommonQueryParam();
                            commonQueryParam.setLineId(temp.getLineId());
                            commonQueryParam.setTableName(influxDbParamUtil.getTableNameByClassId(epdPqd.getClassId()));
                            if (epdPqd.getName() == null || epdPqd.getName().isEmpty()) {
                                commonQueryParam.setColumnName(epdPqd.getName()+ (param.getFrequency() == null ? "":"_"+param.getFrequency()));
                            } else {
                                commonQueryParam.setColumnName(epdPqd.getOtherName()+ (param.getFrequency() == null ? "":"_"+param.getFrequency()));
                            }
                            commonQueryParam.setPhasic(epdPqd.getPhase());
                            commonQueryParam.setStartTime(LocalDateTimeUtil.format(wl.getStartTime(), DateTimeFormatter.ofPattern(DataParam.timeFormat)));
                            commonQueryParam.setEndTime(LocalDateTimeUtil.format(wl.getEndTime(), DateTimeFormatter.ofPattern(DataParam.timeFormat)));
                            commonQueryParam.setDataType(commonStatisticalQueryParam.getValueType().toUpperCase());
                            commonQueryParam.setProcess(data1.get(0).getProcess()+"");
                            commonQueryParam.setClDid(influxDbParamUtil.getClDidByLineId(temp.getLineId()));
                            return commonQueryParam;
                        }).collect(Collectors.toList());
                        List<StatisticalDataDTO> deviceRtData = commonService.getDeviceRtDataByTime(commonQueryParams);
                        //此处设空时为了有多段时将线条断开前端显示
                        if(!CollectionUtils.isEmpty(deviceRtData)){
                            deviceRtData.get(deviceRtData.size()-1).setValue(null);
                        }
                        List<ThdDataVO> collect1 = deviceRtData.stream().map(temp -> {
                            String unit;
                            ThdDataVO vo = new ThdDataVO();
                            vo.setLineId(temp.getLineId());
                            vo.setPhase(Objects.equals("T",temp.getPhaseType())?null:temp.getPhaseType());
                            String position = finalCsLinePOList.stream().filter(csLinePO -> Objects.equals(csLinePO.getLineId(), vo.getLineId())).collect(Collectors.toList()).get(0).getPosition();
                            vo.setPosition(position);
                            vo.setTime(temp.getTime());
                            vo.setStatMethod(temp.getValueType());
                            if(temp.getValue()!=null) {
                                double re = 0;
                                if (Objects.equals("Primary",commonStatisticalQueryParam.getDataLevel())) {
                                    if (Objects.equals("Primary",csDataSet.getDataLevel())) {
                                        vo.setStatisticalData(Double.valueOf(df.format(temp.getValue())));
                                        unit = epdPqd.getUnit();
                                    } else {
                                        if(Objects.nonNull(epdPqd.getPrimaryFormula())){
                                            switch (epdPqd.getPrimaryFormula()) {
                                                case "*PT":
                                                    re = temp.getValue() * pt / 1000;
                                                    unit = "k" + epdPqd.getUnit();
                                                    break;
                                                case "*CT":
                                                    re = temp.getValue() * ct;
                                                    unit = epdPqd.getUnit();
                                                    break;
                                                case "*PT*CT":
                                                    re = temp.getValue() * pt * ct / 1000;
                                                    unit = "k" + epdPqd.getUnit();
                                                    break;
                                                default:
                                                    re = temp.getValue();
                                                    unit = epdPqd.getUnit();
                                                    break;
                                            }
                                            vo.setStatisticalData(Double.valueOf(df.format(re)));
                                        }else {
                                            re = temp.getValue();
                                            unit = epdPqd.getUnit();
                                            vo.setStatisticalData(Double.valueOf(df.format(re)));
                                        }

                                    }
                                } else {
                                    if (Objects.equals("Primary",csDataSet.getDataLevel())) {
                                        if(Objects.nonNull(epdPqd.getPrimaryFormula())){
                                            switch (epdPqd.getPrimaryFormula()) {
                                                case "*PT":
                                                    re = temp.getValue() / pt;
                                                    break;
                                                case "*CT":
                                                    re = temp.getValue() / ct;
                                                    break;
                                                case "*PT*CT":
                                                    re = temp.getValue() / pt / ct;
                                                    break;
                                                default:
                                                    re = temp.getValue();
                                                    break;
                                            }
                                            vo.setStatisticalData(Double.valueOf(df.format(re)));
                                        }else {
                                            re = temp.getValue();
                                            vo.setStatisticalData(Double.valueOf(df.format(re)));
                                        }
                                    } else {
                                        vo.setStatisticalData(Double.valueOf(df.format(temp.getValue())));
                                    }
                                    unit = epdPqd.getUnit();
                                }
                            } else {
                                vo.setStatisticalData(null);
                                if (Objects.equals("Primary",commonStatisticalQueryParam.getDataLevel())) {
                                    if (Objects.equals("Primary",csDataSet.getDataLevel())) {
                                        unit = epdPqd.getUnit();
                                    } else {
                                        if(Objects.nonNull(epdPqd.getPrimaryFormula())){
                                            switch (epdPqd.getPrimaryFormula()) {
                                                case "*PT":
                                                    unit = "k" + epdPqd.getUnit();
                                                    break;
                                                case "*CT":
                                                    unit = epdPqd.getUnit();
                                                    break;
                                                case "*PT*CT":
                                                    unit = "k" + epdPqd.getUnit();
                                                    break;
                                                default:
                                                    unit = epdPqd.getUnit();
                                                    break;
                                            }
                                        }else {
                                            unit = epdPqd.getUnit();
                                        }
                                    }
                                } else {
                                    unit = epdPqd.getUnit();
                                }
                            }
                            vo.setUnit(unit);
                            vo.setStatisticalIndex(epdPqd.getId());
                            vo.setStatisticalName(epdPqd.getName());
                            vo.setAnotherName(epdPqd.getShowName());
                            return vo;
                        }).collect(Collectors.toList());
                        result.addAll(collect1);
                    });
                }
            }
        }
        return result;
    }


    @Override
    public WlRecord findDevBaseData(WlRecordParam.Record param) {
        LambdaQueryWrapper<WlRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WlRecord::getGcName,param.getProName())
                .eq(WlRecord::getDevId,param.getDevId())
                .eq(WlRecord::getLineId,param.getLineId())
                .eq(WlRecord::getStartTime,param.getProStartTime())
                .eq(WlRecord::getType,1)
                .eq(WlRecord::getState,1);
        return this.getOne(lambdaQueryWrapper);
    }

    @Override
    public List<RecordVo> findDevBaseDataByLineId(WlRecordParam.lineRecord param) {
        List<RecordVo> result = new ArrayList<>();
        LambdaQueryWrapper<WlRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(WlRecord::getLineId,param.getLineId())
                .between(WlRecord::getStartTime,param.getItemStartTime(),param.getItemEndTime())
                .eq(WlRecord::getType,1)
                .eq(WlRecord::getState,1)
                .orderByDesc(WlRecord::getStartTime);
        if (Objects.equals(param.getDataSource(),0)) {
            lambdaQueryWrapper.eq(WlRecord::getItemName,"补召");
        } else if (Objects.equals(param.getDataSource(),1)) {
            lambdaQueryWrapper.eq(WlRecord::getItemName,"在线监测");
        }
        List<WlRecord> list = this.list(lambdaQueryWrapper);
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(item->{
                RecordVo vo = new RecordVo();
                BeanUtils.copyProperties(item,vo);
                result.add(vo);
            });
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dayDealNoEndTimeEvent(String date) {
        DateTime dateEnd = DateUtil.parse(date,DatePattern.NORM_DATE_PATTERN);
        DateTime dateStart = DateUtil.offsetDay(dateEnd,-30);
        System.out.println("进入定时任务");
        LambdaQueryWrapper<WlRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.between(WlRecord::getStartTime,dateStart,dateEnd).eq(WlRecord::getType,1).eq(WlRecord::getState,DataStateEnum.ENABLE.getCode());
        List<WlRecord> wlRecordList = this.list(lambdaQueryWrapper);
        if(CollUtil.isNotEmpty(wlRecordList)){

            //需要处理的基础数据
           List<WlRecord> needDealList =  wlRecordList.stream().filter(it->Objects.isNull(it.getEndTime())).collect(Collectors.toList());
           List<String> needIds = needDealList.stream().map(WlRecord::getLineId).distinct().collect(Collectors.toList());

            Map<String,List<WlRecord>> lineMap = wlRecordList.stream().collect(Collectors.groupingBy(WlRecord::getLineId));

            List<WlRecord> poList = new ArrayList<>();
            lineMap.forEach((lineId,list)->{
                if(needIds.contains(lineId)){
                    //选择起始时间进行倒序
                    list = list.stream().sorted(Comparator.comparing(WlRecord::getStartTime)).collect(Collectors.toList());
                    for(int i=0;i<list.size();i++){
                        LocalDateTime start = list.get(i).getStartTime();
                        String startSql = start.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                        if(i==list.size()-1){
                            //判断最迟时间的数据是否没有结束时间
                            if(Objects.isNull(list.get(i).getEndTime())){
                                LocalDateTime now = LocalDateTime.now();
                                String sqlNow = now.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                                InfluxQueryWrapper influxQueryWrapper = new InfluxQueryWrapper("data_v",StatisticalDataDTO.class);
                                influxQueryWrapper.select(StatisticalDataDTO::getLineId)
                                        .select(StatisticalDataDTO::getPhaseType)
                                        .select(StatisticalDataDTO::getValueType)
                                        .last("freq")
                                        .eq(InfluxDBTableConstant.LINE_ID,lineId)
                                        .eq(InfluxDBTableConstant.PHASIC_TYPE,"T")
                                        .between(InfluxDBTableConstant.TIME,startSql,sqlNow);
                                System.out.println(influxQueryWrapper.generateSql());
                                StatisticalDataDTO statisticalDataDTO = commonMapper.getLineRtData(influxQueryWrapper);
                                if(Objects.nonNull(statisticalDataDTO)){
                                    LocalDateTime endTime = statisticalDataDTO.getTime().atOffset(ZoneOffset.ofHours(0)).toLocalDateTime();
                                    Duration duration = Duration.between(endTime,now);
                                    long hour = duration.toHours();
                                    if(hour>6){
                                        WlRecord wlRecord = new WlRecord();
                                        wlRecord.setId(list.get(i).getId());
                                        wlRecord.setEndTime(endTime);
                                        poList.add(wlRecord);
                                    }
                                }

                            }
                        }else {
                            //如果不存在结束时间，则取后面一条的起始时间作为结束判断标识
                            if(Objects.isNull(list.get(i).getEndTime())){
                                String end = list.get(i+1).getStartTime().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                                InfluxQueryWrapper influxQueryWrapper = new InfluxQueryWrapper("data_v",StatisticalDataDTO.class);
                                influxQueryWrapper.select(StatisticalDataDTO::getLineId)
                                        .select(StatisticalDataDTO::getPhaseType)
                                        .select(StatisticalDataDTO::getValueType)
                                        .last("freq")
                                        .eq(InfluxDBTableConstant.LINE_ID,lineId)
                                        .eq(InfluxDBTableConstant.PHASIC_TYPE,"T")
                                        .between(InfluxDBTableConstant.TIME,startSql,end);
                                System.out.println(influxQueryWrapper.generateSql());
                                StatisticalDataDTO statisticalDataDTO = commonMapper.getLineRtData(influxQueryWrapper);
                                WlRecord wlRecord = new WlRecord();
                                wlRecord.setId(list.get(i).getId());

                                if(Objects.nonNull(statisticalDataDTO)){
                                   LocalDateTime endTime = statisticalDataDTO.getTime().atOffset(ZoneOffset.ofHours(0)).toLocalDateTime();
                                   wlRecord.setEndTime(endTime);
                               }else {
                                   //TODO 如果查询时间段内无数据，说明装置可能时间段内掉线，出错，需要标识出来
                                    wlRecord.setEndTime(list.get(i+1).getStartTime());
                               }
                                poList.add(wlRecord);
                            }
                        }
                    }
                }

            });

            if(CollUtil.isNotEmpty(poList)){
                this.updateBatchById(poList);
            }

        }

    }

    @Override
    public List<WlRecord> getWlAssByWlId(String wlId) {
        return this.baseMapper.getWlAssByWlId(wlId);
    }

    @Override
    public void deleteItem(String id) {
        LambdaUpdateWrapper<WlRecord> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(WlRecord::getId,id).set(WlRecord::getState,0);
        this.update(lambdaUpdateWrapper);
    }

    /**
     * 数据项内的时间进行覆盖:解决多个数据项的startTime及endTime之间存在时间冲突
     * @param data 数据项
     * @param flag 覆盖规则(0:从左到右依次覆盖,1:时间范围度最大依次覆盖)  *注:从左到右依次覆盖规则下多个数据项必须按照 "开始时间升序排序"
     */
    private static List<WlRecord> fuseWlRecordTime(List<WlRecord> data,int flag){
        List<WlRecord> rs = new ArrayList<>();
        log.info("覆盖规则为:{}",flag == 0 ? "从左到右依次覆盖":"时间范围度最大依次覆盖");
        log.info("覆盖前源数据:");
        for(WlRecord wlRecord : data){
            log.info("id:{} , startTime:{} , endTime:{}",wlRecord.getId(),wlRecord.getStartTime().format(DateTimeFormatter.ofPattern(DataParam.timeFormat)),wlRecord.getEndTime().format(DateTimeFormatter.ofPattern(DataParam.timeFormat)));
        }
        if(flag == 0){
            //为防止意外 还是进行下排序
            data = data.stream().sorted(Comparator.comparing(WlRecord::getStartTime)).collect(Collectors.toList());
            //从左到右依次覆盖
            //由于覆盖规则是最左原则 所以第一个左主数据一定是有效的
            rs.add(data.get(0));
            WlRecord tempRecord = null;
            for (int i = 0; i < data.size(); i++) {
                if(i<data.size()-1){
                    WlRecord current = null;
                    //当前比较的左主数据
                    if(tempRecord == null){
                        //正常便利获取左主数据(1-2,2-3,3-4...)
                        current = data.get(i);
                    }else{
                        //上一轮左主数据把上一轮的被比数据吃掉了 那么继续拿上一轮数据作为左主数据进行比较(1-2,1-3,1-4,4-5,4-5...)
                        current = tempRecord;
                    }
                    //下一个被比较数据
                    int index = i + 1;
                    WlRecord next = data.get(index);
                    //判断下一个数据时间范围是不是在当前已添加集合项时间范围内(判断是否有修改的必要)
                    if((getStartOrEndTimeByList(rs,1).compareTo(next.getStartTime())<0 || getStartOrEndTimeByList(rs,1).compareTo(next.getStartTime())==0)
                            && (getStartOrEndTimeByList(rs,2).compareTo(next.getEndTime())>0 || getStartOrEndTimeByList(rs,2).compareTo(next.getEndTime())==0)){
                        //如果当前集合项时间范围把下一个节点吃掉了 那么此节点将不变继续作为当前比较的左主数据 参加下一轮比较
                        tempRecord = current;
                        continue;
                    }else if(current.getEndTime().compareTo(next.getStartTime())<0){
                        //这种属于两个节点的数据本来就没有交叉 属于正常时间串
                        rs.add(next);
                        tempRecord = null;
                    }else{
                        //时间出现交叉
                        next.setStartTime(current.getEndTime().plusSeconds(1));
                        rs.add(next);
                        tempRecord = null;
                    }
                }
            }
        }else{
            //时间范围度最大依次覆盖
            //此处逻辑暂定 默认按照上面最左原则
        }
        rs = rs.stream().sorted(Comparator.comparing(WlRecord::getStartTime)).collect(Collectors.toList());
        log.info("覆盖后新数据:");
        for(WlRecord wlRecord : rs){
            log.info("id:{} , startTime:{} , endTime:{}",wlRecord.getId(),wlRecord.getStartTime().format(DateTimeFormatter.ofPattern(DataParam.timeFormat)),wlRecord.getEndTime().format(DateTimeFormatter.ofPattern(DataParam.timeFormat)));
        }
        return rs;
    }

    //获取集合中最开始时间或最结束时间
    private static LocalDateTime getStartOrEndTimeByList(List<WlRecord> rs,int type){
        rs = rs.stream().sorted(Comparator.comparing(type == 1?WlRecord::getStartTime:WlRecord::getEndTime)).collect(Collectors.toList());
        return type == 1?rs.get(0).getStartTime():rs.get(rs.size()-1).getEndTime();
    }

    private void formatQueryParamList(CommonStatisticalQueryParam commonStatisticalQueryParam){
        List<CommonStatisticalQueryParam> list = new ArrayList<>();
        if(commonStatisticalQueryParam.getList() != null && commonStatisticalQueryParam.getList().size() > 0){
            for(CommonStatisticalQueryParam param : commonStatisticalQueryParam.getList()){
                if(param.getFrequencys() != null && param.getFrequencys().size() > 0){
                    for (String frequency : param.getFrequencys()){
                        CommonStatisticalQueryParam cp = new CommonStatisticalQueryParam();
                        cp.setStatisticalId(param.getStatisticalId());
                        cp.setFrequency(frequency);
                        list.add(cp);
                    }
                }else{
                    CommonStatisticalQueryParam cp = new CommonStatisticalQueryParam();
                    cp.setStatisticalId(param.getStatisticalId());
                    list.add(cp);
                }
            }
            commonStatisticalQueryParam.setList(list);
        }
    }

    /**
     * 获取测试项绑定的基础数据最早的设备开始时间
     * @param testRecordId
     * @return
     */
    private LocalDateTime getFirstTimeById(String testRecordId) {
        LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
        List<String> recordIds = this.baseMapper.getDataRecordBytestId(testRecordId);
        if(recordIds.isEmpty()){
            recordIds.add("-1");
        }
        qw.eq(WlRecord::getState,"1").in(WlRecord::getId,recordIds).orderByAsc(WlRecord::getStartTime);
        List<WlRecord> list = this.baseMapper.selectList(qw);
        if(list.isEmpty()){
            return null;
        }
        return list.get(0).getStartTime();
    }

    /**
     * 获取测试项绑定的基础数据最晚的设备结束时间
     * @param testRecordId
     * @return
     */
    private LocalDateTime getLastTimeById(String testRecordId) {
        LambdaQueryWrapper<WlRecord> qw = new LambdaQueryWrapper();
        List<String> recordIds = this.baseMapper.getDataRecordBytestId(testRecordId);
        if(recordIds.isEmpty()){
            recordIds.add("-1");
        }
        qw.eq(WlRecord::getState,"1").in(WlRecord::getId,recordIds).orderByDesc(WlRecord::getEndTime);
        List<WlRecord> list = this.baseMapper.selectList(qw);
        if(list.isEmpty()){
            return null;
        }
        return list.get(0).getEndTime();
    }
}
