package service;

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


public class ExpressionEvaluator {



    public static double evaluate(String expression) {
        // 1. 预处理，将特殊运算（开方、平方、三角函数）直接计算并替换为数值
        String processedExpr = preprocessSpecialOperations(expression);

        // 2. 使用双栈算法计算最终的四则运算表达式
        return calculateStandardExpression(processedExpr);
    }


    private static String preprocessSpecialOperations(String expr) {
        // 替换中文运算符
        expr = expr.replace('×', '*').replace('÷', '/');

        // 匹配并计算三角函数，例如 sin(30°)
        Pattern trigPattern = Pattern.compile("(sin|cos|tan)\\((\\d+)°\\)");
        Matcher trigMatcher = trigPattern.matcher(expr);
        while (trigMatcher.find()) {
            String func = trigMatcher.group(1);
            double angle = Double.parseDouble(trigMatcher.group(2));
            double value = 0.0;
            switch (func) {
                case "sin": value = Math.sin(Math.toRadians(angle)); break;
                case "cos": value = Math.cos(Math.toRadians(angle)); break;
                case "tan": value = Math.tan(Math.toRadians(angle)); break;
            }
            expr = trigMatcher.replaceFirst(String.format("%.4f", value));
            trigMatcher = trigPattern.matcher(expr);
        }

        // 匹配并计算平方，例如 5^2
        Pattern squarePattern = Pattern.compile("(\\d+)\\^2");
        Matcher squareMatcher = squarePattern.matcher(expr);
        while (squareMatcher.find()) {
            double base = Double.parseDouble(squareMatcher.group(1));
            expr = squareMatcher.replaceFirst(String.valueOf(base * base));
            squareMatcher = squarePattern.matcher(expr);
        }

        // 匹配并计算开方，例如 √(16)
        Pattern sqrtPattern = Pattern.compile("√\\((\\d+)\\)");
        Matcher sqrtMatcher = sqrtPattern.matcher(expr);
        while (sqrtMatcher.find()) {
            double num = Double.parseDouble(sqrtMatcher.group(1));
            expr = sqrtMatcher.replaceFirst(String.valueOf(Math.sqrt(num)));
            sqrtMatcher = sqrtPattern.matcher(expr);
        }

        return expr;
    }


    private static double calculateStandardExpression(String expression) {
        Stack<Double> values = new Stack<>();
        Stack<Character> ops = new Stack<>();
        char[] tokens = expression.toCharArray();

        for (int i = 0; i < tokens.length; i++) {
            if (tokens[i] == ' ') continue;

            if ((tokens[i] >= '0' && tokens[i] <= '9') || tokens[i] == '.') {
                StringBuilder sbuf = new StringBuilder();
                while (i < tokens.length && ((tokens[i] >= '0' && tokens[i] <= '9') || tokens[i] == '.')) {
                    sbuf.append(tokens[i++]);
                }
                i--;
                values.push(Double.parseDouble(sbuf.toString()));
            } else if (tokens[i] == '(') {
                ops.push(tokens[i]);
            } else if (tokens[i] == ')') {
                while (ops.peek() != '(') {
                    values.push(applyOp(ops.pop(), values.pop(), values.pop()));
                }
                ops.pop();
            } else if (isOperator(tokens[i])) {
                while (!ops.empty() && hasPrecedence(tokens[i], ops.peek())) {
                    values.push(applyOp(ops.pop(), values.pop(), values.pop()));
                }
                ops.push(tokens[i]);
            }
        }

        while (!ops.empty()) {
            values.push(applyOp(ops.pop(), values.pop(), values.pop()));
        }

        return values.pop();
    }

    private static boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

    private static boolean hasPrecedence(char op1, char op2) {
        if (op2 == '(' || op2 == ')') return false;
        return (op1 != '*' && op1 != '/') || (op2 != '+' && op2 != '-');
    }

    private static double applyOp(char op, double b, double a) {
        switch (op) {
            case '+': return a + b;
            case '-': return a - b;
            case '*': return a * b;
            case '/':
                if (b == 0) throw new UnsupportedOperationException("不能除以零");
                return a / b;
        }
        return 0;
    }
}