package com.ads.cal.calculator.utils;

import android.util.Log;

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

public class CalculatorUtils {

    public static String replaceAllString(String s) {
        if (null != s) {
            s = s.replaceAll("×", "*");
            s = s.replaceAll("÷", "/");
            s = s.replaceAll("√", "sqrt");
        }

        return s;

//        我有一个数学表达式的字符串 他是不正确的
//        5+6×(√7÷(3-2+cos(9+sin(10-1
//                请帮我写一个方法把他变成正确的表达式 要符合EvalEx库的标准
    }

    public static String fixMathExpression(String input) {
        // 移除不必要的空格
        input = input.replaceAll("\\s+", "");

        // 替换特殊符号
        input = input.replace("×", "*"); // 替换乘号
        input = input.replace("÷", "/"); // 替换除号
        input = input.replaceAll("√(\\d+)", "sqrt($1)");
        input = input.replaceAll("(\\d)%", "($1*0.01)");
        input = input.replaceAll("π", "3.1415926");

        // 添加缺失的函数括号
        input = input.replaceAll("(sin|cos|tan|sqrt)([^\\(])", "$1($2)");
        // 添加缺失的乘法操作符
        input = input.replaceAll("(\\d)([a-zA-Z\\(])", "$1*$2");
        input = input.replaceAll("([\\)a-zA-Z])(\\d)", "$1*$2");
        // 在)和cos之间添加乘号
        input = input.replaceAll("\\)(sin|cos|tan|sqrt)", ")*$1");

        // 修复不正确的括号
        int openParenthesesCount = input.length() - input.replace("(", "").length();
        int closeParenthesesCount = input.length() - input.replace(")", "").length();
        int missingParentheses = openParenthesesCount - closeParenthesesCount;
        for (int i = 0; i < missingParentheses; i++) {
            input += ")";
        }
        // 补全不规范的数学表达式
        input = input.replaceAll("([0-9\\)])\\(", "$1*(");
        input = input.replaceAll("\\)([0-9\\(])", ")*$1");

        return input;
    }


    enum Operator {
        ADD('+'),
        SUB('-'),
        MUL('×'),
        DIV('÷'),
        POW('^'),
        PERCENT('%'),
        SQRT('√');

        private final char symbol;

        Operator(char symbol) {
            this.symbol = symbol;
        }

        public char getSymbol() {
            return symbol;
        }
    }

    private static final Map<Operator, Integer> OPERATOR_PRECEDENCE = Map.of(
            Operator.ADD, 1,
            Operator.SUB, 1,
            Operator.MUL, 2,
            Operator.DIV, 2,
            Operator.POW, 3,
            Operator.SQRT, 3,
            Operator.PERCENT, 3
    );

    public static String evaluateExpression(String expression) {
        if (null == expression || expression.length() == 0) {
            return "0";
        }
        expression = expression.replaceAll("\\s", ""); // 移除空白字符
        char[] tokens = expression.toCharArray();

        Stack<Double> values = new Stack<>();
        Stack<Operator> operators = new Stack<>();
        for (int i = tokens.length - 1; i >= 0; i--) {
            if (Character.isDigit(tokens[i])) {
                StringBuilder sb = new StringBuilder();
                while (i >= 0 && i < tokens.length && (Character.isDigit(tokens[i]) || tokens[i] == '.')) {
                    sb.append(tokens[i]);
                    i--;
                }
                values.push(Double.parseDouble(sb.reverse().toString()));
                i++;
            } else if (tokens[i] == '(') {
                operators.push(Operator.ADD); // 添加一个虚拟的+操作符，以处理负数表达式
                operators.push(Operator.SUB); // 添加一个虚拟的-操作符，以处理负数表达式
            } else if (tokens[i] == ')') {
                if (!operators.isEmpty()) {
                    Operator topOperator = operators.peek();
                    if (null != topOperator) {
                        while (topOperator != Operator.ADD && topOperator != Operator.SUB) {
                            Double operand1 = null;
                            Double operand2 = null;
                            if (!values.isEmpty()) {
                                operand1 = values.pop();
                            }
                            if (!values.isEmpty()) {
                                operand2 = values.pop();
                            }
                            if (!operators.isEmpty()) {
                                topOperator = operators.pop();
                            }
                            if (topOperator != null && operand2 != null && operand1 != null) {
                                values.push(applyOperator(topOperator, operand1, operand2));
                            }
                        }
                        if (!operators.isEmpty()) {
                            operators.pop(); // 弹出虚拟的+操作符
                        }
                        if (!operators.isEmpty()) {
                            operators.pop(); // 弹出虚拟的-操作符
                        }
                    }
                }
            } else if (isOperator(tokens[i])) {
                Operator currentOperator = getOperatorBySymbol(tokens[i]);
                Double operand1 = null;
                Double operand2 = null;
                while (!operators.isEmpty() && hasHigherPrecedence(currentOperator, operators.peek())) {
                    Operator topOperator = operators.pop();
                    if (!values.isEmpty()) {
                        operand1 = values.pop();
                        if (isSimpleOperator(topOperator.getSymbol())) {
                            values.push(applyOperator(topOperator, operand1, 0));
                            continue;
                        }
                    }
                    if (!values.isEmpty()) {
                        operand2 = values.pop();
                    }
                    if (operand2 != null && operand1 != null) {
                        values.push(applyOperator(topOperator, operand1, operand2));
                    }
                }
                if (values.isEmpty() && null != operand1) {
                    values.push(operand1);
                }
                operators.push(currentOperator);
            }
        }
        if (operators.isEmpty()) {
            return "";
        }

        String result = "";
        // 计算并返回最终结果
        while (!operators.isEmpty()) {
            Operator ch1 = operators.pop();
            Double operand1 = null, operand2 = null;
            if (!values.isEmpty()) {
                operand1 = values.pop();
                result = String.valueOf(operand1);
            }
            if (isSimpleOperator(ch1.symbol) && null != operand1) {
                values.push(applyOperator(ch1, operand1, 0));
                continue;
            }
            if (!values.isEmpty()) {
                operand2 = values.pop();
            }
            if (null != operand1 && null != operand2) {
                values.push(applyOperator(ch1, operand1, operand2));
            }
        }

        if (!values.isEmpty()) {
            return String.valueOf(values.pop());
        } else {
            return result;
        }
    }

    public static boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '×' || c == '÷' || c == '^' || c == '√' || c == '%';
    }

    private static boolean isSimpleOperator(char c) {
        return c == '%' || c == '√';
    }

    private static Operator getOperatorBySymbol(char symbol) {
        for (Operator op : Operator.values()) {
            if (op.getSymbol() == symbol) {
                return op;
            }
        }
        throw new IllegalArgumentException("Invalid operator: " + symbol);
    }

    private static boolean hasHigherPrecedence(Operator op1, Operator op2) {
        return OPERATOR_PRECEDENCE.get(op2) > OPERATOR_PRECEDENCE.get(op1);
    }

    private static double applyOperator(Operator operator, double operand1, double operand2) {
        switch (operator) {
            case ADD:
                return operand1 + operand2;
            case SUB:
                return operand1 - operand2;
            case MUL:
                return operand1 * operand2;
            case DIV:
                if (operand2 == 0) {
                    return Double.NaN;
                }
                return operand1 / operand2;
            case POW:
                return Math.pow(operand1, operand2);
            case SQRT:
                return Math.sqrt(operand2);
            case PERCENT:
                return operand1 / 100;
            default:
                throw new IllegalArgumentException("Invalid operator: " + operator);
        }
    }
}
