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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.yhy.module.core.controller.admin.quota.vo.QuotaFeeItemWithRateRespVO;
import com.yhy.module.core.controller.admin.quota.vo.QuotaResourceRespVO;
import com.yhy.module.core.controller.admin.workbench.vo.price.AdjustmentDetail;
import com.yhy.module.core.controller.admin.workbench.vo.price.CategoryPriceSum;
import com.yhy.module.core.controller.admin.workbench.vo.price.FeeItemPriceResult;
import com.yhy.module.core.controller.admin.workbench.vo.price.QuotaUnitPriceResult;
import com.yhy.module.core.controller.admin.workbench.vo.price.ResourcePriceDetail;
import com.yhy.module.core.dal.dataobject.resource.ResourceCategoryDO;
import com.yhy.module.core.dal.dataobject.resource.ResourceItemDO;
import com.yhy.module.core.dal.dataobject.workbench.WbBoqDivisionDO;
import com.yhy.module.core.dal.mysql.resource.ResourceCategoryMapper;
import com.yhy.module.core.dal.mysql.workbench.WbBoqDivisionMapper;
import com.yhy.module.core.service.quota.QuotaFeeItemService;
import com.yhy.module.core.service.quota.QuotaResourceService;
import com.yhy.module.core.service.workbench.QuotaPriceCalculatorService;
import com.yhy.module.core.service.workbench.WbBoqResourceService;
import com.yhy.module.core.service.workbench.WbUnifiedFeeConfigService;
import com.yhy.module.core.service.workbench.WbUnitFeeSettingService;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * 定额单价计算服务实现类
 * 
 * 设计原则：
 * 1. 复用后台已有的工料机合价计算逻辑
 * 2. 新增分类汇总和取费计算逻辑
 * 3. 支持分层验证和调试
 * 4. 现阶段保证实时性，不缓存计算结果
 * 
 * @author yhy
 */
@Service
@Slf4j
public class QuotaPriceCalculatorServiceImpl implements QuotaPriceCalculatorService {

    private static final int SCALE = 6;
    private static final RoundingMode ROUNDING_MODE = RoundingMode.HALF_UP;
    private static final BigDecimal HUNDRED = new BigDecimal("100");

    @Resource
    private WbBoqDivisionMapper wbBoqDivisionMapper;

    @Resource
    private ResourceCategoryMapper resourceCategoryMapper;

    @Resource
    private QuotaFeeItemService quotaFeeItemService;

    @Resource
    private WbUnitFeeSettingService wbUnitFeeSettingService;

    @Resource
    private QuotaResourceService quotaResourceService;
    
    @Resource
    private WbBoqResourceService wbBoqResourceService;

    @Resource
    private WbUnifiedFeeConfigService wbUnifiedFeeConfigService;

    @Resource
    private com.yhy.module.core.service.quota.QuotaUnifiedFeeService quotaUnifiedFeeService;

    @Resource
    private com.yhy.module.core.service.quota.QuotaUnifiedFeeResourceService quotaUnifiedFeeResourceService;

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

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

    @Resource
    private com.yhy.module.core.dal.mysql.resource.ResourceItemMapper resourceItemMapper;

    // ========== 主计算接口 ==========

    @Override
    public QuotaUnitPriceResult calculateQuotaUnitPrice(Long quotaItemId, Long divisionId) {
        return calculateQuotaUnitPrice(quotaItemId, divisionId, false);
    }

    @Override
    public QuotaUnitPriceResult calculateQuotaUnitPrice(Long quotaItemId, Long divisionId, boolean debug) {
        long startTime = System.currentTimeMillis();
        
        try {
            // log.debug("[定额单价计算] 开始 - quotaItemId={}, divisionId={}, debug={}", quotaItemId, divisionId, debug);
            
            // 1. 获取定额基价ID（优先从divisionId获取）
            Long effectiveQuotaItemId = quotaItemId;
            if (divisionId != null && effectiveQuotaItemId == null) {
                WbBoqDivisionDO division = wbBoqDivisionMapper.selectById(divisionId);
                if (division != null) {
                    effectiveQuotaItemId = division.getSourceQuotaItemId();
                }
            }
            
            if (effectiveQuotaItemId == null) {
                log.warn("[定额单价计算] 无法获取定额基价ID");
                return QuotaUnitPriceResult.fail(divisionId, quotaItemId, "无法获取定额基价ID");
            }
            
            // 2. 优先使用工作台工料机数据（包含价格来源虚拟替换），如果没有则使用后台数据
            List<ResourcePriceDetail> resourceDetails;
            if (divisionId != null) {
                // 使用工作台工料机数据（包含价格来源虚拟替换）
                List<com.yhy.module.core.controller.admin.workbench.vo.WbBoqResourceRespVO> wbResources = 
                        wbBoqResourceService.getListByDivisionId(divisionId);
                if (CollUtil.isNotEmpty(wbResources)) {
                    // log.debug("[定额单价计算] 使用工作台工料机数据（含价格来源替换）- 数量={}", wbResources.size());
                    resourceDetails = convertWbResourcesToResourcePriceDetails(wbResources);
                } else {
                    // 【已禁用】工作台没有数据时，不再 fallback 到后台数据，直接返回零单价
                    // 计算逻辑已收归工作台，后台不再参与计算
                    return QuotaUnitPriceResult.success(divisionId, effectiveQuotaItemId, BigDecimal.ZERO);
                }
            } else {
                // 【已禁用】没有divisionId时，不再使用后台数据，直接返回零单价
                // 计算逻辑已收归工作台，后台不再参与计算
                return QuotaUnitPriceResult.success(divisionId, effectiveQuotaItemId, BigDecimal.ZERO);
            }
            
            // 3. 第1层：工料机合价数据已准备好
            // log.debug("[定额单价计算] 第1层完成 - 工料机数量={}", resourceDetails.size());
            
            // 4. 第2层：调整消耗量信息（后台已计算，此处仅用于调试）
            List<AdjustmentDetail> adjustmentDetails = null;
            if (debug) {
                // log.debug("[定额单价计算] 第2层 - 调整信息已由后台计算");
                adjustmentDetails = new ArrayList<>();
            }
            
            // 4. 第3层：按机类分类汇总
            // log.debug("[定额单价计算] 第3层开始 - 按机类分类汇总");
            Map<Long, CategoryPriceSum> categorySums = calculateCategorySums(resourceDetails);
            // log.debug("[定额单价计算] 第3层完成 - 分类数量={}", categorySums.size());
            // if (log.isDebugEnabled()) {
            //     categorySums.forEach((k, v) -> 
            //         log.trace("  分类[{}]: 除税基价合价={}", k, v.getTaxExclBaseSum()));
            // }
            
            // 5. 第4-5层：获取取费项并计算子单价（传入categorySums避免重复加载工料机）
            // log.debug("[定额单价计算] 第4-5层开始 - 计算单价构成");
            List<QuotaFeeItemWithRateRespVO> feeItems = getFeeItems(divisionId, effectiveQuotaItemId, categorySums);
            List<FeeItemPriceResult> feeItemDetails = calculateFeeItemPrices(feeItems, categorySums);
            // log.debug("[定额单价计算] 第4-5层完成 - 取费项数量={}", feeItemDetails.size());
            
            // 6. 第6层：计算综合单价
            BigDecimal unitPrice = calculateTotalPrice(feeItemDetails);
            // log.debug("[定额单价计算] 完成 - divisionId={}, unitPrice={}, 总耗时={}ms", 
            //         divisionId, unitPrice, System.currentTimeMillis() - startTime);
            
            // 7. 构建结果
            QuotaUnitPriceResult result = QuotaUnitPriceResult.success(divisionId, effectiveQuotaItemId, unitPrice);
            result.setCalculateTimeMs(System.currentTimeMillis() - startTime);
            
            if (debug) {
                result.setResourceDetails(resourceDetails);
                result.setAdjustmentDetails(adjustmentDetails);
                result.setCategorySums(categorySums);
                result.setFeeItemDetails(feeItemDetails);
            }
            
            return result;
            
        } catch (Exception e) {
            log.error("[定额单价计算] 异常 - divisionId={}, quotaItemId={}", divisionId, quotaItemId, e);
            return QuotaUnitPriceResult.fail(divisionId, quotaItemId, "计算异常: " + e.getMessage());
        }
    }

    @Override
    public Map<Long, QuotaUnitPriceResult> batchCalculateQuotaUnitPrices(List<Long> divisionIds) {
        if (CollUtil.isEmpty(divisionIds)) {
            return new HashMap<>();
        }
        
        log.debug("[定额单价批量计算] 开始 - 数量={}", divisionIds.size());
        long startTime = System.currentTimeMillis();
        
        // 1. 批量查询定额节点
        List<WbBoqDivisionDO> divisions = wbBoqDivisionMapper.selectList(
                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<WbBoqDivisionDO>()
                        .in(WbBoqDivisionDO::getId, divisionIds));
        Map<Long, WbBoqDivisionDO> divisionMap = divisions.stream()
                .collect(Collectors.toMap(WbBoqDivisionDO::getId, Function.identity()));
        
        // 2. 并行计算（每个divisionId调用calculateQuotaUnitPrice，内部会调用QuotaResourceService获取数据）
        Map<Long, QuotaUnitPriceResult> results = new ConcurrentHashMap<>();
        divisionIds.parallelStream().forEach(divisionId -> {
            WbBoqDivisionDO division = divisionMap.get(divisionId);
            if (division == null) {
                results.put(divisionId, QuotaUnitPriceResult.fail(divisionId, null, "定额节点不存在"));
                return;
            }
            
            Long quotaItemId = division.getSourceQuotaItemId();
            QuotaUnitPriceResult result = calculateQuotaUnitPrice(quotaItemId, divisionId, false);
            results.put(divisionId, result);
        });
        
        log.debug("[定额单价批量计算] 完成 - 数量={}, 耗时={}ms", 
                divisionIds.size(), System.currentTimeMillis() - startTime);
        
        return results;
    }

    // ========== 分层验证接口 ==========

    @Override
    public Map<Long, CategoryPriceSum> calculateCategorySums(List<ResourcePriceDetail> resourceDetails) {
        Map<Long, CategoryPriceSum> result = new HashMap<>();
        
        if (CollUtil.isEmpty(resourceDetails)) {
            return result;
        }
        
        // 获取机类字典
        Map<Long, ResourceCategoryDO> categoryMap = getCategoryMap();
        
        for (ResourcePriceDetail detail : resourceDetails) {
            Long categoryId = detail.getCategoryId();
            if (categoryId == null) {
                continue;
            }
            
            // 所有工料机（包括%单位工料机）按categoryId汇总，与分类值标签页逻辑一致
            // 复合工料机：分类统计时只取父值（子工料机不在列表中）
            // 注意：工作台工料机列表只包含顶层数据，子数据不在列表中
            
            CategoryPriceSum sum = result.computeIfAbsent(categoryId, k -> {
                ResourceCategoryDO category = categoryMap.get(k);
                CategoryPriceSum newSum = new CategoryPriceSum(k);
                if (category != null) {
                    newSum.setCategoryCode(category.getCode());
                    newSum.setCategoryName(category.getName());
                }
                return newSum;
            });
            
            // 累加四个合价
            sum.addTaxExclBaseSum(detail.getTaxExclBaseTotalSum());
            sum.addTaxInclBaseSum(detail.getTaxInclBaseTotalSum());
            sum.addTaxExclCompileSum(detail.getTaxExclCompileTotalSum());
            sum.addTaxInclCompileSum(detail.getTaxInclCompileTotalSum());
        }
        
        return result;
    }

    @Override
    public BigDecimal evaluateCalcBaseFormula(Map<String, Object> calcBase, Map<Long, CategoryPriceSum> categorySums) {
        if (MapUtil.isEmpty(calcBase)) {
            return BigDecimal.ZERO;
        }
        
        String formula = (String) calcBase.get("formula");
        if (StrUtil.isBlank(formula)) {
            return BigDecimal.ZERO;
        }
        
        @SuppressWarnings("unchecked")
        Map<String, Object> variables = (Map<String, Object>) calcBase.get("variables");
        if (MapUtil.isEmpty(variables)) {
            // 如果没有变量，尝试直接解析为数字
            try {
                return new BigDecimal(formula.trim());
            } catch (NumberFormatException e) {
                log.warn("[公式解析] 无变量且非数字公式: {}", formula);
                return BigDecimal.ZERO;
            }
        }
        
        // 构建变量值映射
        Map<String, BigDecimal> varValues = new HashMap<>();
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            String varName = entry.getKey();
            Object varValue = entry.getValue();
            
            if (!(varValue instanceof Map)) {
                continue;
            }
            
            @SuppressWarnings("unchecked")
            Map<String, Object> varInfo = (Map<String, Object>) varValue;
            
            Object categoryIdObj = varInfo.get("categoryId");
            String priceField = (String) varInfo.get("priceField");
            
            if (categoryIdObj == null || priceField == null) {
                varValues.put(varName, BigDecimal.ZERO);
                continue;
            }
            
            Long categoryId = ((Number) categoryIdObj).longValue();
            CategoryPriceSum sum = categorySums.get(categoryId);
            
            BigDecimal value = BigDecimal.ZERO;
            if (sum != null) {
                value = sum.getPriceByField(priceField);
            }
            
            varValues.put(varName, value != null ? value : BigDecimal.ZERO);
        }
        
        // 使用简单的表达式计算（替换变量后计算）
        return evaluateFormula(formula, varValues);
    }

    @Override
    public FeeItemPriceResult calculateFeeItemPrice(QuotaFeeItemWithRateRespVO feeItem, 
            Map<Long, CategoryPriceSum> categorySums) {
        
        FeeItemPriceResult result = FeeItemPriceResult.builder()
                .feeItemId(feeItem.getFeeItemId())
                .code(feeItem.getCode())
                .name(feeItem.getFeeItemName())
                .calcBase(feeItem.getCalcBase())
                .build();
        
        try {
            // 优先使用已计算的子单价（来自 WbUnitFeeSettingService.getMergedFeeListByDivisionId）
            if (feeItem.getSubPrice() != null && feeItem.getSubPrice().compareTo(BigDecimal.ZERO) != 0) {
                result.setCalcBaseValue(feeItem.getCalcBaseValue());
                result.setRateCode(feeItem.getRatePercentage());
                result.setSubPrice(feeItem.getSubPrice());
                log.debug("[取费项计算] 使用已计算的子单价 - code={}, subPrice={}", 
                        feeItem.getCode(), feeItem.getSubPrice());
                return result;
            }
            
            // 1. 计算基数值
            BigDecimal calcBaseValue = BigDecimal.ZERO;
            if (feeItem.getCalcBase() != null) {
                calcBaseValue = evaluateCalcBaseFormula(feeItem.getCalcBase(), categorySums);
            }
            result.setCalcBaseValue(calcBaseValue);
            
            // 2. 获取费率百分比
            BigDecimal ratePercent = BigDecimal.ZERO;
            String rateCode = feeItem.getRatePercentage();
            result.setRateCode(rateCode);
            
            // 优先使用 rateValue（费率实际值）
            if (feeItem.getRateValue() != null && feeItem.getRateValue().compareTo(BigDecimal.ZERO) != 0) {
                ratePercent = feeItem.getRateValue();
            } else if (StrUtil.isNotBlank(rateCode)) {
                try {
                    ratePercent = new BigDecimal(rateCode);
                } catch (NumberFormatException e) {
                    // 费率代号可能是非数字（如引用其他取费项），跳过
                    log.debug("[取费项计算] 费率代号非数字: {}", rateCode);
                }
            }
            result.setRatePercent(ratePercent);
            
            // 3. 计算子单价
            BigDecimal subPrice;
            if (ratePercent.compareTo(BigDecimal.ZERO) == 0) {
                // 费率为0或未配置时，直接使用计算基数值作为子单价
                // 这适用于统一取费单价场景，calcBase公式直接计算出最终值
                subPrice = calcBaseValue.setScale(SCALE, ROUNDING_MODE);
            } else {
                // 子单价 = 计算基数值 × (费率% / 100)
                subPrice = calcBaseValue
                        .multiply(ratePercent)
                        .divide(HUNDRED, SCALE, ROUNDING_MODE);
            }
            result.setSubPrice(subPrice);
            
        } catch (Exception e) {
            log.error("[取费项计算] 异常 - feeItemId={}, code={}", feeItem.getFeeItemId(), feeItem.getCode(), e);
            result.setSubPrice(BigDecimal.ZERO);
            result.setErrorMessage("计算异常: " + e.getMessage());
        }
        
        return result;
    }

    @Override
    public List<FeeItemPriceResult> calculateFeeItemPrices(List<QuotaFeeItemWithRateRespVO> feeItems, 
            Map<Long, CategoryPriceSum> categorySums) {
        
        if (CollUtil.isEmpty(feeItems)) {
            return new ArrayList<>();
        }
        
        List<FeeItemPriceResult> results = new ArrayList<>();
        for (QuotaFeeItemWithRateRespVO feeItem : feeItems) {
            FeeItemPriceResult result = calculateFeeItemPrice(feeItem, categorySums);
            results.add(result);
        }
        
        return results;
    }

    @Override
    public BigDecimal calculateTotalPrice(List<FeeItemPriceResult> feeItemResults) {
        if (CollUtil.isEmpty(feeItemResults)) {
            return BigDecimal.ZERO;
        }
        
        // 综合单价代号
        final String ZHDJ_CODE = "ZHDJ";
        
        // 1. 构建取费项代号到子单价的映射
        Map<String, BigDecimal> feeItemSubPriceMap = new java.util.HashMap<>();
        FeeItemPriceResult zhdjItem = null;
        
        for (FeeItemPriceResult item : feeItemResults) {
            if (ZHDJ_CODE.equals(item.getCode())) {
                zhdjItem = item;
            } else if (item.getCode() != null && item.getSubPrice() != null) {
                feeItemSubPriceMap.put(item.getCode(), item.getSubPrice());
            }
        }
        
        // 2. 如果有综合单价行
        if (zhdjItem != null) {
            BigDecimal calcBaseValue = BigDecimal.ZERO;
            boolean hasFormula = false;
            
            // 检查综合单价是否有calcBase公式
            if (zhdjItem.getCalcBase() != null) {
                @SuppressWarnings("unchecked")
                Map<String, Object> calcBase = zhdjItem.getCalcBase();
                String formula = (String) calcBase.get("formula");
                
                if (formula != null && !formula.isEmpty()) {
                    hasFormula = true;
                    // 使用公式计算（引用其他取费项的子单价）
                    calcBaseValue = evaluateZhdjFormula(formula, feeItemSubPriceMap);
                }
            }
            
            // 只有在没有配置公式时，才使用子单价之和作为回退
            // 如果配置了公式但计算结果为0，则直接使用0（不回退）
            if (!hasFormula && calcBaseValue.compareTo(BigDecimal.ZERO) == 0) {
                for (BigDecimal subPrice : feeItemSubPriceMap.values()) {
                    calcBaseValue = calcBaseValue.add(subPrice);
                }
            }
            
            // 应用费率
            BigDecimal zhdjRate = parseZhdjRate(zhdjItem.getRateCode());
            return calcBaseValue
                    .multiply(zhdjRate)
                    .divide(HUNDRED, SCALE, ROUNDING_MODE);
        }
        
        // 3. 没有综合单价行，直接返回子单价之和
        BigDecimal totalSubPrice = BigDecimal.ZERO;
        for (BigDecimal subPrice : feeItemSubPriceMap.values()) {
            totalSubPrice = totalSubPrice.add(subPrice);
        }
        return totalSubPrice.setScale(SCALE, ROUNDING_MODE);
    }
    
    /**
     * 解析综合单价公式（变量为其他取费项的代号）
     */
    private BigDecimal evaluateZhdjFormula(String formula, Map<String, BigDecimal> feeItemSubPriceMap) {
        if (formula == null || formula.isEmpty()) {
            return BigDecimal.ZERO;
        }

        try {
            // 替换变量为对应的子单价值
            String expression = formula;
            for (Map.Entry<String, BigDecimal> entry : feeItemSubPriceMap.entrySet()) {
                String varName = entry.getKey();
                BigDecimal value = entry.getValue();
                expression = expression.replaceAll("\\b" + java.util.regex.Pattern.quote(varName) + "\\b", 
                        value.toPlainString());
            }

            // 使用JavaScript引擎计算表达式
            javax.script.ScriptEngineManager manager = new javax.script.ScriptEngineManager();
            javax.script.ScriptEngine engine = manager.getEngineByName("JavaScript");
            if (engine == null) {
                engine = manager.getEngineByName("nashorn");
            }
            if (engine == null) {
                log.warn("[综合单价计算] 无法获取JavaScript引擎");
                return BigDecimal.ZERO;
            }

            Object result = engine.eval(expression);
            if (result instanceof Number) {
                return new BigDecimal(result.toString()).setScale(SCALE, ROUNDING_MODE);
            }
            return BigDecimal.ZERO;
        } catch (Exception e) {
            log.error("[综合单价计算] 公式计算异常: formula={}, error={}", formula, e.getMessage());
            return BigDecimal.ZERO;
        }
    }
    
    /**
     * 解析综合单价的费率代号
     * 
     * @param rateCode 费率代号（只允许数字或空值）
     * @return 费率百分比，空值返回100
     */
    private BigDecimal parseZhdjRate(String rateCode) {
        if (StrUtil.isBlank(rateCode)) {
            return HUNDRED; // 空值默认100%
        }
        
        try {
            return new BigDecimal(rateCode.trim());
        } catch (NumberFormatException e) {
            log.warn("[综合单价费率] 费率代号非数字，使用默认值100%: {}", rateCode);
            return HUNDRED;
        }
    }

    // ========== 私有方法 ==========

    /**
     * 获取机类字典（缓存）
     */
    @Cacheable(value = "resourceCategory", key = "'all'")
    public Map<Long, ResourceCategoryDO> getCategoryMap() {
        List<ResourceCategoryDO> categories = resourceCategoryMapper.selectList();
        return categories.stream()
                .collect(Collectors.toMap(ResourceCategoryDO::getId, Function.identity()));
    }

    /**
     * 获取取费项列表
     * 
     * 优先使用工作台覆写值，否则使用标准库取费项
     */
    private List<QuotaFeeItemWithRateRespVO> getFeeItems(Long divisionId, Long quotaItemId) {
        return getFeeItems(divisionId, quotaItemId, null);
    }

    /**
     * 获取取费项列表（支持传入预计算的分类汇总，避免重复查询工料机）
     */
    private List<QuotaFeeItemWithRateRespVO> getFeeItems(Long divisionId, Long quotaItemId, 
            Map<Long, CategoryPriceSum> categorySums) {
        // 尝试获取工作台覆写的取费项
        if (divisionId != null) {
            try {
                List<QuotaFeeItemWithRateRespVO> mergedList = categorySums != null
                        ? wbUnitFeeSettingService.getMergedFeeListByDivisionId(divisionId, categorySums)
                        : wbUnitFeeSettingService.getMergedFeeListByDivisionId(divisionId);
                if (CollUtil.isNotEmpty(mergedList)) {
                    return mergedList;
                }
            } catch (Exception e) {
                log.warn("[获取取费项] 获取工作台覆写失败，使用标准库取费项 - divisionId={}", divisionId, e);
            }
        }
        
        // 使用标准库取费项
        if (quotaItemId != null) {
            // 需要通过定额基价ID获取对应的目录ID
            // 这里简化处理，直接返回空列表，实际需要根据业务逻辑获取
            log.debug("[获取取费项] 使用标准库取费项 - quotaItemId={}", quotaItemId);
        }
        
        return new ArrayList<>();
    }

    /**
     * 安全乘法（处理null值）
     */
    private BigDecimal safeMultiply(BigDecimal a, BigDecimal b) {
        if (a == null || b == null) {
            return BigDecimal.ZERO;
        }
        return a.multiply(b).setScale(SCALE, ROUNDING_MODE);
    }

    /**
     * 简单表达式计算
     * 
     * 支持：加减乘除、括号、变量替换
     */
    private BigDecimal evaluateFormula(String formula, Map<String, BigDecimal> varValues) {
        if (StrUtil.isBlank(formula)) {
            return BigDecimal.ZERO;
        }
        
        // 替换变量
        String expression = formula;
        
        // 按变量名长度降序排序，避免短变量名替换长变量名的一部分
        List<String> sortedVarNames = new ArrayList<>(varValues.keySet());
        sortedVarNames.sort((a, b) -> Integer.compare(b.length(), a.length()));
        
        for (String varName : sortedVarNames) {
            BigDecimal value = varValues.get(varName);
            expression = expression.replace(varName, value.toPlainString());
        }
        
        // 计算表达式
        try {
            return evaluateExpression(expression);
        } catch (Exception e) {
            log.warn("[公式计算] 计算失败 - formula={}, expression={}", formula, expression, e);
            return BigDecimal.ZERO;
        }
    }

    /**
     * 计算数学表达式（支持加减乘除和括号）
     */
    private BigDecimal evaluateExpression(String expression) {
        expression = expression.replaceAll("\\s+", "");
        return parseExpression(expression, new int[]{0});
    }

    private BigDecimal parseExpression(String expr, int[] pos) {
        BigDecimal result = parseTerm(expr, pos);
        
        while (pos[0] < expr.length()) {
            char op = expr.charAt(pos[0]);
            if (op == '+') {
                pos[0]++;
                result = result.add(parseTerm(expr, pos));
            } else if (op == '-') {
                pos[0]++;
                result = result.subtract(parseTerm(expr, pos));
            } else {
                break;
            }
        }
        
        return result;
    }

    private BigDecimal parseTerm(String expr, int[] pos) {
        BigDecimal result = parseFactor(expr, pos);
        
        while (pos[0] < expr.length()) {
            char op = expr.charAt(pos[0]);
            if (op == '*') {
                pos[0]++;
                result = result.multiply(parseFactor(expr, pos));
            } else if (op == '/') {
                pos[0]++;
                BigDecimal divisor = parseFactor(expr, pos);
                if (divisor.compareTo(BigDecimal.ZERO) == 0) {
                    return BigDecimal.ZERO;
                }
                result = result.divide(divisor, SCALE, ROUNDING_MODE);
            } else {
                break;
            }
        }
        
        return result;
    }

    private BigDecimal parseFactor(String expr, int[] pos) {
        if (pos[0] >= expr.length()) {
            return BigDecimal.ZERO;
        }
        
        char c = expr.charAt(pos[0]);
        
        // 处理负号
        boolean negative = false;
        if (c == '-') {
            negative = true;
            pos[0]++;
            if (pos[0] >= expr.length()) {
                return BigDecimal.ZERO;
            }
            c = expr.charAt(pos[0]);
        }
        
        BigDecimal result;
        
        if (c == '(') {
            pos[0]++;
            result = parseExpression(expr, pos);
            if (pos[0] < expr.length() && expr.charAt(pos[0]) == ')') {
                pos[0]++;
            }
        } else {
            // 解析数字
            int start = pos[0];
            while (pos[0] < expr.length() && (Character.isDigit(expr.charAt(pos[0])) || expr.charAt(pos[0]) == '.')) {
                pos[0]++;
            }
            if (start == pos[0]) {
                return BigDecimal.ZERO;
            }
            result = new BigDecimal(expr.substring(start, pos[0]));
        }
        
        return negative ? result.negate() : result;
    }

    /**
     * 将工作台工料机VO转换为ResourcePriceDetail（包含价格来源虚拟替换后的数据）
     * 直接复用 VO 中已计算好的合价（含%工料机公式计算值和复合工料机汇总值）
     */
    private List<ResourcePriceDetail> convertWbResourcesToResourcePriceDetails(
            List<com.yhy.module.core.controller.admin.workbench.vo.WbBoqResourceRespVO> wbResources) {
        List<ResourcePriceDetail> result = new ArrayList<>();
        
        for (com.yhy.module.core.controller.admin.workbench.vo.WbBoqResourceRespVO resource : wbResources) {
            BigDecimal originalQty = resource.getConsumeQty() != null ? resource.getConsumeQty() : BigDecimal.ZERO;
            BigDecimal effectiveQty = resource.getAdjustConsumeQty() != null ? resource.getAdjustConsumeQty() : originalQty;
            BigDecimal taxExclBasePrice = resource.getTaxExclBasePrice() != null ? resource.getTaxExclBasePrice() : BigDecimal.ZERO;
            BigDecimal taxInclBasePrice = resource.getTaxInclBasePrice() != null ? resource.getTaxInclBasePrice() : BigDecimal.ZERO;
            BigDecimal taxExclCompilePrice = resource.getTaxExclCompilePrice() != null ? resource.getTaxExclCompilePrice() : BigDecimal.ZERO;
            BigDecimal taxInclCompilePrice = resource.getTaxInclCompilePrice() != null ? resource.getTaxInclCompilePrice() : BigDecimal.ZERO;
            
            // 直接使用 VO 中已计算好的合价（%工料机和复合工料机的合价已由 getListByDivisionId 计算）
            BigDecimal taxExclBaseTotalSum = resource.getTaxExclBaseTotalSum();
            BigDecimal taxInclBaseTotalSum = resource.getTaxInclBaseTotalSum();
            BigDecimal taxExclCompileTotalSum = resource.getTaxExclCompileTotalSum();
            BigDecimal taxInclCompileTotalSum = resource.getTaxInclCompileTotalSum();
            
            boolean isMerged = resource.getChildren() != null && !resource.getChildren().isEmpty();
            boolean isPercentUnit = "%".equals(resource.getUnit());
            
            ResourcePriceDetail detail = ResourcePriceDetail.builder()
                    .resourceId(resource.getId())
                    .resourceCode(resource.getCode())
                    .resourceName(resource.getName())
                    .resourceType(resource.getResourceType())
                    .categoryId(resource.getCategoryId())
                    .dosage(originalQty)
                    .adjustedDosage(effectiveQty)
                    .effectiveDosage(effectiveQty)
                    .taxExclBasePrice(taxExclBasePrice)
                    .taxInclBasePrice(taxInclBasePrice)
                    .taxExclCompilePrice(taxExclCompilePrice)
                    .taxInclCompilePrice(taxInclCompilePrice)
                    .taxExclBaseTotalSum(taxExclBaseTotalSum)
                    .taxInclBaseTotalSum(taxInclBaseTotalSum)
                    .taxExclCompileTotalSum(taxExclCompileTotalSum)
                    .taxInclCompileTotalSum(taxInclCompileTotalSum)
                    .isMerged(isMerged)
                    .isPercentUnit(isPercentUnit)
                    .calcBase(resource.getCalcBase())
                    .build();
            
            result.add(detail);
        }
        
        return result;
    }
    
    /**
     * 将后台定额工料机VO转换为ResourcePriceDetail（复用后台已计算好的数据）
     */
    private List<ResourcePriceDetail> convertToResourcePriceDetails(List<QuotaResourceRespVO> quotaResources) {
        List<ResourcePriceDetail> result = new ArrayList<>();
        
        for (QuotaResourceRespVO resource : quotaResources) {
            boolean isPercentUnit = "%".equals(resource.getResourceUnit());
            
            ResourcePriceDetail detail = ResourcePriceDetail.builder()
                    .resourceId(resource.getId())
                    .resourceCode(resource.getResourceCode())
                    .resourceName(resource.getResourceName())
                    .resourceType(resource.getResourceType())
                    .categoryId(resource.getResourceCategoryId())
                    .dosage(resource.getDosage())
                    .adjustedDosage(resource.getAdjustedDosage())
                    .effectiveDosage(resource.getActualDosage())
                    .taxExclBasePrice(resource.getResourceTaxExclBasePrice())
                    .taxInclBasePrice(resource.getResourceTaxInclBasePrice())
                    .taxExclCompilePrice(resource.getResourceTaxExclCompilePrice())
                    .taxInclCompilePrice(resource.getResourceTaxInclCompilePrice())
                    .taxExclBaseTotalSum(resource.getTaxExclBaseTotalSum())
                    .taxInclBaseTotalSum(resource.getTaxInclBaseTotalSum())
                    .taxExclCompileTotalSum(resource.getTaxExclCompileTotalSum())
                    .taxInclCompileTotalSum(resource.getTaxInclCompileTotalSum())
                    .isMerged(resource.getIsMerged() != null && resource.getIsMerged())
                    .isPercentUnit(isPercentUnit)
                    .build();
            
            result.add(detail);
        }
        
        return result;
    }

    // ========== 统一取费父定额单价计算 ==========

    @Override
    public BigDecimal calculateUnifiedFeeParentPrice(Long divisionId) {
        QuotaUnitPriceResult result = calculateUnifiedFeeParentPrice(divisionId, false);
        return Boolean.TRUE.equals(result.getSuccess()) ? result.getUnitPrice() : BigDecimal.ZERO;
    }

    @Override
    public QuotaUnitPriceResult calculateUnifiedFeeParentPrice(Long divisionId, boolean debug) {
        long startTime = System.currentTimeMillis();
        
        try {
            // 1. 获取统一取费节点
            WbBoqDivisionDO unifiedFeeNode = wbBoqDivisionMapper.selectById(divisionId);
            if (unifiedFeeNode == null || !"unified_fee".equals(unifiedFeeNode.getNodeType())) {
                return QuotaUnitPriceResult.fail(divisionId, null, "非统一取费节点");
            }

            // 2. 获取母定额列表（汇总来源的quota节点）
            List<com.yhy.module.core.controller.admin.workbench.vo.WbUnifiedFeeSummaryItemVO> summaryItems = 
                wbUnifiedFeeConfigService.getSummarySourceByDivisionId(divisionId);
            
            if (CollUtil.isEmpty(summaryItems)) {
                log.debug("[统一取费单价] 汇总来源为空 - divisionId={}", divisionId);
                return QuotaUnitPriceResult.success(divisionId, null, BigDecimal.ZERO);
            }

            // 3. 获取统一取费单价的取费项配置
            // 从节点attributes获取sourceUnifiedFeeSettingId，然后获取catalogItemId
            Map<String, Object> attributes = unifiedFeeNode.getAttributes();
            if (attributes == null || attributes.get("sourceUnifiedFeeSettingId") == null) {
                return QuotaUnitPriceResult.fail(divisionId, null, "缺少sourceUnifiedFeeSettingId");
            }
            
            Long sourceUnifiedFeeSettingId = Long.parseLong(attributes.get("sourceUnifiedFeeSettingId").toString());
            Long compileTreeId = unifiedFeeNode.getCompileTreeId();
            
            // 通过sourceUnifiedFeeSettingId从快照表获取统一取费设置
            com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO unifiedFeeSetting = 
                getUnifiedFeeSettingFromSnapshot(compileTreeId, sourceUnifiedFeeSettingId);
            if (unifiedFeeSetting == null) {
                log.warn("[统一取费单价] 快照中统一取费设置不存在 - compileTreeId={}, sourceId={}", compileTreeId, sourceUnifiedFeeSettingId);
                return QuotaUnitPriceResult.fail(divisionId, null, "统一取费设置不存在");
            }
            
            // 4. 获取比例配置
            BigDecimal thisListPercentage = BigDecimal.valueOf(100); // 默认100%
            BigDecimal specifiedListPercentage = BigDecimal.valueOf(100); // 默认100%
            Boolean isSpecifiedList = false;
            
            // 注意：JSONB 反序列化时 key 存在但值为 JSON null 或空字符串时需跳过，否则 BigDecimal 构造会抛异常
            Object rawThisListPercentage = attributes.get("thisListPercentage");
            if (rawThisListPercentage != null) {
                String strVal = rawThisListPercentage.toString().trim();
                if (!strVal.isEmpty() && !"null".equals(strVal)) {
                    thisListPercentage = new BigDecimal(strVal);
                }
            }
            Object rawSpecifiedListPercentage = attributes.get("specifiedListPercentage");
            if (rawSpecifiedListPercentage != null) {
                String strVal = rawSpecifiedListPercentage.toString().trim();
                if (!strVal.isEmpty() && !"null".equals(strVal)) {
                    specifiedListPercentage = new BigDecimal(strVal);
                }
            }
            Object rawIsSpecifiedList = attributes.get("isSpecifiedList");
            if (rawIsSpecifiedList != null) {
                String strVal = rawIsSpecifiedList.toString().trim();
                if (!strVal.isEmpty() && !"null".equals(strVal)) {
                    isSpecifiedList = Boolean.valueOf(strVal);
                }
            }
            
            log.info("[统一取费单价] 比例配置 - thisListPercentage={}, specifiedListPercentage={}, isSpecifiedList={}", 
                    thisListPercentage, specifiedListPercentage, isSpecifiedList);

            // 5. 获取统一取费设置的子费用列表（从快照表读取）
            List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO> childSettings = 
                getChildSettingsFromSnapshot(compileTreeId, unifiedFeeSetting.getId());
            log.info("[统一取费单价] 子费用数量={}", childSettings.size());

            // 6. 对每个母定额计算贡献的单价
            BigDecimal totalPrice = BigDecimal.ZERO;
            List<Map<String, Object>> debugDetails = debug ? new ArrayList<>() : null;
            
            log.info("[统一取费单价] 开始计算 - divisionId={}, 母定额数量={}", divisionId, summaryItems.size());
            
            for (com.yhy.module.core.controller.admin.workbench.vo.WbUnifiedFeeSummaryItemVO summaryItem : summaryItems) {
                Long motherDivisionId = summaryItem.getId();
                BigDecimal motherQuantity = summaryItem.getQuantity() != null ? summaryItem.getQuantity() : BigDecimal.ONE;
                
                log.info("[统一取费单价] 处理母定额 - id={}, code={}, qty={}", 
                        motherDivisionId, summaryItem.getCode(), motherQuantity);
                
                // 6a. 获取母定额的工料机分类合价
                Map<Long, CategoryPriceSum> motherCategorySums = getMotherCategorySums(motherDivisionId);
                log.info("[统一取费单价] 母定额分类合价 - categorySums={}", motherCategorySums);
                
                // 6b. 获取母定额的sourceCatalogItemId用于取费章节过滤
                Long motherCatalogItemId = summaryItem.getSourceCatalogItemId();
                log.info("[统一取费单价] 母定额sourceCatalogItemId={}", motherCatalogItemId);
                
                // 6c. 遍历子费用，只计算匹配取费章节的子费用下的子目工料机合价
                BigDecimal childUnitPrice = BigDecimal.ZERO;
                for (com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO childSetting : childSettings) {
                    // 检查母定额是否在该子费用的取费章节范围内
                    if (!isMotherQuotaInFeeChapter(motherCatalogItemId, childSetting.getFeeChapter())) {
                        log.debug("[统一取费单价] 子费用 {} 的取费章节不匹配，跳过", childSetting.getCode());
                        continue;
                    }
                    
                    // 获取子费用下的子目工料机列表（从快照表读取）
                    List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeResourceDO> snapshotResources = 
                        wbSnapshotReadService.getUnifiedFeeResources(compileTreeId, childSetting.getId());
                    log.info("[统一取费单价] 子费用 {} 匹配，子目工料机数量={}", childSetting.getCode(), snapshotResources.size());
                    
                    for (com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeResourceDO snapshotRes : snapshotResources) {
                        Long resourceItemId = snapshotRes.getResourceItemId();
                        if (resourceItemId == null) continue;
                        ResourceItemDO resourceItem = resourceItemMapper.selectById(resourceItemId);
                        if (resourceItem == null) continue;

                        BigDecimal dosage = snapshotRes.getEffectiveDosage() != null ? snapshotRes.getEffectiveDosage() : BigDecimal.ZERO;

                        // 检查是否为%工料机（从ResourceItemDO获取单位）
                        if ("%".equals(resourceItem.getUnit())) {
                            // calcBase存储在yhy_resource_item.calc_base字段
                            Map<String, Object> calcBase = resourceItem.getCalcBase();
                            BigDecimal calcBaseValue = evaluateCalcBaseForUnifiedFee(calcBase, motherCategorySums);
                            
                            // dosage 表示百分比，如 100 表示 100%
                            BigDecimal resourcePrice = calcBaseValue.multiply(dosage).divide(HUNDRED, SCALE, ROUNDING_MODE);
                            
                            log.info("[统一取费单价] %工料机 - code={}, calcBase={}, calcBaseValue={}, dosage={}%, resourcePrice={}", 
                                    resourceItem.getCode(), calcBase, calcBaseValue, dosage, resourcePrice);
                            
                            childUnitPrice = childUnitPrice.add(resourcePrice);
                        } else {
                            // 普通工料机：使用单价 × 消耗量
                            BigDecimal price = resourceItem.getTaxExclCompilePrice() != null ? 
                                resourceItem.getTaxExclCompilePrice() : BigDecimal.ZERO;
                            BigDecimal resourcePrice = price.multiply(dosage).setScale(SCALE, ROUNDING_MODE);
                            
                            log.info("[统一取费单价] 普通工料机 - code={}, price={}, dosage={}, resourcePrice={}", 
                                    resourceItem.getCode(), price, dosage, resourcePrice);
                            
                            childUnitPrice = childUnitPrice.add(resourcePrice);
                        }
                    }
                }
                
                log.info("[统一取费单价] 子定额综合单价B={}", childUnitPrice);
                
                // 5e. B × 母定额的工程量 = 该母定额贡献的单价
                BigDecimal contribution = childUnitPrice.multiply(motherQuantity).setScale(SCALE, ROUNDING_MODE);
                log.info("[统一取费单价] 母定额贡献单价={}", contribution);
                totalPrice = totalPrice.add(contribution);
                
                if (debug) {
                    Map<String, Object> detail = new HashMap<>();
                    detail.put("motherDivisionId", motherDivisionId);
                    detail.put("motherCode", summaryItem.getCode());
                    detail.put("motherName", summaryItem.getName());
                    detail.put("motherQuantity", motherQuantity);
                    detail.put("categorySums", motherCategorySums);
                    detail.put("childUnitPrice", childUnitPrice);
                    detail.put("contribution", contribution);
                    debugDetails.add(detail);
                }
            }

            // 6. 应用比例计算
            BigDecimal finalPrice;
            if (isSpecifiedList) {
                // 指定清单节点：应用指定清单比例%
                finalPrice = totalPrice.multiply(specifiedListPercentage)
                        .divide(BigDecimal.valueOf(100), SCALE, ROUNDING_MODE);
                log.info("[统一取费单价] 指定清单节点 - totalPrice={}, specifiedListPercentage={}%, finalPrice={}", 
                        totalPrice, specifiedListPercentage, finalPrice);
            } else {
                // 普通节点：应用本清单比例%
                finalPrice = totalPrice.multiply(thisListPercentage)
                        .divide(BigDecimal.valueOf(100), SCALE, ROUNDING_MODE);
                log.info("[统一取费单价] 普通节点 - totalPrice={}, thisListPercentage={}%, finalPrice={}", 
                        totalPrice, thisListPercentage, finalPrice);
            }

            // 7. 构建结果
            QuotaUnitPriceResult result = QuotaUnitPriceResult.success(divisionId, null, finalPrice);
            result.setCalculateTimeMs(System.currentTimeMillis() - startTime);
            
            if (debug && debugDetails != null) {
                // 将调试信息存入result（可以扩展QuotaUnitPriceResult添加unifiedFeeDetails字段）
                log.debug("[统一取费单价] 计算完成 - divisionId={}, totalPrice={}, details={}", 
                        divisionId, totalPrice, debugDetails);
            }
            
            return result;
            
        } catch (Exception e) {
            log.error("[统一取费单价] 计算异常 - divisionId={}", divisionId, e);
            return QuotaUnitPriceResult.fail(divisionId, null, "计算异常: " + e.getMessage());
        }
    }

    @Override
    public Map<Long, CategoryPriceSum> getUnifiedFeeCategorySums(Long divisionId) {
        Map<Long, CategoryPriceSum> result = new HashMap<>();
        try {
            // 1. 获取统一取费节点
            WbBoqDivisionDO unifiedFeeNode = wbBoqDivisionMapper.selectById(divisionId);
            if (unifiedFeeNode == null || !"unified_fee".equals(unifiedFeeNode.getNodeType())) {
                return result;
            }

            Map<String, Object> attributes = unifiedFeeNode.getAttributes();
            if (attributes == null || attributes.get("sourceUnifiedFeeSettingId") == null) {
                return result;
            }

            Long sourceUnifiedFeeSettingId = Long.valueOf(attributes.get("sourceUnifiedFeeSettingId").toString());
            Long compileTreeId = unifiedFeeNode.getCompileTreeId();

            // 2. 获取母定额列表
            List<com.yhy.module.core.controller.admin.workbench.vo.WbUnifiedFeeSummaryItemVO> summaryItems =
                wbUnifiedFeeConfigService.getSummarySourceByDivisionId(divisionId);
            if (CollUtil.isEmpty(summaryItems)) {
                return result;
            }

            // 3. 从快照表获取统一取费设置
            com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO unifiedFeeSetting =
                getUnifiedFeeSettingFromSnapshot(compileTreeId, sourceUnifiedFeeSettingId);
            if (unifiedFeeSetting == null) {
                return result;
            }

            // 4. 获取子费用列表
            List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO> childSettings =
                getChildSettingsFromSnapshot(compileTreeId, unifiedFeeSetting.getId());

            // 5. 对每个母定额计算分类合价贡献
            for (com.yhy.module.core.controller.admin.workbench.vo.WbUnifiedFeeSummaryItemVO summaryItem : summaryItems) {
                Long motherDivisionId = summaryItem.getId();
                BigDecimal motherQuantity = summaryItem.getQuantity() != null ? summaryItem.getQuantity() : BigDecimal.ONE;
                Long motherCatalogItemId = summaryItem.getSourceCatalogItemId();

                // 获取母定额的工料机分类合价
                Map<Long, CategoryPriceSum> motherCategorySums = getMotherCategorySums(motherDivisionId);

                // 遍历子费用
                for (com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO childSetting : childSettings) {
                    // 取费章节过滤
                    if (!isMotherQuotaInFeeChapter(motherCatalogItemId, childSetting.getFeeChapter())) {
                        continue;
                    }

                    // 获取子费用的子目工料机（直接使用快照DO，calcBase从ResourceItemDO获取）
                    List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeResourceDO> snapshotResources =
                        wbSnapshotReadService.getUnifiedFeeResources(compileTreeId, childSetting.getId());

                    for (com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeResourceDO snapshotRes : snapshotResources) {
                        Long resourceItemId = snapshotRes.getResourceItemId();
                        if (resourceItemId == null) continue;

                        ResourceItemDO resourceItem = resourceItemMapper.selectById(resourceItemId);
                        if (resourceItem == null) continue;
                        Long categoryId = resourceItem.getCategoryId();
                        if (categoryId == null) continue;

                        CategoryPriceSum sum = result.computeIfAbsent(categoryId, k -> {
                            CategoryPriceSum newSum = new CategoryPriceSum(k);
                            ResourceCategoryDO category = getCategoryMap().get(k);
                            if (category != null) {
                                newSum.setCategoryCode(category.getCode());
                                newSum.setCategoryName(category.getName());
                            }
                            return newSum;
                        });

                        BigDecimal dosage = snapshotRes.getEffectiveDosage() != null ? snapshotRes.getEffectiveDosage() : BigDecimal.ZERO;

                        if ("%".equals(resourceItem.getUnit())) {
                            // %工料机：用calcBase公式计算基数值，再乘以dosage%
                            // calcBase存储在yhy_resource_item.calc_base字段，而非快照attributes中
                            Map<String, Object> calcBase = resourceItem.getCalcBase();
                            // 分别对四个价格字段计算
                            BigDecimal calcBaseExclBase = evaluateCalcBaseForUnifiedFeeByField(calcBase, motherCategorySums, "taxExclBaseSum");
                            BigDecimal calcBaseInclBase = evaluateCalcBaseForUnifiedFeeByField(calcBase, motherCategorySums, "taxInclBaseSum");
                            BigDecimal calcBaseExclCompile = evaluateCalcBaseForUnifiedFeeByField(calcBase, motherCategorySums, "taxExclCompileSum");
                            BigDecimal calcBaseInclCompile = evaluateCalcBaseForUnifiedFeeByField(calcBase, motherCategorySums, "taxInclCompileSum");

                            BigDecimal dosagePercent = dosage.divide(HUNDRED, SCALE, ROUNDING_MODE);
                            // 合价 = calcBase × dosage% × 母定额工程量
                            sum.addTaxExclBaseSum(calcBaseExclBase.multiply(dosagePercent).multiply(motherQuantity).setScale(SCALE, ROUNDING_MODE));
                            sum.addTaxInclBaseSum(calcBaseInclBase.multiply(dosagePercent).multiply(motherQuantity).setScale(SCALE, ROUNDING_MODE));
                            sum.addTaxExclCompileSum(calcBaseExclCompile.multiply(dosagePercent).multiply(motherQuantity).setScale(SCALE, ROUNDING_MODE));
                            sum.addTaxInclCompileSum(calcBaseInclCompile.multiply(dosagePercent).multiply(motherQuantity).setScale(SCALE, ROUNDING_MODE));
                        } else {
                            // 普通工料机：单价 × 消耗量 × 母定额工程量
                            BigDecimal exclBase = resourceItem.getTaxExclBasePrice() != null ? resourceItem.getTaxExclBasePrice() : BigDecimal.ZERO;
                            BigDecimal inclBase = resourceItem.getTaxInclBasePrice() != null ? resourceItem.getTaxInclBasePrice() : BigDecimal.ZERO;
                            BigDecimal exclCompile = resourceItem.getTaxExclCompilePrice() != null ? resourceItem.getTaxExclCompilePrice() : BigDecimal.ZERO;
                            BigDecimal inclCompile = resourceItem.getTaxInclCompilePrice() != null ? resourceItem.getTaxInclCompilePrice() : BigDecimal.ZERO;

                            BigDecimal qty = dosage.multiply(motherQuantity);
                            sum.addTaxExclBaseSum(exclBase.multiply(qty).setScale(SCALE, ROUNDING_MODE));
                            sum.addTaxInclBaseSum(inclBase.multiply(qty).setScale(SCALE, ROUNDING_MODE));
                            sum.addTaxExclCompileSum(exclCompile.multiply(qty).setScale(SCALE, ROUNDING_MODE));
                            sum.addTaxInclCompileSum(inclCompile.multiply(qty).setScale(SCALE, ROUNDING_MODE));
                        }
                    }
                }
            }

            log.info("[统一取费分类合价] divisionId={}, categorySums={}", divisionId, result);
            return result;
        } catch (Exception e) {
            log.error("[统一取费分类合价] 计算异常 - divisionId={}", divisionId, e);
            return result;
        }
    }

    /**
     * 根据指定的价格字段类型计算统一取费的calcBase值
     */
    private BigDecimal evaluateCalcBaseForUnifiedFeeByField(Map<String, Object> calcBase,
            Map<Long, CategoryPriceSum> categorySums, String priceField) {
        if (MapUtil.isEmpty(calcBase)) {
            return BigDecimal.ZERO;
        }
        String formula = (String) calcBase.get("formula");
        if (StrUtil.isBlank(formula)) {
            return BigDecimal.ZERO;
        }
        @SuppressWarnings("unchecked")
        Map<String, Object> variables = (Map<String, Object>) calcBase.get("variables");
        if (MapUtil.isEmpty(variables)) {
            try {
                return new BigDecimal(formula.trim());
            } catch (NumberFormatException e) {
                return BigDecimal.ZERO;
            }
        }

        Map<String, BigDecimal> varValues = new HashMap<>();
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            String varName = entry.getKey();
            Object varValue = entry.getValue();
            Long categoryId = null;
            if (varValue instanceof Number) {
                categoryId = ((Number) varValue).longValue();
            } else if (varValue instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> varInfo = (Map<String, Object>) varValue;
                Object categoryIdObj = varInfo.get("categoryId");
                if (categoryIdObj != null) {
                    categoryId = ((Number) categoryIdObj).longValue();
                }
            }
            if (categoryId == null) {
                varValues.put(varName, BigDecimal.ZERO);
                continue;
            }
            CategoryPriceSum sum = categorySums.get(categoryId);
            BigDecimal value = BigDecimal.ZERO;
            if (sum != null) {
                switch (priceField) {
                    case "taxExclBaseSum": value = sum.getTaxExclBaseSum(); break;
                    case "taxInclBaseSum": value = sum.getTaxInclBaseSum(); break;
                    case "taxExclCompileSum": value = sum.getTaxExclCompileSum(); break;
                    case "taxInclCompileSum": value = sum.getTaxInclCompileSum(); break;
                    default: value = sum.getTaxExclCompileSum(); break;
                }
            }
            varValues.put(varName, value != null ? value : BigDecimal.ZERO);
        }
        return evaluateFormula(formula, varValues);
    }

    /**
     * 获取母定额的工料机分类合价
     */
    private Map<Long, CategoryPriceSum> getMotherCategorySums(Long motherDivisionId) {
        // 获取母定额的工料机列表
        List<com.yhy.module.core.controller.admin.workbench.vo.WbBoqResourceRespVO> wbResources = 
                wbBoqResourceService.getListByDivisionId(motherDivisionId);
        
        if (CollUtil.isEmpty(wbResources)) {
            // 【已禁用】不再 fallback 到后台数据，直接返回空
            // 计算逻辑已收归工作台，后台不再参与计算
            return new HashMap<>();
        }
        
        List<ResourcePriceDetail> resourceDetails = convertWbResourcesToResourcePriceDetails(wbResources);
        return calculateCategorySums(resourceDetails);
    }

    /**
     * 从快照表获取统一取费设置（通过sourceId查找）
     */
    private com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO getUnifiedFeeSettingFromSnapshot(Long compileTreeId, Long sourceId) {
        try {
            List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO> settings = 
                wbUnifiedFeeSettingMapper.selectByCompileTreeId(compileTreeId);
            return settings.stream()
                    .filter(s -> sourceId.equals(s.getSourceId()))
                    .findFirst()
                    .orElse(null);
        } catch (Exception e) {
            log.warn("[统一取费单价] 从快照获取统一取费设置失败 - compileTreeId={}, sourceId={}", compileTreeId, sourceId, e);
            return null;
        }
    }

    /**
     * 从快照表获取统一取费设置的子费用列表
     */
    private List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO> getChildSettingsFromSnapshot(Long compileTreeId, Long parentSnapshotId) {
        try {
            List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeSettingDO> settings = 
                wbUnifiedFeeSettingMapper.selectByCompileTreeId(compileTreeId);
            return settings.stream()
                    .filter(s -> parentSnapshotId.equals(s.getParentId()))
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.warn("[统一取费单价] 从快照获取子费用列表失败 - compileTreeId={}, parentSnapshotId={}", compileTreeId, parentSnapshotId, e);
            return new ArrayList<>();
        }
    }

    /**
     * 将快照统一取费子目工料机转换为VO格式
     */
    private List<com.yhy.module.core.controller.admin.quota.vo.QuotaUnifiedFeeResourceRespVO> convertWbUnifiedFeeResourcesToVO(
            List<com.yhy.module.core.dal.dataobject.workbench.WbUnifiedFeeResourceDO> snapshotResources) {
        if (CollUtil.isEmpty(snapshotResources)) {
            return new ArrayList<>();
        }
        return snapshotResources.stream().map(wb -> {
            com.yhy.module.core.controller.admin.quota.vo.QuotaUnifiedFeeResourceRespVO vo = 
                new com.yhy.module.core.controller.admin.quota.vo.QuotaUnifiedFeeResourceRespVO();
            vo.setId(wb.getId());
            vo.setUnifiedFeeSettingId(wb.getUnifiedFeeSettingId());
            vo.setDosage(wb.getEffectiveDosage());
            vo.setSortOrder(wb.getSortOrder());
            // 从attributes中获取额外字段
            Map<String, Object> attrs = wb.getAttributes();
            if (attrs != null) {
                if (attrs.get("resourceCode") != null) {
                    vo.setResourceCode(attrs.get("resourceCode").toString());
                }
                if (attrs.get("resourceName") != null) {
                    vo.setResourceName(attrs.get("resourceName").toString());
                }
                if (attrs.get("resourceUnit") != null) {
                    vo.setResourceUnit(attrs.get("resourceUnit").toString());
                }
                if (attrs.get("calcBase") != null) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> calcBase = (Map<String, Object>) attrs.get("calcBase");
                    vo.setCalcBase(calcBase);
                }
                if (attrs.get("resourceTaxExclCompilePrice") != null) {
                    vo.setResourceTaxExclCompilePrice(new BigDecimal(attrs.get("resourceTaxExclCompilePrice").toString()));
                }
            }
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 检查母定额是否在子费用的取费章节范围内
     * @param motherCatalogItemId 母定额的目录节点ID
     * @param feeChapter 子费用的取费章节JSON数组字符串，如 ["2027009068267687937"]
     * @return 如果匹配或feeChapter为空则返回true
     */
    private boolean isMotherQuotaInFeeChapter(Long motherCatalogItemId, String feeChapter) {
        // 如果feeChapter为空，表示不限制，所有母定额都匹配
        if (StrUtil.isBlank(feeChapter) || "[]".equals(feeChapter)) {
            return true;
        }
        
        // 如果母定额没有catalogItemId，无法匹配
        if (motherCatalogItemId == null) {
            log.warn("[统一取费单价] 母定额缺少sourceCatalogItemId，无法进行取费章节过滤");
            return true; // 默认匹配，避免漏算
        }
        
        try {
            // 解析feeChapter JSON数组
            List<String> chapterIds = cn.hutool.json.JSONUtil.toList(feeChapter, String.class);
            if (chapterIds == null || chapterIds.isEmpty()) {
                return true;
            }
            
            // 检查母定额的catalogItemId是否在取费章节列表中
            String motherCatalogIdStr = motherCatalogItemId.toString();
            return chapterIds.contains(motherCatalogIdStr);
        } catch (Exception e) {
            log.warn("[统一取费单价] 解析feeChapter失败: {}", feeChapter, e);
            return true; // 解析失败时默认匹配
        }
    }

    /**
     * 计算统一取费子目工料机的计算基数值
     * 子目工料机的calcBase格式：{"formula": "材", "variables": {"材": 3}}
     * 其中 variables 的值是 categoryId
     */
    private BigDecimal evaluateCalcBaseForUnifiedFee(Map<String, Object> calcBase, Map<Long, CategoryPriceSum> categorySums) {
        if (MapUtil.isEmpty(calcBase)) {
            return BigDecimal.ZERO;
        }
        
        String formula = (String) calcBase.get("formula");
        if (StrUtil.isBlank(formula)) {
            return BigDecimal.ZERO;
        }
        
        @SuppressWarnings("unchecked")
        Map<String, Object> variables = (Map<String, Object>) calcBase.get("variables");
        if (MapUtil.isEmpty(variables)) {
            // 如果没有变量，尝试直接解析为数字
            try {
                return new BigDecimal(formula.trim());
            } catch (NumberFormatException e) {
                log.warn("[统一取费calcBase] 无变量且非数字公式: {}", formula);
                return BigDecimal.ZERO;
            }
        }
        
        // 构建变量值映射
        // 统一取费子目工料机的calcBase格式与定额取费不同
        // 格式：{"formula": "材", "variables": {"材": 3}}
        // 其中 variables 的值直接是 categoryId（数字）
        Map<String, BigDecimal> varValues = new HashMap<>();
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            String varName = entry.getKey();
            Object varValue = entry.getValue();
            
            Long categoryId = null;
            if (varValue instanceof Number) {
                // 直接是 categoryId
                categoryId = ((Number) varValue).longValue();
            } else if (varValue instanceof Map) {
                // 兼容定额取费的格式：{"categoryId": 3, "priceField": "tax_excl_base_price"}
                @SuppressWarnings("unchecked")
                Map<String, Object> varInfo = (Map<String, Object>) varValue;
                Object categoryIdObj = varInfo.get("categoryId");
                if (categoryIdObj != null) {
                    categoryId = ((Number) categoryIdObj).longValue();
                }
            }
            
            if (categoryId == null) {
                varValues.put(varName, BigDecimal.ZERO);
                continue;
            }
            
            CategoryPriceSum sum = categorySums.get(categoryId);
            BigDecimal value = BigDecimal.ZERO;
            if (sum != null) {
                // 默认使用除税编制价合价
                value = sum.getTaxExclCompileSum();
            }
            
            varValues.put(varName, value != null ? value : BigDecimal.ZERO);
            log.debug("[统一取费calcBase] 变量 {} -> categoryId={}, value={}", varName, categoryId, value);
        }
        
        // 使用简单的表达式计算（替换变量后计算）
        return evaluateFormula(formula, varValues);
    }
}
