package com.njcn.gather.steady.checksquare.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.gather.steady.checksquare.component.SteadyChecksquareCalculator;
import com.njcn.gather.steady.checksquare.component.SteadyChecksquareHarmonicParityRuleComponent;
import com.njcn.gather.steady.checksquare.component.SteadyChecksquareInfluxQueryComponent;
import com.njcn.gather.steady.checksquare.component.SteadyChecksquareValueOrderRuleComponent;
import com.njcn.gather.steady.checksquare.pojo.constant.SteadyChecksquareConst;
import com.njcn.gather.steady.checksquare.pojo.param.SteadyChecksquareHistoryQueryParam;
import com.njcn.gather.steady.checksquare.pojo.param.SteadyChecksquareQueryParam;
import com.njcn.gather.steady.checksquare.pojo.po.SteadyChecksquareDetailPO;
import com.njcn.gather.steady.checksquare.pojo.po.SteadyChecksquareItemPO;
import com.njcn.gather.steady.checksquare.pojo.po.SteadyChecksquareStatSummaryPO;
import com.njcn.gather.steady.checksquare.pojo.po.SteadyChecksquareTaskPO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareHarmonicParityDetailVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareHarmonicParityRuleVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareItemDetailVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareItemVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareQueryVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareSegmentVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareStatDetailVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareStatSummaryVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareTaskVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareValueOrderDetailVO;
import com.njcn.gather.steady.checksquare.pojo.vo.SteadyChecksquareValueOrderRuleVO;
import com.njcn.gather.steady.checksquare.service.SteadyChecksquareDetailService;
import com.njcn.gather.steady.checksquare.service.SteadyChecksquareItemService;
import com.njcn.gather.steady.checksquare.service.SteadyChecksquareService;
import com.njcn.gather.steady.checksquare.service.SteadyChecksquareStatSummaryService;
import com.njcn.gather.steady.checksquare.service.SteadyChecksquareTaskService;
import com.njcn.gather.steady.checksquare.util.SteadyChecksquareIdUtil;
import com.njcn.gather.steady.datavie.component.SteadyTrendIndicatorCatalog;
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendIndicatorDefinitionBO;
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO;
import com.njcn.gather.tool.adddata.component.AddDataTimeSlotCalculator;
import com.njcn.gather.tool.addledger.pojo.constant.AddLedgerConst;
import com.njcn.gather.tool.addledger.pojo.vo.AddLedgerLinePathVO;
import com.njcn.gather.tool.addledger.service.AddLedgerService;
import com.njcn.web.factory.PageFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.stream.Collectors;

/**
 * 数据校验服务实现。 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SteadyChecksquareServiceImpl implements SteadyChecksquareService {

    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final String EMPTY_TEXT = "-";
    private static final int FLICKER_SHORT_INTERVAL_MINUTES = 10;
    private static final int FLICKER_LONG_INTERVAL_MINUTES = 120;
    private static final int HARMONIC_AGGREGATE_ORDER_START = 2;
    private static final int HARMONIC_AGGREGATE_ORDER_END = 50;
    private static final long MAX_CREATE_RANGE_DAYS = 7L;
    private static final int DETAIL_SAVE_BATCH_SIZE = 1000;

    private final SteadyTrendIndicatorCatalog indicatorCatalog;
    private final SteadyChecksquareInfluxQueryComponent influxQueryComponent;
    private final SteadyChecksquareCalculator calculator;
    private final SteadyChecksquareValueOrderRuleComponent valueOrderRuleComponent;
    private final SteadyChecksquareHarmonicParityRuleComponent harmonicParityRuleComponent;
    private final AddDataTimeSlotCalculator timeSlotCalculator;
    private final AddLedgerService addLedgerService;
    private final SteadyChecksquareTaskService taskService;
    private final SteadyChecksquareItemService itemService;
    private final SteadyChecksquareStatSummaryService statSummaryService;
    private final SteadyChecksquareDetailService detailService;
    private final ObjectMapper objectMapper;

    @Autowired(required = false)
    private TransactionTemplate transactionTemplate;

    @Autowired(required = false)
    @Qualifier("steadyChecksquareExecutorService")
    private ExecutorService steadyChecksquareExecutorService;

    @Override
    public Page<SteadyChecksquareTaskVO> query(SteadyChecksquareHistoryQueryParam param) {
        SteadyChecksquareHistoryQueryParam query = param == null ? new SteadyChecksquareHistoryQueryParam() : param;
        LambdaQueryWrapper<SteadyChecksquareTaskPO> wrapper = new LambdaQueryWrapper<SteadyChecksquareTaskPO>()
                .eq(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_ENABLED)
                .like(trimToNull(query.getLineId()) != null, SteadyChecksquareTaskPO::getLineIdsText, "|" + trimToNull(query.getLineId()) + "|")
                .like(trimToNull(query.getIndicatorCode()) != null, SteadyChecksquareTaskPO::getIndicatorCodesText, "|" + trimToNull(query.getIndicatorCode()) + "|")
                .ge(trimToNull(query.getTimeStart()) != null, SteadyChecksquareTaskPO::getTimeStart, parseOptionalTime(query.getTimeStart()))
                .le(trimToNull(query.getTimeEnd()) != null, SteadyChecksquareTaskPO::getTimeEnd, parseOptionalTime(query.getTimeEnd()))
                .gt(Boolean.TRUE.equals(query.getHasAbnormal()), SteadyChecksquareTaskPO::getAbnormalItemCount, 0)
                .orderByDesc(SteadyChecksquareTaskPO::getCreateTime);
        Page<SteadyChecksquareTaskPO> page = taskService.page(new Page<SteadyChecksquareTaskPO>(
                PageFactory.getPageNum(query), PageFactory.getPageSize(query)), wrapper);
        Page<SteadyChecksquareTaskVO> result = new Page<SteadyChecksquareTaskVO>(page.getCurrent(), page.getSize(), page.getTotal());
        result.setRecords(page.getRecords().stream().map(this::toTaskVO).collect(Collectors.toList()));
        return result;
    }

    @Override
    public SteadyChecksquareTaskVO create(SteadyChecksquareQueryParam param) {
        long createStartMillis = System.currentTimeMillis();
        validateCreateBaseParam(param);
        List<String> lineIds = resolveLineIds(param);
        LocalDateTime startTime = parseRequiredTime(param.getTimeStart(), "开始时间不能为空");
        LocalDateTime endTime = parseRequiredTime(param.getTimeEnd(), "结束时间不能为空");
        SteadyChecksquareTaskPO existedTask = findExistingTask(lineIds, startTime, endTime);
        if (existedTask != null) {
            log.info("数据校验创建命中已有任务，taskId={}，lineId={}，costMs={}",
                    existedTask.getId(), lineIds, System.currentTimeMillis() - createStartMillis);
            return toTaskVO(existedTask);
        }
        CreateContext context = prepareCreateContext(param);
        SteadyChecksquareQueryParam taskParam = copyCreateParam(param, context.indicatorCodes);
        SteadyChecksquareTaskPO task = saveRunningTaskInTransaction(taskParam, context);
        try {
            submitCreateTask(task.getId(), taskParam);
        } catch (RejectedExecutionException ex) {
            markTaskFail(task.getId(), ex.getMessage());
            throw fail("数据校验任务线程池已满，请稍后重试");
        }
        log.info("数据校验创建任务已提交后台执行，taskId={}，lineId={}，indicatorCount={}，costMs={}",
                task.getId(), context.lineIds, context.indicatorCodes.size(), System.currentTimeMillis() - createStartMillis);
        return toTaskVO(task);
    }
    @Override
    public SteadyChecksquareTaskVO restart(String taskId) {
        SteadyChecksquareTaskPO task = requireTask(taskId);
        if (!SteadyChecksquareConst.TASK_STATUS_FAIL.equals(task.getTaskStatus())) {
            throw fail("只有执行失败的数据校验任务允许重新启动");
        }
        SteadyChecksquareQueryParam taskParam = buildRestartParam(task);
        SteadyChecksquareTaskPO runningTask = resetFailTaskInTransaction(task);
        try {
            submitCreateTask(runningTask.getId(), taskParam);
        } catch (RejectedExecutionException ex) {
            markTaskFail(runningTask.getId(), ex.getMessage());
            throw fail("数据校验任务线程池已满，请稍后重试");
        }
        return toTaskVO(runningTask);
    }

    @Override
    public boolean delete(List<String> taskIds) {
        List<String> ids = normalizeTextList(taskIds);
        if (ids.isEmpty()) {
            throw fail("数据校验任务 ID 不能为空");
        }
        List<SteadyChecksquareTaskPO> tasks = taskService.lambdaQuery()
                .in(SteadyChecksquareTaskPO::getId, ids)
                .eq(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_ENABLED)
                .list();
        if (tasks == null || tasks.size() != ids.size()) {
            throw fail("数据校验任务不存在或已删除");
        }
        if (transactionTemplate != null) {
            return Boolean.TRUE.equals(transactionTemplate.execute(status -> deleteTasksAndItems(ids)));
        }
        return deleteTasksAndItems(ids);
    }

    @Override
    public SteadyChecksquareQueryVO detail(String taskId) {
        SteadyChecksquareTaskPO task = requireTask(taskId);
        List<SteadyChecksquareItemPO> items = itemService.lambdaQuery()
                .eq(SteadyChecksquareItemPO::getTaskId, task.getId())
                .eq(SteadyChecksquareItemPO::getState, SteadyChecksquareConst.STATE_ENABLED)
                .list();
        SteadyChecksquareQueryVO result = new SteadyChecksquareQueryVO();
        result.setTaskId(task.getId());
        result.setTaskNo(task.getTaskNo());
        result.setLineIds(readTaskLineIds(task));
        result.setLineName(task.getLineName());
        result.setTimeStart(formatTime(task.getTimeStart()));
        result.setTimeEnd(formatTime(task.getTimeEnd()));
        result.setIntervalMinutes(task.getIntervalMinutes());
        Map<String, List<SteadyChecksquareStatSummaryVO>> summaryMap = loadSummaryMap(items);
        for (SteadyChecksquareItemPO item : items) {
            SteadyChecksquareItemVO itemVO = toItemVO(item);
            List<SteadyChecksquareStatSummaryVO> summaries = summaryMap.get(item.getId());
            itemVO.setStatSummaries(summaries == null ? new ArrayList<SteadyChecksquareStatSummaryVO>() : summaries);
            result.getItems().add(itemVO);
        }
        return result;
    }

    @Override
    public SteadyChecksquareItemDetailVO itemDetail(String itemId, String detailType, String statType) {
        return itemDetail(itemId, detailType, statType, null, null);
    }

    @Override
    public SteadyChecksquareItemDetailVO itemDetail(String itemId, String detailType, String statType,
                                                   Integer pageNum, Integer pageSize) {
        SteadyChecksquareItemPO item = requireItem(itemId);
        String type = trimToNull(detailType);
        if (type == null) {
            throw fail("明细类型不能为空");
        }
        if (!isSupportedDetailType(type)) {
            throw fail("明细类型不支持：" + type);
        }
        SteadyChecksquareItemDetailVO result = new SteadyChecksquareItemDetailVO();
        result.setItemId(item.getId());
        result.setLineId(item.getLineId());
        result.setLineName(item.getLineName());
        result.setDetailType(type);
        result.setStatType(statType);
        LambdaQueryWrapper<SteadyChecksquareDetailPO> wrapper = new LambdaQueryWrapper<SteadyChecksquareDetailPO>()
                .eq(SteadyChecksquareDetailPO::getItemId, item.getId())
                .eq(SteadyChecksquareDetailPO::getDetailType, type)
                .eq(trimToNull(statType) != null, SteadyChecksquareDetailPO::getStatType, trimToNull(statType))
                .orderByAsc(SteadyChecksquareDetailPO::getStartTime)
                .orderByAsc(SteadyChecksquareDetailPO::getPointTime);
        List<SteadyChecksquareDetailPO> details;
        if (isPaged(pageNum, pageSize)) {
            Page<SteadyChecksquareDetailPO> page = detailService.page(
                    new Page<SteadyChecksquareDetailPO>(pageNum, pageSize), wrapper);
            result.setPageNum((int) page.getCurrent());
            result.setPageSize((int) page.getSize());
            result.setTotal(page.getTotal());
            details = page.getRecords() == null ? new ArrayList<SteadyChecksquareDetailPO>() : page.getRecords();
        } else {
            details = detailService.list(wrapper);
            if (details == null) {
                details = new ArrayList<SteadyChecksquareDetailPO>();
            }
        }
        for (SteadyChecksquareDetailPO detail : details) {
            fillItemDetail(result, detail);
        }
        return result;
    }

    private boolean deleteTasksAndItems(List<String> taskIds) {
        LambdaUpdateWrapper<SteadyChecksquareTaskPO> taskWrapper = new LambdaUpdateWrapper<SteadyChecksquareTaskPO>()
                .set(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_DELETED)
                .in(SteadyChecksquareTaskPO::getId, taskIds)
                .eq(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_ENABLED);
        boolean taskResult = taskService.update(taskWrapper);
        LambdaUpdateWrapper<SteadyChecksquareItemPO> itemWrapper = new LambdaUpdateWrapper<SteadyChecksquareItemPO>()
                .set(SteadyChecksquareItemPO::getState, SteadyChecksquareConst.STATE_DELETED)
                .in(SteadyChecksquareItemPO::getTaskId, taskIds)
                .eq(SteadyChecksquareItemPO::getState, SteadyChecksquareConst.STATE_ENABLED);
        itemService.update(itemWrapper);
        return taskResult;
    }

    private SteadyChecksquareTaskPO resetFailTaskInTransaction(SteadyChecksquareTaskPO task) {
        if (transactionTemplate == null) {
            return resetFailTask(task);
        }
        return transactionTemplate.execute(status -> resetFailTask(task));
    }

    private SteadyChecksquareTaskPO resetFailTask(SteadyChecksquareTaskPO task) {
        LocalDateTime now = LocalDateTime.now();
        LambdaUpdateWrapper<SteadyChecksquareTaskPO> wrapper = new LambdaUpdateWrapper<SteadyChecksquareTaskPO>()
                .set(SteadyChecksquareTaskPO::getTaskStatus, SteadyChecksquareConst.TASK_STATUS_RUNNING)
                .set(SteadyChecksquareTaskPO::getItemCount, 0)
                .set(SteadyChecksquareTaskPO::getAbnormalItemCount, 0)
                .set(SteadyChecksquareTaskPO::getMinDataIntegrity, BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP))
                .set(SteadyChecksquareTaskPO::getResultMessage, "数据校验任务重新执行中")
                .set(SteadyChecksquareTaskPO::getUpdateTime, now)
                .eq(SteadyChecksquareTaskPO::getId, task.getId())
                .eq(SteadyChecksquareTaskPO::getTaskStatus, SteadyChecksquareConst.TASK_STATUS_FAIL)
                .eq(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_ENABLED);
        if (!taskService.update(wrapper)) {
            throw fail("数据校验任务状态已变化，请刷新后重试");
        }
        clearTaskResults(task.getId());
        task.setTaskStatus(SteadyChecksquareConst.TASK_STATUS_RUNNING);
        task.setItemCount(0);
        task.setAbnormalItemCount(0);
        task.setMinDataIntegrity(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP));
        task.setResultMessage("数据校验任务重新执行中");
        task.setUpdateTime(now);
        return task;
    }

    private void clearTaskResults(String taskId) {
        List<SteadyChecksquareItemPO> items = itemService.lambdaQuery()
                .eq(SteadyChecksquareItemPO::getTaskId, taskId)
                .list();
        if (items == null || items.isEmpty()) {
            return;
        }
        List<String> itemIds = items.stream().map(SteadyChecksquareItemPO::getId).collect(Collectors.toList());
        detailService.remove(new LambdaQueryWrapper<SteadyChecksquareDetailPO>()
                .in(SteadyChecksquareDetailPO::getItemId, itemIds));
        statSummaryService.remove(new LambdaQueryWrapper<SteadyChecksquareStatSummaryPO>()
                .in(SteadyChecksquareStatSummaryPO::getItemId, itemIds));
        itemService.remove(new LambdaQueryWrapper<SteadyChecksquareItemPO>()
                .eq(SteadyChecksquareItemPO::getTaskId, taskId));
    }

    private SteadyChecksquareQueryParam buildRestartParam(SteadyChecksquareTaskPO task) {
        List<String> lineIds = readTaskLineIds(task);
        List<String> indicatorCodes = readStringList(task.getIndicatorCodesJson());
        if (indicatorCodes.isEmpty()) {
            indicatorCodes = parseTextListSearchValue(task.getIndicatorCodesText());
        }
        SteadyChecksquareQueryParam param = new SteadyChecksquareQueryParam();
        param.setLineIds(lineIds);
        param.setIndicatorCodes(indicatorCodes);
        param.setTimeStart(formatTime(task.getTimeStart()));
        param.setTimeEnd(formatTime(task.getTimeEnd()));
        return param;
    }

    private CreateContext prepareCreateContext(SteadyChecksquareQueryParam param) {
        validateParam(param);
        List<String> lineIds = resolveLineIds(param);
        LocalDateTime startTime = parseRequiredTime(param.getTimeStart(), "开始时间不能为空");
        LocalDateTime endTime = parseRequiredTime(param.getTimeEnd(), "结束时间不能为空");
        if (startTime.isAfter(endTime)) {
            throw fail("开始时间不能大于结束时间");
        }
        Map<String, AddLedgerLinePathVO> linePathMap = requireLinePaths(lineIds);
        int intervalMinutes = resolveIntervalMinutes(linePathMap.get(lineIds.get(0)));
        List<String> indicatorCodes = resolveIndicatorCodes(param);
        for (String indicatorCode : indicatorCodes) {
            requireIndicator(indicatorCode);
        }
        validateCreateTimeRange(startTime, endTime);
        return new CreateContext(lineIds, linePathMap, startTime, endTime, intervalMinutes, indicatorCodes);
    }

    private void validateCreateTimeRange(LocalDateTime startTime, LocalDateTime endTime) {
        if (Duration.between(startTime, endTime).compareTo(Duration.ofDays(MAX_CREATE_RANGE_DAYS)) > 0) {
            throw fail("数据校验时间范围不能超过7天");
        }
    }

    private SteadyChecksquareTaskPO findExistingTask(List<String> lineIds, LocalDateTime startTime, LocalDateTime endTime) {
        List<SteadyChecksquareTaskPO> tasks = taskService.lambdaQuery()
                .eq(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_ENABLED)
                .eq(SteadyChecksquareTaskPO::getLineIdsText, buildTextListSearchValue(lineIds))
                .eq(SteadyChecksquareTaskPO::getTimeStart, startTime)
                .eq(SteadyChecksquareTaskPO::getTimeEnd, endTime)
                .orderByDesc(SteadyChecksquareTaskPO::getCreateTime)
                .list();
        return tasks == null || tasks.isEmpty() ? null : tasks.get(0);
    }

    private void markTaskFail(String taskId, String message) {
        LambdaUpdateWrapper<SteadyChecksquareTaskPO> wrapper = new LambdaUpdateWrapper<SteadyChecksquareTaskPO>()
                .set(SteadyChecksquareTaskPO::getTaskStatus, SteadyChecksquareConst.TASK_STATUS_FAIL)
                .set(SteadyChecksquareTaskPO::getResultMessage, limitMessage(message))
                .set(SteadyChecksquareTaskPO::getUpdateTime, LocalDateTime.now())
                .eq(SteadyChecksquareTaskPO::getId, taskId)
                .eq(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_ENABLED);
        taskService.update(wrapper);
    }

    private SteadyChecksquareQueryVO calculate(SteadyChecksquareQueryParam param) {
        validateParam(param);
        List<String> lineIds = resolveLineIds(param);
        LocalDateTime startTime = parseRequiredTime(param.getTimeStart(), "开始时间不能为空");
        LocalDateTime endTime = parseRequiredTime(param.getTimeEnd(), "结束时间不能为空");
        if (startTime.isAfter(endTime)) {
            throw fail("开始时间不能大于结束时间");
        }
        Map<String, AddLedgerLinePathVO> linePathMap = requireLinePaths(lineIds);
        int intervalMinutes = resolveIntervalMinutes(linePathMap.get(lineIds.get(0)));
        SteadyChecksquareQueryVO result = new SteadyChecksquareQueryVO();
        result.setLineIds(new ArrayList<String>(lineIds));
        result.setLineName(buildLineNames(lineIds, linePathMap));
        result.setTimeStart(param.getTimeStart());
        result.setTimeEnd(param.getTimeEnd());
        result.setIntervalMinutes(intervalMinutes);

        long startMillis = System.currentTimeMillis();
        List<String> indicatorCodes = resolveIndicatorCodes(param);
        List<SteadyTrendIndicatorDefinitionBO> indicators = new ArrayList<SteadyTrendIndicatorDefinitionBO>();
        for (String indicatorCode : indicatorCodes) {
            indicators.add(requireIndicator(indicatorCode));
        }
        log.info("数据校验新增检测开始，lineId={}，indicatorCount={}，timeStart={}，timeEnd={}，intervalMinutes={}",
                lineIds, indicatorCodes.size(), startTime, endTime, intervalMinutes);
        for (String lineId : lineIds) {
            AddLedgerLinePathVO linePath = linePathMap.get(lineId);
            int lineIntervalMinutes = resolveIntervalMinutes(linePath);
            String lineName = linePath == null ? null : trimToNull(linePath.getLineName());
            prefetchNormalIndicatorPoints(lineId, indicators, startTime, endTime, lineIntervalMinutes);
            for (SteadyTrendIndicatorDefinitionBO indicator : indicators) {
                int itemIntervalMinutes = resolveIndicatorIntervalMinutes(indicator, lineIntervalMinutes);
                List<LocalDateTime> itemSlots = timeSlotCalculator.buildTimeSlots(startTime, endTime, itemIntervalMinutes);
                result.getItems().addAll(buildIndicatorItems(lineId, lineName, indicator, startTime, endTime,
                        itemSlots, itemIntervalMinutes));
            }
        }
        log.info("数据校验新增检测结束，lineIds={}，itemCount={}，costMs={}", lineIds, result.getItems().size(), System.currentTimeMillis() - startMillis);
        return result;
    }

    private SteadyChecksquareTaskPO saveResultInTransaction(SteadyChecksquareQueryParam param, SteadyChecksquareQueryVO result) {
        if (transactionTemplate == null) {
            return saveResult(param, result);
        }
        return transactionTemplate.execute(status -> saveResult(param, result));
    }

    private SteadyChecksquareTaskPO saveRunningTaskInTransaction(SteadyChecksquareQueryParam param, CreateContext context) {
        if (transactionTemplate == null) {
            return saveRunningTask(param, context);
        }
        return transactionTemplate.execute(status -> saveRunningTask(param, context));
    }

    private SteadyChecksquareTaskPO saveResultInTransaction(String taskId, SteadyChecksquareQueryParam param, SteadyChecksquareQueryVO result) {
        if (transactionTemplate == null) {
            return saveResult(taskId, param, result);
        }
        return transactionTemplate.execute(status -> saveResult(taskId, param, result));
    }

    private SteadyChecksquareTaskPO saveResult(SteadyChecksquareQueryParam param, SteadyChecksquareQueryVO result) {
        return saveResult(null, param, result);
    }

    private SteadyChecksquareTaskPO saveRunningTask(SteadyChecksquareQueryParam param, CreateContext context) {
        LocalDateTime now = LocalDateTime.now();
        SteadyChecksquareTaskPO task = new SteadyChecksquareTaskPO();
        task.setId(SteadyChecksquareIdUtil.uuid());
        task.setTaskNo(SteadyChecksquareIdUtil.taskNo());
        task.setLineId(context.lineIds.get(0));
        task.setLineName(buildLineNames(context.lineIds, context.linePathMap));
        task.setLineIdsJson(writeJson(context.lineIds));
        task.setLineIdsText(buildTextListSearchValue(context.lineIds));
        task.setTimeStart(context.startTime);
        task.setTimeEnd(context.endTime);
        task.setIntervalMinutes(context.intervalMinutes);
        task.setIndicatorCodesJson(writeJson(context.indicatorCodes));
        task.setIndicatorCodesText(buildIndicatorCodesText(context.indicatorCodes));
        task.setTaskStatus(SteadyChecksquareConst.TASK_STATUS_RUNNING);
        task.setItemCount(0);
        task.setAbnormalItemCount(0);
        task.setMinDataIntegrity(BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP));
        task.setResultMessage("数据校验任务执行中");
        task.setState(SteadyChecksquareConst.STATE_ENABLED);
        task.setCreateTime(now);
        task.setUpdateTime(now);
        taskService.save(task);
        return task;
    }

    private void submitCreateTask(String taskId, SteadyChecksquareQueryParam param) {
        if (steadyChecksquareExecutorService == null) {
            executeCreateTask(taskId, param);
            return;
        }
        steadyChecksquareExecutorService.submit(() -> executeCreateTask(taskId, param));
    }

    private void executeCreateTask(String taskId, SteadyChecksquareQueryParam param) {
        long startMillis = System.currentTimeMillis();
        influxQueryComponent.enableRequestCache();
        try {
            SteadyChecksquareQueryVO result = calculate(param);
            SteadyChecksquareTaskPO task = saveResultInTransaction(taskId, param, result);
            log.info("数据校验后台任务执行成功，taskId={}，itemCount={}，costMs={}",
                    taskId, task.getItemCount(), System.currentTimeMillis() - startMillis);
        } catch (Exception ex) {
            log.error("数据校验后台任务执行失败，taskId={}，costMs={}", taskId, System.currentTimeMillis() - startMillis, ex);
            markTaskFail(taskId, ex.getMessage());
        } finally {
            influxQueryComponent.clearRequestCache();
        }
    }

    private SteadyChecksquareTaskPO saveResult(String taskId, SteadyChecksquareQueryParam param, SteadyChecksquareQueryVO result) {
        long saveStartMillis = System.currentTimeMillis();
        LocalDateTime now = LocalDateTime.now();
        SteadyChecksquareTaskPO task = new SteadyChecksquareTaskPO();
        task.setId(trimToNull(taskId) == null ? SteadyChecksquareIdUtil.uuid() : taskId);
        if (trimToNull(taskId) == null) {
            task.setTaskNo(SteadyChecksquareIdUtil.taskNo());
        }
        List<String> lineIds = resolveResultLineIds(result);
        task.setLineId(lineIds.isEmpty() ? null : lineIds.get(0));
        task.setLineName(result.getLineName());
        task.setLineIdsJson(writeJson(lineIds));
        task.setLineIdsText(buildTextListSearchValue(lineIds));
        task.setTimeStart(parseRequiredTime(result.getTimeStart(), "开始时间不能为空"));
        task.setTimeEnd(parseRequiredTime(result.getTimeEnd(), "结束时间不能为空"));
        task.setIntervalMinutes(result.getIntervalMinutes());
        List<String> indicatorCodes = resolveIndicatorCodes(param);
        task.setIndicatorCodesJson(writeJson(indicatorCodes));
        task.setIndicatorCodesText(buildIndicatorCodesText(indicatorCodes));
        task.setTaskStatus(SteadyChecksquareConst.TASK_STATUS_SUCCESS);
        task.setItemCount(result.getItems().size());
        task.setAbnormalItemCount(countAbnormalItems(result.getItems()));
        task.setMinDataIntegrity(minDataIntegrity(result.getItems()));
        task.setResultMessage("数据校验完成");
        task.setState(SteadyChecksquareConst.STATE_ENABLED);
        task.setCreateTime(now);
        task.setUpdateTime(now);
        if (trimToNull(taskId) == null) {
            taskService.save(task);
        } else {
            updateCompletedTask(task);
        }

        List<SteadyChecksquareItemPO> itemPOs = new ArrayList<SteadyChecksquareItemPO>();
        List<SteadyChecksquareStatSummaryPO> summaryPOs = new ArrayList<SteadyChecksquareStatSummaryPO>();
        List<SteadyChecksquareDetailPO> detailPOs = new ArrayList<SteadyChecksquareDetailPO>();
        for (SteadyChecksquareItemVO item : result.getItems()) {
            SteadyChecksquareItemPO itemPO = buildItemPO(task.getId(), item, now);
            item.setItemId(itemPO.getId());
            itemPOs.add(itemPO);
            summaryPOs.addAll(buildSummaryPOs(itemPO.getId(), item, now));
            detailPOs.addAll(buildDetailPOs(itemPO.getId(), item, now));
        }
        if (!itemPOs.isEmpty()) {
            itemService.saveBatch(itemPOs);
        }
        if (!summaryPOs.isEmpty()) {
            statSummaryService.saveBatch(summaryPOs);
        }
        if (!detailPOs.isEmpty()) {
            saveDetailBatchInChunks(detailPOs);
        }
        log.info("数据校验结果保存完成，taskId={}，itemCount={}，summaryCount={}，detailCount={}，costMs={}",
                task.getId(), itemPOs.size(), summaryPOs.size(), detailPOs.size(), System.currentTimeMillis() - saveStartMillis);
        return task;
    }

    private void updateCompletedTask(SteadyChecksquareTaskPO task) {
        LambdaUpdateWrapper<SteadyChecksquareTaskPO> wrapper = new LambdaUpdateWrapper<SteadyChecksquareTaskPO>()
                .set(SteadyChecksquareTaskPO::getLineName, task.getLineName())
                .set(SteadyChecksquareTaskPO::getLineIdsJson, task.getLineIdsJson())
                .set(SteadyChecksquareTaskPO::getLineIdsText, task.getLineIdsText())
                .set(SteadyChecksquareTaskPO::getIndicatorCodesJson, task.getIndicatorCodesJson())
                .set(SteadyChecksquareTaskPO::getIndicatorCodesText, task.getIndicatorCodesText())
                .set(SteadyChecksquareTaskPO::getIntervalMinutes, task.getIntervalMinutes())
                .set(SteadyChecksquareTaskPO::getTaskStatus, task.getTaskStatus())
                .set(SteadyChecksquareTaskPO::getItemCount, task.getItemCount())
                .set(SteadyChecksquareTaskPO::getAbnormalItemCount, task.getAbnormalItemCount())
                .set(SteadyChecksquareTaskPO::getMinDataIntegrity, task.getMinDataIntegrity())
                .set(SteadyChecksquareTaskPO::getResultMessage, task.getResultMessage())
                .set(SteadyChecksquareTaskPO::getUpdateTime, task.getUpdateTime())
                .eq(SteadyChecksquareTaskPO::getId, task.getId())
                .eq(SteadyChecksquareTaskPO::getState, SteadyChecksquareConst.STATE_ENABLED);
        taskService.update(wrapper);
    }

    private void saveDetailBatchInChunks(List<SteadyChecksquareDetailPO> detailPOs) {
        for (int start = 0; start < detailPOs.size(); start += DETAIL_SAVE_BATCH_SIZE) {
            int end = Math.min(start + DETAIL_SAVE_BATCH_SIZE, detailPOs.size());
            detailService.saveBatch(detailPOs.subList(start, end));
        }
    }

    private SteadyChecksquareItemPO buildItemPO(String taskId, SteadyChecksquareItemVO item, LocalDateTime now) {
        SteadyChecksquareItemPO po = new SteadyChecksquareItemPO();
        po.setId(SteadyChecksquareIdUtil.uuid());
        po.setTaskId(taskId);
        po.setItemKey(item.getItemKey());
        po.setLineId(item.getLineId());
        po.setLineName(item.getLineName());
        po.setIndicatorCode(item.getIndicatorCode());
        po.setIndicatorName(item.getIndicatorName());
        po.setHarmonicOrder(item.getHarmonicOrder());
        po.setIntervalMinutes(item.getIntervalMinutes());
        po.setHasData(toFlag(item.getHasData()));
        po.setExpectedPointCount(nullToZero(item.getExpectedPointCount()));
        po.setActualPointCount(nullToZero(item.getActualPointCount()));
        po.setMissingPointCount(nullToZero(item.getMissingPointCount()));
        po.setDataIntegrity(item.getDataIntegrity() == null ? BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP) : item.getDataIntegrity());
        po.setDataIntegrityText(item.getDataIntegrityText());
        po.setAbnormal(toFlag(item.getAbnormal()));
        po.setAbnormalPointCount(nullToZero(item.getAbnormalPointCount()));
        po.setHarmonicParityAbnormal(toFlag(item.getHarmonicParityAbnormal()));
        po.setHarmonicParityAbnormalPointCount(nullToZero(item.getHarmonicParityAbnormalPointCount()));
        po.setState(SteadyChecksquareConst.STATE_ENABLED);
        po.setCreateTime(now);
        po.setUpdateTime(now);
        return po;
    }

    private List<SteadyChecksquareStatSummaryPO> buildSummaryPOs(String itemId, SteadyChecksquareItemVO item, LocalDateTime now) {
        List<SteadyChecksquareStatSummaryPO> result = new ArrayList<SteadyChecksquareStatSummaryPO>();
        for (SteadyChecksquareStatSummaryVO summary : item.getStatSummaries()) {
            SteadyChecksquareStatSummaryPO po = new SteadyChecksquareStatSummaryPO();
            po.setId(SteadyChecksquareIdUtil.uuid());
            po.setItemId(itemId);
            po.setStatType(summary.getStatType());
            po.setSupported(toFlag(summary.getSupported()));
            po.setHasData(toFlag(summary.getHasData()));
            po.setExpectedPointCount(nullToZero(summary.getExpectedPointCount()));
            po.setActualPointCount(nullToZero(summary.getActualPointCount()));
            po.setMissingPointCount(nullToZero(summary.getMissingPointCount()));
            po.setDataIntegrity(summary.getDataIntegrity() == null ? BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP) : summary.getDataIntegrity());
            po.setDataIntegrityText(summary.getDataIntegrityText());
            po.setCreateTime(now);
            result.add(po);
        }
        return result;
    }

    private List<SteadyChecksquareDetailPO> buildDetailPOs(String itemId, SteadyChecksquareItemVO item, LocalDateTime now) {
        List<SteadyChecksquareDetailPO> result = new ArrayList<SteadyChecksquareDetailPO>();
        for (SteadyChecksquareStatDetailVO detail : item.getStatDetails()) {
            for (SteadyChecksquareSegmentVO segment : detail.getSegments()) {
                SteadyChecksquareDetailPO po = new SteadyChecksquareDetailPO();
                po.setId(SteadyChecksquareIdUtil.uuid());
                po.setItemId(itemId);
                po.setDetailType(SteadyChecksquareConst.DETAIL_TYPE_SEGMENT);
                po.setStatType(detail.getStatType());
                po.setHarmonicOrder(segment.getHarmonicOrder());
                po.setStartTime(parseOptionalTime(segment.getStartTime()));
                po.setEndTime(parseOptionalTime(segment.getEndTime()));
                po.setSegmentStatus(segment.getStatus());
                po.setMissingPointCount(segment.getMissingPointCount());
                po.setDurationMinutes(segment.getDurationMinutes());
                po.setCreateTime(now);
                result.add(po);
            }
        }
        for (SteadyChecksquareValueOrderDetailVO detail : item.getAbnormalDetails()) {
            SteadyChecksquareDetailPO po = new SteadyChecksquareDetailPO();
            po.setId(SteadyChecksquareIdUtil.uuid());
            po.setItemId(itemId);
            po.setDetailType(SteadyChecksquareConst.DETAIL_TYPE_VALUE_ORDER);
            po.setPointTime(parseOptionalTime(detail.getTime()));
            po.setPhase(detail.getPhase());
            po.setHarmonicOrder(detail.getHarmonicOrder());
            po.setMaxValue(detail.getMaxValue());
            po.setMinValue(detail.getMinValue());
            po.setAvgValue(detail.getAvgValue());
            po.setCp95Value(detail.getCp95Value());
            po.setCreateTime(now);
            result.add(po);
        }
        for (SteadyChecksquareHarmonicParityDetailVO detail : item.getHarmonicParityAbnormalDetails()) {
            SteadyChecksquareDetailPO po = new SteadyChecksquareDetailPO();
            po.setId(SteadyChecksquareIdUtil.uuid());
            po.setItemId(itemId);
            po.setDetailType(SteadyChecksquareConst.DETAIL_TYPE_HARMONIC_PARITY);
            po.setPointTime(parseOptionalTime(detail.getTime()));
            po.setPhase(detail.getPhase());
            po.setStatType(detail.getStatType());
            po.setEvenHarmonicOrder(detail.getEvenHarmonicOrder());
            po.setEvenValue(detail.getEvenValue());
            po.setOddHarmonicOrdersJson(writeJson(detail.getOddHarmonicOrders()));
            po.setOddValuesJson(writeJson(detail.getOddValues()));
            po.setOddMedianValue(detail.getOddMedianValue());
            po.setThresholdMultiplier(detail.getThresholdMultiplier());
            po.setCreateTime(now);
            result.add(po);
        }
        return result;
    }

    private void prefetchNormalIndicatorPoints(String lineId, List<SteadyTrendIndicatorDefinitionBO> indicators,
                                               LocalDateTime startTime, LocalDateTime endTime, int lineIntervalMinutes) {
        Map<String, List<SteadyTrendResolvedFieldBO>> fieldMap =
                new LinkedHashMap<String, List<SteadyTrendResolvedFieldBO>>();
        Map<String, Integer> intervalMap = new LinkedHashMap<String, Integer>();
        for (SteadyTrendIndicatorDefinitionBO indicator : indicators) {
            if (Boolean.TRUE.equals(indicator.getHarmonic())) {
                continue;
            }
            int intervalMinutes = resolveIndicatorIntervalMinutes(indicator, lineIntervalMinutes);
            for (String statType : indicator.getSupportStats()) {
                for (String phase : indicator.getPhaseCodes()) {
                    SteadyTrendResolvedFieldBO field = buildResolvedField(lineId, indicator, null, phase, statType);
                    String key = buildPrefetchKey(field, intervalMinutes);
                    List<SteadyTrendResolvedFieldBO> fields = fieldMap.get(key);
                    if (fields == null) {
                        fields = new ArrayList<SteadyTrendResolvedFieldBO>();
                        fieldMap.put(key, fields);
                        intervalMap.put(key, intervalMinutes);
                    }
                    fields.add(field);
                }
            }
        }
        for (Map.Entry<String, List<SteadyTrendResolvedFieldBO>> entry : fieldMap.entrySet()) {
            influxQueryComponent.queryValuePointMap(entry.getValue(), startTime, endTime, intervalMap.get(entry.getKey()));
        }
    }

    private String buildPrefetchKey(SteadyTrendResolvedFieldBO field, int intervalMinutes) {
        return field.getMeasurement() + "|" + field.getLineId() + "|" + field.getPhase() + "|"
                + field.getStatType() + "|" + intervalMinutes;
    }

    private List<SteadyChecksquareItemVO> buildIndicatorItems(String lineId, String lineName,
                                                              SteadyTrendIndicatorDefinitionBO indicator,
                                                              LocalDateTime startTime, LocalDateTime endTime,
                                                              List<LocalDateTime> slots, int intervalMinutes) {
        List<SteadyChecksquareItemVO> result = new ArrayList<SteadyChecksquareItemVO>();
        if (Boolean.TRUE.equals(indicator.getHarmonic())) {
            List<Integer> harmonicOrders = buildAggregateHarmonicOrders(indicator);
            prefetchHarmonicIndicatorPoints(lineId, indicator, harmonicOrders, startTime, endTime, intervalMinutes);
            for (Integer order : harmonicOrders) {
                result.add(buildItem(lineId, lineName, indicator, order, startTime, endTime, slots, intervalMinutes));
            }
            fillHarmonicParityRuleResult(result, lineId, indicator, startTime, endTime, intervalMinutes);
            return Collections.singletonList(aggregateHarmonicItems(lineId, lineName, indicator, result, intervalMinutes));
        }
        result.add(buildItem(lineId, lineName, indicator, null, startTime, endTime, slots, intervalMinutes));
        return result;
    }

    private void prefetchHarmonicIndicatorPoints(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
                                                 List<Integer> harmonicOrders, LocalDateTime startTime,
                                                 LocalDateTime endTime, int intervalMinutes) {
        if (harmonicOrders == null || harmonicOrders.isEmpty()) {
            return;
        }
        for (String statType : indicator.getSupportStats()) {
            for (String phase : indicator.getPhaseCodes()) {
                List<SteadyTrendResolvedFieldBO> fields = new ArrayList<SteadyTrendResolvedFieldBO>();
                for (Integer order : harmonicOrders) {
                    fields.add(buildResolvedField(lineId, indicator, order, phase, statType));
                }
                influxQueryComponent.queryValuePointMap(fields, startTime, endTime, intervalMinutes);
            }
        }
    }

    private SteadyChecksquareItemVO aggregateHarmonicItems(String lineId, String lineName,
                                                           SteadyTrendIndicatorDefinitionBO indicator,
                                                           List<SteadyChecksquareItemVO> orderItems, int intervalMinutes) {
        SteadyChecksquareItemVO result = new SteadyChecksquareItemVO();
        result.setItemKey(buildItemKey(lineId, indicator, null));
        result.setLineId(lineId);
        result.setLineName(lineName);
        result.setIndicatorCode(indicator.getIndicatorCode());
        result.setIndicatorName(indicator.getName());
        result.setHarmonicOrder(null);
        result.setIntervalMinutes(intervalMinutes);
        result.setExpectedPointCount(averageInteger(orderItems, "expectedPointCount"));
        result.setActualPointCount(averageInteger(orderItems, "actualPointCount"));
        result.setMissingPointCount(averageInteger(orderItems, "missingPointCount"));
        result.setDataIntegrity(averageDataIntegrity(orderItems));
        result.setHasData(hasDataByIntegrity(result.getDataIntegrity()));
        result.setDataIntegrityText(formatRateText(result.getDataIntegrity()));
        result.setAbnormal(anyAbnormal(orderItems));
        result.setAbnormalPointCount(averageAbnormalCount(orderItems, "abnormalPointCount", result.getAbnormal()));
        result.setHarmonicParityAbnormal(anyHarmonicParityAbnormal(orderItems));
        result.setHarmonicParityAbnormalPointCount(averageAbnormalCount(orderItems,
                "harmonicParityAbnormalPointCount", result.getHarmonicParityAbnormal()));
        for (SteadyChecksquareItemVO orderItem : orderItems) {
            result.getAbnormalDetails().addAll(orderItem.getAbnormalDetails());
            result.getHarmonicParityAbnormalDetails().addAll(orderItem.getHarmonicParityAbnormalDetails());
        }
        result.setStatSummaries(aggregateStatSummaries(orderItems));
        result.setStatDetails(aggregateStatDetails(orderItems));
        return result;
    }

    private List<SteadyChecksquareStatSummaryVO> aggregateStatSummaries(List<SteadyChecksquareItemVO> orderItems) {
        Map<String, List<SteadyChecksquareStatSummaryVO>> summaryMap = new LinkedHashMap<String, List<SteadyChecksquareStatSummaryVO>>();
        for (SteadyChecksquareItemVO item : orderItems) {
            for (SteadyChecksquareStatSummaryVO summary : item.getStatSummaries()) {
                List<SteadyChecksquareStatSummaryVO> summaries = summaryMap.get(summary.getStatType());
                if (summaries == null) {
                    summaries = new ArrayList<SteadyChecksquareStatSummaryVO>();
                    summaryMap.put(summary.getStatType(), summaries);
                }
                summaries.add(summary);
            }
        }
        List<SteadyChecksquareStatSummaryVO> result = new ArrayList<SteadyChecksquareStatSummaryVO>();
        for (Map.Entry<String, List<SteadyChecksquareStatSummaryVO>> entry : summaryMap.entrySet()) {
            SteadyChecksquareStatSummaryVO summary = new SteadyChecksquareStatSummaryVO();
            summary.setStatType(entry.getKey());
            summary.setSupported(true);
            summary.setExpectedPointCount(averageSummaryInteger(entry.getValue(), "expectedPointCount"));
            summary.setActualPointCount(averageSummaryInteger(entry.getValue(), "actualPointCount"));
            summary.setMissingPointCount(averageSummaryInteger(entry.getValue(), "missingPointCount"));
            summary.setDataIntegrity(averageSummaryDataIntegrity(entry.getValue()));
            summary.setHasData(hasDataByIntegrity(summary.getDataIntegrity()));
            summary.setDataIntegrityText(formatRateText(summary.getDataIntegrity()));
            result.add(summary);
        }
        return result;
    }

    private List<SteadyChecksquareStatDetailVO> aggregateStatDetails(List<SteadyChecksquareItemVO> orderItems) {
        Map<String, SteadyChecksquareStatDetailVO> detailMap = new LinkedHashMap<String, SteadyChecksquareStatDetailVO>();
        for (SteadyChecksquareItemVO item : orderItems) {
            for (SteadyChecksquareStatDetailVO detail : item.getStatDetails()) {
                SteadyChecksquareStatDetailVO aggregateDetail = detailMap.get(detail.getStatType());
                if (aggregateDetail == null) {
                    aggregateDetail = new SteadyChecksquareStatDetailVO();
                    aggregateDetail.setStatType(detail.getStatType());
                    aggregateDetail.setSupported(true);
                    detailMap.put(detail.getStatType(), aggregateDetail);
                }
                if (item.getHarmonicOrder() != null) {
                    for (SteadyChecksquareSegmentVO segment : detail.getSegments()) {
                        segment.setHarmonicOrder(item.getHarmonicOrder());
                    }
                }
                aggregateDetail.getSegments().addAll(detail.getSegments());
            }
        }
        return new ArrayList<SteadyChecksquareStatDetailVO>(detailMap.values());
    }

    private SteadyChecksquareItemVO buildItem(String lineId, String lineName,
                                              SteadyTrendIndicatorDefinitionBO indicator, Integer harmonicOrder,
                                              LocalDateTime startTime, LocalDateTime endTime,
                                              List<LocalDateTime> slots, int intervalMinutes) {
        SteadyChecksquareItemVO item = new SteadyChecksquareItemVO();
        item.setItemKey(buildItemKey(lineId, indicator, harmonicOrder));
        item.setLineId(lineId);
        item.setLineName(lineName);
        item.setIndicatorCode(indicator.getIndicatorCode());
        item.setIndicatorName(indicator.getName());
        item.setHarmonicOrder(harmonicOrder);
        item.setIntervalMinutes(intervalMinutes);
        item.setHarmonicParityAbnormal(false);
        item.setHarmonicParityAbnormalPointCount(0);

        int totalExpected = 0;
        int totalActual = 0;
        for (String statType : indicator.getSupportStats()) {
            Set<LocalDateTime> actualSlots = queryMergedActualSlots(lineId, indicator, harmonicOrder, statType, startTime, endTime, intervalMinutes);
            Set<LocalDateTime> effectiveActualSlots = retainExpectedSlots(slots, actualSlots);
            List<SteadyChecksquareSegmentVO> segments = calculator.buildSegments(slots, effectiveActualSlots, intervalMinutes);
            SteadyChecksquareStatSummaryVO summary = buildSummary(statType, slots.size(), effectiveActualSlots.size(), segments);
            SteadyChecksquareStatDetailVO detail = buildDetail(statType, segments);
            item.getStatSummaries().add(summary);
            item.getStatDetails().add(detail);
            totalExpected += summary.getExpectedPointCount();
            totalActual += summary.getActualPointCount();
        }

        item.setExpectedPointCount(totalExpected);
        item.setActualPointCount(totalActual);
        item.setMissingPointCount(Math.max(0, totalExpected - totalActual));
        item.setDataIntegrity(calculateDataIntegrity(totalActual, totalExpected));
        item.setHasData(hasDataByIntegrity(item.getDataIntegrity()));
        item.setDataIntegrityText(formatRateText(item.getDataIntegrity()));
        fillValueOrderRuleResult(item, lineId, indicator, harmonicOrder, startTime, endTime, intervalMinutes);
        return item;
    }

    private void fillHarmonicParityRuleResult(List<SteadyChecksquareItemVO> items, String lineId,
                                              SteadyTrendIndicatorDefinitionBO indicator,
                                              LocalDateTime startTime, LocalDateTime endTime,
                                              int intervalMinutes) {
        SteadyChecksquareHarmonicParityRuleVO ruleResult = harmonicParityRuleComponent.check(lineId, indicator,
                startTime, endTime, intervalMinutes);
        if (ruleResult == null || ruleResult.getAbnormalDetails() == null || ruleResult.getAbnormalDetails().isEmpty()) {
            for (SteadyChecksquareItemVO item : items) {
                item.setHarmonicParityAbnormal(false);
                item.setHarmonicParityAbnormalPointCount(0);
            }
            return;
        }
        for (SteadyChecksquareItemVO item : items) {
            List<SteadyChecksquareHarmonicParityDetailVO> matchedDetails =
                    filterHarmonicParityDetails(ruleResult, item.getHarmonicOrder());
            item.setHarmonicParityAbnormal(!matchedDetails.isEmpty());
            item.setHarmonicParityAbnormalPointCount(matchedDetails.size());
            item.setHarmonicParityAbnormalDetails(matchedDetails);
        }
    }

    private List<SteadyChecksquareHarmonicParityDetailVO> filterHarmonicParityDetails(
            SteadyChecksquareHarmonicParityRuleVO ruleResult, Integer harmonicOrder) {
        List<SteadyChecksquareHarmonicParityDetailVO> result = new ArrayList<SteadyChecksquareHarmonicParityDetailVO>();
        if (ruleResult == null || ruleResult.getAbnormalDetails() == null || harmonicOrder == null) {
            return result;
        }
        for (SteadyChecksquareHarmonicParityDetailVO detail : ruleResult.getAbnormalDetails()) {
            if (detail != null && harmonicOrder.equals(detail.getEvenHarmonicOrder())) {
                result.add(detail);
            }
        }
        return result;
    }

    private void fillValueOrderRuleResult(SteadyChecksquareItemVO item, String lineId, SteadyTrendIndicatorDefinitionBO indicator,
                                          Integer harmonicOrder, LocalDateTime startTime, LocalDateTime endTime,
                                          int intervalMinutes) {
        SteadyChecksquareValueOrderRuleVO ruleResult = valueOrderRuleComponent.check(lineId, indicator, harmonicOrder,
                startTime, endTime, intervalMinutes);
        item.setAbnormal(ruleResult.getAbnormal());
        item.setAbnormalPointCount(ruleResult.getAbnormalPointCount());
        item.setAbnormalDetails(ruleResult.getAbnormalDetails());
    }

    private Set<LocalDateTime> queryMergedActualSlots(String lineId, SteadyTrendIndicatorDefinitionBO indicator, Integer harmonicOrder,
                                                      String statType, LocalDateTime startTime, LocalDateTime endTime,
                                                      int intervalMinutes) {
        Set<LocalDateTime> result = new HashSet<LocalDateTime>();
        for (String phase : indicator.getPhaseCodes()) {
            SteadyTrendResolvedFieldBO field = buildResolvedField(lineId, indicator, harmonicOrder, phase, statType);
            result.addAll(influxQueryComponent.queryExistingSlots(field, startTime, endTime, intervalMinutes));
        }
        return result;
    }

    private Set<LocalDateTime> retainExpectedSlots(List<LocalDateTime> slots, Set<LocalDateTime> actualSlots) {
        Set<LocalDateTime> result = new HashSet<LocalDateTime>();
        if (slots == null || actualSlots == null || actualSlots.isEmpty()) {
            return result;
        }
        for (LocalDateTime slot : slots) {
            if (actualSlots.contains(slot)) {
                result.add(slot);
            }
        }
        return result;
    }

    private SteadyTrendResolvedFieldBO buildResolvedField(String lineId, SteadyTrendIndicatorDefinitionBO indicator,
                                                          Integer harmonicOrder, String phase, String statType) {
        SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
        field.setMeasurement(indicator.getTableName());
        field.setField(resolveField(indicator, harmonicOrder));
        field.setLineId(lineId);
        field.setIndicatorCode(indicator.getIndicatorCode());
        field.setIndicatorName(indicator.getName());
        field.setPhase(phase);
        field.setStatType(statType);
        field.setUnit(indicator.getUnit());
        return field;
    }

    private String resolveField(SteadyTrendIndicatorDefinitionBO indicator, Integer harmonicOrder) {
        if (Boolean.TRUE.equals(indicator.getHarmonic())) {
            return indicator.getHarmonicFieldPrefix() + "_" + harmonicOrder;
        }
        List<SteadyTrendSeriesFieldBO> fields = indicator.getSeriesFields();
        if (fields == null || fields.isEmpty()) {
            throw fail("稳态指标不支持：" + indicator.getIndicatorCode());
        }
        return fields.get(0).getField();
    }

    private SteadyChecksquareStatSummaryVO buildSummary(String statType, int expectedCount, int actualCount,
                                                        List<SteadyChecksquareSegmentVO> segments) {
        SteadyChecksquareStatSummaryVO summary = new SteadyChecksquareStatSummaryVO();
        summary.setStatType(statType);
        summary.setSupported(true);
        summary.setExpectedPointCount(expectedCount);
        summary.setActualPointCount(actualCount);
        summary.setMissingPointCount(Math.max(0, expectedCount - actualCount));
        summary.setDataIntegrity(calculateDataIntegrity(actualCount, expectedCount));
        summary.setHasData(hasDataByIntegrity(summary.getDataIntegrity()));
        summary.setDataIntegrityText(formatRateText(summary.getDataIntegrity()));
        return summary;
    }

    private SteadyChecksquareStatDetailVO buildDetail(String statType, List<SteadyChecksquareSegmentVO> segments) {
        SteadyChecksquareStatDetailVO detail = new SteadyChecksquareStatDetailVO();
        detail.setStatType(statType);
        detail.setSupported(true);
        detail.setSegments(segments);
        return detail;
    }

    private String buildItemKey(String lineId, SteadyTrendIndicatorDefinitionBO indicator, Integer harmonicOrder) {
        if (harmonicOrder == null) {
            return lineId + "|" + indicator.getIndicatorCode();
        }
        return lineId + "|" + indicator.getIndicatorCode() + "|" + harmonicOrder;
    }

    private void validateParam(SteadyChecksquareQueryParam param) {
        validateParam(param, false);
    }

    private void validateCreateBaseParam(SteadyChecksquareQueryParam param) {
        if (param == null) {
            throw fail("数据校验参数不能为空");
        }
        if (resolveLineIds(param).isEmpty()) {
            throw fail("监测点ID不能为空");
        }
        parseRequiredTime(param.getTimeStart(), "开始时间不能为空");
        parseRequiredTime(param.getTimeEnd(), "结束时间不能为空");
    }

    private void validateParam(SteadyChecksquareQueryParam param, boolean allowEmptyIndicators) {
        if (param == null) {
            throw fail("数据校验参数不能为空");
        }
        if (resolveLineIds(param).isEmpty()) {
            throw fail("监测点ID不能为空");
        }
        parseRequiredTime(param.getTimeStart(), "开始时间不能为空");
        parseRequiredTime(param.getTimeEnd(), "结束时间不能为空");
    }

    private LocalDateTime parseRequiredTime(String time, String emptyMessage) {
        String text = trimToNull(time);
        if (text == null) {
            throw fail(emptyMessage);
        }
        try {
            return LocalDateTime.parse(text, TIME_FORMATTER);
        } catch (DateTimeParseException ex) {
            throw fail("时间格式不正确，仅支持 yyyy-MM-dd HH:mm:ss");
        }
    }

    private LocalDateTime parseOptionalTime(String time) {
        String text = trimToNull(time);
        if (text == null) {
            return null;
        }
        return parseRequiredTime(text, "时间不能为空");
    }

    private AddLedgerLinePathVO requireLinePath(String lineId) {
        Map<String, AddLedgerLinePathVO> linePathMap = addLedgerService.listLinePathByLineIds(Collections.singletonList(lineId));
        AddLedgerLinePathVO linePath = linePathMap.get(lineId);
        if (linePath == null) {
            throw fail("监测点不存在或不可用");
        }
        return linePath;
    }

    private Map<String, AddLedgerLinePathVO> requireLinePaths(List<String> lineIds) {
        Map<String, AddLedgerLinePathVO> linePathMap = addLedgerService.listLinePathByLineIds(lineIds);
        for (String lineId : lineIds) {
            if (linePathMap == null || linePathMap.get(lineId) == null) {
                throw fail("监测点不存在或不可用");
            }
        }
        return linePathMap;
    }

    private String buildLineNames(List<String> lineIds, Map<String, AddLedgerLinePathVO> linePathMap) {
        List<String> names = new ArrayList<String>();
        for (String lineId : lineIds) {
            AddLedgerLinePathVO linePath = linePathMap.get(lineId);
            String lineName = linePath == null ? null : trimToNull(linePath.getLineName());
            names.add(lineName == null ? EMPTY_TEXT : lineName);
        }
        return String.join("、", names);
    }

    private int resolveIntervalMinutes(AddLedgerLinePathVO linePath) {
        Integer interval = linePath.getLineInterval();
        if (interval == null || interval <= 0) {
            return AddLedgerConst.LINE_INTERVAL_DEFAULT;
        }
        return interval;
    }

    private int resolveIndicatorIntervalMinutes(SteadyTrendIndicatorDefinitionBO indicator, int lineIntervalMinutes) {
        String indicatorCode = indicator == null ? null : indicator.getIndicatorCode();
        if ("FLUC".equals(indicatorCode) || "PST".equals(indicatorCode)) {
            return FLICKER_SHORT_INTERVAL_MINUTES;
        }
        if ("PLT".equals(indicatorCode)) {
            return FLICKER_LONG_INTERVAL_MINUTES;
        }
        return lineIntervalMinutes;
    }

    private SteadyTrendIndicatorDefinitionBO requireIndicator(String indicatorCode) {
        SteadyTrendIndicatorDefinitionBO indicator = indicatorCatalog.getIndicator(indicatorCode);
        if (indicator == null) {
            throw fail("稳态指标不支持：" + indicatorCode);
        }
        return indicator;
    }

    private List<Integer> buildAggregateHarmonicOrders(SteadyTrendIndicatorDefinitionBO indicator) {
        int start = Math.max(HARMONIC_AGGREGATE_ORDER_START, indicator.getHarmonicOrderStart());
        int end = Math.min(HARMONIC_AGGREGATE_ORDER_END, indicator.getHarmonicOrderEnd());
        if (start > end) {
            throw fail("谐波次数只能在" + HARMONIC_AGGREGATE_ORDER_START + "到" + HARMONIC_AGGREGATE_ORDER_END + "之间");
        }
        List<Integer> result = new ArrayList<Integer>();
        for (int order = start; order <= end; order++) {
            result.add(order);
        }
        return result;
    }

    private Map<String, List<SteadyChecksquareStatSummaryVO>> loadSummaryMap(List<SteadyChecksquareItemPO> items) {
        Map<String, List<SteadyChecksquareStatSummaryVO>> result =
                new LinkedHashMap<String, List<SteadyChecksquareStatSummaryVO>>();
        if (items == null || items.isEmpty()) {
            return result;
        }
        List<String> itemIds = new ArrayList<String>();
        for (SteadyChecksquareItemPO item : items) {
            itemIds.add(item.getId());
            result.put(item.getId(), new ArrayList<SteadyChecksquareStatSummaryVO>());
        }
        List<SteadyChecksquareStatSummaryPO> summaries = statSummaryService.lambdaQuery()
                .in(SteadyChecksquareStatSummaryPO::getItemId, itemIds)
                .list();
        for (SteadyChecksquareStatSummaryPO summary : summaries) {
            List<SteadyChecksquareStatSummaryVO> itemSummaries = result.get(summary.getItemId());
            if (itemSummaries != null) {
                itemSummaries.add(toSummaryVO(summary));
            }
        }
        return result;
    }

    private void fillItemDetail(SteadyChecksquareItemDetailVO result, SteadyChecksquareDetailPO detail) {
        if (SteadyChecksquareConst.DETAIL_TYPE_SEGMENT.equals(detail.getDetailType())) {
            SteadyChecksquareSegmentVO segment = new SteadyChecksquareSegmentVO();
            segment.setStartTime(formatTime(detail.getStartTime()));
            segment.setEndTime(formatTime(detail.getEndTime()));
            segment.setStatus(detail.getSegmentStatus());
            segment.setHarmonicOrder(detail.getHarmonicOrder());
            segment.setMissingPointCount(detail.getMissingPointCount());
            segment.setDurationMinutes(detail.getDurationMinutes());
            result.getSegments().add(segment);
            return;
        }
        if (SteadyChecksquareConst.DETAIL_TYPE_VALUE_ORDER.equals(detail.getDetailType())) {
            SteadyChecksquareValueOrderDetailVO valueDetail = new SteadyChecksquareValueOrderDetailVO();
            valueDetail.setTime(formatTime(detail.getPointTime()));
            valueDetail.setPhase(detail.getPhase());
            valueDetail.setHarmonicOrder(detail.getHarmonicOrder());
            valueDetail.setMaxValue(detail.getMaxValue());
            valueDetail.setMinValue(detail.getMinValue());
            valueDetail.setAvgValue(detail.getAvgValue());
            valueDetail.setCp95Value(detail.getCp95Value());
            result.getValueOrderDetails().add(valueDetail);
            return;
        }
        if (SteadyChecksquareConst.DETAIL_TYPE_HARMONIC_PARITY.equals(detail.getDetailType())) {
            SteadyChecksquareHarmonicParityDetailVO parityDetail = new SteadyChecksquareHarmonicParityDetailVO();
            parityDetail.setTime(formatTime(detail.getPointTime()));
            parityDetail.setPhase(detail.getPhase());
            parityDetail.setStatType(detail.getStatType());
            parityDetail.setEvenHarmonicOrder(detail.getEvenHarmonicOrder());
            parityDetail.setEvenValue(detail.getEvenValue());
            parityDetail.setOddHarmonicOrders(readIntegerList(detail.getOddHarmonicOrdersJson()));
            parityDetail.setOddValues(readBigDecimalList(detail.getOddValuesJson()));
            parityDetail.setOddMedianValue(detail.getOddMedianValue());
            parityDetail.setThresholdMultiplier(detail.getThresholdMultiplier());
            result.getHarmonicParityDetails().add(parityDetail);
        }
    }

    private SteadyChecksquareTaskPO requireTask(String taskId) {
        SteadyChecksquareTaskPO task = taskService.getById(taskId);
        if (task == null || !Integer.valueOf(SteadyChecksquareConst.STATE_ENABLED).equals(task.getState())) {
            throw fail("数据校验任务不存在或已删除");
        }
        return task;
    }

    private SteadyChecksquareItemPO requireItem(String itemId) {
        SteadyChecksquareItemPO item = itemService.getById(itemId);
        if (item == null || !Integer.valueOf(SteadyChecksquareConst.STATE_ENABLED).equals(item.getState())) {
            throw fail("数据校验检测项不存在或已删除");
        }
        return item;
    }

    private boolean isSupportedDetailType(String detailType) {
        return SteadyChecksquareConst.DETAIL_TYPE_SEGMENT.equals(detailType)
                || SteadyChecksquareConst.DETAIL_TYPE_VALUE_ORDER.equals(detailType)
                || SteadyChecksquareConst.DETAIL_TYPE_HARMONIC_PARITY.equals(detailType);
    }

    private boolean isPaged(Integer pageNum, Integer pageSize) {
        return pageNum != null && pageNum > 0 && pageSize != null && pageSize > 0;
    }

    private SteadyChecksquareTaskVO toTaskVO(SteadyChecksquareTaskPO task) {
        SteadyChecksquareTaskVO vo = new SteadyChecksquareTaskVO();
        vo.setTaskId(task.getId());
        vo.setTaskNo(task.getTaskNo());
        vo.setLineIds(readTaskLineIds(task));
        vo.setLineName(task.getLineName());
        vo.setTimeStart(formatTime(task.getTimeStart()));
        vo.setTimeEnd(formatTime(task.getTimeEnd()));
        vo.setIntervalMinutes(task.getIntervalMinutes());
        vo.setTaskStatus(task.getTaskStatus());
        vo.setItemCount(task.getItemCount());
        vo.setAbnormalItemCount(task.getAbnormalItemCount());
        vo.setMinDataIntegrity(task.getMinDataIntegrity());
        vo.setCreateTime(formatTime(task.getCreateTime()));
        return vo;
    }

    private SteadyChecksquareItemVO toItemVO(SteadyChecksquareItemPO item) {
        SteadyChecksquareItemVO vo = new SteadyChecksquareItemVO();
        vo.setItemId(item.getId());
        vo.setItemKey(item.getItemKey());
        vo.setLineId(item.getLineId());
        vo.setLineName(item.getLineName());
        vo.setIndicatorCode(item.getIndicatorCode());
        vo.setIndicatorName(item.getIndicatorName());
        vo.setHarmonicOrder(item.getHarmonicOrder());
        vo.setIntervalMinutes(item.getIntervalMinutes());
        vo.setHasData(toBoolean(item.getHasData()));
        vo.setExpectedPointCount(item.getExpectedPointCount());
        vo.setActualPointCount(item.getActualPointCount());
        vo.setMissingPointCount(item.getMissingPointCount());
        vo.setDataIntegrity(item.getDataIntegrity());
        vo.setDataIntegrityText(item.getDataIntegrityText());
        vo.setAbnormal(toBoolean(item.getAbnormal()));
        vo.setAbnormalPointCount(item.getAbnormalPointCount());
        vo.setHarmonicParityAbnormal(toBoolean(item.getHarmonicParityAbnormal()));
        vo.setHarmonicParityAbnormalPointCount(item.getHarmonicParityAbnormalPointCount());
        return vo;
    }

    private SteadyChecksquareStatSummaryVO toSummaryVO(SteadyChecksquareStatSummaryPO summary) {
        SteadyChecksquareStatSummaryVO vo = new SteadyChecksquareStatSummaryVO();
        vo.setStatType(summary.getStatType());
        vo.setSupported(toBoolean(summary.getSupported()));
        vo.setHasData(toBoolean(summary.getHasData()));
        vo.setExpectedPointCount(summary.getExpectedPointCount());
        vo.setActualPointCount(summary.getActualPointCount());
        vo.setMissingPointCount(summary.getMissingPointCount());
        vo.setDataIntegrity(summary.getDataIntegrity());
        vo.setDataIntegrityText(summary.getDataIntegrityText());
        return vo;
    }

    private int countAbnormalItems(List<SteadyChecksquareItemVO> items) {
        int count = 0;
        for (SteadyChecksquareItemVO item : items) {
            if (!Boolean.TRUE.equals(item.getHasData())
                    || Boolean.TRUE.equals(item.getAbnormal())
                    || Boolean.TRUE.equals(item.getHarmonicParityAbnormal())) {
                count++;
            }
        }
        return count;
    }

    private BigDecimal minDataIntegrity(List<SteadyChecksquareItemVO> items) {
        BigDecimal min = BigDecimal.ONE.setScale(6, RoundingMode.HALF_UP);
        if (items == null || items.isEmpty()) {
            return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
        }
        for (SteadyChecksquareItemVO item : items) {
            if (item.getDataIntegrity() != null && item.getDataIntegrity().compareTo(min) < 0) {
                min = item.getDataIntegrity();
            }
        }
        return min;
    }

    private Boolean anyAbnormal(List<SteadyChecksquareItemVO> items) {
        for (SteadyChecksquareItemVO item : items) {
            if (Boolean.TRUE.equals(item.getAbnormal())) {
                return true;
            }
        }
        return false;
    }

    private Boolean anyHarmonicParityAbnormal(List<SteadyChecksquareItemVO> items) {
        for (SteadyChecksquareItemVO item : items) {
            if (Boolean.TRUE.equals(item.getHarmonicParityAbnormal())) {
                return true;
            }
        }
        return false;
    }

    private Integer averageInteger(List<SteadyChecksquareItemVO> items, String fieldName) {
        if (items == null || items.isEmpty()) {
            return 0;
        }
        int total = 0;
        for (SteadyChecksquareItemVO item : items) {
            total += valueOfItemInteger(item, fieldName);
        }
        return new BigDecimal(total).divide(new BigDecimal(items.size()), 0, RoundingMode.HALF_UP).intValue();
    }

    private Integer averageAbnormalCount(List<SteadyChecksquareItemVO> items, String fieldName, Boolean abnormal) {
        Integer average = averageInteger(items, fieldName);
        if (Boolean.TRUE.equals(abnormal) && average <= 0) {
            return 1;
        }
        return average;
    }

    private Integer averageSummaryInteger(List<SteadyChecksquareStatSummaryVO> summaries, String fieldName) {
        if (summaries == null || summaries.isEmpty()) {
            return 0;
        }
        int total = 0;
        for (SteadyChecksquareStatSummaryVO summary : summaries) {
            total += valueOfSummaryInteger(summary, fieldName);
        }
        return new BigDecimal(total).divide(new BigDecimal(summaries.size()), 0, RoundingMode.HALF_UP).intValue();
    }

    private BigDecimal averageDataIntegrity(List<SteadyChecksquareItemVO> items) {
        if (items == null || items.isEmpty()) {
            return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
        }
        BigDecimal total = BigDecimal.ZERO;
        for (SteadyChecksquareItemVO item : items) {
            total = total.add(item.getDataIntegrity() == null ? BigDecimal.ZERO : item.getDataIntegrity());
        }
        return total.divide(new BigDecimal(items.size()), 6, RoundingMode.HALF_UP);
    }

    private BigDecimal averageSummaryDataIntegrity(List<SteadyChecksquareStatSummaryVO> summaries) {
        if (summaries == null || summaries.isEmpty()) {
            return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
        }
        BigDecimal total = BigDecimal.ZERO;
        for (SteadyChecksquareStatSummaryVO summary : summaries) {
            total = total.add(summary.getDataIntegrity() == null ? BigDecimal.ZERO : summary.getDataIntegrity());
        }
        return total.divide(new BigDecimal(summaries.size()), 6, RoundingMode.HALF_UP);
    }

    private int valueOfItemInteger(SteadyChecksquareItemVO item, String fieldName) {
        if ("expectedPointCount".equals(fieldName)) {
            return nullToZero(item.getExpectedPointCount());
        }
        if ("actualPointCount".equals(fieldName)) {
            return nullToZero(item.getActualPointCount());
        }
        if ("missingPointCount".equals(fieldName)) {
            return nullToZero(item.getMissingPointCount());
        }
        if ("abnormalPointCount".equals(fieldName)) {
            return nullToZero(item.getAbnormalPointCount());
        }
        if ("harmonicParityAbnormalPointCount".equals(fieldName)) {
            return nullToZero(item.getHarmonicParityAbnormalPointCount());
        }
        return 0;
    }

    private int valueOfSummaryInteger(SteadyChecksquareStatSummaryVO summary, String fieldName) {
        if ("expectedPointCount".equals(fieldName)) {
            return nullToZero(summary.getExpectedPointCount());
        }
        if ("actualPointCount".equals(fieldName)) {
            return nullToZero(summary.getActualPointCount());
        }
        if ("missingPointCount".equals(fieldName)) {
            return nullToZero(summary.getMissingPointCount());
        }
        return 0;
    }

    private int nullToZero(Integer value) {
        return value == null ? 0 : value;
    }

    private BigDecimal calculateDataIntegrity(int actualCount, int expectedCount) {
        if (expectedCount <= 0) {
            return BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP);
        }
        return new BigDecimal(actualCount).divide(new BigDecimal(expectedCount), 6, RoundingMode.HALF_UP);
    }

    private boolean hasDataByIntegrity(BigDecimal dataIntegrity) {
        return dataIntegrity != null && dataIntegrity.compareTo(BigDecimal.ZERO) > 0;
    }

    private String formatRateText(BigDecimal rate) {
        if (rate == null) {
            return null;
        }
        return rate.multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP).toPlainString() + "%";
    }

    private String formatTime(LocalDateTime time) {
        if (time == null) {
            return null;
        }
        return time.format(TIME_FORMATTER);
    }

    private int toFlag(Boolean value) {
        return Boolean.TRUE.equals(value) ? 1 : 0;
    }

    private Boolean toBoolean(Integer value) {
        return value != null && value == 1;
    }

    private List<String> normalizeTextList(List<String> values) {
        if (values == null || values.isEmpty()) {
            return new ArrayList<String>();
        }
        Set<String> result = new LinkedHashSet<String>();
        for (String value : values) {
            String text = trimToNull(value);
            if (text != null) {
                result.add(text);
            }
        }
        return new ArrayList<String>(result);
    }

    private List<String> resolveLineIds(SteadyChecksquareQueryParam param) {
        return normalizeTextList(param == null ? null : param.getLineIds());
    }

    private List<String> resolveIndicatorCodes(SteadyChecksquareQueryParam param) {
        List<String> indicatorCodes = normalizeTextList(param == null ? null : param.getIndicatorCodes());
        if (!indicatorCodes.isEmpty()) {
            return indicatorCodes;
        }
        List<String> allIndicatorCodes = new ArrayList<String>();
        for (SteadyTrendIndicatorDefinitionBO indicator : indicatorCatalog.listIndicators()) {
            allIndicatorCodes.add(indicator.getIndicatorCode());
        }
        return allIndicatorCodes;
    }

    private List<String> resolveResultLineIds(SteadyChecksquareQueryVO result) {
        return normalizeTextList(result == null ? null : result.getLineIds());
    }

    private List<String> readTaskLineIds(SteadyChecksquareTaskPO task) {
        List<String> lineIds = readStringList(task.getLineIdsJson());
        if (lineIds.isEmpty() && trimToNull(task.getLineId()) != null) {
            lineIds.add(trimToNull(task.getLineId()));
        }
        return lineIds;
    }

    private SteadyChecksquareQueryParam copyCreateParam(SteadyChecksquareQueryParam param, List<String> indicatorCodes) {
        SteadyChecksquareQueryParam result = new SteadyChecksquareQueryParam();
        List<String> lineIds = resolveLineIds(param);
        result.setLineIds(new ArrayList<String>(lineIds));
        result.setIndicatorCodes(new ArrayList<String>(indicatorCodes));
        result.setTimeStart(param.getTimeStart());
        result.setTimeEnd(param.getTimeEnd());
        return result;
    }

    private String trimToNull(String value) {
        if (value == null) {
            return null;
        }
        String trimmed = value.trim();
        return trimmed.isEmpty() ? null : trimmed;
    }

    private String writeJson(Object value) {
        try {
            return objectMapper.writeValueAsString(value);
        } catch (Exception exception) {
            throw new BusinessException(CommonResponseEnum.JSON_CONVERT_EXCEPTION, exception.getMessage());
        }
    }

    private String buildIndicatorCodesText(List<String> indicatorCodes) {
        return buildTextListSearchValue(indicatorCodes);
    }

    private String buildTextListSearchValue(List<String> values) {
        if (values == null || values.isEmpty()) {
            return null;
        }
        StringBuilder builder = new StringBuilder("|");
        for (String value : values) {
            builder.append(value).append("|");
        }
        return builder.toString();
    }

    private String limitMessage(String message) {
        String text = trimToNull(message);
        if (text == null) {
            return "数据校验任务执行失败";
        }
        return text.length() > 2000 ? text.substring(0, 2000) : text;
    }

    private List<String> parseTextListSearchValue(String value) {
        String text = trimToNull(value);
        if (text == null) {
            return new ArrayList<String>();
        }
        return normalizeTextList(Arrays.asList(text.split("\\|")));
    }

    private List<Integer> readIntegerList(String json) {
        if (trimToNull(json) == null) {
            return new ArrayList<Integer>();
        }
        try {
            Integer[] values = objectMapper.readValue(json, Integer[].class);
            return new ArrayList<Integer>(Arrays.asList(values));
        } catch (Exception exception) {
            throw new BusinessException(CommonResponseEnum.JSON_CONVERT_EXCEPTION, exception.getMessage());
        }
    }

    private List<String> readStringList(String json) {
        if (trimToNull(json) == null) {
            return new ArrayList<String>();
        }
        try {
            String[] values = objectMapper.readValue(json, String[].class);
            return normalizeTextList(Arrays.asList(values));
        } catch (Exception exception) {
            throw new BusinessException(CommonResponseEnum.JSON_CONVERT_EXCEPTION, exception.getMessage());
        }
    }

    private List<BigDecimal> readBigDecimalList(String json) {
        if (trimToNull(json) == null) {
            return new ArrayList<BigDecimal>();
        }
        try {
            BigDecimal[] values = objectMapper.readValue(json, BigDecimal[].class);
            return new ArrayList<BigDecimal>(Arrays.asList(values));
        } catch (Exception exception) {
            throw new BusinessException(CommonResponseEnum.JSON_CONVERT_EXCEPTION, exception.getMessage());
        }
    }

    private BusinessException fail(String message) {
        return new BusinessException(CommonResponseEnum.FAIL, message);
    }

    private static class CreateContext {
        private final List<String> lineIds;
        private final Map<String, AddLedgerLinePathVO> linePathMap;
        private final LocalDateTime startTime;
        private final LocalDateTime endTime;
        private final int intervalMinutes;
        private final List<String> indicatorCodes;

        private CreateContext(List<String> lineIds, Map<String, AddLedgerLinePathVO> linePathMap, LocalDateTime startTime,
                              LocalDateTime endTime, int intervalMinutes, List<String> indicatorCodes) {
            this.lineIds = lineIds;
            this.linePathMap = linePathMap;
            this.startTime = startTime;
            this.endTime = endTime;
            this.intervalMinutes = intervalMinutes;
            this.indicatorCodes = indicatorCodes;
        }
    }
}



