package com.njcn.csdevice.service.impl;

import cn.hutool.core.util.IdUtil;
import com.alibaba.nacos.shaded.com.google.gson.Gson;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.tocrhz.mqtt.publisher.MqttPublisher;
import com.njcn.advance.api.EventCauseFeignClient;
import com.njcn.advance.pojo.dto.EventAnalysisDTO;
import com.njcn.common.pojo.enums.common.DataStateEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.constant.DataParam;
import com.njcn.csdevice.enums.AlgorithmResponseEnum;
import com.njcn.csdevice.mapper.PortableOfflLogMapper;
import com.njcn.csdevice.param.UploadDataParam;
import com.njcn.csdevice.pojo.dto.CsEquipmentDeliveryDTO;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.csdevice.pojo.po.PortableOffMainLog;
import com.njcn.csdevice.pojo.po.PortableOfflLog;
import com.njcn.csdevice.pojo.po.WlRecord;
import com.njcn.csdevice.service.*;
import com.njcn.csdevice.util.InfluxDbParamUtil;
import com.njcn.csharmonic.api.EventFeignClient;
import com.njcn.csharmonic.api.OfflineDataUploadFeignClient;
import com.njcn.csharmonic.offline.constant.OfflineConstant;
import com.njcn.csharmonic.offline.log.Log;
import com.njcn.csharmonic.offline.log.vo.NewBodyTaglogbuffer;
import com.njcn.csharmonic.offline.log.vo.NewHeadTaglogbuffer;
import com.njcn.csharmonic.offline.log.vo.NewTaglogbuffer;
import com.njcn.csharmonic.offline.log.vo.TagComtradeCfg;
import com.njcn.csharmonic.offline.mincfg.AnalyseComtradeCfg;
import com.njcn.csharmonic.offline.mincfg.vo.CmnModeCfg;
import com.njcn.csharmonic.offline.vo.Response;
import com.njcn.csharmonic.pojo.po.CsEventPO;
import com.njcn.event.common.mapper.WlRmpEventDetailMapper;
import com.njcn.event.common.service.EventAnalysisService;
import com.njcn.event.pojo.po.RmpEventDetailPO;
import com.njcn.influx.imapper.*;
import com.njcn.influx.pojo.po.*;
import com.njcn.influx.pojo.po.cs.EntData;
import com.njcn.influx.pojo.po.cs.PqdData;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.api.EleEvtFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.web.pojo.param.BaseParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 *  离线数据导入 服务实现类
 * </p>
 *
 * @author guofeihu
 * @since 2024-07-03
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PortableOfflLogServiceImpl extends ServiceImpl<PortableOfflLogMapper, PortableOfflLog> implements IPortableOfflLogService {


    private final  DecimalFormat df = new DecimalFormat("#0.000");
    private final FileStorageUtil fileStorageUtil;
    private final DicDataFeignClient dicDataFeignClient;
    private final OfflineDataUploadFeignClient offlineDataUploadFeignClient;
    private final EleEvtFeignClient eleEvtFeignClient;
    private final EventFeignClient eventFeignClient;
    private final EquipmentFeignClient equipmentFeignClient;
    private final InfluxDbParamUtil influxDbParamUtil;
    private final PqdDataMapper pqdDataMapper;
    private final EvtDataMapper evtDataMapper;

    private final DataVMapper dataVMapper;
    private final DataIMapper dataIMapper;
    private final DataHarmRateVMapper dataHarmRateV;
    private final DataHarmRateIMapper dataHarmRateI;
    private final DataInHarmVMapper dataInHarmV;
    private final DataHarmPowerPMapper dataHarmPowerP;
    private final DataHarmPowerQMapper dataHarmPowerQ;
    private final DataHarmPowerSMapper dataHarmPowerS;
    private final DataFlickerMapper dataFlicker;
    private final DataFlucMapper dataFluc;
    private final DataPltMapper dataPlt;
    private final DataHarmPhasicVMapper dataHarmPhasicV;
    private final DataHarmPhasicIMapper dataHarmPhasicI;

    private final IPqdDataSplitService pqdDataSplitService;
    private final MqttPublisher publisher;
    private final PortableOffMainLogService portableOffMainLogService;
    private final IWlRecordService wlRecordService;
    private final CsLinePOService csLinePOService;
    private final WlRmpEventDetailMapper wlRmpEventDetailMapper;
    private final EventCauseFeignClient eventCauseFeignClient;
    private final EventAnalysisService eventAnalysisService;

    @Override
    public Page<PortableOfflLog> queryPage(BaseParam baseParam) {
        Page<PortableOfflLog> returnpage = new Page<> (baseParam.getPageNum(), baseParam.getPageSize ());
        if(baseParam.getSearchBeginTime()!=null) {
            baseParam.setSearchBeginTime(baseParam.getSearchBeginTime()+DataParam.startTime);
        }
        if(baseParam.getSearchEndTime()!=null) {
            baseParam.setSearchEndTime(baseParam.getSearchEndTime()+DataParam.endTime);
        }
        returnpage  = this.getBaseMapper().queryPage(returnpage,baseParam);
        return returnpage;
    }

    public byte[] uploadAnalysis(List<MultipartFile> files,String type) throws Exception{
        byte[] bytes = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);

        List<Response> responses = new ArrayList<>();
        //min解析较为特殊需要同时解析所有文件
        if(!files.isEmpty() && OfflineConstant.MIN.equals(type)){
            Response response = new Response();
            response.setFilename(OfflineConstant.MIN);
            List<PqdData> pqdData = null;
            try {
                pqdData = AnalyseComtradeCfg.processDirectory(files);
            } catch (Exception e) {
                log.error("min文件夹下的数据文件解析失败");
                response.setState(2);
            }
            response.setObj(pqdData);
            responses.add(response);
        }else{
            for(MultipartFile file : files){
                Response response = new Response();
                response.setFilename(file.getOriginalFilename());
                if(OfflineConstant.COMTRADE.equals(type) && file.getOriginalFilename().indexOf(OfflineConstant.CFG) != -1) {
                    TagComtradeCfg tagComtradeCfg = null;
                    try {
                        tagComtradeCfg = AnalyseComtradeCfg.analyseComtradeCfg(file);
                    } catch (Exception e) {
                        log.error("当前文件：{}，解析失败",file.getOriginalFilename());
                        response.setState(2);
                    }
                    response.setObj(tagComtradeCfg);
                }else if(OfflineConstant.LOG.equals(type) && file.getOriginalFilename().indexOf(OfflineConstant.BIN) != -1){
                    List<NewTaglogbuffer> newTaglogbuffers = null;
                    try {
                        newTaglogbuffers = Log.convertLog(file);
                    } catch (Exception e) {
                        log.error("当前文件：{}，解析失败",file.getOriginalFilename());
                        response.setState(2);
                    }
                    response.setObj(newTaglogbuffers);
                }
                responses.add(response);
            }
        }
        try {
            oos.writeObject(responses);
            bytes = baos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException(OfflineConstant.DATATOBYTE_FAIL);
        } finally {
            oos.close();
            baos.close();
        }
        return bytes;
    }

    @Override
    @DSTransactional
    public void importEquipment(UploadDataParam uploadDataParam){
        String lineId = uploadDataParam.getLineId();
        //获取监测点信息
        LambdaQueryWrapper<CsLinePO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CsLinePO::getLineId,lineId).eq(CsLinePO::getStatus,1);
        CsLinePO po = csLinePOService.getOne(queryWrapper);
        //String cdid  = uploadDataParam.getLineId().substring(uploadDataParam.getLineId().length() - 1);
        Integer cdid  = po.getClDid();
        //第一步解析redcord.bin文件获取监测点序号做校验
        List<MultipartFile> record = uploadDataParam.getFiles().stream().filter(
                temp -> temp.getOriginalFilename().contains("record.bin"))
                .collect(Collectors.toList());
        if(CollectionUtils.isEmpty(record)){
           throw  new BusinessException(AlgorithmResponseEnum.RECORD_FILE_LOST);
        }else {
            InputStream inputStream = null;
            try {
                inputStream = record.get(0).getInputStream();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            CmnModeCfg cmnModeCfg = AnalyseComtradeCfg.convertRecord(inputStream);
            //监测点序号
            int lineIdx = cmnModeCfg.line_idx;

            if(lineIdx != cdid){
                throw  new BusinessException(AlgorithmResponseEnum.LINE_NUM_MISMATCH);
            }

        }


        //获取离线上传对应的字典规则(字典用来控制上传的文件夹名称,其中字典的name代表名称,code代表该文件夹下对应的解析规则且code不能更改)
        List<DictData> dictDatas = dicDataFeignClient.getDicDataByTypeCode(DataParam.wlRecordUpload).getData();
        List<Response> responses = new ArrayList<>();
        //临时cfg解析集合
        List<Response> cfgResponse = new ArrayList<>();
        //便利每个文件夹
        for(DictData dictData : dictDatas){
            List<MultipartFile> fileList = new ArrayList<>();
            for(MultipartFile file : uploadDataParam.getFiles()){
                //获取每个文件夹下对应的文件信息
                if(checkPrevsFolder(file.getOriginalFilename(),dictData.getName())!=null) {
                    fileList.add(file);
                }
            }
            if(!fileList.isEmpty()){
                //将当前文件夹下的文件统一解析
                byte[] resp = new byte[0];
                try {
                    resp = uploadAnalysis(fileList,dictData.getCode());
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //解析的返回的是复杂对象所以直接转成byte数组
                ByteArrayInputStream bis = new ByteArrayInputStream(resp);
                ObjectInputStream ois = null;
                try {
                    ois = new ObjectInputStream(bis);
                    Object obj = ois.readObject();
                    //实际返回的是List<Response> 也即:该文件夹下所有解析的文件对应的结果集
                    List<Response> response = (List<Response>) obj;
                    //临时记录下cfg结果集(用作log绑定对应的cfg波形文件)
                    if(OfflineConstant.COMTRADE.equals(dictData.getCode())){
                        cfgResponse.addAll(response);
                    }
                    responses.addAll(response);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new BusinessException(OfflineConstant.BYTETODATA_FAIL);
                } finally {
                    try {
                        ois.close();
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        List<CsEquipmentDeliveryDTO> data1 = equipmentFeignClient.queryDeviceById(Stream.of(uploadDataParam.getDevId()).collect(Collectors.toList())).getData();
        CsEquipmentDeliveryDTO csEquipmentDeliveryDTO = data1.get(0);
        //min文件夹下的文件是否解析过
        boolean minFlag = true;
        //开始上传文件、记录上传日志、解析的文件结果入库
        //最外层便利所有文件确保所有文件都上传及记录上传日志
        int nowStep = uploadDataParam.getFiles().size();
        PortableOffMainLog portableOffMainLog = new PortableOffMainLog();
        portableOffMainLog.setId(IdUtil.fastSimpleUUID());
        portableOffMainLog.setStartTime(LocalDateTime.now());
        String paths = uploadDataParam.getFiles().stream().map(MultipartFile::getOriginalFilename)
                .reduce((s1, s2) -> getCommonPrefix(s1, s2))
                .orElse(null);
        String[] split = paths.split("/");
        portableOffMainLog.setProjectName(split.length>0?split[split.length-1]:"/");
        int successcCount = 0;
        portableOffMainLog.setStatus("1");

        List<PortableOfflLog> portableOfflLogs = new ArrayList<>();
        for(MultipartFile file : uploadDataParam.getFiles()){

            //初始上传日志基本信息
            PortableOfflLog portableOfflLog = new PortableOfflLog();
            portableOfflLog.setLogMainId(portableOffMainLog.getId());
            portableOfflLog.setName(file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("/")+1));
            portableOfflLog.setPath(file.getOriginalFilename());
            portableOfflLog.setDataPath(fileStorageUtil.uploadMultipart(file, DataParam.wlRecordPath+uploadDataParam.getDevId()+"/"+uploadDataParam.getLineId()+"/"+getFolderName()+"/"));
            portableOfflLog.setLogsIndex(IdUtil.simpleUUID());
            portableOfflLog.setState(0);
            //默认总条数及入库数为0(防止解析的数据重复插入及上传的文件目录路径错误)
            portableOfflLog.setAllCount(0);
            portableOfflLog.setRealCount(0);
            if(file.getOriginalFilename().contains("record.bin")){
                portableOfflLog.setAllCount(1);
                portableOfflLog.setState(1);
            }

            //开始匹配解析的文件结果入库
            for(Response response : responses){
                //min解析结果较为特殊所有的文件解析后只有一条结果
                if(OfflineConstant.MIN.equals(response.getFilename()) && checkPrevsFolder(file.getOriginalFilename(),OfflineConstant.MIN)!=null&&minFlag){

                    List<PqdData> pqdData = (List<PqdData>) response.getObj();
                    pqdData.forEach(temp->{
                        temp.setClDid(String.valueOf(cdid));
                        temp.setIsAbnormal(0);
                        temp.setProcess(data1.get(0).getProcess()+"");
                        temp.setLineId(uploadDataParam.getLineId());
                    });

                    Instant instantMax = pqdData.stream().map(PqdData::getTime).max(Instant::compareTo).get();
                    Instant instantMin = pqdData.stream().map(PqdData::getTime).min(Instant::compareTo).get();
                    //插入测试项
                    WlRecord wlRecord = new WlRecord();
                    wlRecord.setId(IdUtil.fastSimpleUUID());
                    wlRecord.setItemName("补召");
                    wlRecord.setGcName("补召");
                    wlRecord.setDevId(csEquipmentDeliveryDTO.getId());
                    wlRecord.setLineId(lineId);

                    wlRecord.setStatisticalInterval(po.getLineInterval());
                    wlRecord.setPt(po.getPtRatio().intValue());
                    wlRecord.setCt(po.getCtRatio().intValue());
                    //电压等级
                    DictData dictData = dicDataFeignClient.getDicDataByCodeAndType(channelVol(new Float(po.getVolGrade())) + "kV","Dev_Voltage_Stand").getData();
                    wlRecord.setVoltageLevel(Objects.isNull(dictData)?null:dictData.getId());
                    //电压接线方式
                    wlRecord.setVolConType(getVolConType(po.getConType()));

                    wlRecord.setStartTime(instantMin.atZone(ZoneId.systemDefault()).toLocalDateTime());
                    wlRecord.setEndTime(instantMax.atZone(ZoneId.systemDefault()).toLocalDateTime());
                    wlRecord.setType(1);
                    wlRecord.setState(DataStateEnum.ENABLE.getCode());
                    wlRecordService.lambdaUpdate().set(WlRecord::getState,DataStateEnum.DELETED.getCode())
                            .eq(WlRecord::getLineId,lineId)
                            .eq(WlRecord::getStartTime,wlRecord.getStartTime())
                            .eq(WlRecord::getEndTime,wlRecord.getEndTime()).update();
                    wlRecordService.save(wlRecord);

                    //如果明确返回了state 那么当前文件解析出错
                    if(response.getState() != null){
                        portableOfflLog.setState(response.getState());
                    }
                    if(pqdData != null && !pqdData.isEmpty()){
                        //否则正常标记为成功解析
                        portableOfflLog.setState(1);
                        portableOfflLog.setName("min文件夹");
                        portableOfflLog.setAllCount(pqdData.size());
                        portableOfflLog.setRealCount(pqdData.size());
                        if(minFlag){
                            log.info("类型min,插入infulxDb的pqdData");
                            List<List<PqdData>> partition = ListUtils.partition(pqdData, 1500);
                            for (List<PqdData> sliceList : partition) {
                                List<PqdData> sublistAsOriginalListType = new ArrayList<>(sliceList);
                                Map<String, Object> map = pqdDataSplitService.splitPqdData(sublistAsOriginalListType);
                                insertData(map);
                            }
                            //min结果集解析入库后就不需要在解析了
                            minFlag = false;
                        }
                    }
                }else if(file.getOriginalFilename().equals(response.getFilename())){
                    //判断当前解析的数据属于哪种结果(目前来说三种:comtrade、log、min(除外))
                    if(checkPrevsFolder(file.getOriginalFilename(),OfflineConstant.COMTRADE)!=null){    //cfg
                        //如果明确返回了state 那么当前文件解析出错
                        //由于dat文件不解析但是日志需要记载所以都设为1

                        TagComtradeCfg tagComtradeCfg = (TagComtradeCfg) response.getObj();

                        //否则正常标记为成功解析
                        portableOfflLog.setState(1);
                        portableOfflLog.setAllCount(1);
                        portableOfflLog.setRealCount(1);
                            //cfg入库

                    }
                    if(checkPrevsFolder(file.getOriginalFilename(),OfflineConstant.LOG)!=null){     //事件
                        //如果明确返回了state 那么当前文件解析出错
                        if(response.getState() != null){
                            portableOfflLog.setState(response.getState());
                        }
                        List<NewTaglogbuffer> newTaglogbuffers = (List<NewTaglogbuffer>) response.getObj();
                        if(newTaglogbuffers != null && !newTaglogbuffers.isEmpty()){
                            List<DictData> list1 = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_REASON.getCode()).getData();
                            List<DictData> list2 = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EVENT_TYPE.getCode()).getData();
                            //否则正常标记为成功解析
                            portableOfflLog.setState(1);
                            portableOfflLog.setAllCount(newTaglogbuffers.size());
                            portableOfflLog.setRealCount(newTaglogbuffers.size());

                            List<CsEventPO> csEventPOS = new ArrayList<>();
                            //事件解析入库
                            for(NewTaglogbuffer newTaglogbuffer : newTaglogbuffers){
                                NewHeadTaglogbuffer newHeadTaglogbuffer = newTaglogbuffer.getNewHeadTaglogbuffer();
                                String strId = "";
                                String strName = newHeadTaglogbuffer.getLogCode()+"";
                                //todo 其他事件做映射
                                //中断标志
                                if(DataParam.intrStr.contains(newHeadTaglogbuffer.getLogCode())){
                                    strId = DataParam.intrStrId;
                                    strName = DataParam.intrStrName;
                                }
                                //暂降标志
                                if(DataParam.dipStr.contains(newHeadTaglogbuffer.getLogCode())){
                                    strId = DataParam.dipStrId;
                                    strName = DataParam.dipStrName;
                                }
                                //暂升标志
                                if(DataParam.swlStr.contains(newHeadTaglogbuffer.getLogCode())){
                                    strId = DataParam.swlStrId;
                                    strName = DataParam.swlStrName;
                                }
                                //插入事件表
                                CsEventPO csEventPO = new CsEventPO();
                                csEventPO.setId(IdUtil.fastSimpleUUID());
                                csEventPO.setLineId(uploadDataParam.getLineId());
                                csEventPO.setDeviceId(uploadDataParam.getDevId());
                                csEventPO.setProcess(csEquipmentDeliveryDTO.getProcess());
                                //todo 做映射目前置空
                                csEventPO.setCode(null);
                                csEventPO.setStartTime(newTaglogbuffer.getStart());
                                csEventPO.setTag(strName);
                                //更具唯一索引做校验存在该事件则跳过;
                                CsEventPO data = eventFeignClient.queryByIndex(csEventPO).getData();
                                if(Objects.nonNull(data)){
                                    continue;
                                }

                                String wavePath = null;
                                //设置波形文件(去cfg结果集里面去找)
                                for (Response res : cfgResponse) {
                                    String cfg = res.getFilename();
                                    String dat = cfg.substring(0,cfg.lastIndexOf("."))+OfflineConstant.DAT;
                                    String sharPath = OfflineConstant.COMTRADE+"/"+csEquipmentDeliveryDTO.getMac().replace(":", "-")+"/";
                                    TagComtradeCfg sing = (TagComtradeCfg) res.getObj();
                                    //如果匹配上则需要将当前cfg文件及对应的dat文件上传到comtrade文件夹中
                                    if (sing!= null && sing.getTimeStart()!= null && sing.getTimeTrigger().compareTo(csEventPO.getStartTime())<=0
                                    &&sing.getTimeEnd().compareTo(csEventPO.getStartTime())>=0) {
                                        for(MultipartFile f : uploadDataParam.getFiles()){
                                            if(f.getOriginalFilename().equals(cfg) || f.getOriginalFilename().equals(dat)){
                                                int lastIndex = f.getOriginalFilename().lastIndexOf('/');
                                                String fileName = f.getOriginalFilename().substring(lastIndex + 1);
                                                String baseName = FilenameUtils.getBaseName(fileName);
                                                String extension = FilenameUtils.getExtension(fileName);
                                                try {
                                                    fileStorageUtil.uploadStreamSpecifyName(f.getInputStream(), sharPath,  baseName + "." + extension.toUpperCase());
                                                } catch (IOException e) {
                                                    throw new RuntimeException(e);
                                                }
                                                wavePath = sharPath+fileName.substring(0,fileName.lastIndexOf("."));
                                            }
                                        }
                                    }
                                }
                                csEventPO.setWavePath(wavePath);

                                //默认暂态事件
                                csEventPO.setType(0);
                                String clDid = influxDbParamUtil.getClDidByLineId(uploadDataParam.getLineId());
                                csEventPO.setClDid(clDid == null ? null : Integer.parseInt(clDid));
                                csEventPO.setProcess(csEquipmentDeliveryDTO.getProcess());


                                EntData entData = new EntData();
                                entData.setUuid(csEventPO.getId());
                                entData.setTime(new Date().toInstant());


                                //entData.setTime(newTaglogbuffer.getStart().toInstant(ZoneOffset.UTC));
                                for(NewBodyTaglogbuffer newBodyTaglogbuffer : newTaglogbuffer.getNewBodyTaglogbuffers()){
                                    if(newBodyTaglogbuffer.getParaCode() == 0) {
                                        entData.setEvtParamVVaDepth(Double.parseDouble(df.format(newBodyTaglogbuffer.getParaValue()/65536D)));
                                    }
                                    if(newBodyTaglogbuffer.getParaCode() == 1) {
                                        entData.setEvtParamTm(Double.parseDouble(df.format(newBodyTaglogbuffer.getParaValue()/65536D)));
                                        csEventPO.setPersistTime(Double.parseDouble(df.format(newBodyTaglogbuffer.getParaValue()/65536D)));
                                    }
                                    if(newBodyTaglogbuffer.getParaCode() == 5) {
                                        int code = newBodyTaglogbuffer.getParaValue()/65536;
                                        switch (code){
                                            case 0:
                                                entData.setEvtParamPhase("A");
                                                break;
                                            case 1:
                                                entData.setEvtParamPhase("B");
                                                break;
                                            case 2:
                                                entData.setEvtParamPhase("C");
                                                break;
                                            case 3:
                                                entData.setEvtParamPhase("AB");
                                                break;
                                            case 4:
                                                entData.setEvtParamPhase("BC");
                                                break;
                                            case 5:
                                                entData.setEvtParamPhase("CA");
                                                break;
                                            case 6:
                                                entData.setEvtParamPhase("ABC");
                                                break;
                                        }
                                    }
                                }
                                log.info("类型log,插入infulxDb的evtData");
                                try {
                                    evtDataMapper.insertOne(entData);
                                    //添加其余数据
                                    csEventPO.setPhase(entData.getEvtParamPhase());
                                    csEventPO.setPersistTime(entData.getEvtParamTm());
                                    csEventPO.setAmplitude(entData.getEvtParamVVaDepth());

                                    if (Objects.equals(csEventPO.getTag(),DataParam.dipStrName)) {
                                        //计算暂降原因和类型
                                        EventAnalysisDTO var1 = new EventAnalysisDTO();
                                        var1.setWlFilePath(wavePath);
                                        EventAnalysisDTO dto = eventCauseFeignClient.analysisCauseAndType(var1).getData();
                                        String id1 = list1.stream()
                                                .filter(item -> Objects.equals(item.getAlgoDescribe(), dto.getCause()))
                                                .map(DictData::getId)
                                                .findFirst()
                                                .orElse(null);
                                        csEventPO.setAdvanceReason(id1);

                                        String id2 = list2.stream()
                                                .filter(item -> Objects.equals(item.getAlgoDescribe(), dto.getType()))
                                                .map(DictData::getId)
                                                .findFirst()
                                                .orElse(null);
                                        csEventPO.setAdvanceType(id2);
                                        if (!Objects.isNull(csEventPO.getAmplitude()) && !Objects.isNull(csEventPO.getPersistTime())) {
                                            //计算暂降严重度
                                            csEventPO.setSeverity(Double.valueOf(getYzd(csEventPO.getPersistTime()*1000,csEventPO.getAmplitude())));
                                        }
                                    }
                                    if (!Objects.isNull(csEventPO.getAmplitude()) && !Objects.isNull(csEventPO.getPersistTime())) {
                                        //计算落点
                                        String dropZone = eventAnalysisService.determineDropZone(String.valueOf(csEventPO.getAmplitude()),String.valueOf(csEventPO.getPersistTime()));
                                        csEventPO.setLandPoint(dropZone);
                                    }
                                    csEventPOS.add(csEventPO);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                            log.info("类型log,插入mysql事件表cs_event");
                            eventFeignClient.saveBatchEventList(csEventPOS);
                            //同步数据到 r_mp_event_detail
                            csEventPOS.forEach(this::insertEvent);
                        }
                    }
                }
            }
            nowStep++;
            String json = "{allStep:"+uploadDataParam.getFiles().size()*2+",nowStep:"+nowStep+"}";

            publisher.send("/dataOnlineRecruitment/Progress/" + uploadDataParam.getLineId(), new Gson().toJson(json), 1, false);
            //无需解析的不需要记录
            if(portableOfflLog.getState()!=0){
                this.baseMapper.insert(portableOfflLog);
                successcCount++;
            }
            portableOfflLogs.add(portableOfflLog);
        }
        portableOffMainLog.setEndTime(LocalDateTime.now());
        portableOffMainLog.setSuccessCount(successcCount);
        portableOffMainLogService.save(portableOffMainLog);
    }

    /**
     * 获取该事件的严重度
     *
     * @param persistTime 持续时间 ms单位
     * @param eventValue  暂降、暂升幅值
     */
    public String getYzd(Double persistTime, Double eventValue) {
        Double yzd;
        // 格式化小数
        DecimalFormat df = new DecimalFormat("0.000");
        if (persistTime <= 20) {
            yzd = 1.0 - eventValue;
        } else if (persistTime > 20 && persistTime <= 200) {
            yzd = 2.0 * (1 - eventValue);
        } else if (persistTime > 200 && persistTime <= 500) {
            yzd = 3.3 * (1 - eventValue);
        } else if (persistTime > 500 && persistTime <= 10000) {
            yzd = 5.0 * (1 - eventValue);
        } else {
            yzd = 10.0 * (1 - eventValue);
        }
        return df.format(yzd);
    }

    public void insertEvent(CsEventPO item) {
        RmpEventDetailPO rmpEventDetailPo = new RmpEventDetailPO();
        rmpEventDetailPo.setEventId(item.getId());
        rmpEventDetailPo.setMeasurementPointId(item.getLineId());
        rmpEventDetailPo.setStartTime(item.getStartTime());
        rmpEventDetailPo.setEventType(getEventType(item.getTag()));
        rmpEventDetailPo.setFeatureAmplitude(item.getAmplitude());
        rmpEventDetailPo.setDuration(item.getPersistTime());
        rmpEventDetailPo.setEventDescribe(getTag(item.getTag()));
        rmpEventDetailPo.setWavePath(item.getWavePath());
        if (!Objects.isNull(item.getWavePath())) {
            rmpEventDetailPo.setFileFlag(1);
        } else {
            rmpEventDetailPo.setFileFlag(0);
        }
        rmpEventDetailPo.setPhase(item.getPhase());
        rmpEventDetailPo.setAdvanceReason(item.getAdvanceReason());
        rmpEventDetailPo.setAdvanceType(item.getAdvanceType());
        if (!Objects.isNull(item.getAdvanceReason()) && !Objects.isNull(item.getAdvanceType())) {
            rmpEventDetailPo.setDealFlag(1);
        } else {
            rmpEventDetailPo.setDealFlag(0);
        }
        wlRmpEventDetailMapper.insert(rmpEventDetailPo);
    }

    public String getTag(String tag) {
        switch (tag) {
            case "Evt_Sys_DipStr":
                tag = DicDataEnum.VOLTAGE_DIP.getCode();
                break;
            case "Evt_Sys_SwlStr":
                tag = DicDataEnum.VOLTAGE_RISE.getCode();
                break;
            case "Evt_Sys_IntrStr":
                tag = DicDataEnum.SHORT_INTERRUPTIONS.getCode();
                break;
            default:
                tag = "Un_Know";
                break;
        }
        return tag;
    }

    public String getEventType(String tag) {
        switch (tag) {
            case "Evt_Sys_DipStr":
                DictData dip = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_DIP.getCode()).getData();
                tag = dip.getId();
                break;
            case "Evt_Sys_SwlStr":
                DictData rise = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_RISE.getCode()).getData();
                tag = rise.getId();
                break;
            case "Evt_Sys_IntrStr":
                DictData interruptions = dicDataFeignClient.getDicDataByCode(DicDataEnum.SHORT_INTERRUPTIONS.getCode()).getData();
                tag = interruptions.getId();
                break;
            default:
                tag = "Un_Know";
                break;
        }
        return tag;
    }

    @Override
    public Page<PortableOffMainLog> queryMainLogPage(BaseParam baseParam) {
        Page<PortableOffMainLog> returnpage = new Page<> (baseParam.getPageNum(), baseParam.getPageSize ());
        QueryWrapper<PortableOffMainLog> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .ge(StringUtils.isNotBlank(baseParam.getSearchBeginTime()), PortableOffMainLog::getCreateTime,baseParam.getSearchBeginTime()+" 00:00:00")
                .le(StringUtils.isNotBlank(baseParam.getSearchEndTime()),PortableOffMainLog::getCreateTime,baseParam.getSearchEndTime()+" 23:59:59").orderByDesc(PortableOffMainLog::getCreateTime);
        Page<PortableOffMainLog> portableOffMainLogPage = portableOffMainLogService.getBaseMapper().selectPage(returnpage, queryWrapper);
        portableOffMainLogPage.getRecords().forEach(temp->{
            List<PortableOfflLog> list = this.lambdaQuery().eq(PortableOfflLog::getLogMainId, temp.getId()).list();
            temp.setPortableOfflLogList(list);
        });

        return returnpage;
    }

    //根据文件全路径(包含文件夹)解析文件的分类
    private String checkPrevsFolder(String filePath,String type){
        List<String> paths = Arrays.asList(filePath.split("/"));
        if(paths.contains(type)){
            return type;
        }
        return null;
    }

    private String getFolderName(){
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
        return sdf.format(calendar.getTime());
    }

    private static String getCommonPrefix(String s1, String s2) {
        for (int i = 0; i <= s1.length() && i <= s2.length(); i++) {
            if (i == s1.length() || i == s2.length() || s1.charAt(i) != s2.charAt(i)) {
                return s1.substring(0, i);
            }
        }
        return s1;
    }

    /**
     * 处理电压
     * @param vol
     * @return
     */
    public String channelVol(Float vol) {
        BigDecimal value = new BigDecimal(vol);
        BigDecimal noZeros = value.stripTrailingZeros();
        return noZeros.toPlainString();
    }

    // 0-星型, 1-角型, 2-V型
    // star-星型、Star_Triangle-星三角、Open_Delta-开口三角
    public String getVolConType(Integer volConType) {
        String result = null;
        String dictDataCode = null;
        switch (volConType) {
            case 0:
                dictDataCode = "Trans_Business";
                break;
            case 1:
                dictDataCode = "Star_Triangle";
                break;
            case 2:
                dictDataCode = "Open_Delta";
                break;
            default:
                break;
        }
        if (!Objects.isNull(dictDataCode)) {
            DictData dictData = dicDataFeignClient.getDicDataByCodeAndType(dictDataCode,"Dev_Connect").getData();
            result = dictData.getId();
        }
        return Objects.isNull(result)?null:result;
    }

    public void insertData(Map<String, Object> map) {
        //13张表
        map.forEach((key, value) -> {
            switch (key) {
                case "data_v":
                    dataVMapper.insertBatch((List<DataV>) value);
                    break;
                case "data_i":
                    dataIMapper.insertBatch((List<DataI>) value);
                    break;
                case "data_flicker":
                    //10分钟入一组
                    List<DataFlicker> list = (List<DataFlicker>) value;
                    if (!CollectionUtils.isEmpty(list)) {
                        list.forEach(item->{
                            Instant time = getTime(item.getTime(),600);
                            item.setTime(time);
                        });
                        dataFlicker.insertBatch(list);
                    }
                    break;
                case "data_fluc":
                    //10分钟入一组
                    List<DataFluc> list2 = (List<DataFluc>) value;
                    if (!CollectionUtils.isEmpty(list2)) {
                        list2.forEach(item->{
                            Instant time = getTime(item.getTime(),600);
                            item.setTime(time);
                        });
                        dataFluc.insertBatch(list2);
                    }
                    break;
                case "data_harmphasic_i":
                    dataHarmPhasicI.insertBatch((List<DataHarmPhasicI>) value);
                    break;
                case "data_harmphasic_v":
                    dataHarmPhasicV.insertBatch((List<DataHarmPhasicV>) value);
                    break;
                case "data_harmpower_p":
                    dataHarmPowerP.insertBatch((List<DataHarmPowerP>) value);
                    break;
                case "data_harmpower_q":
                    dataHarmPowerQ.insertBatch((List<DataHarmPowerQ>) value);
                    break;
                case "data_harmpower_s":
                    dataHarmPowerS.insertBatch((List<DataHarmPowerS>) value);
                    break;
                case "data_harmrate_v":
                    dataHarmRateV.insertBatch((List<DataHarmRateV>) value);
                    break;
                case "data_harmrate_i":
                    dataHarmRateI.insertBatch((List<DataHarmRateI>) value);
                    break;
                case "data_inharm_v":
                    dataInHarmV.insertBatch((List<DataInHarmV>) value);
                    break;
                case "data_plt":
                    //2小时入一组
                    List<DataPlt> list3 = (List<DataPlt>) value;
                    if (!CollectionUtils.isEmpty(list3)) {
                        list3.forEach(item->{
                            Instant time = getTime(item.getTime(),7200);
                            item.setTime(time);
                        });
                        dataPlt.insertBatch(list3);
                    }
                    break;
                case "pqd_data":
                    pqdDataMapper.insertBatch((List<PqdData>) value);
                    break;
                default:
                    log.warn("不支持的目标表: {}", key);
                    break;
            }
        });
    }

    public Instant getTime(Instant time, Integer interval) {
        long originalTimeSec = time.getEpochSecond();
        long newTimeSec = (originalTimeSec / interval) * interval;
        return Instant.ofEpochSecond(newTimeSec);
    }
}
