package com.njcn.csreport.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsCommTerminalFeignClient;
import com.njcn.csdevice.api.CsLedgerFeignClient;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.pojo.dto.DevDetailDTO;
import com.njcn.csdevice.pojo.dto.LineParamDTO;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.csharmonic.api.EventFeignClient;
import com.njcn.csharmonic.api.RStatLimitRateDFeignClient;
import com.njcn.csharmonic.api.SysExcelFeignClient;
import com.njcn.csharmonic.api.SysExcelRelationFeignClient;
import com.njcn.csharmonic.enums.CsHarmonicResponseEnum;
import com.njcn.csharmonic.pojo.param.StatSubstationBizBaseParam;
import com.njcn.csharmonic.pojo.po.CsEventPO;
import com.njcn.csharmonic.pojo.po.RStatLimitRateDPO;
import com.njcn.csreport.mapper.CsAppReportMapper;
import com.njcn.csreport.pojo.po.CsAppReport;
import com.njcn.csreport.pojo.vo.ReportEventVO;
import com.njcn.csreport.pojo.vo.ReportHarmonicVO;
import com.njcn.csreport.service.ICsAppReportService;
import com.njcn.cssystem.utils.TimeUtil;
import com.njcn.device.biz.pojo.po.PqsDeviceUnit;
import com.njcn.device.pq.pojo.vo.AreaLineInfoVO;
import com.njcn.event.common.service.CommMonitorEventReportService;
import com.njcn.harmonic.common.mapper.ExcelRptTempMapper;
import com.njcn.harmonic.common.pojo.dto.DeviceUnitCommDTO;
import com.njcn.harmonic.common.pojo.vo.ReportTemplateVO;
import com.njcn.harmonic.common.service.CustomReportTableService;
import com.njcn.harmonic.pojo.param.ReportSearchParam;
import com.njcn.harmonic.pojo.po.ExcelRptTemp;
import com.njcn.harmonic.pojo.po.excel.SysExcel;
import com.njcn.harmonic.utils.PublicDataUtils;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.constant.UserType;
import com.njcn.user.pojo.vo.UserVO;
import com.njcn.web.utils.RequestUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xy
 * @since 2026-03-19
 */
@Service
@AllArgsConstructor
@Slf4j
public class CsAppReportServiceImpl extends ServiceImpl<CsAppReportMapper, CsAppReport> implements ICsAppReportService {

    private final RStatLimitRateDFeignClient rStatLimitRateDClient;
    private final CsLineFeignClient csLineFeignClient;
    private final SysExcelFeignClient sysExcelClient;
    private final SysExcelRelationFeignClient sysExcelRelationClient;
    private final DicDataFeignClient dicDataFeignClient;
    private final ExcelRptTempMapper excelRptTempMapper;
    private final CsCommTerminalFeignClient csCommTerminalFeignClient;
    private final CustomReportTableService customReportTableService;
    private final FileStorageUtil fileStorageUtil;
    private final UserFeignClient userFeignClient;
    private final EventFeignClient eventFeignClient;
    private final CommMonitorEventReportService commMonitorEventReportService;
    private final CsLedgerFeignClient csLedgerFeignClient;

    @Override
    public List<ReportHarmonicVO> getReportList(LineParamDTO param) {
        String[] timeRange = PublicDataUtils.calculateTimeRange(param.getTime());
        String startTime = timeRange[0];
        String endTime = timeRange[1];
        LocalDate startLocalDate = LocalDate.parse(startTime, DateTimeFormatter.ISO_LOCAL_DATE);
        LocalDate endLocalDate = LocalDate.parse(endTime, DateTimeFormatter.ISO_LOCAL_DATE);

        List<TimeRange> timeRanges;
        if (param.getTimeType() == 0) {
            timeRanges = splitIntoDays(startLocalDate, endLocalDate);
        } else {
            timeRanges = splitIntoMonthsForCurrentYear(endLocalDate);
        }

        String queryStartTime = timeRanges.get(timeRanges.size() - 1).start.format(DateTimeFormatter.ISO_LOCAL_DATE);
        String queryEndTime = timeRanges.get(0).end.format(DateTimeFormatter.ISO_LOCAL_DATE);

        StatSubstationBizBaseParam rStatLimitQueryParam = new StatSubstationBizBaseParam();
        rStatLimitQueryParam.setIds(Collections.singletonList(param.getLineId()));
        rStatLimitQueryParam.setStartTime(queryStartTime);
        rStatLimitQueryParam.setEndTime(queryEndTime);
        List<RStatLimitRateDPO> limitRates =  rStatLimitRateDClient.getLinesRate(rStatLimitQueryParam).getData();
        CsLinePO po = csLineFeignClient.getById(param.getLineId()).getData();
        return timeRanges.stream().map(weekRange -> {
            List<RStatLimitRateDPO> weekData = limitRates.stream()
                    .filter(rate -> !rate.getTime().isBefore(weekRange.start) && !rate.getTime().isAfter(weekRange.end))
                    .collect(Collectors.toList());

            ReportHarmonicVO vo = new ReportHarmonicVO();
            vo.setLineId(param.getLineId());
            vo.setLineName(po.getName());
            vo.setStartTime(weekRange.start.format(DateTimeFormatter.ISO_LOCAL_DATE));
            vo.setEndTime(weekRange.end.format(DateTimeFormatter.ISO_LOCAL_DATE));
            vo.setOverLimitDesc(buildOverLimitDesc(weekData,po.getLineInterval()));
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public String downloadHarmonicReport(LineParamDTO param) {
        String filePath = "";
        //先查询是否已经生成过文件
        LambdaQueryWrapper<CsAppReport> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CsAppReport::getLineId, param.getLineId())
                .eq(CsAppReport::getStartTime, param.getStartTime())
                .eq(CsAppReport::getEndTime, param.getEndTime())
                .eq(CsAppReport::getReportType, 0);
        CsAppReport report = this.getOne(queryWrapper);
        if (report != null) {
            filePath = report.getFilePath();
            if (filePath != null) {
                return fileStorageUtil.getFileUrl(filePath);
            } else {
                return "报表文件缺失,请联系管理员!";
            }
        }
        //没有则生成报告，并返回报告路径
        ReportSearchParam reportSearchParam = new ReportSearchParam();
        reportSearchParam.setLineId(param.getLineId());
        reportSearchParam.setStartTime(param.getStartTime());
        reportSearchParam.setEndTime(param.getEndTime());
        reportSearchParam.setResourceType(1);

        List<SysExcel> sysExcels = sysExcelClient.querySysExcel().getData();
        if (CollectionUtil.isNotEmpty(sysExcels)) {
            SysExcel sysExcel = sysExcels.stream()
                    .filter(item -> Objects.equals(item.getExcelType(), "2"))
                    .findFirst()
                    .orElseThrow(() -> new BusinessException("excel报表模板缺失!"));
            String tempId = getTempId(sysExcel.getId(), param.getLineId());
            reportSearchParam.setTempId(tempId);
            ExcelRptTemp excelRptTemp = excelRptTempMapper.selectById(tempId);
            if (Objects.isNull(excelRptTemp)) {
                throw new BusinessException(CsHarmonicResponseEnum.CUSTOM_REPORT_ACTIVE);
            }
            //通用报表
            Map<String,String> map = csLineFeignClient.getCustomDetailByLineId(param.getLineId()).getData();
            Map<String,String> newMap = convertKeysToUpperCase(map);
            PqsDeviceUnit deviceUnit  = csCommTerminalFeignClient.lineUnitDetail(param.getLineId()).getData();
            DeviceUnitCommDTO deviceUnitCommDTO = BeanUtil.copyProperties(deviceUnit, DeviceUnitCommDTO.class);
            filePath = customReportTableService.saveStableEventReport(reportSearchParam,newMap,deviceUnitCommDTO);
        }
        if (!Objects.equals(filePath, "") && filePath != null) {
            //存储本次生成的记录
            CsAppReport po = new CsAppReport();
            po.setId(IdUtil.fastSimpleUUID());
            po.setLineId(param.getLineId());
            po.setStartTime(LocalDate.parse(param.getStartTime()));
            po.setEndTime(LocalDate.parse(param.getEndTime()));
            po.setFilePath(filePath);
            po.setReportType(0);
            this.save(po);
        }
        filePath = fileStorageUtil.getFileUrl(filePath);
        return filePath;
    }

    @Override
    public void applicationReport(LineParamDTO param) {
        CsAppReport po = new CsAppReport();
        po.setId(IdUtil.fastSimpleUUID());
        if (Objects.isNull(param.getLineId())) {
            throw new BusinessException("请选择监测点!");
        }
        po.setLineId(param.getLineId());
        po.setEventList(String.join(",", param.getList()));
        po.setStartTime(LocalDate.parse(param.getStartTime()));
        po.setEndTime(LocalDate.parse(param.getEndTime()));
        po.setReportType(1);
        this.save(po);
    }

    @Override
    public Page<ReportEventVO> getApplicationReportList(LineParamDTO param) {
        Page<ReportEventVO> page = new Page<>();
        Page<CsAppReport> page1 = new Page<> (param.getPageNum(), param.getPageSize());


        List<ReportEventVO> result = new ArrayList<>();
        LambdaQueryWrapper<CsAppReport> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.between(CsAppReport::getCreateTime, param.getStartTime(), param.getEndTime())
                .eq(CsAppReport::getReportType, 1)
                .orderByDesc(CsAppReport::getCreateTime);
        //获取当前用户
        UserVO userVO = userFeignClient.getUserById(RequestUtil.getUserIndex()).getData();
        if (!userVO.getType().equals(UserType.SUPER_ADMINISTRATOR) && !userVO.getType().equals(UserType.ADMINISTRATOR)) {
            queryWrapper.eq(CsAppReport::getCreateBy, userVO.getId());
        }
        Page<CsAppReport> page2 = this.baseMapper.selectPage(page1,queryWrapper);
        BeanUtil.copyProperties(page2, page);
        List<CsAppReport> list = page2.getRecords();

//        List<CsAppReport> list = this.list(queryWrapper);
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(item->{
                ReportEventVO vo = new ReportEventVO();
                vo.setEventId(item.getId());
                vo.setTime(item.getCreateTime());
                vo.setEventNums(item.getEventList().split(",").length);
                vo.setFilePath(item.getFilePath());
                vo.setIsComplete(Objects.isNull(item.getFilePath()) ? 0 : 1);
                String applyUser = item.getCreateBy();
                if (applyUser != null && !applyUser.isEmpty()) {
                    UserVO applyUserVo = userFeignClient.getUserById(applyUser).getData();
                    vo.setApplyUser(Objects.isNull(applyUserVo)? null : applyUserVo.getName());
                } else {
                    vo.setApplyUser(null);
                }
                CsLinePO linePO = csLineFeignClient.getById(item.getLineId()).getData();
                DevDetailDTO devDetailDTO = csLedgerFeignClient.queryDevDetail(linePO.getDeviceId()).getData();
                vo.setLineName(linePO.getName());
                vo.setDeviceName(devDetailDTO.getEquipmentName());
                vo.setProjectName(devDetailDTO.getProjectName());
                vo.setEngineeringName(devDetailDTO.getEngineeringName());

                result.add(vo);
                page.setRecords(result);
            });
        }
        return page;
    }

    @Override
    public Boolean createEventReport(String id) {
        if (StringUtils.isBlank(id)) {
            throw new BusinessException("id缺失");
        }
        CsAppReport report = this.getById(id);
        if (report == null) {
            throw new BusinessException("报告记录缺失");
        }
        //生成暂态报告
        //step1: 获取暂态事件
        String eventIds = report.getEventList();
        if (StringUtils.isBlank(eventIds)) {
            throw new BusinessException("暂态事件缺失");
        }
        List<String> eventIdList = Arrays.asList(eventIds.split(","));
        //获取事件集合
        List<CsEventPO> eventList = eventFeignClient.getEventByIdList(eventIdList).getData();
        // 收集缺失波形文件的事件
        List<CsEventPO> missingWaveEventList = eventList.stream()
                .filter(item -> StringUtils.isBlank(item.getWavePath()))
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(missingWaveEventList)) {
            throw new BusinessException("所选的暂态事件波形缺失，无法生成报告");
        }
        //获取监测点id集合
        List<String> lineIdList = eventList.stream().map(CsEventPO::getLineId).distinct().collect(Collectors.toList());
        //获取监测点集合
        List<CsLinePO> lineList = csLineFeignClient.queryLineById(lineIdList).getData();
        Map<String,CsLinePO> lineMap = lineList.stream().collect(Collectors.toMap(CsLinePO::getLineId, item->item));
        Map<String, AreaLineInfoVO> map = new HashMap<>();
        AtomicReference<String> lineName = new AtomicReference<>();
        eventList.forEach(item->{
            CsLinePO po = lineMap.get(item.getLineId());
            AreaLineInfoVO vo = new AreaLineInfoVO();
            //获取台账信息
            DevDetailDTO devDetailDTO =csLedgerFeignClient.queryDevDetail(po.getDeviceId()).getData();
            vo.setGdName(devDetailDTO.getEngineeringName());
            vo.setSubName(devDetailDTO.getProjectName());
            vo.setIp(devDetailDTO.getDevMac());
            vo.setLineId(po.getLineId());
            vo.setNum(Objects.isNull(po.getLineNo())?po.getClDid():po.getLineNo());
            lineName.set(po.getName());
            vo.setLineName(po.getName());
            vo.setPt1(po.getPtRatio().intValue());
            vo.setPt2(Objects.isNull(po.getPt2Ratio())?1:po.getPt2Ratio().intValue());
            vo.setCt1(po.getCtRatio().intValue());
            vo.setCt2(Objects.isNull(po.getCt2Ratio())?1:po.getCt2Ratio().intValue());
            vo.setPtType(po.getConType());
            map.put(item.getId(),vo);
        });
        //step2: 生成事件报告
        String fileName = "暂降事件报告_" + lineName.get() + LocalDateTime.now().format(DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_PATTERN)) + ".docx";
        String filePath = commMonitorEventReportService.saveStableEventReport(eventIdList,map,fileName);
        //step3: 存储文件服务器
        report.setFilePath(filePath);
        return this.updateById(report);
    }

    @Override
    public String downloadEventReport(String id) {
        if (StringUtils.isBlank(id)) {
            log.warn("下载事件报表失败，报表 ID 为空");
            return  "id缺失";

        }

        CsAppReport report = this.getById(id);
        if (report == null) {
            log.warn("下载事件报表失败，报表不存在，ID: {}", id);
            return  "事件不存在";
        }

        String filePath = report.getFilePath();
        if (filePath == null) {
            log.warn("下载事件报表失败，报表文件缺失，ID: {}, 报表数据：{}", id, report);
            return "报表文件缺失，请联系管理员!";
        }

        try {
            return fileStorageUtil.getFileUrl(filePath);
        } catch (Exception e) {
            log.error("获取文件 URL 失败，ID: {}, 文件路径：{}", id, filePath, e);
            return "获取文件下载地址失败，请稍后重试";
        }
    }

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

        return newMap;
    }

    public String getTempId(String oldTempId, String lineId) {
        //根据模板类型的id获取模板
        List<ReportTemplateVO> result = sysExcelRelationClient.queryList(oldTempId).getData();
        if (CollUtil.isEmpty(result)) {
            throw new BusinessException("未配置相关模板");
        }
        //根据监测点获取接线方式
        CsLinePO po = csLineFeignClient.getById(lineId).getData();
        //根据接线方式获取模板id
        int conType = po.getConType();

        DictData dicData;
        //角型
        if (conType == 1) {
            dicData = dicDataFeignClient.getDicDataByCode(DicDataEnum.STAR_TRIANGLE.getCode()).getData();
        }
        //v型
        else if (conType == 2){
            dicData = dicDataFeignClient.getDicDataByCode(DicDataEnum.OPEN_DELTA.getCode()).getData();
        }
        //星型 或 其他
        else {
            dicData = dicDataFeignClient.getDicDataByCode(DicDataEnum.STAR.getCode()).getData();
        }
        String tempId;
        Optional<ReportTemplateVO> vo = result.stream().filter(item -> Objects.equals(dicData.getId(),item.getWiringMethod())).findFirst();
        if (vo.isPresent()) {
            tempId = vo.get().getId();
        } else {
            throw new BusinessException("未找到此接线方式的模板");
        }
        return tempId;
    }

    private List<TimeRange> splitIntoDays(LocalDate startDate, LocalDate endDate) {
        List<TimeRange> ranges = new ArrayList<>();
        LocalDate current = endDate;
        while (!current.isBefore(startDate)) {
            ranges.add(new TimeRange(current, current));
            current = current.minusDays(1);
        }
        return ranges;
    }

    private List<TimeRange> splitIntoMonthsForCurrentYear(LocalDate now) {
        List<TimeRange> timeRanges = new ArrayList<>();
        int currentYear = now.getYear();
        int nowYear = LocalDate.now().getYear();
        int num = LocalDate.now().getMonthValue();
        if (currentYear < nowYear) {
            num = 12;
        }
        for (int month = num; month >= 1; month--) {
            LocalDate monthStart = LocalDate.of(currentYear, month, 1);
            LocalDate monthEnd;

            if (month == now.getMonthValue()) {
                monthEnd = now;
            } else {
                monthEnd = monthStart.withDayOfMonth(monthStart.lengthOfMonth());
            }

            timeRanges.add(new TimeRange(monthStart, monthEnd));
        }
        return timeRanges;
    }


    //fixme 代码较为冗余，后期可以采用反射的方式进行优化
    private String buildOverLimitDesc(List<RStatLimitRateDPO> dataList,Integer lineInterval) {
        String tag = "";
        if (Objects.isNull(lineInterval)) {
            lineInterval = 1;
        }
        int maxData = dataList.size() * 24 * 60;
        RStatLimitRateDPO result = new RStatLimitRateDPO();
        if (CollectionUtil.isNotEmpty(dataList)) {
            int data1 = 0,data2 = 0,data3 = 0,data4 = 0,data5 = 0,data6 = 0,data7 = 0,data8 = 0,data9 = 0,data10 = 0
                    ,data11 = 0,data12 = 0,data13 = 0,data14 = 0,data15 = 0,data16 = 0,data17 = 0,data18 = 0,data19 = 0,data20 = 0
                    ,data21 = 0,data22 = 0,data23 = 0,data24 = 0,data25 = 0,data26 = 0,data27 = 0,data28 = 0,data29 = 0,data30 = 0
                    ,data31 = 0,data32 = 0,data33 = 0,data34 = 0,data35 = 0,data36 = 0,data37 = 0,data38 = 0,data39 = 0,data40 = 0
                    ,data41 = 0,data42 = 0,data43 = 0,data44 = 0,data45 = 0,data46 = 0,data47 = 0,data48 = 0,data49 = 0,data50 = 0
                    ,data51 = 0,data52 = 0,data53 = 0,data54 = 0,data55 = 0,data56 = 0,data57 = 0,data58 = 0,data59 = 0,data60 = 0
                    ,data61 = 0,data62 = 0,data63 = 0,data64 = 0,data65 = 0,data66 = 0,data67 = 0,data68 = 0,data69 = 0,data70 = 0;
            for (RStatLimitRateDPO item : dataList) {
                result.setLineId(item.getLineId());

                data1 = data1 + item.getFreqDevOvertime();
                result.setFreqDevOvertime(data1);

                data2 = data2 + item.getVoltageDevOvertime();
                result.setVoltageDevOvertime(data2);

                data3 = data3 + item.getUbalanceOvertime();
                result.setUbalanceOvertime(data3);

                data4 = data4 + item.getFlickerOvertime();
                result.setFlickerOvertime(data4);

                data5 = data5 + item.getUaberranceOvertime();
                result.setUaberranceOvertime(data5);

                data6 = data6 + item.getUharm2Overtime();
                result.setUharm2Overtime(data6);

                data7 = data7 + item.getUharm3Overtime();
                result.setUharm3Overtime(data7);

                data8 = data8 + item.getUharm4Overtime();
                result.setUharm4Overtime(data8);

                data9 = data9 + item.getUharm5Overtime();
                result.setUharm5Overtime(data9);

                data10 = data10 + item.getUharm6Overtime();
                result.setUharm6Overtime(data10);

                data11 = data11 + item.getUharm7Overtime();
                result.setUharm7Overtime(data11);

                data12 = data12 + item.getUharm8Overtime();
                result.setUharm8Overtime(data12);

                data13 = data13 + item.getUharm9Overtime();
                result.setUharm9Overtime(data13);

                data14 = data14 + item.getUharm10Overtime();
                result.setUharm10Overtime(data14);

                data15 = data15 + item.getUharm11Overtime();
                result.setUharm11Overtime(data15);

                data16 = data16 + item.getUharm12Overtime();
                result.setUharm12Overtime(data16);

                data17 = data17 + item.getUharm13Overtime();
                result.setUharm13Overtime(data17);

                data18 = data18 + item.getUharm14Overtime();
                result.setUharm14Overtime(data18);

                data19 = data19 + item.getUharm15Overtime();
                result.setUharm15Overtime(data19);

                data20 = data20 + item.getUharm16Overtime();
                result.setUharm16Overtime(data20);

                data21 = data21 + item.getUharm17Overtime();
                result.setUharm17Overtime(data21);

                data22 = data22 + item.getUharm18Overtime();
                result.setUharm18Overtime(data22);

                data23 = data23 + item.getUharm19Overtime();
                result.setUharm19Overtime(data23);

                data24 = data24 + item.getUharm20Overtime();
                result.setUharm20Overtime(data24);

                data25 = data25 + item.getUharm21Overtime();
                result.setUharm21Overtime(data25);

                data26 = data26 + item.getUharm22Overtime();
                result.setUharm22Overtime(data26);

                data27 = data27 + item.getUharm23Overtime();
                result.setUharm23Overtime(data27);

                data28 = data28 + item.getUharm24Overtime();
                result.setUharm24Overtime(data28);

                data29 = data29 + item.getUharm25Overtime();
                result.setUharm25Overtime(data29);

                data30 = data30 + item.getIharm2Overtime();
                result.setIharm2Overtime(data30);

                data31 = data31 + item.getIharm3Overtime();
                result.setIharm3Overtime(data31);

                data32 = data32 + item.getIharm4Overtime();
                result.setIharm4Overtime(data32);

                data33 = data33 + item.getIharm5Overtime();
                result.setIharm5Overtime(data33);

                data34 = data34 + item.getIharm6Overtime();
                result.setIharm6Overtime(data34);

                data35 = data35 + item.getIharm7Overtime();
                result.setIharm7Overtime(data35);

                data36 = data36 + item.getIharm8Overtime();
                result.setIharm8Overtime(data36);

                data37 = data37 + item.getIharm9Overtime();
                result.setIharm9Overtime(data37);

                data38 = data38 + item.getIharm10Overtime();
                result.setIharm10Overtime(data38);

                data39 = data39 + item.getIharm11Overtime();
                result.setIharm11Overtime(data39);

                data40 = data40 + item.getIharm12Overtime();
                result.setIharm12Overtime(data40);

                data41 = data41 + item.getIharm13Overtime();
                result.setIharm13Overtime(data41);

                data42 = data42 + item.getIharm14Overtime();
                result.setIharm14Overtime(data42);

                data43 = data43 + item.getIharm15Overtime();
                result.setIharm15Overtime(data43);

                data44 = data44 + item.getIharm16Overtime();
                result.setIharm16Overtime(data44);

                data45 = data45 + item.getIharm17Overtime();
                result.setIharm17Overtime(data45);

                data46 = data46 + item.getIharm18Overtime();
                result.setIharm18Overtime(data46);

                data47 = data47 + item.getIharm19Overtime();
                result.setIharm19Overtime(data47);

                data48 = data48 + item.getIharm20Overtime();
                result.setIharm20Overtime(data48);

                data49 = data49 + item.getIharm21Overtime();
                result.setIharm21Overtime(data49);

                data50 = data50 + item.getIharm22Overtime();
                result.setIharm22Overtime(data50);

                data51 = data51 + item.getIharm23Overtime();
                result.setIharm23Overtime(data51);

                data52 = data52 + item.getIharm24Overtime();
                result.setIharm24Overtime(data52);

                data53 = data53 + item.getIharm25Overtime();
                result.setIharm25Overtime(data53);

                data54 = data54 + item.getInuharm1Overtime();
                result.setInuharm1Overtime(data54);

                data55 = data55 + item.getInuharm2Overtime();
                result.setInuharm2Overtime(data55);

                data56 = data56 + item.getInuharm3Overtime();
                result.setInuharm3Overtime(data56);

                data57 = data57 + item.getInuharm4Overtime();
                result.setInuharm4Overtime(data57);

                data58 = data58 + item.getInuharm5Overtime();
                result.setInuharm5Overtime(data58);

                data59 = data59 + item.getInuharm6Overtime();
                result.setInuharm6Overtime(data59);

                data60 = data60 + item.getInuharm7Overtime();
                result.setInuharm7Overtime(data60);

                data61 = data61 + item.getInuharm8Overtime();
                result.setInuharm8Overtime(data61);

                data62 = data62 + item.getInuharm9Overtime();
                result.setInuharm9Overtime(data62);

                data63 = data63 + item.getInuharm10Overtime();
                result.setInuharm10Overtime(data63);

                data64 = data64 + item.getInuharm11Overtime();
                result.setInuharm11Overtime(data64);

                data65 = data65 + item.getInuharm12Overtime();
                result.setInuharm12Overtime(data65);

                data66 = data66 + item.getInuharm13Overtime();
                result.setInuharm13Overtime(data66);

                data67 = data67 + item.getInuharm14Overtime();
                result.setInuharm14Overtime(data67);

                data68 = data68 + item.getInuharm15Overtime();
                result.setInuharm15Overtime(data68);

                data69 = data69 + item.getInuharm16Overtime();
                result.setInuharm16Overtime(data69);

                data70 = data70 + item.getINegOvertime();
                result.setINegOvertime(data70);
            }
        } else {
            return tag;
        }

        // 基础越限项
        Integer freqDevOvertime = result.getFreqDevOvertime();
        if (freqDevOvertime > 0) {
            tag = tag + "频率偏差越限" + TimeUtil.convertMinutes(Math.min(freqDevOvertime * lineInterval,maxData)) + "，";
        }

        Integer voltageDevOvertime = result.getVoltageDevOvertime();
        if (voltageDevOvertime > 0) {
            tag = tag + "电压偏差越限" + TimeUtil.convertMinutes(Math.min(voltageDevOvertime * lineInterval,maxData)) + "，";
        }

        Integer ubalanceOvertime = result.getUbalanceOvertime();
        if (ubalanceOvertime > 0) {
            tag = tag + "三相电压不平衡度越限" + TimeUtil.convertMinutes(Math.min(ubalanceOvertime * lineInterval,maxData)) + "，";
        }

        Integer flickerOvertime = result.getFlickerOvertime();
        if (flickerOvertime > 0) {
            tag = tag + "闪变越限" + TimeUtil.convertMinutes(Math.min(flickerOvertime * lineInterval,maxData)) + "，";
        }

        Integer uaberranceOvertime = result.getUaberranceOvertime();
        if (uaberranceOvertime > 0) {
            tag = tag + "电压总谐波畸变率越限" + TimeUtil.convertMinutes(Math.min(uaberranceOvertime * lineInterval,maxData)) + "，";
        }

        Integer iNegOvertime = result.getINegOvertime();
        if (iNegOvertime > 0) {
            tag = tag + "负序电流越限" + TimeUtil.convertMinutes(Math.min(iNegOvertime * lineInterval,maxData)) + "，";
        }

        // 谐波电压含有率（2-25 次）
        tag = buildHarmonicVoltageTags(result, tag, lineInterval, maxData);

        // 谐波电流有效值（2-25 次）
        tag = buildHarmonicCurrentTags(result, tag, lineInterval, maxData);

        // 间谐波电压含有率（0.5-15.5 次）
        tag = buildInterharmonicVoltageTags(result, tag, lineInterval, maxData);

        // 去除末尾逗号
        return trimTrailingComma(tag);
    }

    private static class TimeRange {
        LocalDate start;
        LocalDate end;

        TimeRange(LocalDate start, LocalDate end) {
            this.start = start;
            this.end = end;
        }
    }

    /**
     * 批量构建谐波电压含有率 tag（2-25 次）
     *
     * @param item        数据对象
     * @param originalTag 原始 tag
     * @return 组装后的 tag
     */
    public static String buildHarmonicVoltageTags(Object item, String originalTag, Integer lineInterval, Integer maxData) {
        String tag = originalTag;
        for (int i = 2; i <= 25; i++) {
            String fieldName = "uharm" + i + "Overtime";
            Integer value = (Integer) ReflectUtil.getFieldValue(item, fieldName);
            if (value != null && value > 0) {
                tag = tag + i + "次谐波电压含有率越限" + TimeUtil.convertMinutes(Math.min(value*lineInterval,maxData)) + "，";
            }
        }
        return tag;
    }

    /**
     * 批量构建谐波电流有效值 tag（2-25 次）
     *
     * @param item        数据对象
     * @param originalTag 原始 tag
     * @return 组装后的 tag
     */
    public static String buildHarmonicCurrentTags(Object item, String originalTag, Integer lineInterval, Integer maxData) {
        String tag = originalTag;
        for (int i = 2; i <= 25; i++) {
            String fieldName = "iharm" + i + "Overtime";
            Integer value = (Integer) ReflectUtil.getFieldValue(item, fieldName);
            if (value != null && value > 0) {
                tag = tag + i + "次谐波电流有效值越限" + TimeUtil.convertMinutes(Math.min(value*lineInterval,maxData)) + "，";
            }
        }
        return tag;
    }

    /**
     * 批量构建间谐波电压含有率 tag（0.5-15.5 次）
     *
     * @param item        数据对象
     * @param originalTag 原始 tag
     * @return 组装后的 tag
     */
    public static String buildInterharmonicVoltageTags(Object item, String originalTag, Integer lineInterval, Integer maxData) {
        String tag = originalTag;
        for (int i = 1; i <= 16; i++) {
            String fieldName = "inuharm" + i + "Overtime";
            Integer value = (Integer) ReflectUtil.getFieldValue(item, fieldName);
            if (value != null && value > 0) {
                double harmonicOrder = i * 1.0 - 0.5;
                tag = tag + harmonicOrder + "次间谐波电压含有率越限" + TimeUtil.convertMinutes(Math.min(value*lineInterval,maxData)) + "，";
            }
        }
        return tag;
    }

    /**
     * 去除字符串末尾的逗号
     *
     * @param str 原字符串
     * @return 处理后的字符串
     */
    public static String trimTrailingComma(String str) {
        return StrUtil.endWith(str, "，") ? StrUtil.subPre(str, str.length() - 1) : str;
    }
}
