"""Pattern matcher for Hephaestus."""

from __future__ import annotations

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

from ..dependencies.container import FileSystem, ProjectManager
from ..models.project_context import PatternMatch
from .pattern_library import PatternLibrary


class PatternMatcher:
    """Advanced pattern matching with confidence scoring."""

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

    def match_patterns_in_file(
        self, file_path: Path, patterns: List[str]
    ) -> List[PatternMatch]:
        """Match patterns in a specific file."""
        matches = []
        content = self.file_system.read_text(file_path)
        lines = content.split("\n")

        for pattern in patterns:
            pattern_matches = self._match_pattern(
                content, lines, pattern, str(file_path)
            )
            matches.extend(pattern_matches)

        return matches

    def match_patterns_in_project(
        self, project_path: Path, patterns: List[str]
    ) -> List[PatternMatch]:
        """Match patterns across entire project."""
        all_matches = []
        all_files = self.project_manager.get_project_files(project_path, "**/*.py")

        for file_path in all_files:
            file_matches = self.match_patterns_in_file(file_path, patterns)
            all_matches.extend(file_matches)

        return all_matches

    def calculate_pattern_confidence(
        self, pattern_match: PatternMatch, file_content: str
    ) -> float:
        """Calculate confidence score for pattern match."""
        base_confidence = 0.5

        # Increase confidence based on match specificity
        if pattern_match.pattern_name in pattern_match.context:
            base_confidence += 0.2

        # Increase confidence based on pattern complexity
        if self._is_complex_pattern(pattern_match.pattern_name):
            base_confidence += 0.1

        # Increase confidence based on file context
        if self._is_relevant_context(pattern_match, file_content):
            base_confidence += 0.2

        return min(base_confidence, 1.0)

    def find_pattern_relationships(
        self, matches: List[PatternMatch]
    ) -> Dict[str, List[str]]:
        """Find relationships between detected patterns."""
        relationships = {}

        # Group matches by file
        file_matches = {}
        for match in matches:
            if match.file_path not in file_matches:
                file_matches[match.file_path] = []
            file_matches[match.file_path].append(match)

        # Analyze relationships within files
        for file_path, file_matches in file_matches.items():
            file_relationships = self._analyze_file_relationships(file_matches)
            for relationship in file_relationships:
                if relationship not in relationships:
                    relationships[relationship] = []
                relationships[relationship].append(file_path)

        return relationships

    def validate_pattern_consistency(self, matches: List[PatternMatch]) -> List[str]:
        """Validate consistency of detected patterns."""
        inconsistencies = []

        # Check for conflicting patterns
        pattern_conflicts = self._find_pattern_conflicts(matches)
        inconsistencies.extend(pattern_conflicts)

        # Check for incomplete patterns
        incomplete_patterns = self._find_incomplete_patterns(matches)
        inconsistencies.extend(incomplete_patterns)

        return inconsistencies

    def _match_pattern(
        self, content: str, lines: List[str], pattern: str, file_path: str
    ) -> List[PatternMatch]:
        """Match a specific pattern in content."""
        matches = []

        # Search for pattern indicators
        pattern_def = self.pattern_library.get_pattern("material_3", pattern)
        if pattern_def:
            matches.extend(
                self._match_pattern_definition(
                    content, lines, pattern, pattern_def, file_path
                )
            )

        pattern_def = self.pattern_library.get_pattern("classic", pattern)
        if pattern_def:
            matches.extend(
                self._match_pattern_definition(
                    content, lines, pattern, pattern_def, file_path
                )
            )

        pattern_def = self.pattern_library.get_pattern("reactive", pattern)
        if pattern_def:
            matches.extend(
                self._match_pattern_definition(
                    content, lines, pattern, pattern_def, file_path
                )
            )

        return matches

    def _match_pattern_definition(
        self,
        content: str,
        lines: List[str],
        pattern: str,
        pattern_def: Dict[str, Any],
        file_path: str,
    ) -> List[PatternMatch]:
        """Match specific pattern definition."""
        matches = []

        indicators = pattern_def.get("indicators", [])

        for indicator in indicators:
            for line_num, line in enumerate(lines, 1):
                if indicator in line:
                    context_start = max(0, line_num - 2)
                    context_end = min(len(lines), line_num + 2)
                    context = "\n".join(lines[context_start:context_end])

                    match = PatternMatch(
                        pattern_type=pattern,
                        pattern_name=pattern,
                        file_path=file_path,
                        line_number=line_num,
                        confidence=0.7,
                        context=context,
                    )
                    matches.append(match)

        return matches

    def _is_complex_pattern(self, pattern_name: str) -> bool:
        """Check if pattern is complex."""
        complex_patterns = [
            "NavigationDrawerLayout",
            "NavigationRailLayout",
            "@reactive_class",
            "@render_effect",
            "@anvil.server.model_class",
        ]
        return pattern_name in complex_patterns

    def _is_relevant_context(self, match: PatternMatch, content: str) -> bool:
        """Check if pattern match is in relevant context."""
        # Check if match is in function/class definition
        context_lines = match.context.split("\n")
        for line in context_lines:
            if any(keyword in line for keyword in ["class ", "def ", "@"]):
                return True
        return False

    def _analyze_file_relationships(
        self, file_matches: List[PatternMatch]
    ) -> List[str]:
        """Analyze relationships between patterns in a file."""
        relationships = []
        pattern_types = [match.pattern_type for match in file_matches]

        # Check for complementary patterns
        if "material_3" in pattern_types and "reactive" in pattern_types:
            relationships.append("material_3_with_reactive")

        if "routing" in pattern_types and "model_classes" in pattern_types:
            relationships.append("routing_with_models")

        if (
            "data_operations" in pattern_types
            and "validation_patterns" in pattern_types
        ):
            relationships.append("data_with_validation")

        return relationships

    def _find_pattern_conflicts(self, matches: List[PatternMatch]) -> List[str]:
        """Find conflicting patterns."""
        conflicts = []

        # Group matches by type
        type_matches = {}
        for match in matches:
            if match.pattern_type not in type_matches:
                type_matches[match.pattern_type] = []
            type_matches[match.pattern_type].append(match)

        # Check for conflicts
        if "material_3" in type_matches and "classic" in type_matches:
            conflicts.append("material_3_and_classic_mix")

        if "reactive" in type_matches and "global_state" in type_matches:
            conflicts.append("reactive_and_global_state")

        return conflicts

    def _find_incomplete_patterns(self, matches: List[PatternMatch]) -> List[str]:
        """Find incomplete or partial patterns."""
        incomplete = []

        # Check for patterns without required components
        for match in matches:
            if match.pattern_type == "material_3":
                if not self._has_required_material_3_components(
                    matches, match.file_path
                ):
                    incomplete.append(f"incomplete_material_3_in_{match.file_path}")

            elif match.pattern_type == "routing":
                if not self._has_complete_routing_setup(matches, match.file_path):
                    incomplete.append(f"incomplete_routing_in_{match.file_path}")

        return incomplete

    def _has_required_material_3_components(
        self, matches: List[PatternMatch], file_path: str
    ) -> bool:
        """Check if Material 3 pattern has required components."""
        file_matches = [m for m in matches if m.file_path == file_path]
        material_3_matches = [m for m in file_matches if m.pattern_type == "material_3"]

        # Check for layout components
        has_layout = any("Layout" in m.pattern_name for m in material_3_matches)

        # Check for theme components
        has_theme = any("role" in m.context for m in material_3_matches)

        return has_layout and has_theme

    def _has_complete_routing_setup(
        self, matches: List[PatternMatch], file_path: str
    ) -> bool:
        """Check if routing setup is complete."""
        file_matches = [m for m in matches if m.file_path == file_path]
        routing_matches = [m for m in file_matches if m.pattern_type == "routing"]

        # Check for route definitions
        has_routes = any("route" in m.pattern_name for m in routing_matches)

        # Check for navigation setup
        has_navigation = any("nav" in m.pattern_name for m in routing_matches)

        return has_routes and has_navigation
