package com.njcn.harmonic.service.report.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
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.common.utils.FileUtil;
import com.njcn.csdevice.api.CsCommTerminalFeignClient;
import com.njcn.csdevice.api.WlRecordFeignClient;
import com.njcn.csdevice.pojo.po.WlRecord;
import com.njcn.device.biz.commApi.CommTerminalGeneralClient;
import com.njcn.device.biz.pojo.po.PqsDeviceUnit;
import com.njcn.device.pq.pojo.vo.PqsDeviceUnitVo;
import com.njcn.harmonic.common.pojo.dto.DeviceUnitCommDTO;
import com.njcn.harmonic.common.service.CustomReportTableService;
import com.njcn.harmonic.enums.HarmonicResponseEnum;
import com.njcn.harmonic.mapper.DeptTempMapper;
import com.njcn.harmonic.mapper.EleEpdMapper;
import com.njcn.harmonic.common.mapper.ExcelRptTempMapper;
import com.njcn.harmonic.pojo.dto.ReportTemplateDTO;
import com.njcn.harmonic.pojo.param.ReportSearchParam;
import com.njcn.harmonic.pojo.param.ReportTemplateParam;
import com.njcn.harmonic.utils.DataChangeUtil;
import com.njcn.influx.constant.InfluxDbSqlConstant;
import com.njcn.influx.pojo.constant.InfluxDBTableConstant;
import com.njcn.influx.utils.InfluxDbUtils;
import com.njcn.oss.enums.OssResponseEnum;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.system.pojo.po.EleEpdPqd;
import com.njcn.harmonic.pojo.po.ExcelRptTemp;
import com.njcn.harmonic.pojo.po.SysDeptTemp;
import com.njcn.harmonic.common.pojo.vo.ReportTemplateVO;
import com.njcn.harmonic.pojo.vo.ReportTreeVO;
import com.njcn.harmonic.pojo.vo.SysDeptTempVO;
import com.njcn.harmonic.service.report.CustomReportService;
import com.njcn.oss.constant.OssPath;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.user.api.DeptFeignClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 自定义报表
 *
 * @author qijian
 * @date 2022/10/15
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CustomReportServiceImpl implements CustomReportService {

    private final ExcelRptTempMapper excelRptTempMapper;

    private final EleEpdMapper eleEpdMapper;

    private final DeptTempMapper deptTempMapper;

    private final FileStorageUtil fileStorageUtil;

    private final DicDataFeignClient dicDataFeignClient;

    private final DeptFeignClient deptFeignClient;

    private final InfluxDbUtils influxDbUtils;

    private final CommTerminalGeneralClient commTerminalGeneralClient;

    private final CsCommTerminalFeignClient csCommTerminalFeignClient;

    private final CustomReportTableService customReportTableService;

    private final WlRecordFeignClient wlRecordFeignClient;


    private final String CELL_DATA = "celldata";
    private final String V = "v";
    private final String STR_ONE = "#";
    private final String STR_TWO = "$";
    private final String STR_THREE = "&";
    private final String STR_FOUR = "%";
    private final String UVOLTAGE_DEV = "UVOLTAGE_DEV";
    private final String VOLTAGE_DEV = "VOLTAGE_DEV";
    private final String PT = "PT";
    private final String CT = "CT";


    @Override
    public void getCustomReport(ReportSearchParam reportSearchParam, HttpServletResponse response) {
        TimeInterval timeInterval = new TimeInterval();

        if (Objects.isNull(reportSearchParam.getCustomType())) {
            //通用报表
            PqsDeviceUnit deviceUnit = commTerminalGeneralClient.lineUnitDetail(reportSearchParam.getLineId()).getData();
            DeviceUnitCommDTO deviceUnitCommDTO = BeanUtil.copyProperties(deviceUnit, DeviceUnitCommDTO.class);

            Map<String,String> finalTerminalMap = convertKeysToUpperCase(commTerminalGeneralClient.getCustomDetailByLineId(reportSearchParam.getLineId()).getData());
            finalTerminalMap.put(PT,formatSciNumber(finalTerminalMap.getOrDefault(PT,"N/A")));
            finalTerminalMap.put(CT,formatSciNumber(finalTerminalMap.getOrDefault(CT,"N/A")));
            customReportTableService.getCustomReport(reportSearchParam,finalTerminalMap,deviceUnitCommDTO, response);
        } else {
            //浙江无线报表
            ExcelRptTemp excelRptTemp = excelRptTempMapper.selectById(reportSearchParam.getTempId());
            if (Objects.isNull(excelRptTemp)) {
                throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_ACTIVE);
            }
            analyzeReportZhejiang(reportSearchParam, excelRptTemp, response);
        }

        log.info("报表执行时间{}秒",timeInterval.intervalSecond());
    }


    @Override
    public boolean addCustomReportTemplate(ReportTemplateParam reportTemplateParam) {
        checkName(reportTemplateParam, false);
        MultipartFile fileContent = reportTemplateParam.getFileContent();
        //检验模板json数据规范
        try {
            String content = FileUtil.multipartFileToString(fileContent);
            new JSONArray(content);
        } catch (Exception e) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
        }
        reportTemplateParam.setContent(fileStorageUtil.uploadMultipart(fileContent, OssPath.HARMONIC_EXCEL_TEMPLATE));
        //新增模板表
        ExcelRptTemp excelRptTemp = new ExcelRptTemp();
        BeanUtils.copyProperties(reportTemplateParam, excelRptTemp);
        excelRptTemp.setState(DataStateEnum.ENABLE.getCode());
        excelRptTemp.setActivation(DataStateEnum.ENABLE.getCode());
        excelRptTempMapper.insert(excelRptTemp);

        //获取主键，并存入部门表
        String tempId = excelRptTemp.getId();
        for (String deptId : reportTemplateParam.getDeptId()) {
            SysDeptTemp sysDeptTemp = new SysDeptTemp();
            sysDeptTemp.setTempId(tempId);
            sysDeptTemp.setDeptId(deptId);
            //未激活状态
            sysDeptTemp.setActivation(DataStateEnum.DELETED.getCode());
            deptTempMapper.insert(sysDeptTemp);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCustomReportTemplate(ReportTemplateParam.UpdateReportTemplateParam reportTemplateParam) {
        checkName(reportTemplateParam, true);
        MultipartFile fileContent = reportTemplateParam.getFileContent();
        //检验模板json数据规范
        try {
            String content = FileUtil.multipartFileToString(fileContent);
            new JSONArray(content);
        } catch (Exception e) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
        }

        //删除之前的文件
        ExcelRptTemp excelRptTempOld = excelRptTempMapper.selectById(reportTemplateParam.getId());
        fileStorageUtil.deleteFile(excelRptTempOld.getContent());
        reportTemplateParam.setContent(fileStorageUtil.uploadMultipart(fileContent, OssPath.HARMONIC_EXCEL_TEMPLATE));
        //修改模板数据
        ExcelRptTemp excelRptTemp = new ExcelRptTemp();
        BeanUtils.copyProperties(reportTemplateParam, excelRptTemp);
        excelRptTemp.setUpdateTime(LocalDateTime.now());
        excelRptTempMapper.updateById(excelRptTemp);

        //多模板绑定部门进行修改
        //1、根据模板主键删除绑定的部门数据
        LambdaQueryWrapper<SysDeptTemp> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(SysDeptTemp::getTempId, excelRptTemp.getId());
        deptTempMapper.delete(lambdaQuery);
        //2、新增部门
        String[] deptIdArr = reportTemplateParam.getValueTitle().split(StrUtil.COMMA);
        for (String bindDeptId : deptIdArr) {
            SysDeptTemp sysDeptTemp = new SysDeptTemp();
            sysDeptTemp.setTempId(excelRptTemp.getId());
            sysDeptTemp.setDeptId(bindDeptId);
            sysDeptTemp.setActivation(DataStateEnum.ENABLE.getCode());
            deptTempMapper.insert(sysDeptTemp);
        }
        return true;
    }

    @Override
    public boolean updateBindTemplate(List<ReportSearchParam> reportSearchParams) {
        //1、根据模板主键删除绑定的部门数据
        LambdaQueryWrapper<SysDeptTemp> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(SysDeptTemp::getTempId, reportSearchParams.get(0).getTempId());
        deptTempMapper.delete(lambdaQuery);
        //2、新增部门
        for (ReportSearchParam reportSearchParam : reportSearchParams) {
            SysDeptTemp sysDeptTemp = new SysDeptTemp();
            sysDeptTemp.setTempId(reportSearchParam.getTempId());
            sysDeptTemp.setDeptId(reportSearchParam.getDeptId());
            sysDeptTemp.setActivation(reportSearchParam.getActivation());
            deptTempMapper.insert(sysDeptTemp);
        }
        return true;
    }

    @Override
    public List<SysDeptTempVO> getDataByTempId(String id) {
        return deptTempMapper.getDeptTempByTempId(id);
    }

    @Override
    public List<ReportTemplateVO> getTemplateByDept(String id) {
        List<String> deptIds = deptFeignClient.getDepSonIdtByDeptId(id).getData();
        return excelRptTempMapper.getReportTemplateByDept(deptIds);
    }

    @Override
    public ExcelRptTemp getCustomReportTemplateById(String id) {
        ExcelRptTemp excelRptTemp = excelRptTempMapper.selectById(id);
        return excelRptTemp;
    }

    @Override
    public void viewCustomReportTemplateById(String id, HttpServletResponse response) {
        ExcelRptTemp excelRptTemp = excelRptTempMapper.selectById(id);
        try {
            fileStorageUtil.downloadStream(response, excelRptTemp.getContent());
        } catch (Exception exception) {
            throw new BusinessException(HarmonicResponseEnum.REPORT_TEMPLATE_DOWNLOAD_ERROR);
        }

    }


    @Override
    public List<ReportTemplateVO> getTemplateList(ReportSearchParam reportSearchParam) {
        return excelRptTempMapper.getReportTemplateList(reportSearchParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delTemplate(ReportSearchParam reportSearchParam) {
        //根据模板ID和部门ID删除绑定的数据
        LambdaQueryWrapper<SysDeptTemp> lambdaQuery = new LambdaQueryWrapper<>();
        lambdaQuery.eq(SysDeptTemp::getTempId, reportSearchParam.getTempId());
        deptTempMapper.delete(lambdaQuery);
        excelRptTempMapper.deleteById(reportSearchParam.getTempId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(ReportSearchParam reportSearchParam) {
        //先全体把激活的改为未激活，再改单个的激活值
        deptTempMapper.updateAllActivation(reportSearchParam.getDeptId());

        SysDeptTemp sysDeptTemp = new SysDeptTemp();
        BeanUtils.copyProperties(reportSearchParam, sysDeptTemp);
        deptTempMapper.updateActivation(sysDeptTemp);
        return true;
    }


    @Override
    public List<ReportTreeVO> reportChooseTree() {
        DictData dic = dicDataFeignClient.getDicDataByNameAndTypeName(DicDataTypeEnum.CS_DATA_TYPE.getName(), DicDataEnum.EPD.getName()).getData();
        LambdaQueryWrapper<EleEpdPqd> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(EleEpdPqd::getDataType, dic.getId()).orderByAsc(EleEpdPqd::getSort);
        List<EleEpdPqd> list = eleEpdMapper.selectList(lambdaQueryWrapper);
        Map<String, List<EleEpdPqd>> map = list.stream().collect(Collectors.groupingBy(EleEpdPqd::getName, LinkedHashMap::new, Collectors.toList()));

        List<ReportTreeVO> tree = new ArrayList<>();
        map.forEach((key, value) -> {

            ReportTreeVO reportTreeVO = new ReportTreeVO();
            reportTreeVO.setName(value.get(0).getOtherName());
            reportTreeVO.setShowName(value.get(0).getShowName());

            //存在1-50次 2-50次情况
            if (Objects.nonNull(value.get(0).getHarmStart()) && Objects.nonNull(value.get(0).getHarmEnd())) {
                List<ReportTreeVO> reHarm = new ArrayList<>();
                for (int i = value.get(0).getHarmStart(); i <= value.get(0).getHarmEnd(); i++) {
                    ReportTreeVO reportTreeCount = new ReportTreeVO();
                    reportTreeCount.setName(value.get(0).getOtherName() + "_" + i);
                    reportTreeCount.setShowName(i + "次" + value.get(0).getShowName());
                    reportTreeVO.setFlag(1);
                    assPhase(value, reportTreeCount, reportTreeCount.getName());
                    reHarm.add(reportTreeCount);
                }
                reportTreeVO.setChildren(reHarm);
            } else {
                assPhase(value, reportTreeVO, value.get(0).getOtherName());
            }
            tree.add(reportTreeVO);
        });
        return tree;
    }

    @Override
    public List<ReportTreeVO> targetLimitChooseTree() {
        List<ReportTreeVO> result = new ArrayList<>();
        DictData dic = dicDataFeignClient.getDicDataByCode(DicDataEnum.EPD.getCode()).getData();
        LambdaQueryWrapper<EleEpdPqd> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(EleEpdPqd::getDataType, dic.getId()).eq(EleEpdPqd::getLimitTable, "pq_overlimit").orderByAsc(EleEpdPqd::getSort);
        List<EleEpdPqd> list = eleEpdMapper.selectList(lambdaQueryWrapper);
        Map<String, List<EleEpdPqd>> map = list.stream().collect(Collectors.groupingBy(EleEpdPqd::getLimitName));
        map.forEach((key, val) -> {
            ReportTreeVO reportTreeVO = new ReportTreeVO();
            reportTreeVO.setShowName(val.get(0).getShowName());

            if (Objects.nonNull(val.get(0).getHarmStart()) && Objects.nonNull(val.get(0).getHarmEnd())) {
                String one = val.get(0).getLimitName();
                List<ReportTreeVO> temList = new ArrayList<>();
                for (int i = val.get(0).getHarmStart(); i <= val.get(0).getHarmEnd(); i++) {
                    double count;
                    ReportTreeVO reportTreeItem = new ReportTreeVO();

                    if (val.get(0).getHarmStart() == 1) {
                        count = i + 0.5;
                        reportTreeItem.setShowName(count + "次" + val.get(0).getShowName());
                        reportTreeItem.setName(STR_FOUR + one + count + STR_ONE + val.get(0).getFormula() + STR_ONE + val.get(0).getLimitTable() + STR_FOUR);
                    } else {
                        reportTreeItem.setShowName(i + "次" + val.get(0).getShowName());
                        reportTreeItem.setName(STR_FOUR + one + i + STR_ONE + val.get(0).getFormula() + STR_ONE + val.get(0).getLimitTable() + STR_FOUR);
                    }

                    reportTreeItem.setFlag(1);
                    temList.add(reportTreeItem);
                }
                reportTreeVO.setChildren(temList);
            } else {
                reportTreeVO.setName(STR_FOUR + val.get(0).getLimitName() + STR_ONE + val.get(0).getLimitTable() + STR_FOUR + val.get(0).getFormula() + STR_FOUR);
                reportTreeVO.setFlag(1);
            }

            result.add(reportTreeVO);
        });
        return result;
    }

    @Override
    public List<ReportTreeVO> terminalChooseTree() {
        List<ReportTreeVO> result = new ArrayList<>();
        DictData dic = dicDataFeignClient.getDicDataByCode(DicDataEnum.TERMINAL_SORT.getCode()).getData();
        LambdaQueryWrapper<EleEpdPqd> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(EleEpdPqd::getDataType, dic.getId()).orderByAsc(EleEpdPqd::getSort);
        List<EleEpdPqd> list = eleEpdMapper.selectList(lambdaQueryWrapper);
        list.forEach(item -> {
            ReportTreeVO reportTreeVO = new ReportTreeVO();
            reportTreeVO.setId(item.getId());
            reportTreeVO.setName(STR_THREE + item.getName() + STR_THREE);
            reportTreeVO.setFlag(1);
            reportTreeVO.setShowName(item.getShowName());
            result.add(reportTreeVO);
        });
        return result;
    }

    /*组装相别*/
    private void assPhase(List<EleEpdPqd> value, ReportTreeVO reportTreeItem, String key) {
        List<ReportTreeVO> phaseTree = new ArrayList<>();
        value.forEach(item -> {
            if (Objects.nonNull(item.getPhase()) && !"M".equals(item.getPhase())) {
                List<ReportTreeVO> statTree = new ArrayList<>();
                ReportTreeVO reportTreePhase = new ReportTreeVO();
                reportTreePhase.setName(item.getPhase());
                reportTreePhase.setShowName(item.getPhase());

                assStatMethod(item, statTree, key, item.getPhase());
                reportTreePhase.setChildren(statTree);
                phaseTree.add(reportTreePhase);
                reportTreeItem.setChildren(phaseTree);

            } else {
                List<ReportTreeVO> statTree = new ArrayList<>();
                assStatMethod(item, statTree, key, "");
                reportTreeItem.setChildren(statTree);
            }
        });

    }


    private void assStatMethod(EleEpdPqd item, List<ReportTreeVO> statTree, String oneKey, String twoKey) {
        //存在向别为M但是Stat_Method不为空
        if (StrUtil.isNotBlank(item.getStatMethod())) {
            String[] arr = item.getStatMethod().split(StrUtil.COMMA);
            List<String> stat = Stream.of(arr).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(stat)) {
                stat.forEach(statItem -> {
                    ReportTreeVO reportTreeStat = new ReportTreeVO();
                    String tem = "";
                    if (Objects.nonNull(item.getLimitName())) {
                        tem = STR_ONE + item.getLimitName();
                    } else {
                        tem = "#NO";
                    }
                    if (StrUtil.isNotBlank(twoKey)) {
                        reportTreeStat.setName(STR_TWO + oneKey + STR_ONE + twoKey + STR_ONE + statItem + STR_ONE + item.getResourcesId().trim() + tem.trim() + STR_TWO);
                    } else {
                        reportTreeStat.setName(STR_TWO + oneKey + STR_ONE + statItem + STR_ONE + item.getResourcesId().trim() + tem.trim() + STR_TWO);
                    }

                    reportTreeStat.setShowName(statItem);
                    statTree.add(reportTreeStat);
                });
            }
        }
    }


    /**
     * 检查名称是否已存在
     *
     * @param reportTemplateParam,isUpdate 参数
     * @return 结果
     */
    private void checkName(ReportTemplateParam reportTemplateParam, boolean isUpdate) {
        LambdaQueryWrapper<ExcelRptTemp> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        //条件组合：where state = 1 and name = ?
        lambdaQueryWrapper.eq(ExcelRptTemp::getState, DataStateEnum.ENABLE.getCode()).eq(ExcelRptTemp::getName, reportTemplateParam.getName());

        //and id <> ?
        if (isUpdate) {
            if (reportTemplateParam instanceof ReportTemplateParam.UpdateReportTemplateParam) {
                lambdaQueryWrapper.ne(ExcelRptTemp::getId, ((ReportTemplateParam.UpdateReportTemplateParam) reportTemplateParam).getId());
            }
        }

        //若存在条件数据抛出异常
        int count = excelRptTempMapper.selectCount(lambdaQueryWrapper);
        if (count > 0) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_REPEAT);
        }

    }


    /**
     * 数据单位信息
     *
     * @param reportSearchParam
     * @return
     */
    private Map<String, String> unitMap(ReportSearchParam reportSearchParam) {
        PqsDeviceUnit deviceUnit;
        if (Objects.isNull(reportSearchParam.getResourceType())) {
            deviceUnit = commTerminalGeneralClient.lineUnitDetail(reportSearchParam.getLineId()).getData();
        } else {
            deviceUnit = csCommTerminalFeignClient.lineUnitDetail(reportSearchParam.getLineId()).getData();
        }
        List<DictData> dictData = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEVICE_UNIT.getCode()).getData();
        Map<String, String> unit = new HashMap<>();
        List<String> list = dictData.stream().map(DictData::getCode).collect(Collectors.toList());
        for (String s : list) {
            //有效值
            if (s.equals(DicDataEnum.EFFECTIVE.getCode())) {
                unit.put(s + "#i", deviceUnit.getIeffective());
                unit.put(s + "#v", deviceUnit.getLineVoltage());
            }
            //功率
            if (s.equals(DicDataEnum.POWER.getCode())) {
                unit.put(s + "#p", deviceUnit.getTotalActiveP());
                unit.put(s + "#q", deviceUnit.getTotalNoP());
                unit.put(s + "#s", deviceUnit.getTotalViewP());
            }
            //畸变率
            if (s.equals(DicDataEnum.DISTORTION.getCode())) {
                unit.put(s + "#v", deviceUnit.getVdistortion());
            }
            //电压偏差
            if (s.equals(DicDataEnum.VOLTAGE.getCode())) {
                unit.put(s + "#v", deviceUnit.getVoltageDev());
            }
            //频率
            if (s.equals(DicDataEnum.UNIT_FREQUENCY.getCode())) {
                unit.put(s + "#freq", deviceUnit.getUnitFrequency());
                unit.put(s + "#freqDev", deviceUnit.getUnitFrequencyDev());
            }
            //三项不平衡度
            if (s.equals(DicDataEnum.UNBALANCE.getCode())) {
                unit.put(s + "#v", STR_FOUR);
                unit.put(s + "#vPos", deviceUnit.getPositiveV());
                unit.put(s + "#vNeg", deviceUnit.getNoPositiveV());
                unit.put(s + "#vZero", deviceUnit.getNoPositiveV());
                unit.put(s + "#i", STR_FOUR);
                unit.put(s + "#iPos", "A");
                unit.put(s + "#iNeg", "A");
                unit.put(s + "#iZero", "A");
            }
            //基波
            if (s.equals(DicDataEnum.FUND.getCode())) {
                unit.put(s + "#i", deviceUnit.getIfund());
                unit.put(s + "#v", deviceUnit.getVfundEffective());

            }
        }
        return unit;
    }


    /**
     * @param data         同类型的cell模板
     * @param sql          单个cell模板
     * @param endList      用于返回最终组装好的数据，类似data
     * @param limitMap     指标是否合格模板
     * @param assNoPassMap 用于存储不合格的指标
     * @date 2023/10/20
     */
    private void assSqlNew(List<ReportTemplateDTO> data, StringBuilder sql, List<ReportTemplateDTO> endList, String method, ReportSearchParam reportSearchParam, Map<String, ReportTemplateDTO> limitMap, Map<String, Float> overLimitMap, Map<String, ReportTemplateDTO> assNoPassMap) {
        //sql拼接示例：select MAX(IHA2) as IHA2 from power_quality_data where Phase = 'A' and LineId='1324564568' and Stat_Method='max' tz('Asia/Shanghai')


        //cp95函数特殊处理 PERCENTILE(field_key, N)
        if (InfluxDbSqlConstant.CP95.equals(method)) {

            for (int i = 0; i < data.size(); i++) {
                if (i == data.size() - 1) {
                    sql.append(InfluxDbSqlConstant.PERCENTILE)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.NUM_95)
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM);
                } else {
                    sql.append(InfluxDbSqlConstant.PERCENTILE)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.NUM_95)
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM).append(StrUtil.COMMA);
                }
            }

        } else {

            for (int i = 0; i < data.size(); i++) {
                if (i == data.size() - 1) {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM);
                } else {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM).append(StrUtil.COMMA);
                }
            }

        }

        sql.append(StrPool.C_SPACE);
        String temS = data.get(0).getResourceId().replace("r_stat_data", "day").replace("_d", "");
        sql.append(InfluxDbSqlConstant.FROM).append(temS);

        sql.append(InfluxDbSqlConstant.WHERE)
                .append(InfluxDBTableConstant.LINE_ID)
                .append(InfluxDbSqlConstant.EQ)
                .append(InfluxDbSqlConstant.QM)
                .append(reportSearchParam.getLineId())
                .append(InfluxDbSqlConstant.QM);
        //相别特殊处理
        if (!InfluxDBTableConstant.NO_PHASE.equals(data.get(0).getPhase())) {
            sql.append(InfluxDbSqlConstant.AND)
                    .append(InfluxDBTableConstant.PHASIC_TYPE)
                    .append(InfluxDbSqlConstant.EQ)
                    .append(InfluxDbSqlConstant.QM)
                    .append(data.get(0).getPhase())
                    .append(InfluxDbSqlConstant.QM);
        }


        //data_flicker、data_fluc、data_plt 无 value_type
        if (!InfluxDBTableConstant.DATA_FLICKER.equals(data.get(0).getClassId()) && !InfluxDBTableConstant.DATA_FLUC.equals(data.get(0).getClassId()) && !InfluxDBTableConstant.DATA_PLT.equals(data.get(0).getClassId())) {
            sql.append(InfluxDbSqlConstant.AND)
                    .append(InfluxDBTableConstant.VALUE_TYPE)
                    .append(InfluxDbSqlConstant.EQ)
                    .append(InfluxDbSqlConstant.QM)
                    .append(data.get(0).getStatMethod())
                    .append(InfluxDbSqlConstant.QM);
        }

        //频率和频率偏差仅统计T相
        if (data.get(0).getTemplateName().equals("freq_dev") || data.get(0).getTemplateName().equals("freq")) {
            sql.append(InfluxDbSqlConstant.AND)
                    .append(InfluxDBTableConstant.PHASIC_TYPE)
                    .append(InfluxDbSqlConstant.EQ)
                    .append(InfluxDbSqlConstant.QM)
                    .append(InfluxDBTableConstant.PHASE_TYPE_T)
                    .append(InfluxDbSqlConstant.QM);
        }
        //时间范围处理
        sql.append(InfluxDbSqlConstant.AND)
                .append(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.GE).append(InfluxDbSqlConstant.QM).append(reportSearchParam.getStartTime()).append(InfluxDbSqlConstant.START_TIME).append(InfluxDbSqlConstant.QM)
                .append(InfluxDbSqlConstant.AND)
                .append(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.LT).append(InfluxDbSqlConstant.QM).append(reportSearchParam.getEndTime()).append(InfluxDbSqlConstant.END_TIME).append(InfluxDbSqlConstant.QM);

        sql.append(InfluxDbSqlConstant.TZ);

        long a = System.currentTimeMillis();
        List<Map<String, Object>> mapList = influxDbUtils.getMapResult(sql.toString());
        long b = System.currentTimeMillis();
        System.out.println(sql);
        System.out.println("当前sql执行了:" + (b - a) + "ms");
        if (CollUtil.isEmpty(mapList)) {
            data = data.stream().peek(item -> item.setValue("/")).collect(Collectors.toList());
        } else {
            Map<String, Object> map = mapList.get(0);
            for (ReportTemplateDTO item : data) {
                if (Objects.nonNull(map) && map.containsKey(item.getItemName())) {
                    double v = Double.parseDouble(map.get(item.getItemName()).toString());
                    item.setValue(String.format("%.3f", v));

                    if (overLimitMap.containsKey(item.getLimitName())) {
                        Float tagVal = overLimitMap.get(item.getLimitName());
                        if (v > tagVal) {
                            item.setOverLimitFlag(1);
                        } else {
                            item.setOverLimitFlag(0);
                        }
                    }

                    //判断是否越限
                    if (limitMap.size() != 0) {
                        String key = item.getLimitName() + STR_ONE + item.getStatMethod().toLowerCase() + "#pq_overlimit";
                        if (limitMap.containsKey(key)) {
                            ReportTemplateDTO tem = limitMap.get(key);
                            double limitVal = Double.parseDouble(tem.getValue());
                            if (v > limitVal) {
                                tem.setOverLimitFlag(1);
                                assNoPassMap.put(key, tem);
                            } else if (!assNoPassMap.containsKey(key)) {
                                tem.setOverLimitFlag(0);
                                assNoPassMap.put(key, tem);
                            }
                        }
                    }
                } else {
                    item.setValue("/");
                }
            }
        }
        endList.addAll(data);
    }




/**
 * @param data         同类型的cell模板
 * @param sql          单个cell模板
 * @param endList      用于返回最终组装好的数据，类似data
 * @param limitMap     指标是否合格模板
 * @param assNoPassMap 用于存储不合格的指标
 * @date 2023/10/20
 */

    private void assSqlByMysql(List<ReportTemplateDTO> data, StringBuilder sql, List<ReportTemplateDTO> endList, String method, ReportSearchParam reportSearchParam, Map<String, ReportTemplateDTO> limitMap, Map<String, Float> overLimitMap, Map<String, ReportTemplateDTO> assNoPassMap,List<String> noPhaseList) {
        //sql拼接示例：select MAX(IHA2) as IHA2 from power_quality_data where Phase = 'A' and LineId='1324564568' and Stat_Method='max' tz('Asia/Shanghai')
        if (InfluxDbSqlConstant.CP95.equals(method)) {
            for (int i = 0; i < data.size(); i++) {
                if (i == data.size() - 1) {
                    sql.append(InfluxDbSqlConstant.MAX)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS)
                            .append("\""+data.get(i).getItemName()+"\"");
                } else {
                    sql.append(InfluxDbSqlConstant.MAX)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS)
                            .append("\""+data.get(i).getItemName()+"\"").append(StrUtil.COMMA);
                }
            }
        } else {
            for (int i = 0; i < data.size(); i++) {
                if (i == data.size() - 1) {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS)
                            .append("\""+data.get(i).getItemName()+"\"");
                } else {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS)
                            .append("\""+data.get(i).getItemName()+"\"").append(StrUtil.COMMA);
                }
            }

        }

        //拼接表名
        sql.append(StrPool.C_SPACE)
                .append(InfluxDbSqlConstant.FROM)
                .append(data.get(0).getResourceId());


        sql.append(InfluxDbSqlConstant.WHERE)
                .append(InfluxDBTableConstant.LINE_ID)
                .append(InfluxDbSqlConstant.EQ)
                .append(InfluxDbSqlConstant.QM)
                .append(reportSearchParam.getLineId())
                .append(InfluxDbSqlConstant.QM);
        //相别特殊处理
        if (!InfluxDBTableConstant.NO_PHASE.equals(data.get(0).getPhase())) {
            sql.append(InfluxDbSqlConstant.AND)
                    .append(InfluxDBTableConstant.PHASIC_TYPE)
                    .append(InfluxDbSqlConstant.EQ)
                    .append(InfluxDbSqlConstant.QM)
                    .append(data.get(0).getPhase())
                    .append(InfluxDbSqlConstant.QM);
        }

        sql.append(InfluxDbSqlConstant.AND)
                .append(InfluxDBTableConstant.VALUE_TYPE)
                .append(InfluxDbSqlConstant.EQ)
                .append(InfluxDbSqlConstant.QM)
                .append(data.get(0).getStatMethod())
                .append(InfluxDbSqlConstant.QM);


        //频率和频率偏差仅统计T相
        if (noPhaseList.contains(data.get(0).getTemplateName())) {
            if(data.get(0).getTemplateName().equalsIgnoreCase("v_unbalance")){
                System.out.println(44);
            }
            sql.append(InfluxDbSqlConstant.AND)
                    .append(InfluxDBTableConstant.PHASIC_TYPE)
                    .append(InfluxDbSqlConstant.EQ)
                    .append(InfluxDbSqlConstant.QM)
                    .append(InfluxDBTableConstant.PHASE_TYPE_T)
                    .append(InfluxDbSqlConstant.QM);
        }
        //时间范围处理
        sql.append(InfluxDbSqlConstant.AND)
                .append(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.GE).append(InfluxDbSqlConstant.QM).append(reportSearchParam.getStartTime()).append(InfluxDbSqlConstant.START_TIME).append(InfluxDbSqlConstant.QM)
                .append(InfluxDbSqlConstant.AND)
                .append(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.LT).append(InfluxDbSqlConstant.QM).append(reportSearchParam.getEndTime()).append(InfluxDbSqlConstant.END_TIME).append(InfluxDbSqlConstant.QM);

        System.out.println(sql);

        List<Map<String, Object>> mapList = SqlRunner.DEFAULT.selectList(sql.toString());
        if (CollUtil.isEmpty(mapList) || Objects.isNull(mapList.get(0))) {
            data = data.stream().peek(item -> item.setValue("/")).collect(Collectors.toList());
        } else {
            //兼容达梦数据库方法
            Map<String, Object> map = convertKeysToUpperCase(mapList.get(0));
            for (ReportTemplateDTO item : data) {
                if (map.containsKey(item.getItemName())) {
                    double v = Double.parseDouble(map.get(item.getItemName()).toString());
                    item.setValue(String.format("%.3f", v));
                    if (overLimitMap.containsKey(item.getLimitName())) {
                        Float tagVal = overLimitMap.get(item.getLimitName());

                        if(item.getLimitName().equalsIgnoreCase(UVOLTAGE_DEV)){
                            //对电压偏差特殊处理
                            Float tagVal_U = overLimitMap.get(UVOLTAGE_DEV);
                            if (v > tagVal || v<tagVal_U) {
                                item.setOverLimitFlag(1);
                            } else {
                                item.setOverLimitFlag(0);
                            }

                        }else {
                            if (v > tagVal) {
                                item.setOverLimitFlag(1);
                            } else {
                                item.setOverLimitFlag(0);
                            }
                        }
                    }

                    //判断是否越限
                    if (!limitMap.isEmpty()) {
                        String key = item.getLimitName() + STR_ONE + item.getStatMethod() + "#PQ_OVERLIMIT";
                        if (limitMap.containsKey(key)) {
                            ReportTemplateDTO tem = limitMap.get(key);
                            double limitVal = Double.parseDouble(tem.getValue());

                            if(VOLTAGE_DEV.equalsIgnoreCase(tem.getLimitName())){
                                //针对电压偏差特殊处理
                                double limitLowVal = Double.parseDouble(tem.getLowValue());

                                if (v > limitVal || v<limitLowVal) {
                                    tem.setOverLimitFlag(1);
                                    assNoPassMap.put(key, tem);
                                } else if (!assNoPassMap.containsKey(key)) {
                                    tem.setOverLimitFlag(0);
                                    assNoPassMap.put(key, tem);
                                }
                            }else {
                                //其他指标
                                if (v > limitVal) {
                                    tem.setOverLimitFlag(1);
                                    assNoPassMap.put(key, tem);
                                } else if (!assNoPassMap.containsKey(key)) {
                                    tem.setOverLimitFlag(0);
                                    assNoPassMap.put(key, tem);
                                }
                            }
                        }
                    }
                } else {
                    item.setValue("/");
                }
            }
        }
        endList.addAll(data);
    }


    /**
     * map key转大写
     */
    public static <V> Map<String, V> convertKeysToUpperCase(Map<String, V> originalMap) {
        Map<String, V> newMap = new HashMap<>();
        for (Map.Entry<String, V> entry : originalMap.entrySet()) {
            newMap.put(entry.getKey().toUpperCase(), entry.getValue());
        }
        return newMap;
    }




    /**
     * 获取测点限值
     *
     * @author cdf
     * @date 2023/10/23
     */
    private Map<String, Float> overLimitDeal(List<ReportTemplateDTO> reportLimitList, ReportSearchParam
            reportSearchParam) {
        Map<String, Float> limitMap = new HashMap<>();
        if (CollUtil.isNotEmpty(reportLimitList)) {
            StringBuilder sql = new StringBuilder(InfluxDbSqlConstant.SELECT);
            for (int i = 0; i < reportLimitList.size(); i++) {
                if (i == reportLimitList.size() - 1) {
                    sql.append(UVOLTAGE_DEV).append(StrUtil.COMMA);
                    sql.append(reportLimitList.get(i).getTemplateName()).append(StrUtil.C_SPACE);
                } else {
                    sql.append(reportLimitList.get(i).getTemplateName()).append(StrUtil.COMMA);
                }
            }

            sql.append(InfluxDbSqlConstant.FROM).append(reportLimitList.get(0).getResourceId()).append(InfluxDbSqlConstant.WHERE).append("id ='").append(reportSearchParam.getLineId()).append("'");
            limitMap = excelRptTempMapper.dynamicSqlMap(sql.toString());
            if (Objects.isNull(limitMap)) {
                throw new BusinessException("当前报表测点限值缺失!");
            }

            for (ReportTemplateDTO item : reportLimitList) {
                if (limitMap.containsKey(item.getTemplateName())) {

                    if(item.getTemplateName().equalsIgnoreCase(VOLTAGE_DEV)){
                        item.setLowValue(limitMap.get(UVOLTAGE_DEV).toString());
                    }
                    item.setValue(limitMap.get(item.getTemplateName()).toString());
                }
            }
        }
        limitMap = convertKeysToUpperCase(limitMap);
        return limitMap;
    }

    /**
     * 报告下载
     */
    private void downReport(JSONArray jsonArray, HttpServletResponse response) {
        InputStream reportStream = IoUtil.toStream(jsonArray.toString(), CharsetUtil.UTF_8);
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + "aa");
        OutputStream toClient = null;
        try {
            toClient = new BufferedOutputStream(response.getOutputStream());
            //通过IOUtils对接输入输出流，实现文件下载
            IOUtils.copy(reportStream, toClient);
            toClient.flush();
        } catch (Exception e) {
            throw new BusinessException(OssResponseEnum.DOWNLOAD_FILE_STREAM_ERROR);
        } finally {
            IOUtils.closeQuietly(reportStream);
            IOUtils.closeQuietly(toClient);
        }
    }




    /**
     * 对多测点数据进行计算求出一组数据
     * @param method
     * @param allList
     * @return
     */
    private Map<String, Object> dealResultMap(String method, List<Map<String, Object>> allList) {
        Map<String, Object> resultMap = new HashMap<>();
        // 遍历列表中的每个Map
        if (method.equals(InfluxDbSqlConstant.MIN)) {
            for (Map<String, Object> map : allList) {
                // 遍历当前Map的键值对
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    String key = entry.getKey();
                    if (Objects.nonNull(entry.getValue()) && !key.equals("time")) {
                        double value = (double) entry.getValue();
                        // 检查结果Map中是否已包含该键
                        if (!resultMap.containsKey(key) || (double) resultMap.get(key) > value) {
                            // 如果不包含，或当前值更大，则更新结果Map
                            resultMap.put(key, value);
                        }
                    }
                }
            }
        } else if (method.equals(InfluxDbSqlConstant.MAX) || method.equals(InfluxDbSqlConstant.PERCENTILE)) {
            for (Map<String, Object> map : allList) {
                // 遍历当前Map的键值对
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    String key = entry.getKey();
                    if (Objects.nonNull(entry.getValue()) && !key.equals("time")) {
                        double value = (double) entry.getValue();
                        // 检查结果Map中是否已包含该键
                        if (!resultMap.containsKey(key) || (double) resultMap.get(key) < value) {
                            // 如果不包含，或当前值更大，则更新结果Map
                            resultMap.put(key, value);
                        }
                    }
                }
            }
        } else if (method.equals(InfluxDbSqlConstant.AVG)) {
            Map<String, Double> sumMap = new HashMap<>();
            Map<String, Integer> countMap = new HashMap<>();
            // 遍历列表中的每个Map
            for (Map<String, Object> map : allList) {
                // 遍历当前Map的键值对
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    String key = entry.getKey();
                    if (Objects.nonNull(entry.getValue()) && !key.equals("time")) {
                        double value = (double) entry.getValue();

                        // 更新累计和
                        sumMap.put(key, sumMap.getOrDefault(key, 0.0) + value);
                        // 更新计数
                        countMap.put(key, countMap.getOrDefault(key, 0) + 1);
                    }
                }
            }

            // 计算平均值并存储到结果Map中
            for (String key : sumMap.keySet()) {
                double sum = sumMap.get(key);
                int count = countMap.get(key);
                double average = BigDecimal.valueOf(sum / count).setScale(3, RoundingMode.HALF_UP).doubleValue();
                resultMap.put(key, average);
            }
        }

        return resultMap;
    }



    /**
     * 处理指标超标结论
     */
    private void dealTargetResult
    (Map<String, ReportTemplateDTO> assNoPassMap, Map<String, ReportTemplateDTO> limitTargetMapX, List<ReportTemplateDTO> endList) {
        assNoPassMap.forEach((key, val) -> {
            limitTargetMapX.remove(key);
            if ("Freq_Dev".toUpperCase().equals(val.getTemplateName())) {
                val.setValue("±" + val.getValue());
            }

            String expend = "";
            if(Objects.nonNull(val.getLowValue())){
                expend = val.getLowValue()+",";
            }
            if (val.getOverLimitFlag() == 1) {
                val.setValue("不合格 (" + expend+val.getValue() + ")");
            } else {
                val.setValue("合格 (" + expend+val.getValue() + ")");
            }
            endList.add(val);
        });

        limitTargetMapX.forEach((key, val) -> {
            if (Objects.isNull(val.getOverLimitFlag())) {
                val.setValue("/");
            } else {
                val.setValue("合格");
            }
            endList.add(val);
        });
    }



    private void analyzeReportZhejiang(ReportSearchParam reportSearchParam, ExcelRptTemp excelRptTemp, HttpServletResponse response) {
        //指标
        List<ReportTemplateDTO> reportTemplateDTOList = new ArrayList<>();
        //限值
        List<ReportTemplateDTO> reportLimitList = new ArrayList<>();
        //台账
        List<ReportTemplateDTO> terminalList = new ArrayList<>();
        JSONArray jsonArray;
        try (InputStream fileStream = fileStorageUtil.getFileStream(excelRptTemp.getContent())) {
            jsonArray = new JSONArray(new JSONTokener(fileStream, new JSONConfig()));
            parseTemplateZhejiang(jsonArray, reportTemplateDTOList, reportLimitList, terminalList);
        } catch (Exception e) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
        }

        DictData pqdDic = dicDataFeignClient.getDicDataByCodeAndType(DicDataEnum.PQD.getCode(), DicDataTypeEnum.CS_DATA_TYPE.getCode()).getData();
        List<EleEpdPqd> eleEpdPqdList = eleEpdMapper.selectList(new LambdaQueryWrapper<EleEpdPqd>().eq(EleEpdPqd::getDataType, pqdDic.getId()).isNotNull(EleEpdPqd::getPrimaryFormula));
        Map<String, List<EleEpdPqd>> pqdMap = eleEpdPqdList.stream().filter(item -> StrUtil.isNotBlank(item.getPrimaryFormula())).collect(Collectors.groupingBy(EleEpdPqd::getName));

        //处理指标是否合格
        reportLimitList = new LinkedHashSet<>(reportLimitList)
                .stream()
                .sorted(Comparator.comparing(ReportTemplateDTO::getItemName))
                .collect(Collectors.toList());

        Map<String, Float> limitMap = overLimitDeal(reportLimitList, reportSearchParam);
        //存放限值指标的map
        Map<String, ReportTemplateDTO> limitTargetMapX = reportLimitList.stream().collect(Collectors.toMap(ReportTemplateDTO::getItemName, Function.identity()));

        //组装最后监测点条件
        List<WlRecord> temList = wlRecordFeignClient.getWlAssByWlId(reportSearchParam.getLineId()).getData();
        //List<WlRecord> wlRecordList = temList.stream().filter(it -> it.getType() == 1).collect(Collectors.toList());
        if (CollUtil.isEmpty(temList) && temList.size()==1) {
            throw new BusinessException("当前测试项无测试数据");
        }

        List<ReportTemplateDTO> endList = new ArrayList<>();
        if (CollUtil.isNotEmpty(reportTemplateDTOList)) {

            //开始组织sql
            reportTemplateDTOList = new LinkedHashSet<>(reportTemplateDTOList)
                    .stream()
                    .sorted(Comparator.comparing(ReportTemplateDTO::getItemName))
                    .collect(Collectors.toList());


            Map<String, List<ReportTemplateDTO>> classMap = reportTemplateDTOList.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getResourceId));
            Map<String, ReportTemplateDTO> assNoPassMap = new HashMap<>();
            long deal = System.currentTimeMillis();
            classMap.forEach((classKey, templateValue) -> {
                Map<String, List<ReportTemplateDTO>> valueTypeMap = templateValue.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getStatMethod));

                //avg.max,min,cp95
                valueTypeMap.forEach((valueTypeKey, valueTypeVal) -> {

                    //相别分组
                    Map<String, List<ReportTemplateDTO>> phaseMap = valueTypeVal.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getPhase));
                    phaseMap.forEach((phaseKey, phaseVal) -> {
                        StringBuilder sql = new StringBuilder(InfluxDbSqlConstant.SELECT);
                        if (InfluxDbSqlConstant.MAX.equalsIgnoreCase(valueTypeKey)) {
                            assSqlZhejiang(phaseVal, sql, endList, InfluxDbSqlConstant.MAX, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, temList, pqdMap);
                        } else if (InfluxDbSqlConstant.MIN.equalsIgnoreCase(valueTypeKey)) {
                            assSqlZhejiang(phaseVal, sql, endList, InfluxDbSqlConstant.MIN, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, temList, pqdMap);
                        } else if (InfluxDbSqlConstant.AVG_WEB.equalsIgnoreCase(valueTypeKey)) {
                            assSqlZhejiang(phaseVal, sql, endList, InfluxDbSqlConstant.AVG, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, temList, pqdMap);
                        } else if (InfluxDbSqlConstant.CP95.equalsIgnoreCase(valueTypeKey)) {
                            assSqlZhejiang(phaseVal, sql, endList, InfluxDbSqlConstant.PERCENTILE, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, temList, pqdMap);
                        }
                    });
                });

            });
            //处理指标最终判定合格还是不合格
            dealTargetResult(assNoPassMap, limitTargetMapX, endList);
            long dealEnd = System.currentTimeMillis();
            System.out.println("查询数据库花费时间" + (dealEnd - deal) / 1000 + "S");
        }
        if (CollUtil.isNotEmpty(endList)) {
            long jie = System.currentTimeMillis();
            //数据单位信息
            Map<String, String> unit = unitMap(reportSearchParam);
            //进行反向赋值到模板
            //1、根据itemName分组
            Map<String, List<ReportTemplateDTO>> assMap = endList.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getItemName));
            //处理台账信息
            Map<String, String> finalTerminalMap;
            if (CollUtil.isNotEmpty(terminalList)) {
                if(Objects.nonNull(reportSearchParam.getCustomType()) && reportSearchParam.getCustomType() == 1){
                    WlRecord wlRecordMain = temList.stream().filter(it -> it.getType() == 0).collect(Collectors.toList()).get(0);
                    finalTerminalMap = new HashMap<>();
                    finalTerminalMap.put("lineName",wlRecordMain.getItemName());
                    //finalTerminalMap.put("statis_time",wlRecordMain.getStartTime()+"_"+wlRecordMain.getEndTime());
                    finalTerminalMap.put("pt",wlRecordMain.getCt().toString());
                    finalTerminalMap.put("ct",wlRecordMain.getPt().toString());

                    finalTerminalMap.put("Standard_Capacity",wlRecordMain.getCapacitySscb().toString());
                    finalTerminalMap.put("Short_Capacity",wlRecordMain.getCapacitySscmin().toString());
                    finalTerminalMap.put("Deal_Capacity",wlRecordMain.getCapacitySi().toString());
                    finalTerminalMap.put("Dev_Capacity",wlRecordMain.getCapacitySt().toString());
                }else {
                    finalTerminalMap = commTerminalGeneralClient.getCustomDetailByLineId(reportSearchParam.getLineId()).getData();
                }
            }else {
                finalTerminalMap = new HashMap<>();
            }
            //2、把itemName的value赋给v和m
            dealExcelResult(jsonArray, assMap, unit,finalTerminalMap);
            long jieEnd = System.currentTimeMillis();
            System.out.println("组装信息耗时 " + (jieEnd - jie) / 1000 + "S");
        }

        long daochu = System.currentTimeMillis();
        //导出自定义报表
        downReport(jsonArray, response);
        long daochuEnd = System.currentTimeMillis();
        System.out.println("导出耗时 " + (daochuEnd - daochu) / 1000 + "S");
    }


    private void assSqlZhejiang(List<ReportTemplateDTO> data, StringBuilder
            sql, List<ReportTemplateDTO> endList, String method, ReportSearchParam reportSearchParam, Map<String, ReportTemplateDTO> limitMap, Map<String, Float> overLimitMap, Map<String,
            ReportTemplateDTO> assNoPassMap, List<WlRecord> wlRecordList, Map<String, List<EleEpdPqd>> pqdMap) {

        //sql拼接示例：select MAX(IHA2) as IHA2 from power_quality_data where Phase = 'A' and LineId='1324564568' and Stat_Method='max' tz('Asia/Shanghai')
        //cp95函数特殊处理 PERCENTILE(field_key, N)
        if (InfluxDbSqlConstant.PERCENTILE.equals(method)) {
            for (int i = 0; i < data.size(); i++) {
                if (i == data.size() - 1) {
                    sql.append(InfluxDbSqlConstant.PERCENTILE)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName()).append(InfluxDbSqlConstant.NUM_95)
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM);
                } else {
                    sql.append(InfluxDbSqlConstant.PERCENTILE)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName()).append(InfluxDbSqlConstant.NUM_95)
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM).append(StrUtil.COMMA);
                }
            }
        } else {
            for (int i = 0; i < data.size(); i++) {
                if (i == data.size() - 1) {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM);
                } else {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM).append(StrUtil.COMMA);
                }
            }

        }

        sql.append(StrPool.C_SPACE).append(InfluxDbSqlConstant.FROM).append("pqd_data");
        //相别特殊处理
        sql.append(InfluxDbSqlConstant.WHERE)
                .append(InfluxDBTableConstant.PHASIC_TYPE)
                .append(InfluxDbSqlConstant.EQ)
                .append(InfluxDbSqlConstant.QM)
                .append(data.get(0).getPhase())
                .append(InfluxDbSqlConstant.QM);

        //data_flicker、data_fluc、data_plt 无 value_type
        sql.append(InfluxDbSqlConstant.AND)
                .append(InfluxDBTableConstant.VALUE_TYPE)
                .append(InfluxDbSqlConstant.EQ)
                .append(InfluxDbSqlConstant.QM)
                .append(data.get(0).getStatMethod().toLowerCase())
                .append(InfluxDbSqlConstant.QM);

        List<Map<String, Object>> allList = new ArrayList<>();

        WlRecord ceShiItem = wlRecordList.stream().filter(it->it.getType()==0).collect(Collectors.toList()).get(0);
        for (WlRecord wlRecord : wlRecordList) {
            if(wlRecord.getType().equals(1)) {
                StringBuilder temSql = new StringBuilder(sql);
                String start = LocalDateTimeUtil.format(wlRecord.getStartTime(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                String end = LocalDateTimeUtil.format(wlRecord.getEndTime(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                temSql.append(" and line_id = '").append(wlRecord.getLineId()).append(InfluxDbSqlConstant.QM)
                        .append(InfluxDbSqlConstant.AND)
                        .append(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.GE).append(InfluxDbSqlConstant.QM).append(start).append(InfluxDbSqlConstant.QM)
                        .append(InfluxDbSqlConstant.AND)
                        .append(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.LT).append(InfluxDbSqlConstant.QM).append(end).append(InfluxDbSqlConstant.QM)
                        .append(InfluxDbSqlConstant.TZ);

                List<Map<String, Object>> temMapList = influxDbUtils.getMapResult(temSql.toString());
                if (CollUtil.isNotEmpty(temMapList)) {
                    Map<String, Object> tem = temMapList.get(0);
                    //需要吧测点为二次值的转换为一次值
                    if (wlRecord.getDataLevel().equals("Secondary")) {
                        for (Map.Entry<String, Object> entry : tem.entrySet()) {
                            if (Objects.nonNull(entry.getValue()) && !entry.getKey().equals("time")) {
                                String key = entry.getKey();
                                double val = (double) entry.getValue();
                                String zi = key.substring(0, key.indexOf(STR_ONE));
                                String[] temStrArr = zi.split("_");
                                boolean flag = isInteger(temStrArr[temStrArr.length-1]);
                                if(flag){
                                    zi = zi.substring(0,zi.lastIndexOf("_"));
                                }
                                if (pqdMap.containsKey(zi)) {
                                    EleEpdPqd eleEpdPqd = pqdMap.get(zi).get(0);
                                    if(!eleEpdPqd.getPrimaryFormula().equals("*CT")){
                                        val = val / 1000;
                                    }
                                    double vRes = DataChangeUtil.secondaryToPrimary(eleEpdPqd.getPrimaryFormula(),val, (double) ceShiItem.getPt(), (double) ceShiItem.getCt());
                                    entry.setValue(vRes);
                                }
                            }
                        }
                    }

                    allList.add(temMapList.get(0));
                }
            }
        }

        Map<String, Object> resultMap = dealResultMap(method, allList);
        if (resultMap.isEmpty()) {
            data = data.stream().peek(item -> item.setValue("/")).collect(Collectors.toList());
        } else {
            //遍历模板对查询出来的数据进行赋值
            for (ReportTemplateDTO item : data) {
                if (resultMap.containsKey(item.getItemName())) {
                    double v = (Double) resultMap.get(item.getItemName());
                    item.setValue(String.format("%.3f", v));

                    if (overLimitMap.containsKey(item.getLimitName())) {
                        Float tagVal = overLimitMap.get(item.getLimitName());
                        if (v > tagVal) {
                            item.setOverLimitFlag(1);
                        } else {
                            item.setOverLimitFlag(0);
                        }
                    }

                    //结论判断是否越限
                    String key = item.getLimitName() + STR_ONE + item.getStatMethod().toLowerCase() + "#pq_overlimit";
                    if (limitMap.containsKey(key)) {
                        ReportTemplateDTO tem = limitMap.get(key);
                        double limitVal = Double.parseDouble(tem.getValue());
                        if (v > limitVal) {
                            tem.setOverLimitFlag(1);
                            tem.setValue(tem.getValue());
                            assNoPassMap.put(key, tem);
                        } else if (!assNoPassMap.containsKey(key)) {
                            tem.setOverLimitFlag(0);
                            tem.setValue(tem.getValue());
                            assNoPassMap.put(key, tem);
                        }
                    }
                } else {
                    item.setValue("/");
                }
            }
        }

        endList.addAll(data);
    }

    /**
     * 解析模板
     *
     * @author cdf
     * @date 2023/10/20
     */
    private void parseTemplateZhejiang(JSONArray
                                               jsonArray, List<ReportTemplateDTO> reportTemplateDTOList, List<ReportTemplateDTO> reportLimitList, List<ReportTemplateDTO> terminalList) {
        try {
            //通过文件服务器获取

            jsonArray.forEach(item -> {
                JSONObject jsonObject = (JSONObject) item;
                JSONArray itemArr = (JSONArray) jsonObject.get(CELL_DATA);
                itemArr.forEach((it) -> {
                    if (Objects.nonNull(it) && !"null".equals(it.toString())) {
                        //获取到1列
                        JSONObject data = (JSONObject) it;
                        JSONObject son = (JSONObject) data.get(V);
                        if (son.containsKey(V)) {
                            String v = son.getStr(V);
                            //数据格式：$HA[_25]#B#max#classId$ 或 $HA[_25]#max#classId$
                            if (v.charAt(0) == '$' && v.contains(STR_ONE)) {
                                //剔除前后$
                                v = v.replace(STR_TWO, "");
                                //封装ReportTemplateDTO
                                ReportTemplateDTO reportTemplateDTO = new ReportTemplateDTO();
                                reportTemplateDTO.setItemName(v);
                                //根据#分割数据
                                String[] vItem = v.split(STR_ONE);
                                if (vItem.length == 5) {
                                    //$HA[_25]#B#max#classId$
                                    reportTemplateDTO.setTemplateName(vItem[0]);
                                    reportTemplateDTO.setPhase(vItem[1]);
                                    reportTemplateDTO.setStatMethod(vItem[2]);
                                    reportTemplateDTO.setResourceId(vItem[3]);
                                    reportTemplateDTO.setLimitName(vItem[4]);
                                } else if (vItem.length == 4) {
                                    //$HA[_25]#max#classId$
                                    reportTemplateDTO.setTemplateName(vItem[0]);
                                    reportTemplateDTO.setPhase("T");
                                    reportTemplateDTO.setStatMethod(vItem[1]);
                                    reportTemplateDTO.setResourceId(vItem[2]);
                                    reportTemplateDTO.setLimitName(vItem[3]);
                                }

                                reportTemplateDTOList.add(reportTemplateDTO);
                            } else if (v.charAt(0) == '%' && v.contains(STR_ONE)) {
                                //封装ReportTemplateDTO
                                ReportTemplateDTO reportTemplateDTO = new ReportTemplateDTO();

                                v = v.replace(STR_FOUR, "");
                                reportTemplateDTO.setItemName(v);
                                //根据#分割数据
                                String[] vItem = v.split(STR_ONE);
                                if (vItem.length == 3) {
                                    //$HA[_25]#B#max#classId$
                                    reportTemplateDTO.setTemplateName(vItem[0]);
                                    reportTemplateDTO.setStatMethod(vItem[1]);
                                    reportTemplateDTO.setResourceId(vItem[2]);
                                }
                                reportLimitList.add(reportTemplateDTO);
                            } else if (v.charAt(0) == '&') {
                                //封装ReportTemplateDTO
                                ReportTemplateDTO reportTemplateDTO = new ReportTemplateDTO();
                                v = v.replace(STR_THREE, "");
                                reportTemplateDTO.setItemName(v);
                                reportTemplateDTO.setTemplateName(v);
                                terminalList.add(reportTemplateDTO);
                            }
                        }
                    }
                });
            });
        } catch (Exception e) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
        }
    }


    private void dealExcelResult(JSONArray
                                         jsonArray, Map<String, List<ReportTemplateDTO>> assMap, Map<String, String> unit,Map<String,String> finalTerminalMap) {
        jsonArray.forEach(item -> {
            JSONObject jsonObject = (JSONObject) item;
            JSONArray itemArr = (JSONArray) jsonObject.get(CELL_DATA);
            itemArr.forEach((it) -> {
                if (Objects.nonNull(it) && !"null".equals(it.toString())) {
                    //获取到1列
                    JSONObject data = (JSONObject) it;
                    JSONObject son = (JSONObject) data.get(V);
                    if (son.containsKey(V)) {
                        String v = son.getStr(V);
                        //数据格式：$HA[_25]#B#max#classId$ 或 $HA[_25]#max#classId$
                        if (v.charAt(0) == '$' && v.contains(STR_ONE)) {
                            String str = "";
                            List<ReportTemplateDTO> rDto = assMap.get(v.replace(STR_TWO, ""));
                            if (Objects.nonNull(rDto)) {
                                str = rDto.get(0).getValue();
                                //没有值，赋"/"
                                if (StringUtils.isBlank(str)) {
                                    str = "/";
                                }
                                son.set(V, str);
                                if (Objects.nonNull(rDto.get(0).getOverLimitFlag()) && rDto.get(0).getOverLimitFlag() == 1) {
                                    son.set("fc", "#990000");
                                }
                            }
                        } else if (v.charAt(0) == '%' && v.contains(STR_ONE)) {
                            //指标合格情况
                            String str = "";
                            List<ReportTemplateDTO> rDto = assMap.get(v.replace(STR_FOUR, ""));
                            if (Objects.nonNull(rDto)) {
                                str = rDto.get(0).getValue();
                                //没有值，赋"/"
                                if (StringUtils.isBlank(str)) {
                                    str = "/";
                                }
                                son.set(V, str);
                                if ("不合格".equals(str)) {
                                    son.set("fc", "#990000");
                                }
                            }
                        } else if (v.charAt(0) == '&') {
                            //结论
                            String tem = v.replace(STR_THREE, "");
                            if (Objects.nonNull(finalTerminalMap)) {
                                if ("statis_time".equals(tem)) {
                                    // son.set(V, reportSearchParam.getStartTime() + InfluxDbSqlConstant.START_TIME + "_" + reportSearchParam.getEndTime() + InfluxDbSqlConstant.END_TIME);
                                } else {
                                    //台账信息
                                    son.set(V, finalTerminalMap.getOrDefault(tem, "/"));
                                }
                            }
                        } else if (v.charAt(0) == '@' && v.contains(STR_ONE)) {
                            //解决数据单位问题 @指标#类型@
                            String replace = v.replace("@", "");
                            son.set(V, unit.getOrDefault(replace, "/"));

                        }
                    }
                }
            });
        });
    }



    public static boolean isInteger(String str) {
        try {
            Integer.parseInt(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }


    /**
     * 解析科学计数字符串，转为完整数字文本，原有小数原样保留
     * @param numStr 数据库返回字符串：123.00 / 1.234E+08 / N/A
     * @return 标准数字字符串
     */
    public String formatSciNumber(String numStr) {
        // 空值或占位符直接返回
        if (numStr == null || "N/A".equals(numStr.trim())) {
            return numStr;
        }
        // 判断是否为科学计数格式
        if (numStr.toLowerCase().contains("e")) {
            // BigDecimal 可完美解析科学计数，输出完整数字，保留全部小数位
            String [] split =numStr.split(":");
            BigDecimal one = new BigDecimal(split[0]);
            BigDecimal two = new BigDecimal(split[1]);
            return (one.toPlainString().concat(":").concat(two.toPlainString()));
        }
        return numStr;
    }

}






























