"""
Ferramenta de cálculos matemáticos
"""
import re
import math
import ast
from typing import Union, Optional


class CalculatorTool:
    """
    Ferramenta segura para cálculos matemáticos
    Prevents code injection by using AST parsing
    """

    ALLOWED_NAMES = {
        'sqrt': math.sqrt,
        'pow': math.pow,
        'abs': abs,
        'round': round,
        'max': max,
        'min': min,
        'sum': sum,
        'len': len,
        'pi': math.pi,
        'e': math.e,
        'sin': math.sin,
        'cos': math.cos,
        'tan': math.tan,
        'log': math.log,
        'log10': math.log10,
        'ceil': math.ceil,
        'floor': math.floor,
        'random': __import__('random').random,
    }

    def calculate(self, expression: str) -> Union[float, int, str]:
        """
        Evaluates a mathematical expression safely
        """
        if not expression or not expression.strip():
            return "Expressão vazia"

        # Remove any dangerous characters
        cleaned = self._sanitize_expression(expression)

        try:
            result = self._safe_eval(cleaned)
            return result
        except Exception as e:
            return f"Erro no cálculo: {str(e)}"

    def _sanitize_expression(self, expression: str) -> str:
        """Sanitize the expression string"""
        # Remove letters that aren't part of allowed functions
        # This is a basic sanitizer - for production, use a proper parser

        # Replace common symbols
        replacements = {
            '×': '*',
            '÷': '/',
            '²': '**2',
            '³': '**3',
            'π': 'pi',
            '√': 'sqrt',
        }

        for old, new in replacements.items():
            expression = expression.replace(old, new)

        return expression.strip()

    def _safe_eval(self, expression: str):
        """Safely evaluate mathematical expression using AST"""
        try:
            tree = ast.parse(expression, mode='eval')
        except SyntaxError:
            raise ValueError("Expressão inválida")

        self._validate_ast(tree)

        compiled = compile(tree, filename="<ast>", mode="eval")
        return eval(compiled, {"__builtins__": {}}, self.ALLOWED_NAMES)

    def _validate_ast(self, node):
        """Validate AST nodes are safe"""
        if isinstance(node, ast.Expression):
            self._validate_ast(node.body)
        elif isinstance(node, ast.BinOp):
            self._validate_ast(node.left)
            self._validate_ast(node.right)
        elif isinstance(node, ast.UnaryOp):
            self._validate_ast(node.operand)
        elif isinstance(node, ast.Call):
            self._validate_ast(node.func)
            for arg in node.args:
                self._validate_ast(arg)
        elif isinstance(node, ast.Name):
            if node.id not in self.ALLOWED_NAMES:
                raise ValueError(f"Função não permitida: {node.id}")
        elif isinstance(node, ast.Constant):
            pass
        elif isinstance(node, ast.Subscript):
            self._validate_ast(node.value)
            self._validate_ast(node.slice)
        elif isinstance(node, ast.Slice):
            if node.lower: self._validate_ast(node.lower)
            if node.upper: self._validate_ast(node.upper)
            if node.step: self._validate_ast(node.step)
        elif isinstance(node, ast.Name):
            pass
        else:
            raise ValueError(f"Tipo de nó não permitido: {type(node).__name__")

    def format_result(self, result) -> str:
        """Format result for display"""
        if isinstance(result, float):
            if result.is_integer():
                return str(int(result))
            return f"{result:.6f}".rstrip('0').rstrip('.')
        return str(result)