"""
算式解析器
负责将字符串表达式解析为Formula对象
"""

from typing import List, Tuple
import re
import math
from .base_types import Formula, FormulaElement, ElementType


class FormulaParser:
    """算式解析器"""
    
    @staticmethod
    def parse(expression: str) -> Formula:
        """解析表达式字符串为Formula对象"""
        # 清理表达式
        expression = expression.replace(' ', '').replace('x', '*').replace('X', '*')
        
        # 识别算式类型
        formula_type = FormulaParser._detect_formula_type(expression)
        
        # 分词
        elements = FormulaParser._tokenize(expression)
        
        # 清理无效小数点
        cleaned_elements = FormulaParser._clean_invalid_decimals(elements)
        
        # 智能缩放处理
        scaled_elements, scale_factors = FormulaParser._apply_smart_scaling(cleaned_elements, formula_type)
        
        return Formula(type=formula_type, elements=scaled_elements, scale_factors=scale_factors)
    
    @staticmethod
    def _clean_invalid_decimals(elements: List[FormulaElement]) -> List[FormulaElement]:
        """清理无效的小数点，如106.0→106, 45.0→45"""
        cleaned_elements = []
        
        for elem in elements:
            if elem.type == ElementType.NUMBER and '.' in elem.value:
                try:
                    num_value = float(elem.value)
                    # 检查是否为整数值的小数表示
                    if num_value.is_integer():
                        # 转换为整数字符串
                        cleaned_value = str(int(num_value))
                        print(f"🔍 清理无效小数点：{elem.value} → {cleaned_value}")
                        cleaned_elements.append(FormulaElement(ElementType.NUMBER, cleaned_value))
                    else:
                        # 保留真正的小数
                        cleaned_elements.append(elem)
                except ValueError:
                    # 如果无法转换，保持原样
                    cleaned_elements.append(elem)
            else:
                cleaned_elements.append(elem)
        
        return cleaned_elements
    
    @staticmethod
    def _apply_smart_scaling(elements: List[FormulaElement], formula_type: str) -> Tuple[List[FormulaElement], List[float]]:
        """应用智能缩放策略"""
        # 提取数字
        numbers = [elem for elem in elements if elem.type == ElementType.NUMBER]
        if len(numbers) != 2:
            return elements, [1.0, 1.0]
        
        num1_str = numbers[0].value
        num2_str = numbers[1].value
        
        try:
            num1 = float(num1_str)
            num2 = float(num2_str)
        except:
            return elements, [1.0, 1.0]
        
        # 根据运算类型选择缩放策略
        if formula_type in ["addition", "subtraction"]:
            ## 加减法不适合缩放
            ## return FormulaParser._scale_for_addition_subtraction(elements, num1, num2)
            return elements, [1.0, 1.0]
        elif formula_type == "multiplication":
            return FormulaParser._scale_for_multiplication(elements, num1, num2)
        elif formula_type == "division":
            return FormulaParser._scale_for_division(elements, num1, num2)
        else:
            return elements, [1.0, 1.0]
    
    @staticmethod
    def _scale_for_addition_subtraction(elements: List[FormulaElement], num1: float, num2: float) -> Tuple[List[FormulaElement], List[float]]:
        """加减法的缩放策略：分别处理两个数的小数和整零数"""
        scale1 = FormulaParser._calculate_number_scale_factor(num1)
        scale2 = FormulaParser._calculate_number_scale_factor(num2)
        
        # 应用缩放
        scaled_num1 = num1 * scale1
        scaled_num2 = num2 * scale2
        
        # 更新元素
        new_elements = []
        num_index = 0
        for elem in elements:
            if elem.type == ElementType.NUMBER:
                if num_index == 0:
                    new_elements.append(FormulaElement(ElementType.NUMBER, str(int(scaled_num1))))
                else:
                    new_elements.append(FormulaElement(ElementType.NUMBER, str(int(scaled_num2))))
                num_index += 1
            else:
                new_elements.append(elem)
        
        print(f"🔍 加减法缩放：{num1}→{scaled_num1}(×{scale1}), {num2}→{scaled_num2}(×{scale2})")
        return new_elements, [scale1, scale2]
    
    @staticmethod
    def _scale_for_multiplication(elements: List[FormulaElement], num1: float, num2: float) -> Tuple[List[FormulaElement], List[float]]:
        """乘法的缩放策略：累计缩放，只记录第一个数的缩放因子"""
        scale1 = FormulaParser._calculate_number_scale_factor(num1)
        scale2 = FormulaParser._calculate_number_scale_factor(num2)
        
        # 乘法时累计缩放效应
        total_scale_effect = scale1 * scale2
        
        # 应用缩放
        scaled_num1 = num1 * scale1
        scaled_num2 = num2 * scale2

        # 更新元素
        new_elements = []
        num_index = 0
        for elem in elements:
            if elem.type == ElementType.NUMBER:
                if num_index == 0:
                    new_elements.append(FormulaElement(ElementType.NUMBER, str(int(scaled_num1))))
                else:
                    new_elements.append(FormulaElement(ElementType.NUMBER, str(int(scaled_num2))))
                num_index += 1
            else:
                new_elements.append(elem)
        
        print(f"🔍 乘法缩放：{num1}→{scaled_num1}(×{scale1}), {num2}→{scaled_num2}(×{scale2}), 总缩放效应：{total_scale_effect}")
        return new_elements, [total_scale_effect, 1.0]
    
    @staticmethod
    def _scale_for_division(elements: List[FormulaElement], num1: float, num2: float) -> Tuple[List[FormulaElement], List[float]]:
        """除法的缩放策略：根据计算结果特征确定缩放因子"""
        scale1 = FormulaParser._calculate_number_scale_factor(num1)
        scale2 = FormulaParser._calculate_number_scale_factor(num2)
        
        # 检查是否需要缩放
        if scale1 == 1.0 and scale2 == 1.0:
            # 没有缩放需求
            return elements, [1.0, 1.0]
        
        # 应用缩放到操作数
        scaled_num1 = num1 * scale1
        scaled_num2 = num2 * scale2
        
        # 计算原始结果
        if num2 != 0:
            original_result = num1 / num2
        else:
            original_result = 0
        
        # 计算缩放后的结果
        if scaled_num2 != 0:
            scaled_result = scaled_num1 / scaled_num2
        else:
            scaled_result = 0
        
        # 分析缩放策略
        # 对于除法，我们希望简化计算，所以优先考虑能够约分的情况
        final_scale1, final_scale2 = scale1, scale2
        result_scale_factor = 1.0
        
        # 特殊处理：如果都是整零数，尝试约分
        if scale1 < 1.0 and scale2 < 1.0:
            # 两个都是整零数，可能可以约分
            # 例如：40÷8 -> 4÷8 不如 40÷8 直接计算
            # 重新考虑是否应该缩放
            gcd_zeros = min(abs(int(1/scale1)), abs(int(1/scale2))) if scale1 != 0 and scale2 != 0 else 1
            if gcd_zeros > 1:
                # 可以约分，保持较小的缩放
                common_scale = 1.0 / gcd_zeros
                final_scale1 = max(scale1, common_scale)
                final_scale2 = max(scale2, common_scale)
                scaled_num1 = num1 * final_scale1
                scaled_num2 = num2 * final_scale2

        # 重新计算缩放后结果
        if scaled_num2 != 0:
            new_scaled_result = scaled_num1 / scaled_num2
        else:
            new_scaled_result = 0
        
        # 计算最终的缩放因子
        if original_result != 0 and new_scaled_result != 0:
            result_scale_factor = original_result / new_scaled_result
            if result_scale_factor < 1.0:
                # 保留最大精确度 0.001
                result_scale_factor = round(result_scale_factor, 3)
        else:
            result_scale_factor = 1.0
        
        # 更新元素
        new_elements = []
        num_index = 0
        for elem in elements:
            if elem.type == ElementType.NUMBER:
                if num_index == 0:
                    new_elements.append(FormulaElement(ElementType.NUMBER, str(int(scaled_num1))))
                else:
                    new_elements.append(FormulaElement(ElementType.NUMBER, str(int(scaled_num2))))
                num_index += 1
            else:
                new_elements.append(elem)
        
        print(f"🔍 除法缩放详情：")
        print(f"  - 原始：{num1} ÷ {num2} = {original_result}")
        print(f"  - 缩放：{scaled_num1} ÷ {scaled_num2} = {new_scaled_result}")
        print(f"  - 缩放因子：{final_scale1}, {final_scale2}")
        print(f"  - 结果缩放因子：{result_scale_factor}")
        
        return new_elements, [result_scale_factor, 1.0]
    
    @staticmethod
    def _calculate_number_scale_factor(num: float) -> float:
        """计算单个数字的缩放因子"""
        # 处理小数（排除整数值的小数表示，因为已经在前面清理过了）
        if '.' in str(num) and not num.is_integer():
            decimal_places = len(str(num).split('.')[1])
            return 10 ** decimal_places
        
        # 处理整零数（整十、整百、整千等）
        if isinstance(num, float):
            num = int(num)
        
        if num == 0:
            return 1.0
        
        # 计算末尾零的个数
        num_str = str(abs(num))
        zero_count = 0
        for char in reversed(num_str):
            if char == '0':
                zero_count += 1
            else:
                break
        
        # 如果有末尾零且非零部分简单，则缩小
        if zero_count > 0:
            non_zero_part = abs(num) // (10 ** zero_count)
            if 1 <= non_zero_part <= 9:  # 单位数
                return round(0.1 ** zero_count, 5)
        
        return 1.0
    
    @staticmethod
    def _detect_formula_type(expression: str) -> str:
        """检测算式类型"""
        if '+' in expression and '-' not in expression:
            return "addition"
        elif '-' in expression and '+' not in expression:
            return "subtraction"
        elif '*' in expression or '×' in expression:
            return "multiplication"
        elif '÷' in expression:
            return "division"
        elif '/' in expression:
            return "fraction"  # 保留"/"作为分数符号
        elif any(op in expression for op in ['==', '>', '<', '>=', '<=']):
            return "comparison"
        elif '+' in expression and '-' in expression:
            return "mixed_addition_subtraction"
        else:
            return "unknown"
    
    @staticmethod
    def _tokenize(expression: str) -> List[FormulaElement]:
        """分词解析"""
        elements = []
        current_token = ""
        
        i = 0
        while i < len(expression):
            char = expression[i]
            
            if char.isdigit() or char == '.':
                current_token += char
            elif char == '/':
                # 检查是否是分数
                if current_token and i + 1 < len(expression) and expression[i + 1].isdigit():
                    current_token += char
                else:
                    if current_token:
                        elements.append(FormulaElement(ElementType.NUMBER, current_token))
                        current_token = ""
                    elements.append(FormulaElement(ElementType.OPERATOR, char))
            elif char in '+-*×÷':
                if current_token:
                    elements.append(FormulaElement(ElementType.NUMBER, current_token))
                    current_token = ""
                elements.append(FormulaElement(ElementType.OPERATOR, char))
            elif char in '()':
                if current_token:
                    elements.append(FormulaElement(ElementType.NUMBER, current_token))
                    current_token = ""
                elements.append(FormulaElement(ElementType.BRACKET, char))
            elif char in '=<>':
                if current_token:
                    elements.append(FormulaElement(ElementType.NUMBER, current_token))
                    current_token = ""
                # 处理复合比较运算符
                if i + 1 < len(expression) and expression[i + 1] == '=':
                    elements.append(FormulaElement(ElementType.OPERATOR, char + '='))
                    i += 1
                else:
                    elements.append(FormulaElement(ElementType.OPERATOR, char))
            
            i += 1
        
        if current_token:
            elements.append(FormulaElement(ElementType.NUMBER, current_token))
        
        return elements