package com.xinda.iot.util;

import org.apache.commons.jexl3.*;

import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FormulaCalculator {
    private static final JexlEngine jexl = new JexlBuilder()
            .cache(512)
            .silent(false)
            .strict(true)
            .create();

    // 匹配字母开头，包含字母、数字的变量名（至少1位）
    private static final Pattern VAR_PATTERN = Pattern.compile("\\b[a-zA-Z][a-zA-Z0-9]*\\b");

    public static String evaluate(String formula, Map<String, String> variables) {
        // 校验公式安全性
//        validateFormula(formula, variables.keySet());

        // 创建上下文并注入变量
        JexlContext context = new MapContext();
        variables.forEach((name, value) -> {
            Number num = parseNumber(value);
            context.set(name, num);
        });

        try {
            // 执行计算
            JexlExpression expr = jexl.createExpression(formula);
            return expr.evaluate(context).toString();
        } catch (JexlException e) {
            throw new RuntimeException("Formula evaluation failed: " + e.getMessage());
        }
    }

    private static Number parseNumber(String value) {
        try {
            if (value.contains(".")) {
                return Double.parseDouble(value);
            }
            return Long.parseLong(value);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid number format: " + value);
        }
    }

    private static void validateFormula(String formula, Set<String> validVars) {
        // 安全字符校验（允许变量名、运算符、数字和括号）
        if (!formula.matches("^[\\w+\\-*/%().]+$")) {
            throw new IllegalArgumentException("包含非法字符");
        }

        // 提取公式中的变量
        Matcher matcher = VAR_PATTERN.matcher(formula);
        Set<String> formulaVars = new HashSet<>();
        while (matcher.find()) {
            String var = matcher.group();
            // 排除纯数字的情况
            if (!var.matches("\\d+")) {
                formulaVars.add(var);
            }
        }

        // 校验变量是否存在
        formulaVars.removeAll(validVars);
        if (!formulaVars.isEmpty()) {
            throw new IllegalArgumentException("未定义的变量: " + formulaVars);
        }
    }


    /**
     * 校验变量集合是否包含公式所需全部参数
     * @param formula 运算公式
     * @param variables 变量集合（key为变量名）
     * @return true-变量完整 | false-存在缺失
     */
    public static boolean containsAllVariables(String formula, Map<String, String> variables) {
        // 提取公式中的有效变量名（过滤纯数字）
        Set<String> requiredVars = extractFormulaVariables(formula);

        // 空值安全校验
        if (variables == null) return requiredVars.isEmpty();

        // 检查所有必要变量是否存在
        return variables.keySet().containsAll(requiredVars);
    }

    /**
     * 公开的变量提取方法
     */
    public static Set<String> extractFormulaVariables(String formula) {
        Matcher matcher = VAR_PATTERN.matcher(formula);
        Set<String> vars = new HashSet<>();
        while (matcher.find()) {
            String var = matcher.group();
            if (!isPureNumber(var)) { // 过滤纯数字
                vars.add(var);
            }
        }
        return Collections.unmodifiableSet(vars);
    }

    /**
     * 判断字符串是否为纯数字
     */
    private static boolean isPureNumber(String str) {
        return str.matches("^\\d+$");
    }
}
