import re
from collections import OrderedDict


class ExpressionCalculator:
    def __init__(self):
        self.expression = None
        self.tokens = None
        self.variables = None
        self.ast = None
        self.last_error = None

    def _tokenize(self, expr):
        """将表达式字符串分解为标记列表"""
        token_spec = [
            ("NUMBER", r"\d+(\.\d*)?"),  # 整数或小数
            ("VARIABLE", r"@?[a-zA-Z_\u4e00-\u9fa5][\w.@\u4e00-\u9fa5]+"),  # 支持带点的复合变量
            ("OPERATOR", r"[+\-*/()]"),  # 运算符
            ("SKIP", r"\s+"),  # 跳过空格
            ("MISMATCH", r"."),  # 其他字符
        ]

        tokens = []
        pos = 0
        while pos < len(expr):
            match = None
            for token_name, pattern in token_spec:
                regex = re.compile(pattern)
                match = regex.match(expr, pos)
                if match:
                    value = match.group(0)
                    if token_name == "NUMBER":
                        tokens.append(("NUMBER", float(value)))
                    elif token_name == "VARIABLE":
                        tokens.append(("VARIABLE", value))
                    elif token_name == "OPERATOR":
                        tokens.append(("OPERATOR", value))
                    elif token_name == "SKIP":
                        pass  # 跳过空格
                    else:
                        raise ValueError(f"非法字符: {value}")
                    pos = match.end()
                    break
            if not match:
                raise ValueError(f"无法解析的字符: {expr[pos]}")
        return tokens

    def _extract_variables(self):
        """提取表达式中的所有变量"""
        variables = OrderedDict()
        for token_type, value in self.tokens:
            if token_type == "VARIABLE" and value not in variables:
                variables[value] = None
        return list(variables.keys())

    def parse_expression(self, expression):
        """解析表达式并返回是否成功

        Returns:
            bool: 解析成功返回True，失败返回False
        """

        self.expression = expression
        self.last_error = None
        try:
            self.tokens = self._tokenize(expression)
            self.variables = self._extract_variables()
            self.ast = self._parse_expression()
            return True
        except Exception as e:
            self.last_error = str(e)
            return False

    def get_last_error(self):
        """获取最后发生的错误信息"""
        return self.last_error

    def _parse_expression(self):
        """解析表达式并构建抽象语法树(AST)"""
        self.current_token = 0
        return self._parse_exp()

    def _parse_exp(self):
        """解析加减表达式: exp -> term { ('+'|'-') term }"""
        node = self._parse_term()
        while self.current_token < len(self.tokens):
            token_type, op = self.tokens[self.current_token]
            if token_type == "OPERATOR" and op in ("+", "-"):
                self.current_token += 1
                right = self._parse_term()
                node = ("BINOP", op, node, right)
            else:
                break
        return node

    def _parse_term(self):
        """解析乘除表达式: term -> factor { ('*'|'/') factor }"""
        node = self._parse_factor()
        while self.current_token < len(self.tokens):
            token_type, op = self.tokens[self.current_token]
            if token_type == "OPERATOR" and op in ("*", "/"):
                self.current_token += 1
                right = self._parse_factor()
                node = ("BINOP", op, node, right)
            else:
                break
        return node

    def _parse_factor(self):
        """解析基本因子: factor -> NUMBER | VARIABLE | '(' exp ')' | ('+'|'-') factor"""
        if self.current_token >= len(self.tokens):
            raise ValueError("表达式不完整")

        token_type, value = self.tokens[self.current_token]

        # 处理括号表达式
        if token_type == "OPERATOR" and value == "(":
            self.current_token += 1
            node = self._parse_exp()
            if self.current_token >= len(self.tokens) or self.tokens[self.current_token][1] != ")":
                raise ValueError("缺少右括号")
            self.current_token += 1
            return node

        # 处理一元运算符
        if token_type == "OPERATOR" and value in ("+", "-"):
            self.current_token += 1
            node = self._parse_factor()
            return ("UNARYOP", value, node)

        # 处理变量
        if token_type == "VARIABLE":
            self.current_token += 1
            return ("VARIABLE", value)

        # 处理数字
        if token_type == "NUMBER":
            self.current_token += 1
            return ("NUMBER", value)

        raise ValueError(f"语法错误: {value}")

    def get_last_error(self):
        """获取最后一次解析错误信息
        Returns:
            str: 错误信息，如果没有错误则返回None
        """
        return self.last_error

    def evaluate(self, variables):
        """计算表达式的值

        Returns:
            tuple: (bool, float) - 第一个元素表示计算是否成功，第二个元素是计算结果（失败时为None）
        """
        # 确保表达式已解析
        if self.ast is None:
            self.last_error = "表达式尚未解析"
            return False, None

        # 检查变量是否齐全
        missing = [var for var in self.variables if var not in variables]
        if missing:
            self.last_error = f"缺少变量值: {', '.join(missing)}"
            return False, None

        # 执行计算
        try:
            result = self._evaluate_node(self.ast, variables)
            self.last_error = None
            return True, result
        except Exception as e:
            self.last_error = str(e)
            return False, None

    def _evaluate_node(self, node, variables):
        """递归计算AST节点的值"""
        node_type = node[0]

        if node_type == "NUMBER":
            return node[1]

        if node_type == "VARIABLE":
            return variables[node[1]]

        if node_type == "UNARYOP":
            op, child = node[1], node[2]
            value = self._evaluate_node(child, variables)
            return value if op == "+" else -value

        if node_type == "BINOP":
            _, op, left, right = node
            left_val = self._evaluate_node(left, variables)
            right_val = self._evaluate_node(right, variables)

            if op == "+":
                return left_val + right_val
            if op == "-":
                return left_val - right_val
            if op == "*":
                return left_val * right_val
            if op == "/":
                if right_val == 0:
                    raise ValueError("除数不能为零")
                return left_val / right_val

        raise ValueError("未知节点类型")

    def __str__(self):
        """返回表达式的字符串表示"""
        return self.expression


# 测试代码
if __name__ == "__main__":
    # 示例表达式
    expr_str = "工程量.数量*工程量.人工费*工程量.人工系数*工程量.定额系数"

    # 创建计算器实例
    calculator = ExpressionCalculator()
    parse_success = calculator.parse_expression(expr_str)
    if not parse_success:
        raise ValueError(f"解析表达式失败: {calculator.get_last_error()}")
    success, result = calculator.evaluate()
    if not success:
        raise ValueError(f"计算表达式失败: {calculator.get_last_error()}")

    # 获取变量列表
    variables = calculator.variables
    print("表达式中的变量:", variables)

    # 为变量赋值
    values = {"工程量.数量": 10, "工程量.人工费": 100, "工程量.人工系数": 1.5, "工程量.定额系数": 0.8}

    # 计算结果
    success, result = calculator.evaluate(values)
    if success:
        print(f"计算结果: {result}")
    else:
        print(f"计算失败: {calculator.get_last_error()}")

    # 测试带括号和混合运算的表达式
    complex_expr = "(工程量.数量 + 5) * (工程量.人工费 - 20) / 2"
    complex_calc = ExpressionCalculator()
    parse_success = complex_calc.parse_expression(complex_expr)
    if not parse_success:
        raise ValueError(f"解析复杂表达式失败: {complex_calc.get_last_error()}")
    success, result = complex_calc.evaluate()
    if not success:
        raise ValueError(f"计算复杂表达式失败: {complex_calc.get_last_error()}")
    print("\n复杂表达式:", complex_expr)
    print("变量列表:", complex_calc.variables)

    success, complex_result = complex_calc.evaluate({"工程量.数量": 15, "工程量.人工费": 120})
    if success:
        print(f"计算结果: {complex_result}")
    else:
        print(f"计算失败: {complex_calc.get_last_error()}")
