package com.zt.plat.module.qms.core.qlexpress.cmp;

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

import org.springframework.stereotype.Component;

import com.alibaba.qlexpress4.Express4Runner;
import com.alibaba.qlexpress4.QLOptions;
import com.alibaba.qlexpress4.QLResult;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

/**
 * 允差值计算器工具类
 */
@Slf4j
@Component
public class AllowanceCalculatorComponent {
	
	@Resource
	private Express4Runner express4Runner;

    /**
     * 计算允差值：支持原生线性公式 和 Express 自定义公式混合模式
     *
     * @param minValue       允差范围最小值 (X1)
     * @param maxValue       允差范围最大值 (X2)
     * @param minYc          最小允差值 (Y1)
     * @param maxYc          最大允差值 (Y2)
     * @param c              常数偏移量 C
     * @param ran            当前测量值 X
     * @param isUseFormula   是否使用自定义公式 (1=是, 其他=否)
     * @param formula        自定义表达式字符串，如 "X > 10 ? 0.5 : 0.3"，变量用 X 表示当前值
     * @param scale          结果保留小数位数
     * @return 允差值 yc
     */
    public BigDecimal calculateAllowableValue(
            BigDecimal minValue,
            BigDecimal maxValue,
            BigDecimal minYc,
            BigDecimal maxYc,
            BigDecimal c,
            BigDecimal ran,
            Integer isUseFormula,
            String formula,
            int scale) {

        // 参数校验
        if (minValue == null || maxValue == null || minYc == null || maxYc == null ||
            c == null || ran == null || scale < 0) {
            throw new IllegalArgumentException("参数不能为空，且 scale >= 0");
        }

        boolean useCustomFormula = isUseFormula != null && isUseFormula.intValue() == 1;

        if (useCustomFormula && (formula == null || formula.trim().isEmpty())) {
            throw new IllegalArgumentException("启用了自定义公式，但 formula 为空");
        }

        BigDecimal ycValue;

        try {
            if (useCustomFormula) {
                log.debug("使用自定义公式计算: formula='{}', X={}", formula, ran);
                ycValue = evaluateCustomFormula(formula, ran, scale);
            } else {
                log.debug("使用线性公式计算: X={}, range=[{},{}], yc=[{},{}]", ran, minValue, maxValue, minYc, maxYc);
                ycValue = calculateLinearAllowance(minValue, maxValue, minYc, maxYc, c, ran, scale);
            }
        } catch (Exception e) {
            log.error("计算允差值失败", e);
            throw new RuntimeException("计算允差值失败: " + e.getMessage(), e);
        }

        return ycValue;
    }

    /**
     * 使用 Express 执行自定义公式
     */
    private BigDecimal evaluateCustomFormula(String formula, BigDecimal xValue, int scale) {
        Map<String, Object> context = new HashMap<>();
        context.put("X", xValue);  // 用户公式中使用 X 作为变量名

        try {
//            Object result = expressRunner.execute(formula, context, null, true, false);
        	QLResult execute = express4Runner.execute(formula, context, QLOptions.builder().precise(true).build());
        	Object result = execute.getResult();
            if (result == null) {
                throw new RuntimeException("Express 公式返回结果为 null");
            }

            BigDecimal decimalResult;
            if (result instanceof BigDecimal) {
                decimalResult = (BigDecimal) result;
            } else if (result instanceof Number) {
                decimalResult = new BigDecimal(((Number) result).toString());
            } else {
                decimalResult = new BigDecimal(result.toString());
            }

            return decimalResult.setScale(scale, RoundingMode.HALF_EVEN);
        } catch (Exception e) {
            throw new RuntimeException("执行自定义公式失败: '" + formula + "', 错误: " + e.getMessage(), e);
        }
    }

    /**
     * 原生 Java 计算线性允差值：yc = k * X + b + c
     */
    private BigDecimal calculateLinearAllowance(
            BigDecimal minValue,
            BigDecimal maxValue,
            BigDecimal minYc,
            BigDecimal maxYc,
            BigDecimal c,
            BigDecimal ran,
            int scale) {

        BigDecimal deltaVa = maxValue.subtract(minValue);
        BigDecimal deltaYc = maxYc.subtract(minYc);

        BigDecimal k;
        if (deltaVa.compareTo(BigDecimal.ZERO) == 0) {
            k = BigDecimal.ZERO; // 防止除零
        } else {
            k = deltaYc.divide(deltaVa, 10, RoundingMode.HALF_EVEN); // 高精度除法
        }

        BigDecimal b = maxYc.subtract(maxValue.multiply(k));
        return k.multiply(ran)
                 .add(b)
                 .add(c)
                 .setScale(scale, RoundingMode.HALF_EVEN);
    }
}
