"""
Mock tools for the Medical Research Assistant Agent.
These tools simulate real API calls without requiring external services.
"""

from typing import Dict, List
import time
import random
import ast
import operator


class MockPubMedSearch:
    """Mock PubMed search tool - returns predefined research papers"""

    def __init__(self):
        self.mock_database = {
            "diabetes type 2 cardiovascular": [
                {
                    "title": "SGLT2 Inhibitors and Cardiovascular Outcomes in Type 2 Diabetes",
                    "authors": "Smith J, et al.",
                    "year": 2024,
                    "summary": "SGLT2 inhibitors show significant reduction in cardiovascular events in T2D patients with CVD history.",
                },
                {
                    "title": "GLP-1 Receptor Agonists for Heart Failure in Diabetes",
                    "authors": "Johnson M, et al.",
                    "year": 2024,
                    "summary": "GLP-1 agonists demonstrate benefits in reducing heart failure hospitalizations in diabetic patients.",
                },
            ],
            "hypertension treatment": [
                {
                    "title": "ACE Inhibitors vs ARBs in Hypertension Management",
                    "authors": "Brown A, et al.",
                    "year": 2024,
                    "summary": "Comparative effectiveness study shows similar outcomes with patient-specific considerations.",
                }
            ],
            "default": [
                {
                    "title": "Recent Advances in Healthcare AI",
                    "authors": "Davis R, et al.",
                    "year": 2024,
                    "summary": "Overview of AI applications in clinical decision support and diagnostics.",
                }
            ],
        }

    def search(self, query: str) -> List[Dict]:
        """Simulate PubMed search with latency"""
        # Simulate network latency
        time.sleep(random.uniform(0.5, 1.5))

        # Find relevant papers
        query_lower = query.lower()
        for keywords, papers in self.mock_database.items():
            if all(word in query_lower for word in keywords.split()):
                return papers

        return self.mock_database["default"]


class MockDrugDatabase:
    """Mock drug interaction database"""

    def __init__(self):
        self.drug_database = {
            "sglt2_inhibitors": {
                "class": "SGLT2 Inhibitors",
                "examples": ["Empagliflozin", "Dapagliflozin", "Canagliflozin"],
                "contraindications": ["Severe renal impairment (eGFR <30)", "DKA risk"],
                "interactions": [
                    "Diuretics (increased dehydration risk)",
                    "Insulin (hypoglycemia risk)",
                ],
                "cardiovascular_benefits": True,
            },
            "glp1_agonists": {
                "class": "GLP-1 Receptor Agonists",
                "examples": ["Semaglutide", "Liraglutide", "Dulaglutide"],
                "contraindications": ["Personal/family history of MTC", "MEN 2"],
                "interactions": ["Insulin (dose adjustment needed)"],
                "cardiovascular_benefits": True,
            },
            "ace_inhibitors": {
                "class": "ACE Inhibitors",
                "examples": ["Lisinopril", "Enalapril", "Ramipril"],
                "contraindications": ["Pregnancy", "Angioedema history", "Bilateral RAS"],
                "interactions": ["NSAIDs (reduced effect)", "Potassium supplements (hyperkalemia)"],
                "cardiovascular_benefits": True,
            },
        }

    def query(self, drug_class: str) -> Dict:
        """Query drug database for specific class"""
        # Simulate database query latency
        time.sleep(random.uniform(0.3, 0.8))

        drug_class_key = drug_class.lower().replace(" ", "_").replace("-", "_")
        return self.drug_database.get(
            drug_class_key,
            {
                "class": drug_class,
                "examples": ["No data available"],
                "contraindications": ["Consult full prescribing information"],
                "interactions": ["Consult drug interaction database"],
                "cardiovascular_benefits": False,
            },
        )


class MockCalculator:
    """Simple calculator for basic computations

    NOTE: This is intentionally simplified for demonstration purposes.
    Production code should use a proper expression parser library.

    Security: Includes recursion depth limit to prevent stack overflow attacks
    from deeply nested expressions like "(((((...)))))"
    """

    # Allowed operators for safe evaluation
    _SAFE_OPERATORS = {
        ast.Add: operator.add,
        ast.Sub: operator.sub,
        ast.Mult: operator.mul,
        ast.Div: operator.truediv,
        ast.USub: operator.neg,
    }

    # Maximum recursion depth to prevent stack overflow
    _MAX_DEPTH = 50

    @staticmethod
    def _safe_eval(node, depth=0):
        """Safely evaluate AST node with restricted operations

        Args:
            node: AST node to evaluate
            depth: Current recursion depth (used to prevent stack overflow)

        Raises:
            ValueError: If expression is too complex (depth > 50)
        """
        # Prevent stack overflow from deeply nested expressions
        if depth > MockCalculator._MAX_DEPTH:
            raise ValueError(
                f"Expression too complex (max depth {MockCalculator._MAX_DEPTH}). "
                "Simplify the expression."
            )

        if isinstance(node, ast.Constant):  # Numbers (ast.Num deprecated in 3.14)
            return node.value
        elif isinstance(node, ast.BinOp):  # Binary operations
            op_type = type(node.op)
            if op_type not in MockCalculator._SAFE_OPERATORS:
                raise ValueError(f"Unsupported operation: {op_type.__name__}")
            left = MockCalculator._safe_eval(node.left, depth + 1)
            right = MockCalculator._safe_eval(node.right, depth + 1)
            return MockCalculator._SAFE_OPERATORS[op_type](left, right)
        elif isinstance(node, ast.UnaryOp):  # Unary operations
            op_type = type(node.op)
            if op_type not in MockCalculator._SAFE_OPERATORS:
                raise ValueError(f"Unsupported operation: {op_type.__name__}")
            operand = MockCalculator._safe_eval(node.operand, depth + 1)
            return MockCalculator._SAFE_OPERATORS[op_type](operand)
        else:
            raise ValueError(f"Unsupported expression type: {type(node).__name__}")

    @staticmethod
    def calculate(expression: str) -> float:
        """Safely evaluate simple mathematical expressions using AST parsing

        Supports: +, -, *, /, and parentheses with numeric literals only.
        Does NOT use eval() to prevent code injection attacks.
        """
        # Simulate computation time
        time.sleep(0.1)

        try:
            # Parse expression into AST
            tree = ast.parse(expression, mode="eval")
            # Evaluate safely with restricted operations
            result = MockCalculator._safe_eval(tree.body)
            return float(result)
        except Exception as e:
            return f"Error: {str(e)}"
