package com.xdap.self_development.utils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FormulaValidatorUtils {
    private static final String PLACEHOLDER = "OPERAND_PLACEHOLDER";

    // 定义支持的数学运算符
    private static final Set<Character> OPERATORS = new HashSet<>(Arrays.asList('+', '-', '*', '/'));
    // 定义支持的常量
    private static final Set<String> CONSTANTS = new HashSet<>(Collections.singletonList("π"));

    private FormulaValidatorUtils() {
        throw new AssertionError("禁止实例化工具类 FormulaValidatorUtils");
    }

    /**
     * 详细验证公式合法性（基于运算逻辑）
     * @param formula 待验证的公式
     * @return 验证结果（是否合法、错误信息）
     */
    public static Map<String, Object> validateFormulaDetailed(String formula) {
        Map<String, Object> result = new HashMap<>();
        String originalFormula = formula;

        // 1. 基础空值检查
        if (formula == null || formula.trim().isEmpty()) {
            result.put("isValid", false);
            result.put("errorMessage", String.format("公式不能为空 [原始公式：%s]", originalFormula));
            return result;
        }

        formula = formula.replaceAll("\\s+", "");

        // 2. 仅对英文括号进行匹配检查
        if (!isEnglishParenthesesBalanced(formula)) {
            result.put("isValid", false);
            result.put("errorMessage", String.format("英文括号不匹配 [原始公式：%s]", originalFormula));
            return result;
        }

        // 3. 语法结构校验
        try {
            // 解析公式并验证运算逻辑
            validateTopLevelFormula(formula, originalFormula);
        } catch (IllegalArgumentException e) {
            result.put("isValid", false);
            result.put("errorMessage", e.getMessage());
            return result;
        }

        // 4. 数字格式校验
        String numberFormatError = checkNumberFormatDetailed(formula, originalFormula);
        if (numberFormatError != null) {
            result.put("isValid", false);
            result.put("errorMessage", numberFormatError);
            return result;
        }

        // 验证通过
        result.put("isValid", true);
        result.put("errorMessage", String.format("公式格式正确 [原始公式：%s]", originalFormula));
        // 可选：返回提取的参数信息
        result.put("parameters", extractParameters(originalFormula));
        return result;
    }

    /**
     * 验证顶层公式语法
     */
    private static void validateTopLevelFormula(String formula, String originalFormula) {
        // 移除所有空格
        String cleaned = formula.replaceAll("\\s+", "");

        // 处理空公式
        if (cleaned.isEmpty()) {
            throw new IllegalArgumentException(String.format("公式不能为空 [原始公式：%s]", originalFormula));
        }

        // 递归解析括号表达式，将括号块视为整体操作数
        String parsedFormula = parseParenthesesBlocks(cleaned, originalFormula);

        // 验证解析后的公式
        validateSubFormula(parsedFormula, cleaned, originalFormula);
    }

    /**
     * 递归解析括号块，将每对匹配的括号内内容视为整体操作数
     * @param formula 待解析公式
     * @param originalFormula 原始公式
     * @return 替换括号块为占位符的公式
     */
    private static String parseParenthesesBlocks(String formula, String originalFormula) {
        // 匹配最外层括号对
        Pattern outerBracketPattern = Pattern.compile("\\(([^()]*)\\)");
        Matcher matcher = outerBracketPattern.matcher(formula);

        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String innerContent = matcher.group(1);

            // 检查括号内是否为空
            if (innerContent.trim().isEmpty()) {
                throw new IllegalArgumentException(String.format("英文括号内不能为空 [错误片段：()][原始公式：%s]", originalFormula));
            }

            // 递归解析括号内的子内容
            String parsedInner = parseParenthesesBlocks(innerContent, originalFormula);

            // 验证括号内的子公式
            validateSubFormula(parsedInner, innerContent, originalFormula);

            // 替换括号块为占位符
            matcher.appendReplacement(sb, PLACEHOLDER);
        }
        matcher.appendTail(sb);

        return sb.toString();
    }

    /**
     * 验证子公式的运算逻辑（操作数+运算符交替规则）
     * @param subFormula 无嵌套括号的子公式（或括号已替换为占位符）
     * @param currentFormula 当前处理的公式片段
     * @param originalFormula 原始公式（用于错误提示）
     * @throws IllegalArgumentException 语法错误时抛出异常
     */
    private static void validateSubFormula(String subFormula, String currentFormula, String originalFormula) {
        if (subFormula.isEmpty()) {
            return;
        }

        // 拆分运算单元
        List<String> tokens = tokenizeFormula(subFormula);

        // 验证运算单元的合法性
        for (int i = 0; i < tokens.size(); i++) {
            String token = tokens.get(i);

            // 占位符直接视为合法操作数
            if (token.equals(PLACEHOLDER)) {
                continue;
            }

            // 第一个token：可以是参数/数字/常量/负号/占位符
            if (i == 0) {
                if ("-".equals(token)) {
                    // 负号开头，检查下一个token是否为有效值
                    if (tokens.size() < 2 || isValidOperand(tokens.get(1)) && !tokens.get(1).equals(PLACEHOLDER)) {
                        throw new IllegalArgumentException(String.format("负号后必须跟有效参数/数字/常量 [错误片段：-%s][原始公式：%s]",
                                tokens.size() >= 2 ? tokens.get(1) : "", originalFormula));
                    }
                } else if (isValidOperand(token)) {
                    throw new IllegalArgumentException(String.format("公式开头必须是参数/数字/常量，当前为无效字符：%s [错误片段：%s][原始公式：%s]",
                            token, currentFormula, originalFormula));
                }
            } else {
                // 偶数位必须是运算符，奇数位必须是操作数/占位符
                if (i % 2 == 0) { // 操作数位置
                    if (isValidOperand(token)) {
                        throw new IllegalArgumentException(String.format("运算符后必须跟有效参数/数字/常量，当前为无效字符：%s [错误片段：%s][原始公式：%s]",
                                token, currentFormula, originalFormula));
                    }
                } else { // 运算符位置
                    if (!isValidOperator(token)) {
                        throw new IllegalArgumentException(String.format("非法运算符或连续运算符：%s [错误片段：%s][原始公式：%s]",
                                token, currentFormula, originalFormula));
                    }
                    // 检查除法分母不能为0
                    if ("/".equals(token) && i + 1 < tokens.size()) {
                        String nextToken = tokens.get(i + 1);
                        if (!nextToken.equals(PLACEHOLDER) && nextToken.matches("^-?0+(\\.0+)?$")) {
                            throw new IllegalArgumentException(String.format("除法运算分母不能为0 [错误片段：/%s][原始公式：%s]",
                                    nextToken, originalFormula));
                        }
                    }
                }
            }
        }

        // 验证公式不能以运算符结尾
        if (!tokens.isEmpty() && isValidOperator(tokens.get(tokens.size() - 1))) {
            throw new IllegalArgumentException(String.format("公式不能以运算符[%s]结尾 [错误片段：%s][原始公式：%s]",
                    tokens.get(tokens.size() - 1), currentFormula, originalFormula));
        }
    }

    /**
     * 将公式拆分为运算单元（操作数+运算符）
     * 优化：确保带字母/数字的中文参数名被完整识别
     * @param formula 无嵌套括号的子公式（或含占位符）
     * @return 拆分后的token列表
     */
    private static List<String> tokenizeFormula(String formula) {
        List<String> tokens = new ArrayList<>();
        StringBuilder currentOperand = new StringBuilder();
        int i = 0;
        while (i < formula.length()) {
            char c = formula.charAt(i);
            if (c == 'O' && formula.startsWith(PLACEHOLDER, i)) {
                if (currentOperand.length() > 0) {
                    tokens.add(currentOperand.toString());
                    currentOperand.setLength(0);
                }
                tokens.add(PLACEHOLDER);
                i += PLACEHOLDER.length();
                continue;
            }
            if (OPERATORS.contains(c)) {
                boolean isNegativeSign = (c == '-') && (i == 0 ||
                        OPERATORS.contains(formula.charAt(i - 1)) ||
                        formula.charAt(i - 1) == '(');
                if (isNegativeSign) {
                    currentOperand.append(c);
                } else {
                    if (currentOperand.length() > 0) {
                        tokens.add(currentOperand.toString());
                        currentOperand.setLength(0);
                    }
                    tokens.add(String.valueOf(c));
                }
            } else {
                currentOperand.append(c);
            }
            i++;
        }
        if (currentOperand.length() > 0) {
            tokens.add(currentOperand.toString());
        }

        return tokens;
    }

    /**
     * 检查是否为合法操作数（核心优化：支持中文+数字+字母+中文括号）
     * @param operand 待检查的操作数
     * @return 是否合法
     */
    private static boolean isValidOperand(String operand) {
        if (operand == null || operand.isEmpty()) {
            return true;
        }

        // 处理负号开头的情况
        String checkOperand = operand.startsWith("-") ? operand.substring(1) : operand;

        // 1. 常量π
        if (CONSTANTS.contains(checkOperand)) {
            return false;
        }

        // 2. 纯数字
        if (checkOperand.matches("\\d+(\\.\\d+)?")) {
            return false;
        }

        // 3. 中文参数名
        // 正则说明：[一-龥] 中文 | [0-9] 数字 | [a-zA-Z] 字母 | [（）] 中文括号
        if (checkOperand.matches("[\\u4e00-\\u9fa50-9a-zA-Z（）]+")) {
            // 确保参数名至少包含一个中文
            return !checkOperand.matches(".*[\\u4e00-\\u9fa5]+.*");
        }

        return true;
    }

    /**
     * 检查是否为合法运算符
     * @param operator 待检查的运算符
     * @return 是否合法
     */
    private static boolean isValidOperator(String operator) {
        return operator != null && operator.length() == 1 && OPERATORS.contains(operator.charAt(0));
    }

    /**
     * 仅检查英文括号是否匹配
     */
    private static boolean isEnglishParenthesesBalanced(String formula) {
        int balance = 0;
        for (char c : formula.toCharArray()) {
            if (c == '(') {
                balance++;
            } else if (c == ')') {
                balance--;
                if (balance < 0) {
                    return false; // 闭括号多于开括号
                }
            }
            // 忽略中文括号
        }
        return balance == 0;
    }

    /**
     * 检查数字格式是否正确
     * @return 错误信息，无错误返回null
     */
    private static String checkNumberFormatDetailed(String formula, String originalFormula) {
        // 先移除中文括号，避免干扰数字格式检查
        String cleanFormula = formula.replaceAll("[（）]", "");

        // 1. 检查多个小数点
        Pattern multiDotPattern = Pattern.compile("\\d+\\.\\d*\\.");
        Matcher multiDotMatcher = multiDotPattern.matcher(cleanFormula);
        if (multiDotMatcher.find()) {
            String errorPart = multiDotMatcher.group();
            return String.format("数字格式错误：存在多个小数点 [%s] [错误片段：%s][原始公式：%s]",
                    errorPart, formula, originalFormula);
        }

        // 2. 检查小数点前后是否有非法字符
        Pattern invalidDotPattern = Pattern.compile("\\.[\\u4e00-\\u9fa5()]|([^0-9.])\\.([^0-9.])");
        Matcher invalidDotMatcher = invalidDotPattern.matcher(cleanFormula);
        if (invalidDotMatcher.find()) {
            String errorPart = invalidDotMatcher.group();
            return String.format("数字格式错误：小数点位置非法 [%s] [错误片段：%s][原始公式：%s]",
                    errorPart, formula, originalFormula);
        }

        // 3. 检查以小数点开头/结尾的孤立小数点
        if (cleanFormula.matches("^(?:\\..*|.*\\D\\.)$")) {
            return String.format("数字格式错误：不能以孤立小数点开头或结尾 [错误片段：%s][原始公式：%s]",
                    formula, originalFormula);
        }

        return null;
    }

    /**
     * 提取公式中的所有参数
     */
    public static List<String> extractParameters(String formula) {
        List<String> parameters = new ArrayList<>();
        if (formula == null || formula.trim().isEmpty()) {
            return parameters;
        }

        // 匹配中文参数名
        Pattern paramPattern = Pattern.compile("[\\u4e00-\\u9fa5][\\u4e00-\\u9fa50-9a-zA-Z（）]*");
        Matcher matcher = paramPattern.matcher(formula);

        while (matcher.find()) {
            String param = matcher.group();
            if (!parameters.contains(param)) {
                parameters.add(param);
            }
        }

        return parameters;
    }
}
