"""Performance analyzer for Hephaestus."""

from __future__ import annotations

import re
from pathlib import Path
from typing import Any, Dict, List

from ..dependencies.container import FileSystem, ProjectManager
from ..models.project_context import PerformanceIssue


class PerformanceAnalyzer:
    """Analyze code performance and identify optimization opportunities."""

    def __init__(self, file_system: FileSystem, project_manager: ProjectManager):
        self.file_system = file_system
        self.project_manager = project_manager

    def analyze_project_performance(self, project_path: Path) -> Dict[str, Any]:
        """Analyze overall project performance."""
        all_files = self.project_manager.get_project_files(project_path, "**/*.py")

        performance_metrics = {
            "complexity_metrics": self._analyze_complexity(all_files),
            "memory_usage": self._analyze_memory_usage(all_files),
            "database_operations": self._analyze_database_operations(all_files),
            "ui_performance": self._analyze_ui_performance(all_files),
            "network_operations": self._analyze_network_operations(all_files),
            "performance_issues": [],
            "optimization_opportunities": [],
        }

        # Identify performance issues
        issues = self._identify_performance_issues(all_files, performance_metrics)
        performance_metrics["performance_issues"] = issues

        # Generate optimization recommendations
        recommendations = self._generate_optimization_recommendations(
            performance_metrics
        )
        performance_metrics["optimization_opportunities"] = recommendations

        return performance_metrics

    def analyze_function_performance(
        self, file_path: Path, function_content: str
    ) -> List[PerformanceIssue]:
        """Analyze individual function performance."""
        issues = []

        # Check for common performance anti-patterns
        if self._has_nested_loops(function_content):
            issues.append(
                PerformanceIssue(
                    issue_type="nested_loops",
                    severity="medium",
                    file_path=str(file_path),
                    line_number=self._find_line_number(function_content, "for"),
                    description="Nested loops detected - potential O(n²) complexity",
                    recommendation="Consider restructuring to reduce nesting or use more efficient algorithms",
                )
            )

        if self._has_inefficient_string_operations(function_content):
            issues.append(
                PerformanceIssue(
                    issue_type="inefficient_string_ops",
                    severity="low",
                    file_path=str(file_path),
                    line_number=self._find_line_number(function_content, "+"),
                    description="Inefficient string concatenation in loop",
                    recommendation="Use f-strings or join() for better performance",
                )
            )

        if self._has_large_data_processing(function_content):
            issues.append(
                PerformanceIssue(
                    issue_type="large_data_processing",
                    severity="high",
                    file_path=str(file_path),
                    line_number=self._find_line_number(function_content, "app_tables"),
                    description="Large data table operations without pagination",
                    recommendation="Implement pagination or data filtering for large datasets",
                )
            )

        return issues

    def calculate_performance_score(self, performance_metrics: Dict[str, Any]) -> float:
        """Calculate overall performance score."""
        score = 100.0

        # Deduct points for performance issues
        issues = performance_metrics.get("performance_issues", [])
        for issue in issues:
            if issue.severity == "critical":
                score -= 20
            elif issue.severity == "high":
                score -= 15
            elif issue.severity == "medium":
                score -= 10
            elif issue.severity == "low":
                score -= 5

        return max(score, 0.0)

    def _analyze_complexity(self, files: List[Path]) -> Dict[str, Any]:
        """Analyze code complexity metrics."""
        total_lines = 0
        total_functions = 0
        max_complexity = 0
        total_complexity = 0

        for file_path in files:
            content = self.file_system.read_text(file_path)
            lines = content.split("\n")
            total_lines += len(lines)

            # Count functions and estimate complexity
            functions = re.findall(r"def\s+\w+\([^)]*\):", content)
            total_functions += len(functions)

            for func in functions:
                # Simple complexity estimation based on control structures
                func_complexity = 1  # Base complexity
                func_complexity += content.count("if ") + content.count("elif ")
                func_complexity += content.count("for ") + content.count("while ")
                func_complexity += content.count("try:")
                max_complexity = max(max_complexity, func_complexity)
                total_complexity += func_complexity

        return {
            "total_lines": total_lines,
            "total_functions": total_functions,
            "average_function_length": total_lines / max(total_functions, 1),
            "max_complexity": max_complexity,
            "average_complexity": total_complexity / max(total_functions, 1),
        }

    def _analyze_memory_usage(self, files: List[Path]) -> Dict[str, Any]:
        """Analyze potential memory usage patterns."""
        memory_issues = {
            "potential_leaks": [],
            "large_allocations": [],
            "inefficient_patterns": [],
        }

        for file_path in files:
            content = self.file_system.read_text(file_path)

            # Check for potential memory leaks
            if re.search(r"global\s+\w+", content):
                memory_issues["potential_leaks"].append(str(file_path))

            # Check for large data structures
            if re.search(r"\w+\s*=\s*\[\s*\]", content):
                lines_with_large_lists = [
                    i + 1
                    for i, line in enumerate(content.split("\n"))
                    if "[]" in line and len(line) > 100
                ]
                if lines_with_large_lists:
                    memory_issues["large_allocations"].append(
                        {"file": str(file_path), "lines": lines_with_large_lists}
                    )

        return memory_issues

    def _analyze_database_operations(self, files: List[Path]) -> Dict[str, Any]:
        """Analyze database operation patterns."""
        db_patterns = {
            "unoptimized_queries": [],
            "missing_indexes": [],
            "large_result_sets": [],
        }

        for file_path in files:
            content = self.file_system.read_text(file_path)

            # Check for unoptimized queries
            if re.search(r"app_tables\.\w+\.search\([^)]*\)", content):
                db_patterns["unoptimized_queries"].append(str(file_path))

            # Check for large result sets without limits
            if re.search(r"\.search\([^)]*limit[^)]*\)", content) is None:
                if re.search(r"app_tables\.\w+\.search\(", content):
                    db_patterns["large_result_sets"].append(str(file_path))

        return db_patterns

    def _analyze_ui_performance(self, files: List[Path]) -> Dict[str, Any]:
        """Analyze UI performance patterns."""
        ui_patterns = {
            "inefficient_updates": [],
            "excessive_rendering": [],
            "missing_optimizations": [],
        }

        for file_path in files:
            content = self.file_system.read_text(file_path)

            # Check for inefficient UI updates
            if re.search(r"self\..*_refresh\(\)", content):
                ui_patterns["inefficient_updates"].append(str(file_path))

            # Check for missing data binding optimizations
            if "TextBox" in content and "data_bindings" not in content:
                ui_patterns["missing_optimizations"].append(
                    {"file": str(file_path), "issue": "missing_data_bindings"}
                )

        return ui_patterns

    def _analyze_network_operations(self, files: List[Path]) -> Dict[str, Any]:
        """Analyze network operation patterns."""
        network_patterns = {
            "unsecured_calls": [],
            "missing_error_handling": [],
            "synchronous_operations": [],
        }

        for file_path in files:
            content = self.file_system.read_text(file_path)

            # Check for unsecured network calls
            if re.search(r"anvil\.server\.call", content):
                if "try:" not in content:
                    network_patterns["missing_error_handling"].append(str(file_path))

            # Check for synchronous operations that could be async
            if re.search(r"anvil\.server\.call.*timeout", content) is None:
                if re.search(r"anvil\.server\.call", content):
                    network_patterns["synchronous_operations"].append(str(file_path))

        return network_patterns

    def _identify_performance_issues(
        self, files: List[Path], metrics: Dict[str, Any]
    ) -> List[PerformanceIssue]:
        """Identify specific performance issues."""
        issues = []

        # Analyze complexity issues
        complexity = metrics.get("complexity_metrics", {})
        if complexity.get("max_complexity", 0) > 10:
            issues.append(
                PerformanceIssue(
                    issue_type="high_complexity",
                    severity="high",
                    file_path="multiple",
                    line_number=0,
                    description=f"High complexity detected: {complexity.get('max_complexity')}",
                    recommendation="Consider breaking down complex functions into smaller ones",
                )
            )

        # Analyze memory issues
        memory = metrics.get("memory_usage", {})
        if memory.get("potential_leaks"):
            issues.append(
                PerformanceIssue(
                    issue_type="memory_leaks",
                    severity="medium",
                    file_path="multiple",
                    line_number=0,
                    description="Potential memory leaks from global variables",
                    recommendation="Review global variable usage and implement proper cleanup",
                )
            )

        return issues

    def _generate_optimization_recommendations(
        self, metrics: Dict[str, Any]
    ) -> List[str]:
        """Generate optimization recommendations."""
        recommendations = []

        # Database optimizations
        db_ops = metrics.get("database_operations", {})
        if db_ops.get("unoptimized_queries"):
            recommendations.append("Add database indexes and optimize query patterns")

        if db_ops.get("large_result_sets"):
            recommendations.append("Implement pagination for large data sets")

        # UI optimizations
        ui_perf = metrics.get("ui_performance", {})
        if ui_perf.get("inefficient_updates"):
            recommendations.append("Use data bindings instead of manual UI updates")

        if ui_perf.get("missing_optimizations"):
            recommendations.append(
                "Implement reactive data binding for better performance"
            )

        # Network optimizations
        network_ops = metrics.get("network_operations", {})
        if network_ops.get("missing_error_handling"):
            recommendations.append("Add proper error handling for network operations")

        if network_ops.get("synchronous_operations"):
            recommendations.append(
                "Consider asynchronous operations for better responsiveness"
            )

        return recommendations

    def _has_nested_loops(self, content: str) -> bool:
        """Check for nested loops."""
        lines = content.split("\n")
        for i, line in enumerate(lines):
            if "for " in line:
                # Check next few lines for another loop
                for j in range(i + 1, min(i + 5, len(lines))):
                    if "for " in lines[j]:
                        return True
        return False

    def _has_inefficient_string_operations(self, content: str) -> bool:
        """Check for inefficient string operations."""
        return bool(re.search(r"for\s+\w+\s+in\s+\w+:\s*\w+\s*\+=\s*\w+", content))

    def _has_large_data_processing(self, content: str) -> bool:
        """Check for large data processing patterns."""
        return (
            "app_tables." in content
            and "limit" not in content
            and content.count(".search(") > 2
        )

    def _find_line_number(self, content: str, pattern: str) -> int:
        """Find line number of pattern in content."""
        lines = content.split("\n")
        for i, line in enumerate(lines, 1):
            if pattern in line:
                return i
        return 0
