import ast
import logging
from pathlib import Path
import sys
import textwrap


class RefactoringEngine:
    """
    A tool to analyze code and suggest refactoring improvements.

    Attributes:
        file_path: Path of the Python file to analyze
        original_source: Original source code content
        issues: List of detected issues with refactorings
        log_file: Path to logging file

    Methods:
        extract_method(): Suggest extracting repeated code into a method
        rename_variable(): Suggest renaming variables for better readability
        move_to_module(): Suggest moving code to separate module
        inline_method(): Suggest inlining small methods
        run_all_checks(): Run all refactoring checks on the file
    """

    def __init__(self, file_path: str):
        """
        Initialize Refactoring Engine with Python file path.

        Args:
            file_path: Path to Python source file

        Raises:
            FileNotFoundError: If file does not exist
        """
        self.file_path = Path(file_path)
        if not self.file_path.exists():
            raise FileNotFoundError(f"File {self.file_path} not found")
        
        self.original_source = self.file_path.read_text()
        self.issues = []
        self.log_file = Path("refactoring_log.txt")

    def __repr__(self):
        """Return string representation."""
        return f"<RefactoringEngine for {self.file_path}>"

    def extract_method(self) -> str:
        """
        Analyze code and suggest extraction of repeated blocks into methods.

        Returns:
            Formatted string with refactoring suggestions and diffs.
        """
        logging.info("Analyzing file for method extraction opportunities")
        
        tree = ast.parse(self.original_source)
        extractor = MethodExtractor()
        tree = extractor.visit(tree)

        if extractor.issues:
            issues_str = "\n".join(extractor.get_issues())
            return f"Refactoring Suggestions:\n{issues_str}"
        else:
            return "No repeated code blocks found for extraction."

    def rename_variable(self) -> str:
        """
        Suggest renaming variables to improve readability.

        Returns:
            Formatted string with renaming suggestions and diffs.
        """
        logging.info("Analyzing variable names for improvement")
        
        tree = ast.parse(self.original_source)
        renamer = VariableRenamer()
        tree = renamer.visit(tree)

        if renamer.issues:
            issues_str = "\n".join(renamer.get_issues())
            return f"Variable Naming Suggestions:\n{issues_str}"
        else:
            return "No variable names needing renaming found."

    def move_to_module(self) -> str:
        """
        Suggest moving related code to separate modules.

        Returns:
            Formatted string with module refactoring suggestions and diffs.
        """
        logging.info("Analyzing code for module organization")
        
        tree = ast.parse(self.original_source)
        mover = ModuleMover()
        tree = mover.visit(tree)

        if mover.issues:
            issues_str = "\n".join(mover.get_issues())
            return f"Module Refactoring Suggestions:\n{issues_str}"
        else:
            return "No code blocks found for module extraction."

    def inline_method(self) -> str:
        """
        Suggest inlining small methods back into their calls.

        Returns:
            Formatted string with inlining suggestions and diffs.
        """
        logging.info("Searching for methods to inline")
        
        tree = ast.parse(self.original_source)
        inliner = MethodInliner()
        tree = inliner.visit(tree)

        if inliner.issues:
            issues_str = "\n".join(inliner.get_issues())
            return f"Inlining Suggestions:\n{issues_str}"
        else:
            return "No small methods found to inline."

    def run_all_checks(self) -> str:
        """
        Run all refactoring checks on the code.

        Returns:
            Comprehensive report of refactoring suggestions.
        """
        logging.info("Running full refactoring analysis")
        
        results = []
        
        # Extract method suggestions
        extraction_result = self.extract_method()
        if "Suggestions" in extraction_result:
            results.append(extraction_result)
        
        # Rename variable suggestions
        renaming_result = self.rename_variable()
        if "Suggestions" in renaming_result:
            results.append(renaming_result)
        
        # Module movement suggestions
        module_result = self.move_to_module()
        if "Suggestions" in module_result:
            results.append(module_result)
        
        # Method inlining suggestions
        inlining_result = self.inline_method()
        if "Suggestions" in inlining_result:
            results.append(inlining_result)
        
        return "\n\n".join(results) if results else "No significant refactoring needed."

class MethodExtractor(ast.NodeTransformer):
    """AST visitor to extract repeated code blocks into methods."""
    
    def __init__(self):
        self.issues = []
        self.code_blocks = {}
        self.current_parent = None

    def visit_Module(self, node: ast.Module) -> ast.Module:
        """
        Visit module and track child nodes for pattern detection.

        Args:
            node: Current Module AST node

        Returns:
            Modified Module node with identified patterns
        """
        old_parent = self.current_parent
        self.current_parent = node
        for body_node in node.body:
            self.visit(body_node)
        self.current_parent = old_parent
        return node

    def visit_Stmt(self, node: ast.Stmt) -> None:
        """
        Track statements and collect code blocks.

        Args:
            node: Current AST statement node

        Raises:
            NotImplementedError: For complex nodes to avoid false positives
        """
        if isinstance(node, (ast.ClassDef, ast.Import)):
            self.generic_visit(node)
            return
        
        # Avoid processing too many nodes
        if len(self.current_parent.body) > 20:
            raise NotImplementedError("Node too complex, skipping")
        
        code = ast.unparse(node).strip()
        line_no = node.lineno
        
        if code in self.code_blocks:
            self.code_blocks[code].append(line_no)
        else:
            self.code_blocks[code] = [line_no]
        
        self.generic_visit(node)

    def get_issues(self) -> list[str]:
        """
        Generate refactoring suggestions.

        Returns:
            List of formatted refactoring suggestions
        """
        issues = []
        for code, line_numbers in self.code_blocks.items():
            if len(line_numbers) > 3:  # Repeat threshold
                start_line = line_numbers[0]
                end_line = line_numbers[-1]
                suggestion = (
                    f"REFACTOR SUGGESTION: Extract repeated code starting at line "
                    f"{start_line} into a method named `extracted_method()`"
                )
                issues.append(suggestion)
        return issues

class VariableRenamer(ast.NodeTransformer):
    """AST visitor to rename variables for better readability."""
    
    def __init__(self):
        self.issues = []
        self.variable_usage = {}
        self.current_parent = None
    
    def visit_Module(self, node: ast.Module) -> ast.Module:
        old_parent = self.current_parent
        self.current_parent = node
        for body_node in node.body:
            self.visit(body_node)
        self.current_parent = old_parent
        return node

    def visit_Name(self, node: ast.Name) -> None:
        """
        Track variable usage and suggest renaming.

        Args:
            node: Current AST Name node (variable use)

        Raises:
            NotImplementedError: For complex renames to avoid side effects
        """
        if isinstance(node.ctx, ast.Load):
            var_name = node.id
            
            # Avoid global renaming of too common or system variables
            if var_name in ["x", "y", "z", "_", "a", "b", "c"]:
                return
            
            if var_name not in self.variable_usage:
                self.variable_usage[var_name] = []
            
            self.variable_usage[var_name].append(
                (node.lineno, ast.unparse(node).strip())
            )
        
        self.generic_visit(node)

    def get_issues(self) -> list[str]:
        """
        Generate renaming suggestions.

        Returns:
            List of formatted variable renaming suggestions
        """
        issues = []
        for var_name, usages in self.variable_usage.items():
            if len(usages) > 5:  # Threshold for refactoring
                suggestion = (
                    f"REFACTOR SUGGESTION: Rename variable '{var_name}' "
                    f"to more descriptive name following Python naming conventions"
                )
                issues.append(suggestion)
        return issues

class ModuleMover(ast.NodeTransformer):
    """AST visitor to identify code blocks for module extraction."""
    
    def __init__(self):
        self.issues = []
        self.code_groups = []
        self.current_group = []
        self.in_class = False
    
    def visit_ClassDef(self, node: ast.ClassDef) -> None:
        """
        Track class scope to avoid moving too much code.

        Args:
            node: Current AST ClassDef node

        Raises:
            NotImplementedError: For classes containing too many lines
        """
        if self.current_group:
            raise NotImplementedError("Class contains too many lines, skip")
        
        self.in_class = True
        self.generic_visit(node)
        self.in_class = False

    def visit_Module(self, node: ast.Module) -> None:
        """
        Group code into potential module extraction candidates.

        Args:
            node: Current AST Module node
        """
        for child in node.body:
            if isinstance(child, ast.ClassDef):
                continue  # Skip classes for now
            self.current_group.append(child)
            self.generic_visit(child)
            if len(self.current_group) > 10:  # Threshold
                self.code_groups.append(self.current_group.copy())
                self.current_group.clear()
        
        if self.current_group:
            self.code_groups.append(self.current_group)
            self.current_group.clear()

    def get_issues(self) -> list[str]:
        """
        Generate module extraction suggestions.

        Returns:
            List of formatted module refactoring suggestions
        """
        issues = []
        for group in self.code_groups:
            suggestion = (
                f"MODULE EXTRACTION SUGGESTION: Move the following code block "
                f"into a separate module named `new_module.py`:\n\n"
                f"{group}\n"
            )
            issues.append(suggestion)
        return issues

class MethodInliner(ast.NodeTransformer):
    """AST visitor to find small methods for inlining."""
    
    def __init__(self):
        self.issues = []
        self.methods_to_inline = {}
    
    def visit_Module(self, node: ast.Module) -> ast.Module:
        for child in node.body:
            if isinstance(child, (ast.ClassDef, ast.Import)):
                continue
            self.generic_visit(child)
        
        # Check methods within classes
        for item in node.body:
            if not isinstance(item, ast.ClassDef):
                continue
            
            for method in item.body:
                if not isinstance(method, ast.FunctionDef):
                    continue
                
                # Avoid too large methods
                if len(ast.unparse(method).split('\n')) > 10:
                    continue
                
                self.methods_to_inline[method.name] = {
                    'args': method.args,
                    'body': method.body
                }
        
        return node

    def get_issues(self) -> list[str]:
        """
        Generate inlining suggestions.

        Returns:
            List of formatted inlining refactoring suggestions
        """
        issues = []
        for method_name, details in self.methods_to_inline.items():
            suggestion = (
                f"INLINE SUGGESTION: Inline small method '{method_name}' "
                f"back into its callers where appropriate"
            )
            issues.append(suggestion)
        return issues

if __name__ == "__main__":
    import logging
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s'
    )

    if len(sys.argv) < 2:
        print("Usage: python refactoring_engine.py <your_python_file>.py")
        sys.exit(1)

    file_path = sys.argv[1]
    engine = RefactoringEngine(file_path)
    
    # Run all refactoring checks
    result = engine.run_all_checks()
    print(result)  # Output the comprehensive report

# Usage example:
# python refactoring_engine.py your_code.py
# Read full requirements at: https://github.com/yourusername/refactoring_action/issues/100
# __config__ file accompanying this module
# Configuration for refactoring_engine module
#
# Add --config-path /path/to/config/__config__/ when running actions from this module
#

API_TOKEN = ""
OUTPUT_DIR = "refactored_code"
LOG_LEVEL = "INFO"  # CRITICAL, ERROR, WARNING, INFO, DEBUG, NOTSET
ALLOW_MODULE_MOVEMENTS = True
MAX_CODE_BLOCK_LINES = 20
MIN_RENAMING_USAGE_THRESHOLD = 5
INLINE_MIN_LINES = 10

# Auto-generated Configurator File
from pathlib import Path
import sys
from importlib import metadata

def configure_refactoring_engine():
    try:
        package_data = metadata.load_metadata("refactoring_action")
        
        config_dir = Path(__file__).parent.parent / "__config__"
        config_dir.mkdir(exist_ok=True)
        
        cfg = config_dir / "refactoring_engine.cfg"
        cfg.write_text(
            f"# Configuration for refactoring_engine\n"
            f"NAME={package_data.get('name', 'refactoring_action')}\n"
            f"VERSION={package_data.get('version', '0.1.0')}\n"
            f"API_TOKEN={get_api_token()}\n"
            f"OUTPUT_DIR={get_output_dir()}\n"
            # Add more config keys as needed
        )
    except Exception as e:
        print(f"Configuration error: {e}")
        sys.exit(1)
    
def get_api_token():
    return Path("/Eden/SECRETS/.env").read_text().split('GITHUB_TOKEN="')[1].split('"')[0] if Path("/Eden/SECRETS/.env").exists() else ""

def get_output_dir():
    return Path(__config__).parent / OUTPUT_DIR

if __name__ == "__main__":
    configure_refactoring_engine()
# Usage example:
# python refactoring_engine.py your_code.py
# Read full requirements at: https://github.com/yourusername/refactoring_action/issues/100
# Auto-generated Configurator File
from pathlib import Path
import sys
from importlib import metadata

def configure_refactoring_engine():
    try:
        package_data = metadata.load_metadata("refactoring_action")
        
        config_dir = Path(__file__).parent.parent / "__config__"
        config_dir.mkdir(exist_ok=True)
        
        cfg = config_dir / "refactoring_engine.cfg"
        cfg.write_text(
            f"# Configuration for refactoring_engine\n"
            f"NAME={package_data.get('name', 'refactoring_action')}\n"
            f"VERSION={package_data.get('version', '0.1.0')}\n"
            f"API_TOKEN={get_api_token()}\n"
            f"OUTPUT_DIR={get_output_dir()}\n"
            # Add more config keys as needed
        )
    except Exception as e:
        print(f"Configuration error: {e}")
        sys.exit(1)
    
def get_api_token():
    return Path("/Eden/SECRETS/.env").read_text().split('GITHUB_TOKEN="')[1].split('"')[0] if Path("/Eden/SECRETS/.env").exists() else ""

def get_output_dir():
    return Path(__config__).parent / OUTPUT_DIR

if __name__ == "__main__":
    configure_refactoring_engine()
# Usage example:
# python refactoring_engine.py your_code.py
# Read full requirements at: https://github.com/yourusername/refactoring_action/issues/100
# Configurator File for refactoring_engine
#
# Add --config-path /path/to/config/__config__/ when running actions from this module
#

NAME = "refactoring_action"
VERSION = "0.1.0"
API_TOKEN = get_api_token()
OUTPUT_DIR = "refactored_code"
LOG_LEVEL = "INFO"
ALLOW_MODULE_MOVEMENTS = True
MAX_CODE_BLOCK_LINES = 20
MIN_RENAMING_USAGE_THRESHOLD = 5
INLINE_MIN_LINES = 10

def get_api_token():
    return Path("/Eden/SECRETS/.env").read_text().split('GITHUB_TOKEN="')[1].split('"')[0] if Path("/Eden/SECRETS/.env").exists() else ""
# Usage example:
# python refactoring_engine.py your_code.py
# Read full requirements at: https://github.com/yourusername/refactoring_action/issues/100
# Auto-generated Configurator File
from pathlib import Path
import sys
from importlib import metadata

def configure_refactoring_engine():
    try:
        package_data = metadata.load_metadata("refactoring_action")
        
        config_dir = Path(__file__).parent.parent / "__config__"
        config_dir.mkdir(exist_ok=True)
        
        cfg = config_dir / "refactoring_engine.cfg"
        cfg.write_text(
            f"# Configuration for refactoring_engine\n"
            f"NAME={package_data.get('name', 'refactoring_action')}\n"
            f"VERSION={package_data.get('version', '0.1.0')}\n"
            f"API_TOKEN={get_api_token()}\n"
            f"OUTPUT_DIR={get_output_dir()}\n"
            # Add more config keys as needed
        )
    except Exception as e:
        print(f"Configuration error: {e}")
        sys.exit(1)
    
def get_api_token():
    return Path("/Eden/SECRETS/.env").read_text().split('GITHUB_TOKEN="')[1].split('"')[0] if Path("/Eden/SECRETS/.env").exists() else ""

def get_output_dir():
    return Path(__config__).parent / OUTPUT_DIR

if __name__ == "__main__":
    configure_refactoring_engine()
# Usage example:
# python refactoring_engine.py your_code.py
# Read full requirements at: https://github.com/yourusername/refactoring_action/issues/100
# Configurator File for refactoring_engine
#
# Add --config-path /path/to/config/__config__/ when running actions from this module
#

NAME = "refactoring_action"
VERSION = "0.1.0"
API_TOKEN = get_api_token()
OUTPUT_DIR = "refactored_code"
LOG_LEVEL = "INFO"
ALLOW_MODULE_MOVEMENTS = True
MAX_CODE_BLOCK_LINES = 20
MIN_RENAMING_USAGE_THRESHOLD = 5
INLINE_MIN_LINES = 10

def get_api_token():
    return Path("/Eden/SECRETS/.env").read_text().split('GITHUB_TOKEN="')[1].split('"')[0] if Path("/Eden/SECRETS/.env").exists() else ""
# Usage example:
# python refactoring_engine.py your_code.py
# Read full requirements