"""Main side-effect classifier."""

import ast
import textwrap
from typing import List, Optional, Tuple

from guardrail.classifier.constants import (
    DB_LIBS,
    FILE_IO_MODULES,
    NETWORK_LIBS,
    SYSTEM_CALLS,
)
from guardrail.classifier.visitors import ImportCollector, SideEffectVisitor


class SideEffectClassifier:
    """Classifies functions as having side effects or being pure-ish."""

    def __init__(self):
        """Initialize the classifier."""
        pass

    def classify_function(
        self, function_source: str, file_imports: Optional[List[str]] = None
    ) -> Tuple[bool, str]:
        """
        Classify a function as having side effects or being pure-ish.

        Args:
            function_source: Source code of the function.
            file_imports: Optional list of import statements from the file.

        Returns:
            Tuple of (has_side_effects: bool, reason: str)
        """
        try:
            dedented_source = textwrap.dedent(function_source)
            tree = ast.parse(dedented_source)
        except SyntaxError:
            return True, "Unable to parse function source"

        visitor = SideEffectVisitor(self._is_side_effect_module)
        visitor.visit(tree)

        if visitor.has_side_effects:
            return True, visitor.reason

        return False, "Pure-ish function (no side effects detected)"

    def _is_side_effect_module(self, module: str) -> bool:
        """Check if a module is known to have side effects."""
        module_lower = module.lower()

        # Check network libraries
        for lib in NETWORK_LIBS:
            if module_lower == lib or module_lower.startswith(f"{lib}."):
                return True

        # Check database libraries
        for lib in DB_LIBS:
            if module_lower == lib or module_lower.startswith(f"{lib}."):
                return True

        # Check file I/O modules
        if module_lower in FILE_IO_MODULES:
            return True

        # Check system call modules
        for lib in SYSTEM_CALLS:
            if module_lower == lib or module_lower.startswith(f"{lib}."):
                return True

        return False

