package com.yhy.module.core.util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 调整公式计算工具类
 * 用于计算工料机的调整公式（虚拟字段）
 * 后台和工作台共用此逻辑
 *
 * @author yhy
 */
public class AdjustmentFormulaCalculator {

    /**
     * 计算调整公式
     *
     * @param resources 工料机列表（需要包含 code 和 categoryId）
     * @param settings 调整设置列表
     * @param codeGetter 获取工料机编码的函数
     * @param categoryIdGetter 获取工料机类别ID的函数
     * @param formulaSetter 设置调整公式的函数
     * @param <T> 工料机类型
     */
    public static <T> void calculateFormulas(
            List<T> resources,
            List<? extends AdjustmentSetting> settings,
            java.util.function.Function<T, String> codeGetter,
            java.util.function.Function<T, Long> categoryIdGetter,
            java.util.function.BiConsumer<T, String> formulaSetter) {
        
        if (resources == null || resources.isEmpty() || settings == null || settings.isEmpty()) {
            return;
        }
        
        // 1. 初始化公式映射（工料机编码 -> 公式）
        Map<String, String> formulaMap = new HashMap<>();
        for (T vo : resources) {
            String code = codeGetter.apply(vo);
            if (code != null) {
                formulaMap.put(code, "x");
            }
        }
        
        // 2. 按类别分组工料机
        Map<Long, List<T>> resourceCategoryMap = new HashMap<>();
        for (T vo : resources) {
            Long categoryId = categoryIdGetter.apply(vo);
            if (categoryId != null) {
                resourceCategoryMap.computeIfAbsent(categoryId, k -> new ArrayList<>()).add(vo);
            }
        }
        
        // 3. 遍历调整设置，计算公式
        for (AdjustmentSetting setting : settings) {
            String adjustmentContent = setting.getAdjustmentContent();
            Map<String, Object> adjustmentRules = setting.getAdjustmentRules();
            
            if (adjustmentRules == null || adjustmentRules.isEmpty()) {
                continue;
            }
            
            String type = (String) adjustmentRules.get("type");
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> items = (List<Map<String, Object>>) adjustmentRules.get("items");
            
            if (items == null || items.isEmpty() || type == null) {
                continue;
            }
            
            switch (type) {
                case "adjust_coefficient":
                    // 调整类别系数：x * 系数
                    if (!"true".equalsIgnoreCase(adjustmentContent)) {
                        break;
                    }
                    for (Map<String, Object> item : items) {
                        Object categoryIdObj = item.get("categoryId");
                        if (categoryIdObj == null) {
                            categoryIdObj = item.get("category");
                        }
                        Object coefficientObj = item.get("coefficient");
                        if (categoryIdObj == null || coefficientObj == null) continue;
                        
                        Long categoryId = Long.parseLong(categoryIdObj.toString());
                        BigDecimal coefficient = new BigDecimal(coefficientObj.toString());
                        String coefficientStr = formatNumber(coefficient);
                        
                        List<T> categoryResources = resourceCategoryMap.get(categoryId);
                        if (categoryResources != null) {
                            for (T vo : categoryResources) {
                                String code = codeGetter.apply(vo);
                                if (code != null && formulaMap.containsKey(code)) {
                                    String currentFormula = formulaMap.get(code);
                                    formulaMap.put(code, "(" + currentFormula + ")*" + coefficientStr);
                                }
                            }
                        }
                    }
                    break;
                    
                case "consumption_adjustment":
                    // 增减材料消耗量：x + 增减值
                    if (!"true".equalsIgnoreCase(adjustmentContent)) {
                        break;
                    }
                    for (Map<String, Object> item : items) {
                        Object codeObj = item.get("code");
                        Object consumptionValueObj = item.get("consumptionValue");
                        if (consumptionValueObj == null) {
                            consumptionValueObj = item.get("consumption");
                        }
                        if (codeObj == null || consumptionValueObj == null) continue;
                        
                        String code = codeObj.toString();
                        BigDecimal consumptionValue = new BigDecimal(consumptionValueObj.toString());
                        
                        if (formulaMap.containsKey(code)) {
                            String currentFormula = formulaMap.get(code);
                            String sign = consumptionValue.compareTo(BigDecimal.ZERO) >= 0 ? "+" : "";
                            formulaMap.put(code, "(" + currentFormula + ")" + sign + formatNumber(consumptionValue));
                        }
                    }
                    break;
                    
                case "dynamic_adjust":
                    // 动态调整类别系数：x * 系数 * A
                    for (Map<String, Object> item : items) {
                        Object categoryObj = item.get("category");
                        if (categoryObj == null) {
                            categoryObj = item.get("categoryId");
                        }
                        Object inputValueObj = item.get("inputValue");
                        Object baseValueObj = item.get("baseValue");
                        Object denominatorValueObj = item.get("denominatorValue");
                        Object coefficientSettingObj = item.get("coefficientSetting");
                        Object valueRuleObj = item.get("valueRule");
                        
                        if (categoryObj == null || inputValueObj == null) continue;
                        
                        Long categoryId = Long.parseLong(categoryObj.toString());
                        BigDecimal inputValue = new BigDecimal(inputValueObj.toString());
                        BigDecimal baseValue = baseValueObj != null ? new BigDecimal(baseValueObj.toString()) : BigDecimal.ZERO;
                        BigDecimal denominatorValue = denominatorValueObj != null ? new BigDecimal(denominatorValueObj.toString()) : BigDecimal.ONE;
                        BigDecimal coefficientSetting = coefficientSettingObj != null ? new BigDecimal(coefficientSettingObj.toString()) : BigDecimal.ONE;
                        String valueRule = valueRuleObj != null ? valueRuleObj.toString() : "original";
                        
                        // 计算 A = (输入值 - 基础值) / 分母值
                        BigDecimal A = inputValue.subtract(baseValue);
                        if (denominatorValue.compareTo(BigDecimal.ZERO) != 0) {
                            A = A.divide(denominatorValue, 6, RoundingMode.HALF_UP);
                        }
                        A = applyValueRule(A, valueRule);
                        
                        List<T> categoryResources = resourceCategoryMap.get(categoryId);
                        if (categoryResources != null) {
                            for (T vo : categoryResources) {
                                String code = codeGetter.apply(vo);
                                if (code != null && formulaMap.containsKey(code)) {
                                    String currentFormula = formulaMap.get(code);
                                    formulaMap.put(code, "(" + currentFormula + ")*" + formatNumber(coefficientSetting) + "*" + formatNumber(A));
                                }
                            }
                        }
                    }
                    break;
                    
                case "dynamic_merge":
                    // 动态合并定额：暂不处理公式（需要查询其他定额的工料机数据）
                    break;
                    
                default:
                    break;
            }
        }
        
        // 4. 将公式设置到对应的VO
        for (T vo : resources) {
            String code = codeGetter.apply(vo);
            if (code != null && formulaMap.containsKey(code)) {
                String formula = formulaMap.get(code);
                if (!"x".equals(formula)) {
                    formulaSetter.accept(vo, formula);
                }
            }
        }
    }
    
    /**
     * 格式化数字，去除尾部多余的0
     */
    public static String formatNumber(BigDecimal number) {
        if (number == null) {
            return "0";
        }
        return number.stripTrailingZeros().toPlainString();
    }
    
    /**
     * 应用值规则
     */
    public static BigDecimal applyValueRule(BigDecimal value, String valueRule) {
        if (value == null || valueRule == null) {
            return value;
        }
        switch (valueRule) {
            case "round_up":
                return value.setScale(0, RoundingMode.CEILING);
            case "round_down":
                return value.setScale(0, RoundingMode.FLOOR);
            case "round":
                return value.setScale(0, RoundingMode.HALF_UP);
            default:
                return value;
        }
    }
    
    /**
     * 调整设置接口
     * 后台和工作台的调整设置DO都需要实现此接口
     */
    public interface AdjustmentSetting {
        String getAdjustmentContent();
        Map<String, Object> getAdjustmentRules();
    }
}
