"""Change detection and function analysis."""

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

import click

from guardrail.changes import ChangeDetector, ChangedFile
from guardrail.classifier import SideEffectClassifier
from guardrail.locator import FunctionInfo, FunctionLocator


def detect_and_analyze_changes(
    root: Path,
) -> Tuple[List[ChangedFile], List[FunctionInfo], List[Tuple[FunctionInfo, str]], Dict]:
    """
    Detect changed files and analyze functions.
    
    Returns:
        Tuple of (changed_files, pure_functions, side_effect_functions, function_to_file)
    """
    click.echo("🔍 Detecting changed files...")
    changed_files = []
    pure_functions = []
    side_effect_functions = []
    function_to_file = {}

    try:
        detector = ChangeDetector(root=root)
        changed_files = detector.get_changed_python_files()

        if changed_files:
            click.echo(f"\n📝 Found {len(changed_files)} changed Python file(s):")
            pure_functions, side_effect_functions, function_to_file = analyze_functions(
                changed_files, root
            )
            print_summary(pure_functions, side_effect_functions)
        else:
            click.echo("✅ No changed Python files detected.")
    except RuntimeError as e:
        click.echo(f"⚠️  Change detection failed: {e}", err=True)
        click.echo("Continuing without change detection...", err=True)
    except Exception as e:
        click.echo(f"⚠️  Unexpected error during change detection: {e}", err=True)
        click.echo("Continuing without change detection...", err=True)

    return changed_files, pure_functions, side_effect_functions, function_to_file


def analyze_functions(
    changed_files: List[ChangedFile], root: Path
) -> Tuple[List[FunctionInfo], List[Tuple[FunctionInfo, str]], Dict]:
    """
    Analyze functions in changed files and classify them.
    
    Returns:
        Tuple of (pure_functions, side_effect_functions, function_to_file)
    """
    click.echo("\n🔎 Analyzing changed functions...")
    classifier = SideEffectClassifier()
    pure_functions = []
    side_effect_functions = []
    function_to_file = {}

    for changed_file in changed_files:
        ranges_str = ", ".join(
            f"{start}-{end}" for start, end in changed_file.changed_ranges
        )
        rel_path = changed_file.path.relative_to(root)
        click.echo(f"\n  📄 {rel_path} (lines: {ranges_str})")

        try:
            locator = FunctionLocator(changed_file.path)
            changed_functions = locator.get_changed_functions(changed_file.changed_ranges)

            if changed_functions:
                file_imports = locator.get_file_imports()
                click.echo(f"    Functions touched: {len(changed_functions)}")

                for func in changed_functions:
                    func_display = (
                        f"{func.parent_class}.{func.name}"
                        if func.is_method
                        else func.name
                    )

                    has_side_effects, reason = classifier.classify_function(
                        func.source, file_imports
                    )

                    if has_side_effects:
                        click.echo(
                            f"      ⚠️  {func_display} (lines {func.lineno}-{func.end_lineno or '?'}) - SKIPPED: {reason}"
                        )
                        side_effect_functions.append((func, reason))
                    else:
                        click.echo(
                            f"      ✅ {func_display} (lines {func.lineno}-{func.end_lineno or '?'}) - Pure-ish"
                        )
                        pure_functions.append(func)
                        function_to_file[func] = changed_file.path

        except SyntaxError as e:
            click.echo(f"    ⚠️  Syntax error in file: {e}", err=True)
        except Exception as e:
            click.echo(f"    ⚠️  Error analyzing file: {e}", err=True)

    return pure_functions, side_effect_functions, function_to_file


def print_summary(
    pure_functions: List[FunctionInfo],
    side_effect_functions: List[Tuple[FunctionInfo, str]],
) -> None:
    """Print summary of function analysis."""
    all_changed_functions = pure_functions + [f for f, _ in side_effect_functions]
    
    if not all_changed_functions:
        return

    click.echo(f"\n📊 Summary:")
    click.echo(f"  • Total functions touched: {len(all_changed_functions)}")
    click.echo(f"  • Pure-ish functions: {len(pure_functions)}")
    click.echo(f"  • Side-effect functions (skipped): {len(side_effect_functions)}")

    if side_effect_functions:
        click.echo(f"\n⚠️  Skipped {len(side_effect_functions)} function(s) with side effects:")
        for func, reason in side_effect_functions:
            func_display = (
                f"{func.parent_class}.{func.name}" if func.is_method else func.name
            )
            click.echo(f"    • {func_display}: {reason}")

