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

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.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONTokener;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.harmonic.common.mapper.ExcelRptTempMapper;
import com.njcn.harmonic.common.mapper.RStatLimitRateDMapper;
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.pojo.dto.ReportTemplateDTO;
import com.njcn.harmonic.pojo.param.ReportSearchParam;
import com.njcn.harmonic.pojo.po.ExcelRptTemp;
import com.njcn.harmonic.pojo.po.day.RStatLimitRateDPO;
import com.njcn.harmonic.pojo.po.day.RStatLimitTargetDPO;
import com.njcn.influx.constant.InfluxDbSqlConstant;
import com.njcn.influx.pojo.constant.InfluxDBTableConstant;
import com.njcn.influx.utils.InfluxDbUtils;
import com.njcn.oss.constant.OssPath;
import com.njcn.oss.enums.OssResponseEnum;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.api.EpdFeignClient;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * pqs
 *
 * @author cdf
 * @date 2026/1/15
 */
@Service
@RequiredArgsConstructor
@Slf4j
@DS("sjzx")
public class CustomReportTableServiceImpl implements CustomReportTableService {

    private final ExcelRptTempMapper excelRptTempMapper;
    private final EpdFeignClient epdFeignClient;
    private final FileStorageUtil fileStorageUtil;
    private final DicDataFeignClient dicDataFeignClient;
    private final RStatLimitRateDMapper rStatLimitRateDMapper;
    private final InfluxDbUtils influxDbUtils;
    private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() + 1);

    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 static final Map<String, String> PHASE_MAPPING = new HashMap<String, String>() {{
        put("AB", "A");
        put("BC", "B");
        put("CA", "C");
        put("M", "T");
    }};

    @Override
    public void getCustomReport(ReportSearchParam reportSearchParam, Map<String, String> ledgerMap, DeviceUnitCommDTO deviceUnitCommDTO, HttpServletResponse response) {
        TimeInterval timeInterval = new TimeInterval();
        ExcelRptTemp excelRptTemp = excelRptTempMapper.selectById(reportSearchParam.getTempId());
        if (Objects.isNull(excelRptTemp)) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_ACTIVE);
        }
        if (Objects.isNull(reportSearchParam.getCustomType())) {
            //通用报表
            analyzeReport(reportSearchParam, excelRptTemp, ledgerMap, deviceUnitCommDTO, response);

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

    @Override
    public String saveStableEventReport(ReportSearchParam reportSearchParam, Map<String, String> newMap, DeviceUnitCommDTO deviceUnitCommDTO) {
        String filePath = "";
        ExcelRptTemp excelRptTemp = excelRptTempMapper.selectById(reportSearchParam.getTempId());
        if (Objects.isNull(excelRptTemp)) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_ACTIVE);
        } else {
            if (Objects.isNull(reportSearchParam.getCustomType())) {
                filePath = this.analyzeReport2(reportSearchParam, excelRptTemp, newMap, deviceUnitCommDTO);
            }
        }
        return filePath;
    }

    private String analyzeReport2(ReportSearchParam reportSearchParam, ExcelRptTemp excelRptTemp, Map<String, String> newMap, DeviceUnitCommDTO deviceUnitCommDTO) {
        Map<String, Object> dataMap = new HashMap<>();
        //定义一个线程集合
        List<Future<?>> futures = new ArrayList<>();
        //指标
        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()));
            parseTemplate(jsonArray, reportTemplateDTOList, reportLimitList, terminalList);
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw new BusinessException(e.getMessage());
            } else {
                throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
            }
        }
        //查询不分相别的指标
        DictData dictData = dicDataFeignClient.getDicDataByCodeAndType(DicDataEnum.EPD.getCode(), DicDataTypeEnum.CS_DATA_TYPE.getCode()).getData();
        if (Objects.isNull(dictData)) {
            throw new BusinessException(CommonResponseEnum.FAIL, "字典类型模板缺少!");
        }

        DictData epdDic = dicDataFeignClient.getDicDataByCodeAndType(DicDataEnum.EPD.getCode(), DicDataTypeEnum.CS_DATA_TYPE.getCode()).getData();
        List<EleEpdPqd> eleEpdPqdList = epdFeignClient.dictMarkByDataType(epdDic.getId()).getData();

        Map<String, String> tMap = new HashMap<>();
        eleEpdPqdList.forEach(item -> {
            String phase;
            if (Objects.isNull(PHASE_MAPPING.get(item.getPhase()))) {
                phase = item.getPhase();
            } else {
                phase = PHASE_MAPPING.get(item.getPhase());
            }
            if (ObjectUtils.isNotNull(item.getHarmStart()) && ObjectUtils.isNotNull(item.getHarmEnd())) {
                for (int i = item.getHarmStart(); i <= item.getHarmEnd() + 1; i++) {
                    tMap.put((item.getOtherName() + "_" + i + phase + item.getResourcesId()).toUpperCase(), item.getPrimaryFormula());
                }
            } else {
                tMap.put((item.getOtherName() + phase + item.getResourcesId()).toUpperCase(), item.getPrimaryFormula());
            }
        });

        eleEpdPqdList = eleEpdPqdList.stream().filter(it -> "T".equals(it.getPhase()) || "M".equals(it.getPhase())).collect(Collectors.toList());
        List<String> noPhaseList = eleEpdPqdList.stream().filter(it -> StrUtil.isNotBlank(it.getOtherName())).map(it -> it.getOtherName().toUpperCase()).collect(Collectors.toList());

        //处理指标是否合格
        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<ReportTemplateDTO> endList = new CopyOnWriteArrayList<>();
        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
            Map<String, ReportTemplateDTO> assNoPassMap = new HashMap<>();
            classMap.forEach((classKey, templateValue) -> {
                Map<String, List<ReportTemplateDTO>> valueTypeMap = templateValue.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getStatMethod));
                //每张表开启一个独立线程查询
                futures.add(executorService.submit(() -> {
                    DynamicDataSourceContextHolder.push("sjzx");
                    //avg.max,min,cp95
                    try {
                        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)) {
                                    assSqlByMysql(tMap, newMap.get("LEVEL"), newMap.get("PT"), newMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.MAX, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList);
                                } else if (InfluxDbSqlConstant.MIN.equalsIgnoreCase(valueTypeKey)) {
                                    assSqlByMysql(tMap, newMap.get("LEVEL"), newMap.get("PT"), newMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.MIN, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList);
                                } else if (InfluxDbSqlConstant.AVG_WEB.equalsIgnoreCase(valueTypeKey)) {
                                    assSqlByMysql(tMap, newMap.get("LEVEL"), newMap.get("PT"), newMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.AVG_WEB, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList);
                                } else if (InfluxDbSqlConstant.CP95.equalsIgnoreCase(valueTypeKey)) {
                                    assSqlByMysql(tMap, newMap.get("LEVEL"), newMap.get("PT"), newMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.CP95, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList);
                                }

                            });
                        });
                    } finally {
                        DynamicDataSourceContextHolder.poll();
                    }
                }));
            });

            // 等待所有任务完成
            for (Future<?> future : futures) {
                try {
                    future.get(); // 这会阻塞直到任务完成或抛出异常
                } catch (InterruptedException | ExecutionException e) {
                    log.error("自定义报表多线程查询流程出错！错误信息{}", e.getMessage());
                    throw  new BusinessException(CommonResponseEnum.FAIL,"自定义报表多线程查询流程出错！");
                }
            }

            //处理指标最终判定合格还是不合格
            dealTargetResult(assNoPassMap, limitTargetMapX, endList);
        }
        resultAssemble2(endList, reportSearchParam, newMap, deviceUnitCommDTO, jsonArray, dataMap);
        //存储自定义报表
        return saveReport(jsonArray, dataMap);
    }

    public void resultAssemble2(List<ReportTemplateDTO> endList, ReportSearchParam reportSearchParam, Map<String, String> finalTerminalMap, DeviceUnitCommDTO deviceUnitCommDTO, JSONArray jsonArray, Map<String, Object> dataMap) {
        if (CollUtil.isNotEmpty(endList)) {
            Map<String, String> unit = this.unitMap(deviceUnitCommDTO);
            Map<String, List<ReportTemplateDTO>> assMap = (Map) endList.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getItemName));
            jsonArray.forEach((item) -> {
                JSONObject jsonObject = (JSONObject) item;
                JSONArray itemArr = (JSONArray) jsonObject.get("celldata");
                itemArr.forEach((it) -> {
                    if (Objects.nonNull(it) && !"null".equals(it.toString())) {
                        JSONObject data = (JSONObject) it;
                        JSONObject son = (JSONObject) data.get("v");
                        if (son.containsKey("v")) {
                            String v = son.getStr("v");
                            String tem;
                            List rDto;
                            if (v.charAt(0) == '$' && v.contains("#")) {
                                tem = "";
                                rDto = (List) assMap.get(v.replace("$", "").toUpperCase());
                                if (Objects.nonNull(rDto)) {
                                    tem = ((ReportTemplateDTO) rDto.get(0)).getValue();
                                    if (StringUtils.isBlank(tem)) {
                                        tem = "/";
                                    }

                                    son.set("v", tem);
                                    dataMap.put(v, tem);
                                    if (Objects.nonNull(((ReportTemplateDTO) rDto.get(0)).getOverLimitFlag()) && ((ReportTemplateDTO) rDto.get(0)).getOverLimitFlag() == 1) {
                                        son.set("fc", "#990000");
                                    }
                                }
                            } else if (v.charAt(0) == '%' && v.contains("#")) {
                                tem = "";
                                rDto = (List) assMap.get(v.replace("%", "").toUpperCase());
                                if (Objects.nonNull(rDto)) {
                                    tem = ((ReportTemplateDTO) rDto.get(0)).getValue();
                                    if (StringUtils.isBlank(tem)) {
                                        tem = "/";
                                    }

                                    son.set("v", tem);
                                    dataMap.put(v, tem);
                                    if ("不合格".equals(tem)) {
                                        son.set("fc", "#990000");
                                        dataMap.put("fc", "#990000");
                                    }
                                }
                            } else if (v.charAt(0) == '&') {
                                tem = v.replace("&", "").toUpperCase();
                                if (finalTerminalMap.size() > 0) {
                                    if ("STATIS_TIME".equals(tem)) {
                                        String localTime = " 23:59:59";
                                        LocalDate localDate = LocalDateTimeUtil.parseDate(reportSearchParam.getEndTime(), "yyyy-MM-dd");
                                        LocalDate nowDate = LocalDate.now();
                                        if (nowDate.isAfter(localDate)) {
                                            son.set("v", reportSearchParam.getStartTime() + " 00:00:00" + "_" + reportSearchParam.getEndTime() + localTime);
                                            dataMap.put(v, reportSearchParam.getStartTime() + " 00:00:00" + "_" + reportSearchParam.getEndTime() + localTime);
                                        } else {
                                            localTime = " " + LocalTime.now().format(DatePattern.NORM_TIME_FORMATTER);
                                            son.set("v", reportSearchParam.getStartTime() + " 00:00:00" + "_" + nowDate + localTime);
                                            dataMap.put(v, reportSearchParam.getStartTime() + " 00:00:00" + "_" + nowDate + localTime);
                                        }
                                    } else {
                                        son.set("v", finalTerminalMap.getOrDefault(tem, "/"));
                                        dataMap.put(v, finalTerminalMap.getOrDefault(tem, "/"));
                                    }
                                }
                            }

                            if (v.charAt(0) == '@' && v.contains("#")) {
                                tem = v.replace("@", "");
                                son.set("v", unit.getOrDefault(tem, "/"));
                                dataMap.put(v, unit.getOrDefault(tem, "/"));
                            }
                        }
                    }
                });
            });
        }
    }


    private String saveReport(JSONArray jsonArray, Map<String, Object> dataMap) {
        String filePath = "";
        Workbook workbook = new XSSFWorkbook();

        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String sheetName = jsonObject.getStr("name");
            JSONArray data = jsonObject.getJSONArray("data");

            Sheet sheet = workbook.createSheet(sheetName);

            List<CellRangeAddress> mergeRegions = new ArrayList<>();
            List<MergedCellInfo> mergedCellInfos = new ArrayList<>();

            if (data != null && !data.isEmpty()) {
                boolean hasMergeMark = false;

                for (int j = 0; j < data.size(); j++) {
                    Row row = sheet.createRow(j);
                    JSONArray rowData = data.getJSONArray(j);

                    if (rowData != null) {
                        for (int k = 0; k < rowData.size(); k++) {
                            JSONObject cellObj = rowData.getJSONObject(k);

                            if (cellObj == null || cellObj.isEmpty()) {
                                continue;
                            }

                            JSONObject mc = cellObj.getJSONObject("mc");

                            if (mc != null && !mc.isEmpty()) {
                                hasMergeMark = true;

                                Integer rs = mc.getInt("rs");
                                Integer cs = mc.getInt("cs");
                                Integer mr = mc.getInt("r");
                                Integer mcCol = mc.getInt("c");

                                if (rs != null && cs != null && mr != null && mcCol != null) {
                                    if (mr == j && mcCol == k) {
                                        int endRow = j + rs - 1;
                                        int endCol = k + cs - 1;
                                        if (endRow > j || endCol > k) {
                                            mergeRegions.add(new CellRangeAddress(j, endRow, k, endCol));

                                            MergedCellInfo info = new MergedCellInfo();
                                            info.row = j;
                                            info.col = k;
                                            info.cellObj = cellObj;
                                            mergedCellInfos.add(info);
                                        }
                                    } else {
                                        continue;
                                    }
                                }
                            }

                            Cell cell = row.createCell(k);
                            Object v = cellObj.get("v");

                            if (v != null) {
                                Object vData = dataMap.get(v);
                                if (vData != null) {
                                    setCellValue(cell, vData);
                                } else {
                                    setCellValue(cell, v);
                                }
                            }
                        }
                    }
                }

                if (!hasMergeMark) {
                    detectAndMergeCells(data, mergeRegions, mergedCellInfos);
                }
            }

            for (CellRangeAddress mergeRegion : mergeRegions) {
                try {
                    sheet.addMergedRegion(mergeRegion);
                } catch (Exception e) {
                    log.warn("添加合并单元格失败：{}", mergeRegion.formatAsString());
                }
            }

            for (MergedCellInfo info : mergedCellInfos) {
                Row row = sheet.getRow(info.row);
                if (row != null) {
                    Cell cell = row.getCell(info.col);
                    if (cell != null) {
                        CellStyle style = workbook.createCellStyle();
                        style.setAlignment(HorizontalAlignment.CENTER);
                        style.setVerticalAlignment(VerticalAlignment.CENTER);

                        Font font = workbook.createFont();
                        font.setFontName("宋体");
                        font.setFontHeightInPoints((short) 11);
                        style.setFont(font);
                        style.setWrapText(true);

                        if (Objects.equals(cell.getStringCellValue(), "非谐波统计报表")
                                || Objects.equals(cell.getStringCellValue(), "谐波电压统计报表")
                                || Objects.equals(cell.getStringCellValue(), "谐波电流统计报表")) {
                            font.setFontHeightInPoints((short) 18);
                            font.setBold(true);
                        }
                        if (Objects.equals(cell.getStringCellValue(), "有效值")
                                || Objects.equals(cell.getStringCellValue(), "功率")
                                || Objects.equals(cell.getStringCellValue(), "电压闪变")
                                || Objects.equals(cell.getStringCellValue(), "畸变率")
                                || Objects.equals(cell.getStringCellValue(), "电压偏差")
                                || Objects.equals(cell.getStringCellValue(), "频率")
                                || Objects.equals(cell.getStringCellValue(), "三相不平衡度")
                                || Objects.equals(cell.getStringCellValue(), "谐波电压含有率")
                                || Objects.equals(cell.getStringCellValue(), "谐波电流幅值")) {
                            font.setFontHeightInPoints((short) 15);
                            font.setBold(true);
                        }

                        cell.setCellStyle(style);
                    }
                }
            }
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            workbook.write(baos);
            workbook.close();
        } catch (IOException e) {
            throw new BusinessException(OssResponseEnum.DOWNLOAD_FILE_STREAM_ERROR);
        }

        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        filePath = fileStorageUtil.uploadStream(bais, OssPath.APP_HARMONIC_REPORT, "稳态报表.xlsx");
        try {
            bais.close();
            baos.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return filePath;
    }

    /**
     * 检测并合并单元格（当没有 mc 标记时）
     */
    private void detectAndMergeCells(JSONArray data, List<CellRangeAddress> mergeRegions,
                                     List<MergedCellInfo> mergedCellInfos) {
        int rows = data.size();
        if (rows == 0) return;

        int cols = 0;
        JSONArray firstRow = data.getJSONArray(0);
        if (firstRow != null) {
            cols = firstRow.size();
        }

        boolean[][] merged = new boolean[rows][cols];

        for (int j = 0; j < rows; j++) {
            JSONArray rowData = data.getJSONArray(j);
            if (rowData == null) continue;

            for (int k = 0; k < rowData.size(); k++) {
                if (merged[j][k]) continue;

                JSONObject cellObj = rowData.getJSONObject(k);
                if (cellObj == null || cellObj.isEmpty()) continue;

                Object v = cellObj.get("v");
                if (v == null || StrUtil.isBlank(v.toString())) continue;

                int mergeEndRow = j;
                int mergeEndCol = k;

                for (int r = j + 1; r < rows; r++) {
                    JSONArray nextRow = data.getJSONArray(r);
                    if (nextRow == null || k >= nextRow.size()) break;

                    JSONObject nextCellObj = nextRow.getJSONObject(k);
                    if (nextCellObj == null || nextCellObj.isEmpty()) break;

                    Object nextV = nextCellObj.get("v");
                    if (nextV == null || !String.valueOf(v).equals(String.valueOf(nextV))) break;

                    mergeEndRow = r;
                    merged[r][k] = true;
                }

                for (int c = k + 1; c < cols; c++) {
                    if (j >= rowData.size()) break;

                    JSONObject rightCellObj = rowData.getJSONObject(c);
                    if (rightCellObj == null || rightCellObj.isEmpty()) break;

                    Object rightV = rightCellObj.get("v");
                    if (rightV == null || !String.valueOf(v).equals(String.valueOf(rightV))) break;

                    mergeEndCol = c;
                    merged[j][c] = true;
                }

                if (mergeEndRow > j || mergeEndCol > k) {
                    mergeRegions.add(new CellRangeAddress(j, mergeEndRow, k, mergeEndCol));

                    MergedCellInfo info = new MergedCellInfo();
                    info.row = j;
                    info.col = k;
                    info.cellObj = cellObj;
                    mergedCellInfos.add(info);
                }
            }
        }
    }

    /**
     * 设置单元格值
     */
    private void setCellValue(Cell cell, Object value) {
        if (value == null) {
            return;
        }
        if (value instanceof String) {
            cell.setCellValue((String) value);
        } else if (value instanceof Number) {
            cell.setCellValue(((Number) value).doubleValue());
        } else if (value instanceof Boolean) {
            cell.setCellValue((Boolean) value);
        } else if (value instanceof Date) {
            cell.setCellValue((Date) value);
        } else {
            cell.setCellValue(value.toString());
        }
    }

    /**
     * 合并单元格信息内部类
     */
    private static class MergedCellInfo {
        int row;
        int col;
        JSONObject cellObj;
    }

    /**
     * 处理
     *
     * @author cdf
     * @date 2023/10/8
     */

    private void analyzeReport(ReportSearchParam reportSearchParam, ExcelRptTemp excelRptTemp, Map<String, String> ledgerMap, DeviceUnitCommDTO deviceUnitCommDTO, HttpServletResponse response) {
        //定义一个线程集合
        List<Future<?>> futures = new ArrayList<>();
        //指标
        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()));
            parseTemplate(jsonArray, reportTemplateDTOList, reportLimitList, terminalList);
        } catch (Exception e) {
            // 自定义报表防止没有默认模板，从resource目录加载默认模板
            String defaultTemplatePath = "file/default_excel_report.json";
            try (InputStream defaultStream = getClass().getClassLoader().getResourceAsStream(defaultTemplatePath)) {
                if (defaultStream == null) {
                    if (e instanceof BusinessException) {
                        throw new BusinessException(e.getMessage());
                    } else {
                        throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
                    }
                } else {
                    jsonArray = new JSONArray(new JSONTokener(defaultStream, new JSONConfig()));
                    parseTemplate(jsonArray, reportTemplateDTOList, reportLimitList, terminalList);
                }
            } catch (Exception e1) {
                throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
            }
        }
        //查询不分相别的指标
        DictData dictData = dicDataFeignClient.getDicDataByCodeAndType(DicDataEnum.EPD.getCode(), DicDataTypeEnum.CS_DATA_TYPE.getCode()).getData();
        if (Objects.isNull(dictData)) {
            throw new BusinessException(CommonResponseEnum.FAIL, "字典类型模板缺少!");
        }
        List<EleEpdPqd> eleEpdPqdList = epdFeignClient.dictMarkByDataType(dictData.getId()).getData();
        Map<String, String> tableMap = eleEpdPqdList.stream().collect(Collectors.toMap(EleEpdPqd::getResourcesId, EleEpdPqd::getClassId, (oldValue, newValue) -> oldValue));


        Map<String, String> tMap = new HashMap<>();
        eleEpdPqdList.forEach(item -> {
            String phase;
            if (Objects.isNull(PHASE_MAPPING.get(item.getPhase()))) {
                phase = item.getPhase();
            } else {
                phase = PHASE_MAPPING.get(item.getPhase());
            }
            if (ObjectUtils.isNotNull(item.getHarmStart()) && ObjectUtils.isNotNull(item.getHarmEnd())) {
                for (int i = item.getHarmStart(); i <= item.getHarmEnd() + 1; i++) {
                    tMap.put((item.getOtherName() + "_" + i + phase + item.getResourcesId()).toUpperCase(), item.getPrimaryFormula());
                }
            } else {
                tMap.put((item.getOtherName() + phase + item.getResourcesId()).toUpperCase(), item.getPrimaryFormula());
            }
        });

        eleEpdPqdList = eleEpdPqdList.stream().filter(it -> "M".equals(it.getPhase())).collect(Collectors.toList());
        List<String> noPhaseList = eleEpdPqdList.stream().filter(it -> StrUtil.isNotBlank(it.getOtherName())).map(it -> it.getOtherName().toUpperCase()).collect(Collectors.toList());

        //处理指标是否合格
        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<ReportTemplateDTO> endList = new CopyOnWriteArrayList<>();
        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
            Map<String, ReportTemplateDTO> assNoPassMap = new HashMap<>();
            classMap.forEach((classKey, templateValue) -> {
                Map<String, List<ReportTemplateDTO>> valueTypeMap = templateValue.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getStatMethod));
                //每张表开启一个独立线程查询
                futures.add(executorService.submit(() -> {
                    DynamicDataSourceContextHolder.push("sjzx");
                    //avg.max,min,cp95
                    try {
                        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)) {
                                    assembleSqlAndQuery(tMap, ledgerMap.get("LEVEL"), ledgerMap.get("PT"), ledgerMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.MAX, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList, tableMap);
                                } else if (InfluxDbSqlConstant.MIN.equalsIgnoreCase(valueTypeKey)) {
                                    assembleSqlAndQuery(tMap, ledgerMap.get("LEVEL"), ledgerMap.get("PT"), ledgerMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.MIN, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList, tableMap);
                                } else if (InfluxDbSqlConstant.AVG_WEB.equalsIgnoreCase(valueTypeKey)) {
                                    assembleSqlAndQuery(tMap, ledgerMap.get("LEVEL"), ledgerMap.get("PT"), ledgerMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.AVG_WEB, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList, tableMap);
                                } else if (InfluxDbSqlConstant.CP95.equalsIgnoreCase(valueTypeKey)) {
                                    assembleSqlAndQuery(tMap, ledgerMap.get("LEVEL"), ledgerMap.get("PT"), ledgerMap.get("CT"), phaseVal, sql, endList, InfluxDbSqlConstant.CP95, reportSearchParam, limitTargetMapX, limitMap, assNoPassMap, noPhaseList, tableMap);
                                }

                            });
                        });
                    } finally {
                        DynamicDataSourceContextHolder.poll();
                    }
                }));
            });

            // 等待所有任务完成
            for (Future<?> future : futures) {
                try {
                    future.get(); // 这会阻塞直到任务完成或抛出异常
                } catch (InterruptedException | ExecutionException e) {
                    log.error("自定义报表多线程查询流程出错！错误信息{}", e.getMessage());
                    throw  new BusinessException(CommonResponseEnum.FAIL,"自定义报表多线程查询流程出错！");
                }
            }

            //处理指标最终判定合格还是不合格
            dealTargetResult(assNoPassMap, limitTargetMapX, endList);
        }
        resultAssemble(endList, reportSearchParam, ledgerMap, deviceUnitCommDTO, jsonArray);
        //导出自定义报表
        downReport(jsonArray, response);
    }


    /**
     * 合格率sheet组装
     * @param reportSearchParam
     * @return
     */
    public Map<String, String> assemblePassRateResult(ReportSearchParam reportSearchParam) {
        Map<String, String> resultMap = new HashMap<>();

        // 1. 查询数据
        LambdaQueryWrapper<RStatLimitRateDPO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RStatLimitRateDPO::getLineId, reportSearchParam.getLineId())
                .between(RStatLimitRateDPO::getTime, reportSearchParam.getStartTime(), reportSearchParam.getEndTime());
        List<RStatLimitRateDPO> list = rStatLimitRateDMapper.selectList(wrapper);
        if (CollUtil.isEmpty(list)) {
            return resultMap;
        }

        // 2. 按相分组
        Map<String, List<RStatLimitRateDPO>> phaseMap = list.stream()
                .collect(Collectors.groupingBy(item -> item.getPhasicType() == null ? "" : item.getPhasicType()));

        RStatLimitRateDPO A = assRStatLimitRateDPO(phaseMap.getOrDefault("A", Collections.emptyList()), false);
        RStatLimitRateDPO B = assRStatLimitRateDPO(phaseMap.getOrDefault("B", Collections.emptyList()), false);
        RStatLimitRateDPO C = assRStatLimitRateDPO(phaseMap.getOrDefault("C", Collections.emptyList()), false);
        RStatLimitRateDPO T = assRStatLimitRateDPO(phaseMap.getOrDefault("T", Collections.emptyList()), true);

        if (getVal(A.getAllTime()) <= 0 || getVal(B.getAllTime()) <= 0 || getVal(C.getAllTime()) <= 0) {
            return resultMap;
        }

        // 3. 工具：计算合过率
        java.util.function.BiFunction<Integer, Integer, Double> calc = (overtime, total) -> {
            int ot = overtime == null ? 0 : overtime;
            int tt = total == null ? 0 : total;
            return tt <= 0 ? 0 : (1 - ot * 1.0 / tt) * 100;
        };
        java.util.function.DoubleFunction<String> fmt = d -> BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP).toString();

        // 4. 通用处理：把三项通过率算出来，put到map
        java.util.function.BiFunction<String, java.util.function.Function<RStatLimitRateDPO, Integer>, Void> process = (name, getter) -> {
            double a = calc.apply(getter.apply(A), A.getAllTime());
            double b = calc.apply(getter.apply(B), B.getAllTime());
            double c = calc.apply(getter.apply(C), C.getAllTime());
            resultMap.put("$" + name + "#A#pass$", fmt.apply(a));
            resultMap.put("$" + name + "#B#pass$", fmt.apply(b));
            resultMap.put("$" + name + "#C#pass$", fmt.apply(c));
            resultMap.put("$" + name + "#all$", fmt.apply(Math.min(a, Math.min(b, c))));
            return null;
        };

        // 5. 电压偏差
        process.apply("voltageDevOvertime", RStatLimitRateDPO::getVoltageDevOvertime);
        // 6. 电压谐波畸变率
        process.apply("uaberranceOvertime", RStatLimitRateDPO::getUaberranceOvertime);

        // 7. T相：三相不平衡 + 频率偏差
        double ubalance = calc.apply(T.getUbalanceOvertime(), A.getAllTime());
        double freqDev = calc.apply(T.getFreqDevOvertime(), A.getAllTime());
        resultMap.put("$ubalanceOvertime$", fmt.apply(ubalance));
        resultMap.put("$freqDevOvertime$", fmt.apply(freqDev));

        // 8. 谐波 2~25（电压 + 电流）
        for (int i = 2; i <= 25; i++) {
            // 电压谐波
            String uField = "uharm" + i + "Overtime";
            double ua = calc.apply(getField(A, uField), A.getAllTime());
            double ub = calc.apply(getField(B, uField), B.getAllTime());
            double uc = calc.apply(getField(C, uField), C.getAllTime());
            resultMap.put("$" + uField + "#A#pass$", fmt.apply(ua));
            resultMap.put("$" + uField + "#B#pass$", fmt.apply(ub));
            resultMap.put("$" + uField + "#C#pass$", fmt.apply(uc));
            resultMap.put("$" + uField + "#all$", fmt.apply(Math.min(ua, Math.min(ub, uc))));

            // 电流谐波
            String iField = "iharm" + i + "Overtime";
            double ia = calc.apply(getField(A, iField), A.getAllTime());
            double ib = calc.apply(getField(B, iField), B.getAllTime());
            double ic = calc.apply(getField(C, iField), C.getAllTime());
            resultMap.put("$" + iField + "#A#pass$", fmt.apply(ia));
            resultMap.put("$" + iField + "#B#pass$", fmt.apply(ib));
            resultMap.put("$" + iField + "#C#pass$", fmt.apply(ic));
            resultMap.put("$" + iField + "#all$", fmt.apply(Math.min(ia, Math.min(ib, ic))));
        }

        // 9. 各相总次数
        resultMap.put("$harmOvertime#A#num$", String.valueOf(getVal(A.getAllTime())));
        resultMap.put("$harmOvertime#B#num$", String.valueOf(getVal(B.getAllTime())));
        resultMap.put("$harmOvertime#C#num$", String.valueOf(getVal(C.getAllTime())));

        // 10. 闪变（单独处理，因为分母是 flickerAllTime）
        if (getVal(A.getFlickerAllTime()) > 0 && getVal(B.getFlickerAllTime()) > 0 && getVal(C.getFlickerAllTime()) > 0) {
            double fa = calc.apply(A.getFlickerOvertime(), A.getFlickerAllTime());
            double fb = calc.apply(B.getFlickerOvertime(), B.getFlickerAllTime());
            double fc = calc.apply(C.getFlickerOvertime(), C.getFlickerAllTime());
            resultMap.put("$flickerOvertime#A#pass$", fmt.apply(fa));
            resultMap.put("$flickerOvertime#B#pass$", fmt.apply(fb));
            resultMap.put("$flickerOvertime#C#pass$", fmt.apply(fc));
            resultMap.put("$flickerOvertime#all$", fmt.apply(Math.min(fa, Math.min(fb, fc))));
            resultMap.put("$flickerOvertime#A#num$", String.valueOf(getVal(A.getFlickerAllTime())));
            resultMap.put("$flickerOvertime#B#num$", String.valueOf(getVal(B.getFlickerAllTime())));
            resultMap.put("$flickerOvertime#C#num$", String.valueOf(getVal(C.getFlickerAllTime())));
        }

        return resultMap;
    }

    // ========== 两个小工具方法 ==========
    private int getVal(Integer v) {
        return v == null ? 0 : v;
    }

    private Integer getField(RStatLimitRateDPO obj, String fieldName) {
        try {
            Field f = RStatLimitRateDPO.class.getDeclaredField(fieldName);
            f.setAccessible(true);
            return (Integer) f.get(obj);
        } catch (Exception e) {
            return 0;
        }
    }

    private double limitPassRateForMap(Map<String, String> resultMap, RStatLimitRateDPO obj, String fieldName, String phase) {
        double tem = 0;
        try {
            Field fieldA = obj.getClass().getDeclaredField(fieldName);
            fieldA.setAccessible(true);
            int valA = (int) fieldA.get(obj);
            tem = (1 - valA * 1.0 / obj.getAllTime()) * 100;
            BigDecimal vA = new BigDecimal(tem).setScale(2, RoundingMode.HALF_UP);
            String keyA = "$" + fieldName + "#" + phase + "#pass$";

            resultMap.put(keyA, vA.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tem;
    }

    private RStatLimitRateDPO assRStatLimitRateDPO(List<RStatLimitRateDPO> limitRateA, boolean allFlag) {
        RStatLimitRateDPO a = new RStatLimitRateDPO();
        for (RStatLimitRateDPO b : limitRateA) {
            a.setAllTime(addInt(a.getAllTime(), b.getAllTime()));
            if (allFlag) {
                a.setFreqDevOvertime(addInt(a.getFreqDevOvertime(), b.getFreqDevOvertime()));
                a.setUbalanceOvertime(addInt(a.getUbalanceOvertime(), b.getUbalanceOvertime()));
                return a;
            }

            a.setFlickerAllTime(addInt(a.getFlickerAllTime(), b.getFlickerAllTime()));
            a.setFlickerOvertime(addInt(a.getFlickerOvertime(), b.getFlickerOvertime()));
            a.setUaberranceOvertime(addInt(a.getUaberranceOvertime(), b.getUaberranceOvertime()));
            a.setVoltageDevOvertime(addInt(a.getVoltageDevOvertime(), b.getVoltageDevOvertime()));

            // uharm2~25 用循环简化
            for (int i = 2; i <= 25; i++) {
                String fieldName = "uharm" + i + "Overtime";
                try {
                    Field field = RStatLimitRateDPO.class.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    Integer valA = (Integer) field.get(a);
                    Integer valB = (Integer) field.get(b);
                    field.set(a, addInt(valA, valB));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            // iharm2~25 用循环简化
            for (int i = 2; i <= 25; i++) {
                String fieldName = "iharm" + i + "Overtime";
                try {
                    Field field = RStatLimitRateDPO.class.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    Integer valA = (Integer) field.get(a);
                    Integer valB = (Integer) field.get(b);
                    field.set(a, addInt(valA, valB));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return a;
    }

    // 安全相加方法
    private Integer addInt(Integer a, Integer b) {
        return (a == null ? 0 : a) + (b == null ? 0 : b);
    }


    /**
     * 解析模板
     *
     * @author cdf
     * @date 2023/10/20
     */
    private void parseTemplate(JSONArray jsonArray, List<ReportTemplateDTO> reportTemplateDTOList, List<ReportTemplateDTO> reportLimitList, List<ReportTemplateDTO> terminalList) {
        try {
            //通过文件服务器获取
            jsonArray.forEach(item -> {
                JSONObject jsonObject = (JSONObject) item;
                if (!"合格率".equals(jsonObject.getStr("name"))) {
                    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.toUpperCase());
                                    //根据#分割数据
                                    String[] vItem = v.split(STR_ONE);
                                    if (vItem.length == 5) {
                                        //$HA[_25]#B#max#classId$
                                        reportTemplateDTO.setTemplateName(vItem[0].toUpperCase());
                                        reportTemplateDTO.setPhase(vItem[1].substring(0, 1).toUpperCase());
                                        reportTemplateDTO.setStatMethod(vItem[2].toUpperCase());
                                        reportTemplateDTO.setResourceId(vItem[3].toUpperCase());
                                        reportTemplateDTO.setLimitName(vItem[4].toUpperCase());
                                    } else if (vItem.length == 4) {
                                        //$HA[_25]#max#classId$
                                        reportTemplateDTO.setTemplateName(vItem[0].toUpperCase());
                                        reportTemplateDTO.setPhase("T");
                                        reportTemplateDTO.setStatMethod(vItem[1].toUpperCase());
                                        reportTemplateDTO.setResourceId(vItem[2].toUpperCase());
                                        reportTemplateDTO.setLimitName(vItem[3].toUpperCase());
                                    }

                                    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.toUpperCase());
                                    //根据#分割数据
                                    String[] vItem = v.split(STR_ONE);
                                    if (vItem.length == 3) {
                                        reportTemplateDTO.setTemplateName(vItem[0].toUpperCase());
                                        reportTemplateDTO.setStatMethod(vItem[1].toUpperCase());
                                        reportTemplateDTO.setResourceId(vItem[2].toUpperCase());
                                    }
                                    reportLimitList.add(reportTemplateDTO);
                                } else if (v.charAt(0) == '&') {
                                    //封装ReportTemplateDTO
                                    ReportTemplateDTO reportTemplateDTO = new ReportTemplateDTO();
                                    v = v.replace(STR_THREE, "");
                                    reportTemplateDTO.setItemName(v.toUpperCase());
                                    reportTemplateDTO.setTemplateName(v.toUpperCase());
                                    terminalList.add(reportTemplateDTO);
                                }
                            }
                        }
                    });
                }
            });
        } catch (Exception e) {
            throw new BusinessException(HarmonicResponseEnum.CUSTOM_REPORT_JSON);
        }
    }


    /**
     * 获取测点限值
     *
     * @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);
        });
    }


    public Double getData(String data) {
        double ratio = 1.0;
        String[] parts = data.split(":");
        if (parts.length == 2) {
            try {
                int num1 = Integer.parseInt(parts[0]);
                int num2 = Integer.parseInt(parts[1]);
                // 如果需要计算比值
                ratio = (double) num1 / num2;
            } catch (NumberFormatException e) {
                System.out.println("字符串格式错误");
            }
        }
        return ratio;
    }

    public String appendData(Map<String, String> tMap, String name, double pt, double ct) {
        String result;
        String format = tMap.get(name);
        if (Objects.equals(format, "*PT")) {
            result = "*" + pt + "/1000";
        } else if (Objects.equals(format, "*CT")) {
            result = "*" + ct;
        } else if (Objects.equals(format, "*PT*CT")) {
            result = "*" + pt + "*" + ct + "/1000";
        } else {
            result = "";
        }
        return result;
    }

    /**
     * @param data         同类型的cell模板
     * @param sql          单个cell模板
     * @param endList      用于返回最终组装好的数据，类似data
     * @param limitMap     指标是否合格模板
     * @param assNoPassMap 用于存储不合格的指标
     * @date 2023/10/20
     */
    private void assSqlByMysql(Map<String, String> tMap, String dataLevel, String pt, String ct, 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(Objects.equals(dataLevel, "Secondary") ? " " + appendData(tMap, data.get(i).getTemplateName() + data.get(i).getPhase() + data.get(0).getResourceId(), getData(pt), getData(ct)) : "")
                            .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(Objects.equals(dataLevel, "Secondary") ? " " + appendData(tMap, data.get(i).getTemplateName() + data.get(i).getPhase() + data.get(0).getResourceId(), getData(pt), getData(ct)) : "")
                            .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(Objects.equals(dataLevel, "Secondary") ? " " + appendData(tMap, data.get(i).getTemplateName() + data.get(i).getPhase() + data.get(0).getResourceId(), getData(pt), getData(ct)) : "")
                            .append(InfluxDbSqlConstant.AS)
                            .append("\"" + data.get(i).getItemName() + "\"");
                } else {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(Objects.equals(dataLevel, "Secondary") ? " " + appendData(tMap, data.get(i).getTemplateName() + data.get(i).getPhase() + data.get(0).getResourceId(), getData(pt), getData(ct)) : "")
                            .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())) {
            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);
    }


    private void assembleSqlAndQuery(Map<String, String> tMap, String dataLevel, String pt, String ct,
                                     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,
                                     Map<String, String> tableMap) {
        // 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特殊情况
        boolean isCp95 = InfluxDbSqlConstant.CP95.equals(method);
        boolean isAvg = InfluxDbSqlConstant.AVG_WEB.equals(method);
        String aggregateFunc;
        // 执行查询
        List<Map<String, Object>> mapList = new ArrayList<>();
        if (Objects.isNull(reportSearchParam.getIsStatisticData()) || reportSearchParam.getIsStatisticData() == 0) {
            aggregateFunc = isCp95 ? InfluxDbSqlConstant.MAX : method;
            for (int i = 0; i < data.size(); i++) {
                sql.append(aggregateFunc)
                        .append(InfluxDbSqlConstant.LBK)
                        .append(data.get(i).getTemplateName())
                        .append(InfluxDbSqlConstant.RBK)
                        .append(Objects.equals(dataLevel, "Secondary") ? " " + appendData(tMap, data.get(i).getTemplateName() + data.get(i).getPhase() + data.get(0).getResourceId(), getData(pt), getData(ct)) : "");
                if (i == data.size() - 1) {
                    sql.append(InfluxDbSqlConstant.AS).append("\"").append(data.get(i).getItemName()).append("\"");
                } else {
                    sql.append(InfluxDbSqlConstant.AS).append("\"").append(data.get(i).getItemName()).append("\"").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);


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


            //相别特殊处理
            if (noPhaseList.contains(data.get(0).getTemplateName())) {
                sql.append(InfluxDbSqlConstant.AND)
                        .append(InfluxDBTableConstant.PHASIC_TYPE)
                        .append(InfluxDbSqlConstant.EQ)
                        .append(InfluxDbSqlConstant.QM)
                        .append(InfluxDBTableConstant.PHASE_TYPE_T)
                        .append(InfluxDbSqlConstant.QM);
            } else {
                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(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);
            mapList = SqlRunner.DEFAULT.selectList(sql.toString());
        } else if (reportSearchParam.getIsStatisticData() == 1) {
            //查分钟数据
            if (isCp95) {
                // InfluxDB的PERCENTILE特殊处理
                for (int i = 0; i < data.size(); i++) {
                    sql.append(method)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName().toLowerCase())
                            .append(InfluxDbSqlConstant.NUM_95)
                            .append(InfluxDbSqlConstant.RBK)
                            .append(InfluxDbSqlConstant.AS).append(InfluxDbSqlConstant.DQM)
                            .append(data.get(i).getItemName()).append(InfluxDbSqlConstant.DQM);
                    if (i != data.size() - 1) {
                        sql.append(StrUtil.COMMA);
                    }
                }
            } else {
                aggregateFunc = isAvg ? InfluxDbSqlConstant.AVG : method;
                for (int i = 0; i < data.size(); i++) {
                    sql.append(aggregateFunc)
                            .append(InfluxDbSqlConstant.LBK)
                            .append(data.get(i).getTemplateName().toLowerCase())
                            .append(InfluxDbSqlConstant.RBK)
                            .append(Objects.equals(dataLevel, "Secondary") ? " " + appendData(tMap, data.get(i).getTemplateName() + data.get(i).getPhase() + data.get(0).getResourceId(), getData(pt), getData(ct)) : "")
                            .append(InfluxDbSqlConstant.AS).append("\"").append(data.get(i).getItemName()).append("\"");
                    if (i != data.size() - 1) {
                        sql.append(StrUtil.COMMA);
                    }
                }
            }
            // 拼接表名
            sql.append(StrPool.C_SPACE).append(InfluxDbSqlConstant.FROM).append(StrPool.C_SPACE);
            if (Objects.nonNull(reportSearchParam.getResourceType()) && reportSearchParam.getResourceType() == 1) {
                sql.append(data.get(0).getClassId().replace("data", "day"));
            } else {
                sql.append(tableMap.get(data.get(0).getResourceId().toLowerCase()).toLowerCase());
            }

            // 拼接WHERE条件
            sql.append(InfluxDbSqlConstant.WHERE)
                    .append(InfluxDBTableConstant.LINE_ID)
                    .append(InfluxDbSqlConstant.EQ)
                    .append(InfluxDbSqlConstant.QM)
                    .append(reportSearchParam.getLineId())
                    .append(InfluxDbSqlConstant.QM);

            // InfluxDB特殊处理：data_flicker、data_fluc、data_plt 无 value_type
            String classTable = tableMap.get(data.get(0).getResourceId().toLowerCase());
            if (!InfluxDBTableConstant.DATA_FLICKER.equals(classTable)
                    && !InfluxDBTableConstant.DATA_FLUC.equals(classTable)
                    && !InfluxDBTableConstant.DATA_PLT.equals(classTable)) {
                sql.append(InfluxDbSqlConstant.AND)
                        .append(InfluxDBTableConstant.VALUE_TYPE)
                        .append(InfluxDbSqlConstant.EQ)
                        .append(InfluxDbSqlConstant.QM)
                        .append(data.get(0).getStatMethod())
                        .append(InfluxDbSqlConstant.QM);
            }

            // 相别特殊处理
            if (!noPhaseList.contains(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(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.GE)
                    .append(InfluxDbSqlConstant.QM).append(reportSearchParam.getStartTime())
                    .append(InfluxDbSqlConstant.QM)
                    .append(InfluxDbSqlConstant.AND)
                    .append(InfluxDbSqlConstant.TIME).append(InfluxDbSqlConstant.LT)
                    .append(InfluxDbSqlConstant.QM).append(reportSearchParam.getEndTime())
                    .append(InfluxDbSqlConstant.QM);

            // InfluxDB需要添加时区
            sql.append(InfluxDbSqlConstant.TZ);
            System.out.println(sql);
            mapList = influxDbUtils.getMapResult(sql.toString());
        }
        // 处理查询结果
        fetchData(mapList, data, limitMap, overLimitMap, assNoPassMap, endList);


    }


    public void fetchData(List<Map<String, Object>> mapList,
                          List<ReportTemplateDTO> data, Map<String,
            ReportTemplateDTO> limitMap,
                          Map<String, Float> overLimitMap,
                          Map<String, ReportTemplateDTO> assNoPassMap,
                          List<ReportTemplateDTO> endList) {
        // 处理查询结果
        if (CollUtil.isEmpty(mapList)) {
            data = data.stream().peek(item -> item.setValue("/")).collect(Collectors.toList());
        } else {
            // 兼容达梦数据库方法
            if (Objects.nonNull(mapList.get(0))) {
                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));

                        // 处理overLimitMap越限判断
                        if (overLimitMap != null && overLimitMap.containsKey(item.getLimitName())) {
                            Float tagVal = overLimitMap.get(item.getLimitName());

                            if (item.getLimitName() != null && 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);
                                }
                            }
                        }

                        // 判断是否越限（limitMap处理）
                        if (limitMap != null && !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);
                                        if (assNoPassMap != null) {
                                            assNoPassMap.put(key, tem);
                                        }
                                    } else if (assNoPassMap != null && !assNoPassMap.containsKey(key)) {
                                        tem.setOverLimitFlag(0);
                                        assNoPassMap.put(key, tem);
                                    }
                                } else {
                                    // 其他指标
                                    if (v > limitVal) {
                                        tem.setOverLimitFlag(1);
                                        if (assNoPassMap != null) {
                                            assNoPassMap.put(key, tem);
                                        }
                                    } else if (assNoPassMap != null && !assNoPassMap.containsKey(key)) {
                                        tem.setOverLimitFlag(0);
                                        assNoPassMap.put(key, tem);
                                    }
                                }
                            }
                        }
                    } else {
                        item.setValue("/");
                    }
                }
            }
        }
        if (endList != null) {
            endList.addAll(data);
        }
    }

    /**
     * 数据单位信息
     */
    private Map<String, String> unitMap(DeviceUnitCommDTO deviceUnit) {
        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;
    }


    /**
     * 处理最终结果
     *
     * @author cdf
     * @date 2026/1/16
     */
    public void resultAssemble(List<ReportTemplateDTO> endList, ReportSearchParam reportSearchParam, Map<String, String> finalTerminalMap, DeviceUnitCommDTO deviceUnitCommDTO, JSONArray jsonArray) {
        if (CollUtil.isNotEmpty(endList)) {
            //数据单位信息
            Map<String, String> unit = unitMap(deviceUnitCommDTO);
            //进行反向赋值到模板
            //1、根据itemName分组
            Map<String, List<ReportTemplateDTO>> assMap = endList.stream().collect(Collectors.groupingBy(ReportTemplateDTO::getItemName));
            //2、把itemName的value赋给v和m
            jsonArray.forEach(item -> {
                JSONObject jsonObject = (JSONObject) item;
                if ("合格率".equals(jsonObject.getStr("name"))) {
                    //新增合格率sheet处理
                    Map<String, String> rateMap = assemblePassRateResult(reportSearchParam);

                    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);

                                if (v.charAt(0) == '&') {
                                    //结论
                                    String tem = v.replace(STR_THREE, "").toUpperCase();
                                    if (!finalTerminalMap.isEmpty()) {
                                        if ("STATIS_TIME".equals(tem)) {
                                            //如何时间是大于当前时间则用当前时间
                                            String localTime = InfluxDbSqlConstant.END_TIME;
                                            LocalDate localDate = LocalDateTimeUtil.parseDate(reportSearchParam.getEndTime(), DatePattern.NORM_DATE_PATTERN);
                                            LocalDate nowDate = LocalDate.now();
                                            if (nowDate.isAfter(localDate)) {
                                                son.set(V, reportSearchParam.getStartTime() + InfluxDbSqlConstant.START_TIME + "_" + reportSearchParam.getEndTime() + localTime);
                                            } else {
                                                localTime = " " + LocalTime.now().format(DatePattern.NORM_TIME_FORMATTER);
                                                son.set(V, reportSearchParam.getStartTime() + InfluxDbSqlConstant.START_TIME + "_" + nowDate + localTime);
                                            }
                                        } else {
                                            //台账信息
                                            son.set(V, finalTerminalMap.getOrDefault(tem, "/"));
                                        }
                                    }
                                } else if (v.charAt(0) == '$') {
                                    if (rateMap.containsKey(v)) {
                                        String val = rateMap.get(v);
                                        son.set(V,val);
                                        if(v.contains("#all$")){
                                            if(Double.parseDouble(val) < 98){
                                                son.set("fc", "#990000");
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    });
                } else {
                    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, "").toUpperCase());
                                    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, "").toUpperCase());
                                    if (Objects.nonNull(rDto)) {
                                        str = rDto.get(0).getValue();
                                        //没有值，赋"/"
                                        if (StringUtils.isBlank(str)) {
                                            str = "/";
                                        }
                                        son.set(V, str);
                                        if (str.contains("不合格")) {
                                            son.set("fc", "#990000");
                                        }
                                    }
                                } else if (v.charAt(0) == '&') {
                                    //结论
                                    String tem = v.replace(STR_THREE, "").toUpperCase();
                                    if (!finalTerminalMap.isEmpty()) {
                                        if ("STATIS_TIME".equals(tem)) {
                                            //如何时间是大于当前时间则用当前时间
                                            String localTime = InfluxDbSqlConstant.END_TIME;
                                            LocalDate localDate = LocalDateTimeUtil.parseDate(reportSearchParam.getEndTime(), DatePattern.NORM_DATE_PATTERN);
                                            LocalDate nowDate = LocalDate.now();
                                            if (nowDate.isAfter(localDate)) {
                                                son.set(V, reportSearchParam.getStartTime() + InfluxDbSqlConstant.START_TIME + "_" + reportSearchParam.getEndTime() + localTime);
                                            } else {
                                                localTime = " " + LocalTime.now().format(DatePattern.NORM_TIME_FORMATTER);
                                                son.set(V, reportSearchParam.getStartTime() + InfluxDbSqlConstant.START_TIME + "_" + nowDate + localTime);
                                            }
                                        } else {
                                            //台账信息
                                            son.set(V, finalTerminalMap.getOrDefault(tem, "/"));
                                        }
                                    }
                                }
                                //解决数据单位问题 @指标#类型@
                                if (v.charAt(0) == '@' && v.contains(STR_ONE)) {
                                    String replace = v.replace("@", "");
                                    son.set(V, unit.getOrDefault(replace, "/"));

                                }
                            }
                        }
                    });
                }
            });
        }
    }

    /**
     * map key转大写
     */
    public <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;
    }

    // 5. 添加线程池销毁方法
    @PreDestroy
    public void destroy() {
        executorService.shutdown();
    }
}
