package com.yhy.module.core.service.workbench.impl;

import com.yhy.module.core.controller.admin.workbench.vo.WbUnifiedFeeSummaryItemVO;
import com.yhy.module.core.dal.dataobject.quota.QuotaUnifiedFeeSettingDO;
import com.yhy.module.core.dal.dataobject.workbench.WbBoqDivisionDO;
import com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeConfigDO;
import com.yhy.module.core.dal.dataobject.workbench.WbUnitInfoDO;
import com.yhy.module.core.dal.mysql.quota.QuotaUnifiedFeeSettingMapper;
import com.yhy.module.core.dal.mysql.workbench.WbBoqDivisionMapper;
import com.yhy.module.core.dal.mysql.workbench.WbUnifiedFeeConfigMapper;
import com.yhy.module.core.dal.mysql.workbench.WbUnitInfoMapper;
import com.yhy.module.core.service.workbench.WbUnifiedFeeConfigService;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工作台统一取费配置 Service 实现类
 */
@Slf4j
@Service
public class WbUnifiedFeeConfigServiceImpl implements WbUnifiedFeeConfigService {

    @Resource
    private WbUnifiedFeeConfigMapper wbUnifiedFeeConfigMapper;

    @Resource
    private WbBoqDivisionMapper wbBoqDivisionMapper;

    @Resource
    private WbUnitInfoMapper wbUnitInfoMapper;

    @Resource
    private QuotaUnifiedFeeSettingMapper quotaUnifiedFeeSettingMapper;

    @Resource
    private com.yhy.module.core.dal.mysql.quota.QuotaItemMapper quotaItemMapper;

    @Resource
    private com.yhy.module.core.service.workbench.WbSnapshotReadService wbSnapshotReadService;

    @Resource
    private com.yhy.module.core.dal.mysql.workbench.WbUnifiedFeeSettingMapper wbUnifiedFeeSettingMapper;

    @Override
    public List<WbUnifiedFeeConfigDO> getListByCompileTreeId(Long compileTreeId) {
        return wbUnifiedFeeConfigMapper.selectListByCompileTreeId(compileTreeId);
    }

    @Override
    public List<WbUnifiedFeeConfigDO> getListByCompileTreeIdAndRateModeId(Long compileTreeId, Long rateModeId) {
        return wbUnifiedFeeConfigMapper.selectListByCompileTreeIdAndRateModeId(compileTreeId, rateModeId);
    }

    @Override
    public WbUnifiedFeeConfigDO getBySourceUnifiedFeeSettingId(Long compileTreeId, Long sourceUnifiedFeeSettingId) {
        return wbUnifiedFeeConfigMapper.selectOne(new LambdaQueryWrapperX<WbUnifiedFeeConfigDO>()
                .eq(WbUnifiedFeeConfigDO::getCompileTreeId, compileTreeId)
                .eq(WbUnifiedFeeConfigDO::getSourceUnifiedFeeSettingId, sourceUnifiedFeeSettingId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrUpdate(WbUnifiedFeeConfigDO config) {
        if (config.getId() != null) {
            // 合并configData而不是完全覆盖
            WbUnifiedFeeConfigDO existing = wbUnifiedFeeConfigMapper.selectById(config.getId());
            if (existing != null && existing.getConfigData() != null && config.getConfigData() != null) {
                Map<String, Object> mergedConfigData = new HashMap<>(existing.getConfigData());
                mergedConfigData.putAll(config.getConfigData());
                config.setConfigData(mergedConfigData);
            }
            wbUnifiedFeeConfigMapper.updateById(config);
            return config.getId();
        } else {
            // 检查是否已存在相同的配置
            WbUnifiedFeeConfigDO existing = getBySourceUnifiedFeeSettingId(
                    config.getCompileTreeId(), config.getSourceUnifiedFeeSettingId());
            if (existing != null) {
                // 合并configData而不是完全覆盖
                if (existing.getConfigData() != null && config.getConfigData() != null) {
                    Map<String, Object> mergedConfigData = new HashMap<>(existing.getConfigData());
                    mergedConfigData.putAll(config.getConfigData());
                    config.setConfigData(mergedConfigData);
                }
                config.setId(existing.getId());
                wbUnifiedFeeConfigMapper.updateById(config);
                return existing.getId();
            } else {
                wbUnifiedFeeConfigMapper.insert(config);
                return config.getId();
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchSave(Long compileTreeId, Long rateModeId, List<WbUnifiedFeeConfigDO> configs) {
        for (WbUnifiedFeeConfigDO config : configs) {
            config.setCompileTreeId(compileTreeId);
            config.setRateModeId(rateModeId);
            saveOrUpdate(config);
        }
    }

    @Override
    public void delete(Long id) {
        wbUnifiedFeeConfigMapper.deleteById(id);
    }

    @Override
    public void deleteByRateModeId(Long compileTreeId, Long rateModeId) {
        wbUnifiedFeeConfigMapper.deleteByRateModeId(compileTreeId, rateModeId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyUnifiedFee(Long compileTreeId) {
        log.info("[应用统一取费] 开始 - compileTreeId={}", compileTreeId);
        
        // 1. 获取该单位工程的所有统一取费配置（支持多个定额专业/费率模式）
        List<WbUnifiedFeeConfigDO> configs = wbUnifiedFeeConfigMapper.selectList(
                new LambdaQueryWrapperX<WbUnifiedFeeConfigDO>()
                        .eq(WbUnifiedFeeConfigDO::getCompileTreeId, compileTreeId));
        if (configs.isEmpty()) {
            log.info("[应用统一取费] 单位工程{}没有统一取费配置", compileTreeId);
            return;
        }
        log.info("[应用统一取费] 找到{}条统一取费配置", configs.size());

        // 3. 获取统一取费设置（父定额）信息 - 优先从快照表读取
        Set<Long> settingIds = configs.stream()
                .map(WbUnifiedFeeConfigDO::getSourceUnifiedFeeSettingId)
                .collect(Collectors.toSet());
        
        // 3.1 尝试从快照表读取
        List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO> snapshotSettings = 
                wbUnifiedFeeSettingMapper.selectByCompileTreeId(compileTreeId);
        Map<Long, com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO> snapshotSettingMap = 
                snapshotSettings.stream()
                        .filter(s -> s.getSourceId() != null)
                        .collect(Collectors.toMap(
                                com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO::getSourceId, 
                                s -> s,
                                (a, b) -> a));
        
        // 3.2 只从快照表读取，不回退到后台标准库
        Map<Long, QuotaUnifiedFeeSettingDO> settingMap;
        if (snapshotSettingMap.isEmpty()) {
            log.warn("[应用统一取费] 快照不存在, compileTreeId={}", compileTreeId);
            settingMap = new HashMap<>();
        } else {
            log.info("[应用统一取费] 从快照表读取统一取费设置, 数量={}", snapshotSettingMap.size());
            // 将快照数据转换为后台数据格式（用于兼容后续逻辑）
            settingMap = new HashMap<>();
            for (Long sourceId : settingIds) {
                com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO snapshot = snapshotSettingMap.get(sourceId);
                if (snapshot != null) {
                    QuotaUnifiedFeeSettingDO converted = new QuotaUnifiedFeeSettingDO();
                    converted.setId(snapshot.getSourceId());
                    converted.setCode(snapshot.getCode());
                    converted.setName(snapshot.getName());
                    converted.setFeeChapter(snapshot.getFeeChapter());
                    converted.setFeeCategory(snapshot.getFeeCategory());
                    converted.setThisListPercentage(snapshot.getThisListPercentage());
                    converted.setSpecifiedListPercentage(snapshot.getSpecifiedListPercentage());
                    converted.setSpecifiedListCode(snapshot.getSpecifiedListCode());
                    converted.setNodeType(snapshot.getNodeType());
                    converted.setUnit(snapshot.getUnit());
                    settingMap.put(sourceId, converted);
                }
            }
        }

        // 4. 获取已存在的统一取费目录节点（用于防止重复添加）
        List<WbBoqDivisionDO> existingUnifiedFeeNodes = wbBoqDivisionMapper.selectList(new LambdaQueryWrapperX<WbBoqDivisionDO>()
                .eq(WbBoqDivisionDO::getCompileTreeId, compileTreeId)
                .eq(WbBoqDivisionDO::getNodeType, "unified_fee"));
        // 构建已存在的映射：parentId + sourceUnifiedFeeSettingId -> 节点
        Map<String, WbBoqDivisionDO> existingMap = new HashMap<>();
        for (WbBoqDivisionDO node : existingUnifiedFeeNodes) {
            Map<String, Object> attrs = node.getAttributes();
            if (attrs != null && attrs.get("sourceUnifiedFeeSettingId") != null) {
                String key = node.getParentId() + "_" + attrs.get("sourceUnifiedFeeSettingId");
                existingMap.put(key, node);
            }
        }

        // 5. 遍历配置，将统一取费目录添加到对应的清单下（与定额同级）
        for (WbUnifiedFeeConfigDO config : configs) {
            Map<String, Object> configData = config.getConfigData();
            if (configData == null) continue;

            // 优先使用quotaIds（定额节点ID），如果没有则使用divisionIds（兼容旧数据）
            @SuppressWarnings("unchecked")
            List<Object> quotaIdList = (List<Object>) configData.get("quotaIds");
            if (quotaIdList == null || quotaIdList.isEmpty()) {
                // 兼容旧数据：使用divisionIds
                @SuppressWarnings("unchecked")
                List<Object> divisionIds = (List<Object>) configData.get("divisionIds");
                quotaIdList = divisionIds;
            }
            
            QuotaUnifiedFeeSettingDO setting = settingMap.get(config.getSourceUnifiedFeeSettingId());
            if (setting == null) continue;
            
            // 如果quotaIds为空，说明用户清空了选择，需要删除对应的统一取费节点
            if (quotaIdList == null || quotaIdList.isEmpty()) {
                log.info("[应用统一取费] 配置{}的quotaIds为空，删除对应的统一取费节点", config.getId());
                // 删除该配置对应的所有统一取费节点
                for (WbBoqDivisionDO existingNode : existingUnifiedFeeNodes) {
                    Map<String, Object> attrs = existingNode.getAttributes();
                    if (attrs != null && config.getSourceUnifiedFeeSettingId().equals(
                            Long.valueOf(attrs.get("sourceUnifiedFeeSettingId").toString()))) {
                        wbBoqDivisionMapper.deleteById(existingNode.getId());
                        log.info("[应用统一取费] 删除统一取费节点：{}", existingNode.getId());
                    }
                }
                continue;
            }

            // 找到所有选中定额的父节点（清单），按父节点分组
            // 统一取费节点应该插入到清单下，与定额同级
            Map<Long, List<Long>> parentToQuotaIds = new HashMap<>();
            for (Object divisionIdObj : quotaIdList) {
                Long quotaId = Long.valueOf(divisionIdObj.toString());
                WbBoqDivisionDO quotaNode = wbBoqDivisionMapper.selectById(quotaId);
                if (quotaNode == null) {
                    log.warn("定额节点不存在：{}", quotaId);
                    continue;
                }
                // 只处理定额类型的节点
                if (!"quota".equals(quotaNode.getNodeType())) {
                    log.warn("节点不是定额类型，跳过：id={}, nodeType={}", quotaId, quotaNode.getNodeType());
                    continue;
                }
                Long parentId = quotaNode.getParentId();
                if (parentId == null) {
                    log.warn("定额节点没有父节点：{}", quotaId);
                    continue;
                }
                parentToQuotaIds.computeIfAbsent(parentId, k -> new ArrayList<>()).add(quotaId);
            }

            // 为每个清单（父节点）创建一个统一取费节点
            for (Map.Entry<Long, List<Long>> entry : parentToQuotaIds.entrySet()) {
                Long parentId = entry.getKey(); // 清单ID
                List<Long> quotaIds = entry.getValue(); // 该清单下被选中的定额ID列表

                // 获取父节点（清单）
                WbBoqDivisionDO parentNode = wbBoqDivisionMapper.selectById(parentId);
                if (parentNode == null) {
                    log.warn("清单节点不存在：{}", parentId);
                    continue;
                }

                // 使用parentId构建key，与existingMap中的key保持一致
                String key = parentId + "_" + config.getSourceUnifiedFeeSettingId();

                // 检查是否已存在
                WbBoqDivisionDO existingNode = existingMap.get(key);
                if (existingNode != null) {
                    // 已存在，更新motherQuotaIds和其他配置
                    Map<String, Object> existingAttrs = existingNode.getAttributes();
                    if (existingAttrs == null) {
                        existingAttrs = new HashMap<>();
                    }
                    existingAttrs.put("motherQuotaIds", quotaIds);
                    existingAttrs.put("feeCategory", configData.get("feeCategory") != null ? configData.get("feeCategory") : setting.getFeeCategory());
                    existingAttrs.put("thisListPercentage", configData.get("thisListPercentage") != null ? configData.get("thisListPercentage") : setting.getThisListPercentage());
                    existingAttrs.put("specifiedListPercentage", configData.get("specifiedListPercentage") != null ? configData.get("specifiedListPercentage") : setting.getSpecifiedListPercentage());
                    existingAttrs.put("specifiedListCode", configData.get("specifiedListCode") != null ? configData.get("specifiedListCode") : setting.getSpecifiedListCode());
                    existingNode.setAttributes(existingAttrs);
                    wbBoqDivisionMapper.updateById(existingNode);
                    log.info("更新统一取费目录：parentId(清单)={}, settingId={}, nodeId={}, 母定额数量={}", 
                            parentId, config.getSourceUnifiedFeeSettingId(), existingNode.getId(), quotaIds.size());
                    continue;
                }

                // 标记为已处理，防止同一次请求中重复添加
                existingMap.put(key, null);
                
                // 获取清单下的最大排序号
                Integer maxSortOrder = wbBoqDivisionMapper.selectMaxSortOrderByParentId(compileTreeId, parentId);
                int newSortOrder = (maxSortOrder != null ? maxSortOrder : 0) + 1;

                // 创建统一取费目录节点（作为清单的子节点，与定额同级）
                WbBoqDivisionDO unifiedFeeNode = new WbBoqDivisionDO();
                unifiedFeeNode.setCompileTreeId(compileTreeId);
                unifiedFeeNode.setParentId(parentId);
                unifiedFeeNode.setNodeType("unified_fee");
                unifiedFeeNode.setSourceType("unified_fee");
                unifiedFeeNode.setCode(setting.getCode());
                unifiedFeeNode.setName(setting.getName());
                unifiedFeeNode.setSortOrder(newSortOrder);
                // 统一取费节点的工程量默认为1
                unifiedFeeNode.setQty(java.math.BigDecimal.ONE);

                // 存储来源信息到attributes，包括选中的定额ID列表
                Map<String, Object> attributes = new HashMap<>();
                attributes.put("sourceUnifiedFeeSettingId", config.getSourceUnifiedFeeSettingId());
                attributes.put("rateModeId", config.getRateModeId());
                attributes.put("feeChapter", setting.getFeeChapter());
                attributes.put("feeCategory", configData.get("feeCategory") != null ? configData.get("feeCategory") : setting.getFeeCategory());
                attributes.put("thisListPercentage", configData.get("thisListPercentage") != null ? configData.get("thisListPercentage") : setting.getThisListPercentage());
                attributes.put("specifiedListPercentage", configData.get("specifiedListPercentage") != null ? configData.get("specifiedListPercentage") : setting.getSpecifiedListPercentage());
                attributes.put("specifiedListCode", configData.get("specifiedListCode") != null ? configData.get("specifiedListCode") : setting.getSpecifiedListCode());
                // 存储选中的母定额ID列表，用于计算汇总
                attributes.put("motherQuotaIds", quotaIds);
                unifiedFeeNode.setAttributes(attributes);

                // 构建path（基于清单的path）
                String[] parentPath = parentNode.getPath();
                String[] newPath = new String[(parentPath != null ? parentPath.length : 0) + 1];
                if (parentPath != null) {
                    System.arraycopy(parentPath, 0, newPath, 0, parentPath.length);
                }

                wbBoqDivisionMapper.insert(unifiedFeeNode);

                // 更新path（包含自己的ID）
                newPath[newPath.length - 1] = String.valueOf(unifiedFeeNode.getId());
                unifiedFeeNode.setPath(newPath);
                wbBoqDivisionMapper.updateById(unifiedFeeNode);

                log.info("添加统一取费目录：parentId(清单)={}, settingId={}, nodeId={}, 母定额数量={}", 
                        parentId, config.getSourceUnifiedFeeSettingId(), unifiedFeeNode.getId(), quotaIds.size());
            }

            // 6. 处理指定清单编码逻辑：在指定清单下也创建统一取费节点
            String specifiedListCode = configData.get("specifiedListCode") != null ? 
                    configData.get("specifiedListCode").toString() : setting.getSpecifiedListCode();
            if (specifiedListCode != null && !specifiedListCode.isEmpty()) {
                // 查找指定清单编码对应的清单节点
                List<WbBoqDivisionDO> specifiedLists = wbBoqDivisionMapper.selectList(
                        new LambdaQueryWrapperX<WbBoqDivisionDO>()
                                .eq(WbBoqDivisionDO::getCompileTreeId, compileTreeId)
                                .eq(WbBoqDivisionDO::getNodeType, "boq")
                                .eq(WbBoqDivisionDO::getCode, specifiedListCode));
                
                for (WbBoqDivisionDO specifiedList : specifiedLists) {
                    Long specifiedParentId = specifiedList.getId();
                    String specifiedKey = specifiedParentId + "_" + config.getSourceUnifiedFeeSettingId() + "_specified";
                    
                    // 检查是否已存在
                    if (existingMap.containsKey(specifiedKey)) {
                        continue;
                    }
                    
                    // 检查指定清单下是否已有该统一取费节点
                    WbBoqDivisionDO existingSpecifiedNode = null;
                    for (WbBoqDivisionDO node : existingUnifiedFeeNodes) {
                        if (specifiedParentId.equals(node.getParentId())) {
                            Map<String, Object> attrs = node.getAttributes();
                            if (attrs != null && config.getSourceUnifiedFeeSettingId().equals(
                                    Long.valueOf(attrs.get("sourceUnifiedFeeSettingId").toString()))) {
                                existingSpecifiedNode = node;
                                break;
                            }
                        }
                    }
                    
                    if (existingSpecifiedNode != null) {
                        // 已存在，更新配置
                        Map<String, Object> existingAttrs = existingSpecifiedNode.getAttributes();
                        if (existingAttrs == null) {
                            existingAttrs = new HashMap<>();
                        }
                        // 指定清单节点的motherQuotaIds应该包含所有相关定额
                        List<Long> allQuotaIds = new ArrayList<>();
                        for (List<Long> ids : parentToQuotaIds.values()) {
                            allQuotaIds.addAll(ids);
                        }
                        existingAttrs.put("motherQuotaIds", allQuotaIds);
                        existingAttrs.put("isSpecifiedList", true);
                        existingSpecifiedNode.setAttributes(existingAttrs);
                        wbBoqDivisionMapper.updateById(existingSpecifiedNode);
                        log.info("更新指定清单统一取费目录：specifiedListCode={}, nodeId={}", 
                                specifiedListCode, existingSpecifiedNode.getId());
                        existingMap.put(specifiedKey, existingSpecifiedNode);
                        continue;
                    }
                    
                    existingMap.put(specifiedKey, null);
                    
                    // 获取指定清单下的最大排序号
                    Integer maxSortOrder = wbBoqDivisionMapper.selectMaxSortOrderByParentId(compileTreeId, specifiedParentId);
                    int newSortOrder = (maxSortOrder != null ? maxSortOrder : 0) + 1;
                    
                    // 创建指定清单下的统一取费节点
                    WbBoqDivisionDO specifiedUnifiedFeeNode = new WbBoqDivisionDO();
                    specifiedUnifiedFeeNode.setCompileTreeId(compileTreeId);
                    specifiedUnifiedFeeNode.setParentId(specifiedParentId);
                    specifiedUnifiedFeeNode.setNodeType("unified_fee");
                    specifiedUnifiedFeeNode.setSourceType("unified_fee");
                    specifiedUnifiedFeeNode.setCode(setting.getCode());
                    specifiedUnifiedFeeNode.setName(setting.getName());
                    specifiedUnifiedFeeNode.setSortOrder(newSortOrder);
                    // 统一取费节点的工程量默认为1
                    specifiedUnifiedFeeNode.setQty(java.math.BigDecimal.ONE);
                    
                    // 存储来源信息，标记为指定清单节点
                    Map<String, Object> specifiedAttrs = new HashMap<>();
                    specifiedAttrs.put("sourceUnifiedFeeSettingId", config.getSourceUnifiedFeeSettingId());
                    specifiedAttrs.put("rateModeId", config.getRateModeId());
                    specifiedAttrs.put("feeChapter", setting.getFeeChapter());
                    specifiedAttrs.put("feeCategory", configData.get("feeCategory") != null ? configData.get("feeCategory") : setting.getFeeCategory());
                    specifiedAttrs.put("thisListPercentage", configData.get("thisListPercentage") != null ? configData.get("thisListPercentage") : setting.getThisListPercentage());
                    specifiedAttrs.put("specifiedListPercentage", configData.get("specifiedListPercentage") != null ? configData.get("specifiedListPercentage") : setting.getSpecifiedListPercentage());
                    specifiedAttrs.put("specifiedListCode", specifiedListCode);
                    specifiedAttrs.put("isSpecifiedList", true);
                    // 指定清单节点的motherQuotaIds应该包含所有相关定额
                    List<Long> allQuotaIds = new ArrayList<>();
                    for (List<Long> ids : parentToQuotaIds.values()) {
                        allQuotaIds.addAll(ids);
                    }
                    specifiedAttrs.put("motherQuotaIds", allQuotaIds);
                    specifiedUnifiedFeeNode.setAttributes(specifiedAttrs);
                    
                    // 构建path
                    String[] specifiedParentPath = specifiedList.getPath();
                    String[] specifiedNewPath = new String[(specifiedParentPath != null ? specifiedParentPath.length : 0) + 1];
                    if (specifiedParentPath != null) {
                        System.arraycopy(specifiedParentPath, 0, specifiedNewPath, 0, specifiedParentPath.length);
                    }
                    
                    wbBoqDivisionMapper.insert(specifiedUnifiedFeeNode);
                    
                    specifiedNewPath[specifiedNewPath.length - 1] = String.valueOf(specifiedUnifiedFeeNode.getId());
                    specifiedUnifiedFeeNode.setPath(specifiedNewPath);
                    wbBoqDivisionMapper.updateById(specifiedUnifiedFeeNode);
                    
                    log.info("添加指定清单统一取费目录：specifiedListCode={}, parentId={}, nodeId={}, 母定额数量={}", 
                            specifiedListCode, specifiedParentId, specifiedUnifiedFeeNode.getId(), allQuotaIds.size());
                }
            }
        }
    }

    @Override
    public List<WbUnifiedFeeSummaryItemVO> getSummarySource(Long compileTreeId, Long sourceUnifiedFeeSettingId) {
        // 1. 获取统一取费配置
        WbUnifiedFeeConfigDO config = getBySourceUnifiedFeeSettingId(compileTreeId, sourceUnifiedFeeSettingId);
        if (config == null || config.getConfigData() == null) {
            return new ArrayList<>();
        }

        // 2. 从configData中获取divisionIds（范围）
        Map<String, Object> configData = config.getConfigData();
        Object divisionIdsObj = configData.get("divisionIds");
        if (divisionIdsObj == null) {
            return new ArrayList<>();
        }

        List<Long> divisionIds = new ArrayList<>();
        if (divisionIdsObj instanceof List) {
            for (Object id : (List<?>) divisionIdsObj) {
                if (id instanceof Number) {
                    divisionIds.add(((Number) id).longValue());
                } else if (id instanceof String) {
                    try {
                        divisionIds.add(Long.parseLong((String) id));
                    } catch (NumberFormatException e) {
                        log.warn("无法解析divisionId: {}", id);
                    }
                }
            }
        }

        if (divisionIds.isEmpty()) {
            return new ArrayList<>();
        }

        // 3. 查询这些分部/清单下的所有定额节点，或者divisionIds本身就是定额节点
        // 情况1：divisionIds是分部/清单ID，查询其下的quota节点
        List<WbBoqDivisionDO> quotaNodes = wbBoqDivisionMapper.selectList(
            new LambdaQueryWrapperX<WbBoqDivisionDO>()
                .eq(WbBoqDivisionDO::getCompileTreeId, compileTreeId)
                .eq(WbBoqDivisionDO::getNodeType, "quota")
                .in(WbBoqDivisionDO::getParentId, divisionIds)
        );
        
        // 情况2：divisionIds本身就是quota节点ID
        if (quotaNodes.isEmpty()) {
            quotaNodes = wbBoqDivisionMapper.selectList(
                new LambdaQueryWrapperX<WbBoqDivisionDO>()
                    .eq(WbBoqDivisionDO::getCompileTreeId, compileTreeId)
                    .eq(WbBoqDivisionDO::getNodeType, "quota")
                    .in(WbBoqDivisionDO::getId, divisionIds)
            );
        }

        // 4. 获取所有父节点ID，用于查询父节点的sortOrder
        Set<Long> parentIds = quotaNodes.stream()
                .map(WbBoqDivisionDO::getParentId)
                .filter(id -> id != null)
                .collect(Collectors.toSet());
        Map<Long, Integer> parentSortOrderMap = new HashMap<>();
        if (!parentIds.isEmpty()) {
            List<WbBoqDivisionDO> parentNodes = wbBoqDivisionMapper.selectBatchIds(new ArrayList<>(parentIds));
            for (WbBoqDivisionDO parent : parentNodes) {
                parentSortOrderMap.put(parent.getId(), parent.getSortOrder() != null ? parent.getSortOrder() : 0);
            }
        }
        
        // 按分部分项顺序排序（先按父节点sortOrder，再按自身sortOrder）
        quotaNodes.sort((a, b) -> {
            Integer parentSortA = parentSortOrderMap.getOrDefault(a.getParentId(), 0);
            Integer parentSortB = parentSortOrderMap.getOrDefault(b.getParentId(), 0);
            int parentCmp = parentSortA.compareTo(parentSortB);
            if (parentCmp != 0) return parentCmp;
            
            Integer sortA = a.getSortOrder() != null ? a.getSortOrder() : 0;
            Integer sortB = b.getSortOrder() != null ? b.getSortOrder() : 0;
            return sortA.compareTo(sortB);
        });

        // 5. 转换为VO（category使用nodeType，前端会通过字典转换为显示文本）
        return quotaNodes.stream().map(node -> {
            WbUnifiedFeeSummaryItemVO vo = new WbUnifiedFeeSummaryItemVO();
            vo.setId(node.getId());
            vo.setCode(node.getCode());
            vo.setCategory(node.getNodeType()); // 前端通过division_category字典转换
            vo.setName(node.getName());
            vo.setUnit(node.getUnit()); // 单位字段
            vo.setQuantity(node.getQty());
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<WbUnifiedFeeSummaryItemVO> getSummarySourceByDivisionId(Long divisionId) {
        // 1. 获取统一取费节点
        WbBoqDivisionDO unifiedFeeNode = wbBoqDivisionMapper.selectById(divisionId);
        if (unifiedFeeNode == null || !"unified_fee".equals(unifiedFeeNode.getNodeType())) {
            return new ArrayList<>();
        }

        // 2. 从节点的attributes中获取motherQuotaIds（优先）或sourceUnifiedFeeSettingId
        Map<String, Object> attributes = unifiedFeeNode.getAttributes();
        if (attributes == null) {
            return new ArrayList<>();
        }

        // 优先使用motherQuotaIds（新逻辑：直接存储在节点属性中）
        @SuppressWarnings("unchecked")
        List<Object> motherQuotaIdsObj = (List<Object>) attributes.get("motherQuotaIds");
        if (motherQuotaIdsObj != null && !motherQuotaIdsObj.isEmpty()) {
            // 直接根据motherQuotaIds获取定额节点
            List<Long> motherQuotaIds = motherQuotaIdsObj.stream()
                    .map(obj -> {
                        if (obj instanceof Number) {
                            return ((Number) obj).longValue();
                        } else if (obj instanceof String) {
                            return Long.parseLong((String) obj);
                        }
                        return null;
                    })
                    .filter(id -> id != null)
                    .collect(Collectors.toList());

            if (!motherQuotaIds.isEmpty()) {
                List<WbBoqDivisionDO> quotaNodes = wbBoqDivisionMapper.selectBatchIds(motherQuotaIds);
                
                // 获取所有父节点ID，用于查询父节点的sortOrder
                Set<Long> parentIds = quotaNodes.stream()
                        .map(WbBoqDivisionDO::getParentId)
                        .filter(id -> id != null)
                        .collect(Collectors.toSet());
                Map<Long, Integer> parentSortOrderMap = new HashMap<>();
                if (!parentIds.isEmpty()) {
                    List<WbBoqDivisionDO> parentNodes = wbBoqDivisionMapper.selectBatchIds(new ArrayList<>(parentIds));
                    for (WbBoqDivisionDO parent : parentNodes) {
                        parentSortOrderMap.put(parent.getId(), parent.getSortOrder() != null ? parent.getSortOrder() : 0);
                    }
                }
                
                // 按分部分项顺序排序（先按父节点sortOrder，再按自身sortOrder）
                quotaNodes.sort((a, b) -> {
                    // 先比较父节点的sortOrder（清单的顺序）
                    Integer parentSortA = parentSortOrderMap.getOrDefault(a.getParentId(), 0);
                    Integer parentSortB = parentSortOrderMap.getOrDefault(b.getParentId(), 0);
                    int parentCmp = parentSortA.compareTo(parentSortB);
                    if (parentCmp != 0) return parentCmp;
                    
                    // 父节点相同则按自身sortOrder排序
                    Integer sortA = a.getSortOrder() != null ? a.getSortOrder() : 0;
                    Integer sortB = b.getSortOrder() != null ? b.getSortOrder() : 0;
                    return sortA.compareTo(sortB);
                });
                // 批量查询定额基价的catalogItemId
                Set<Long> quotaItemIds = quotaNodes.stream()
                        .map(WbBoqDivisionDO::getSourceQuotaItemId)
                        .filter(id -> id != null)
                        .collect(Collectors.toSet());
                Map<Long, Long> quotaItemToCatalogMap = new HashMap<>();
                if (!quotaItemIds.isEmpty()) {
                    List<com.yhy.module.core.dal.dataobject.quota.QuotaItemDO> quotaItems = 
                        quotaItemMapper.selectBatchIds(new ArrayList<>(quotaItemIds));
                    for (com.yhy.module.core.dal.dataobject.quota.QuotaItemDO item : quotaItems) {
                        quotaItemToCatalogMap.put(item.getId(), item.getCatalogItemId());
                    }
                }
                
                return quotaNodes.stream().map(node -> {
                    WbUnifiedFeeSummaryItemVO vo = new WbUnifiedFeeSummaryItemVO();
                    vo.setId(node.getId());
                    vo.setCode(node.getCode());
                    vo.setCategory(node.getNodeType());
                    vo.setName(node.getName());
                    vo.setUnit(node.getUnit());
                    vo.setQuantity(node.getQty());
                    // 设置sourceCatalogItemId用于取费章节过滤
                    if (node.getSourceQuotaItemId() != null) {
                        vo.setSourceCatalogItemId(quotaItemToCatalogMap.get(node.getSourceQuotaItemId()));
                    }
                    return vo;
                }).collect(Collectors.toList());
            }
        }

        // 兼容旧逻辑：使用sourceUnifiedFeeSettingId从配置中获取
        Object settingIdObj = attributes.get("sourceUnifiedFeeSettingId");
        if (settingIdObj == null) {
            return new ArrayList<>();
        }

        Long sourceUnifiedFeeSettingId;
        if (settingIdObj instanceof Number) {
            sourceUnifiedFeeSettingId = ((Number) settingIdObj).longValue();
        } else if (settingIdObj instanceof String) {
            try {
                sourceUnifiedFeeSettingId = Long.parseLong((String) settingIdObj);
            } catch (NumberFormatException e) {
                log.warn("无法解析sourceUnifiedFeeSettingId: {}", settingIdObj);
                return new ArrayList<>();
            }
        } else {
            return new ArrayList<>();
        }

        // 调用原有方法获取汇总来源
        return getSummarySource(unifiedFeeNode.getCompileTreeId(), sourceUnifiedFeeSettingId);
    }
}
