"""Migrating existing AST-based rules to Ruff-based implementations.

This module shows how to gradually replace existing rules with Ruff equivalents
while maintaining backward compatibility.
"""

from pathlib import Path
from typing import Dict, List, Type

from prefact.config import Config
from prefact.models import Issue
from prefact.rules import BaseRule, get_all_rules


class RuleMigrationManager:
    """Manages migration from AST-based rules to Ruff-based rules."""
    
    # Mapping of old rule IDs to new Ruff-based rule class names
    # (using strings to avoid circular imports)
    MIGRATION_MAP: Dict[str, str] = {
        "unused-imports": "RuffUnusedImports",
        "duplicate-imports": "RuffDuplicateImports",
        "wildcard-imports": "RuffWildcardImports",
        "sorted-imports": "RuffSortedImports",
        "print-statements": "RuffPrintStatements",
    }
    
    # Rules that should remain AST-based (Ruff doesn't handle them well)
    KEEP_AST_RULES = {
        "relative-imports",  # Requires package context
        "string-concat",     # Complex transformation
        "missing-return-type",  # Type checking needed
    }
    
    def __init__(self, config: Config) -> None:
        self.config = config
        self._migrated_rules: Dict[str, Type[BaseRule]] = {}
        
    def get_migrated_rule(self, rule_id: str) -> Type[BaseRule]:
        """Get the Ruff-based rule if available, otherwise return None."""
        if rule_id in self.MIGRATION_MAP:
            if rule_id not in self._migrated_rules:
                # Lazy import to avoid circular dependency
                from prefact.rules.ruff_based import (
                    RuffDuplicateImports,
                    RuffPrintStatements,
                    RuffSortedImports,
                    RuffUnusedImports,
                    RuffWildcardImports,
                )
                
                rule_classes = {
                    "RuffUnusedImports": RuffUnusedImports,
                    "RuffDuplicateImports": RuffDuplicateImports,
                    "RuffWildcardImports": RuffWildcardImports,
                    "RuffSortedImports": RuffSortedImports,
                    "RuffPrintStatements": RuffPrintStatements,
                }
                
                class_name = self.MIGRATION_MAP[rule_id]
                self._migrated_rules[rule_id] = rule_classes[class_name]
            return self._migrated_rules[rule_id]
        return None
    
    def should_use_ruff(self, rule_id: str) -> bool:
        """Check if a rule should use Ruff implementation."""
        return (
            rule_id in self.MIGRATION_MAP and 
            rule_id not in self.KEEP_AST_RULES and
            self.config.get_rule_option(rule_id, "use_ruff", True)
        )
    
    def create_hybrid_rule(self, rule_id: str) -> Type[BaseRule]:
        """Create a hybrid rule that can switch between AST and Ruff."""
        if rule_id not in self.MIGRATION_MAP:
            return get_all_rules().get(rule_id)
        
        class HybridRule(BaseRule):
            rule_id = rule_id
            description = f"Hybrid implementation for {rule_id}"
            
            def __init__(self, config: Config) -> None:
                super().__init__(config)
                self.migration_manager = RuleMigrationManager(config)
                self.ast_rule = get_all_rules().get(rule_id)(config)
                self.ruff_rule = self.MIGRATION_MAP[rule_id](config)
                
            def scan_file(self, path: Path, source: str) -> List[Issue]:
                if self.migration_manager.should_use_ruff(rule_id):
                    return self.ruff_rule.scan_file(path, source)
                return self.ast_rule.scan_file(path, source)
                
            def fix(self, path: Path, source: str, issues: List[Issue]) -> tuple[str, List]:
                if self.migration_manager.should_use_ruff(rule_id):
                    return self.ruff_rule.fix(path, source, issues)
                return self.ast_rule.fix(path, source, issues)
                
            def validate(self, path: Path, original: str, fixed: str):
                if self.migration_manager.should_use_ruff(rule_id):
                    return self.ruff_rule.validate(path, original, fixed)
                return self.ast_rule.validate(path, original, fixed)
        
        return HybridRule


# Example: Enhanced scanner with Ruff integration
class HybridScanner:
    """Scanner that can use both AST and Ruff-based rules."""
    
    def __init__(self, config: Config) -> None:
        self.config = config
        self.migration_manager = RuleMigrationManager(config)
        self.rules = self._load_rules()
        
    def _load_rules(self) -> Dict[str, BaseRule]:
        """Load rules, preferring Ruff implementations where available."""
        rules = {}
        all_rule_classes = get_all_rules()
        
        for rule_id, rule_class in all_rule_classes.items():
            if self.migration_manager.should_use_ruff(rule_id):
                # Use Ruff-based rule
                ruff_rule = self.migration_manager.get_migrated_rule(rule_id)
                if ruff_rule:
                    rules[rule_id] = ruff_rule(self.config)
                    continue
            
            # Use original AST-based rule
            if rule_id not in RuleMigrationManager.KEEP_AST_RULES:
                rules[rule_id] = rule_class(self.config)
        
        return rules
    
    def scan_file(self, path: Path, source: str) -> List[Issue]:
        """Scan a file using appropriate rules."""
        all_issues = []
        
        for rule_id, rule in self.rules.items():
            if self.config.is_rule_enabled(rule_id):
                issues = rule.scan_file(path, source)
                all_issues.extend(issues)
        
        return all_issues


# Performance comparison utilities
class PerformanceProfiler:
    """Compare performance between AST and Ruff implementations."""
    
    @staticmethod
    def profile_rule(rule: BaseRule, file_path: Path, source: str) -> Dict:
        """Profile a single rule execution."""
        import time
        
        start_time = time.perf_counter()
        issues = rule.scan_file(file_path, source)
        end_time = time.perf_counter()
        
        return {
            "rule_id": rule.rule_id,
            "issues_found": len(issues),
            "time_ms": (end_time - start_time) * 1000,
            "implementation": rule.__class__.__module__
        }
    
    @staticmethod
    def compare_implementations(
        file_path: Path, 
        source: str,
        config: Config
    ) -> Dict[str, Dict]:
        """Compare AST vs Ruff implementations for applicable rules."""
        results = {}
        migration_manager = RuleMigrationManager(config)
        
        for rule_id in migration_manager.MIGRATION_MAP:
            # Get AST implementation
            ast_rule_class = get_all_rules().get(rule_id)
            if not ast_rule_class:
                continue
                
            # Get Ruff implementation
            ruff_rule_class = migration_manager.get_migrated_rule(rule_id)
            if not ruff_rule_class:
                continue
            
            # Profile both
            ast_rule = ast_rule_class(config)
            ruff_rule = ruff_rule_class(config)
            
            results[rule_id] = {
                "ast": PerformanceProfiler.profile_rule(ast_rule, file_path, source),
                "ruff": PerformanceProfiler.profile_rule(ruff_rule, file_path, source)
            }
            
            # Calculate speedup
            ast_time = results[rule_id]["ast"]["time_ms"]
            ruff_time = results[rule_id]["ruff"]["time_ms"]
            if ruff_time > 0:
                results[rule_id]["speedup"] = ast_time / ruff_time
        
        return results


# Configuration for enabling Ruff-based rules
def add_ruff_config_to_prefact_yaml(config_path: Path) -> None:
    """Add Ruff-specific configuration to prefact.yaml."""
    import yaml
    
    with open(config_path) as f:
        config = yaml.safe_load(f) or {}
    
    # Add Ruff settings
    if "ruff" not in config:
        config["ruff"] = {
            "enabled": True,
            "rules": {
                "unused-imports": {"use_ruff": True},
                "wildcard-imports": {"use_ruff": True},
                "print-statements": {"use_ruff": True},
                "sorted-imports": {"use_ruff": True},
                "duplicate-imports": {"use_ruff": True},
            },
            "ignore_patterns": ["cli.py", "scripts/"]  # For print statements
        }
    
    with open(config_path, "w") as f:
        yaml.dump(config, f, default_flow_style=False)
