"""Component manager for Anvil form operations."""

from __future__ import annotations

import yaml
from typing import Any

from ..dependencies.container import FileSystem
from ..models.project_context import ProjectContext
from ..validators.component_validator import ComponentValidator


class ComponentManager:
    """Manage components in Anvil forms with intelligent context awareness."""

    def __init__(self, file_system: FileSystem):
        self.file_system: FileSystem = file_system
        self.validator: ComponentValidator = ComponentValidator()

    def add_component_to_form(
        self,
        form_path: str,
        component_type: str,
        position: str,
        properties: dict[str, Any],
        layout_properties: dict[str, Any] | None = None,
        event_bindings: dict[str, str] | None = None,
        data_bindings: list[dict[str, Any]] | None = None,
        project_context: ProjectContext | None = None,
    ) -> tuple[bool, str]:
        """Add a component to an existing form with intelligent positioning."""
        try:
            # Load existing form
            form_config = self._load_form(form_path)
            if not form_config:
                return False, f"Could not load form from {form_path}"

            # Create component configuration
            component = self._create_component_config(
                component_type=component_type,
                position=position,
                properties=properties,
                layout_properties=layout_properties,
                event_bindings=event_bindings,
                data_bindings=data_bindings,
                project_context=project_context,
            )

            # Validate component
            is_valid, errors = self.validator.validate_component(component)
            if not is_valid:
                return False, f"Component validation failed: {'; '.join(errors)}"

            # Add component to form
            form_config["components"].append(component)

            # Validate updated form
            is_valid, errors = self.validator.validate_form_config(form_config)
            if not is_valid:
                return False, f"Form validation failed: {'; '.join(errors)}"

            # Save updated form
            self._save_form(form_path, form_config)
            return (
                True,
                f"Component {component.get('name', component_type)} added successfully",
            )

        except Exception as e:
            return False, f"Error adding component: {str(e)}"

    def update_component_properties(
        self,
        form_path: str,
        component_name: str,
        properties: dict[str, Any],
        project_context: ProjectContext | None = None,
    ) -> tuple[bool, str]:
        """Update properties of an existing component."""
        try:
            # Load existing form
            form_config = self._load_form(form_path)
            if not form_config:
                return False, f"Could not load form from {form_path}"

            # Find component
            component = self._find_component(form_config, component_name)
            if not component:
                return False, f"Component '{component_name}' not found in form"

            # Store original properties for rollback
            original_properties = component.get("properties", {}).copy()

            # Update properties
            component["properties"] = properties

            # Validate updated component
            is_valid, errors = self.validator.validate_component(component)
            if not is_valid:
                # Rollback changes
                component["properties"] = original_properties
                return False, f"Component validation failed: {'; '.join(errors)}"

            # Validate updated form
            is_valid, errors = self.validator.validate_form_config(form_config)
            if not is_valid:
                # Rollback changes
                component["properties"] = original_properties
                return False, f"Form validation failed: {'; '.join(errors)}"

            # Save updated form
            self._save_form(form_path, form_config)
            return True, f"Component '{component_name}' properties updated successfully"

        except Exception as e:
            return False, f"Error updating component properties: {str(e)}"

    def remove_component_from_form(
        self,
        form_path: str,
        component_name: str,
        project_context: ProjectContext | None = None,
    ) -> tuple[bool, str]:
        """Remove a component from a form with cleanup."""
        try:
            # Load existing form
            form_config = self._load_form(form_path)
            if not form_config:
                return False, f"Could not load form from {form_path}"

            # Find component index
            component_index = self._find_component_index(form_config, component_name)
            if component_index == -1:
                return False, f"Component '{component_name}' not found in form"

            # Store component for rollback
            removed_component = form_config["components"][component_index]

            # Check for dependencies
            dependencies = self._analyze_component_dependencies(
                form_config, component_name
            )
            if dependencies:
                return (
                    False,
                    f"Cannot remove component '{component_name}' - it has dependencies: {', '.join(dependencies)}",
                )

            # Remove component
            form_config["components"].pop(component_index)

            # Validate updated form
            is_valid, errors = self.validator.validate_form_config(form_config)
            if not is_valid:
                # Rollback changes
                form_config["components"].insert(component_index, removed_component)
                return False, f"Form validation failed: {'; '.join(errors)}"

            # Save updated form
            self._save_form(form_path, form_config)
            return True, f"Component '{component_name}' removed successfully"

        except Exception as e:
            return False, f"Error removing component: {str(e)}"

    def move_component(
        self,
        form_path: str,
        component_name: str,
        new_position: str,
        project_context: ProjectContext | None = None,
    ) -> tuple[bool, str]:
        """Move a component to a new position within form."""
        try:
            # Load existing form
            form_config = self._load_form(form_path)
            if not form_config:
                return False, f"Could not load form from {form_path}"

            # Find component
            component = self._find_component(form_config, component_name)
            if not component:
                return False, f"Component '{component_name}' not found in form"

            # Store original position for rollback
            original_layout = component.get("layout_properties", {}).copy()

            # Update position
            if "layout_properties" not in component:
                component["layout_properties"] = {}
            component["layout_properties"]["grid_position"] = new_position

            # Validate updated component
            is_valid, errors = self.validator.validate_component(component)
            if not is_valid:
                # Rollback changes
                component["layout_properties"] = original_layout
                return False, f"Component validation failed: {'; '.join(errors)}"

            # Validate updated form
            is_valid, errors = self.validator.validate_form_config(form_config)
            if not is_valid:
                # Rollback changes
                component["layout_properties"] = original_layout
                return False, f"Form validation failed: {'; '.join(errors)}"

            # Save updated form
            self._save_form(form_path, form_config)
            return (
                True,
                f"Component '{component_name}' moved to position {new_position}",
            )

        except Exception as e:
            return False, f"Error moving component: {str(e)}"

    def list_form_components(
        self,
        form_path: str,
        component_type_filter: str | None = None,
        project_context: ProjectContext | None = None,
    ) -> tuple[bool, str, list[dict[str, Any]]]:
        """List components in a form with optional filtering."""
        try:
            # Load existing form
            form_config = self._load_form(form_path)
            if not form_config:
                return False, f"Could not load form from {form_path}", []

            components = form_config.get("components", [])

            # Apply filter if specified
            if component_type_filter:
                components = [
                    comp
                    for comp in components
                    if comp.get("type") == component_type_filter
                ]

            # Enhance component information
            enhanced_components = []
            for comp in components:
                enhanced_comp = comp.copy()
                enhanced_comp["dependencies"] = self._analyze_component_dependencies(
                    form_config, comp.get("name", "")
                )
                enhanced_comp["usage_stats"] = self._get_component_usage_stats(comp)
                enhanced_components.append(enhanced_comp)

            return (
                True,
                f"Found {len(enhanced_components)} components",
                enhanced_components,
            )

        except Exception as e:
            return False, f"Error listing components: {str(e)}", []

    def _load_form(self, form_path: str) -> dict[str, Any] | None:
        """Load form configuration from YAML file."""
        try:
            if not self.file_system.exists(form_path):
                return None

            content = self.file_system.read_text(form_path)
            return yaml.safe_load(content)
        except Exception:
            return None

    def _save_form(self, form_path: str, form_config: dict[str, Any]) -> None:
        """Save form configuration to YAML file."""
        yaml_content = yaml.dump(form_config, default_flow_style=False, indent=2)
        self.file_system.write_text(form_path, yaml_content)

    def _create_component_config(
        self,
        component_type: str,
        position: str,
        properties: dict[str, Any],
        layout_properties: dict[str, Any] | None,
        event_bindings: dict[str, str] | None,
        data_bindings: list[dict[str, Any]] | None,
        project_context: ProjectContext | None,
    ) -> dict[str, Any]:
        """Create component configuration with context-aware enhancements."""
        component = {
            "name": self._generate_component_name(component_type, properties),
            "type": component_type,
            "properties": properties.copy(),
        }

        # Add layout properties
        if layout_properties:
            component["layout_properties"] = layout_properties.copy()
        else:
            component["layout_properties"] = {"grid_position": position}

        # Add event bindings
        if event_bindings:
            component["event_bindings"] = event_bindings.copy()

        # Add data bindings
        if data_bindings:
            component["data_bindings"] = data_bindings.copy()

        # Apply context-aware enhancements
        if project_context:
            component = self._apply_context_enhancements(component, project_context)

        return component

    def _generate_component_name(
        self, component_type: str, properties: dict[str, Any]
    ) -> str:
        """Generate a unique component name based on type and properties."""
        # Use text property if available, otherwise use type
        base_name = properties.get("text", "").lower().replace(" ", "_")
        if not base_name:
            base_name = component_type.lower()

        # Add type prefix for clarity
        return f"{component_type.lower()}_{base_name}"

    def _apply_context_enhancements(
        self, component: dict[str, Any], project_context: ProjectContext
    ) -> dict[str, Any]:
        """Apply context-aware enhancements to component configuration."""
        component_type = component["type"]
        properties = component["properties"]

        # Modern projects: prefer Material 3 roles
        if project_context.generation_mode == "modern":
            if component_type == "Button" and "role" not in properties:
                properties["role"] = "outlined-button"
            elif component_type == "TextBox" and "role" not in properties:
                properties["role"] = "outlined-text-field"

        # Hybrid projects: add migration suggestions
        elif project_context.generation_mode == "hybrid":
            if component_type == "Button" and "role" not in properties:
                properties["role"] = "outlined-button"  # Enhanced default

        # Legacy projects: maintain compatibility
        else:
            if component_type == "Button" and "role" not in properties:
                properties["role"] = "raised-button"  # Legacy default

        return component

    def _find_component(
        self, form_config: dict[str, Any], component_name: str
    ) -> dict[str, Any] | None:
        """Find a component by name in form configuration."""
        for component in form_config.get("components", []):
            if component.get("name") == component_name:
                return component
        return None

    def _find_component_index(
        self, form_config: dict[str, Any], component_name: str
    ) -> int:
        """Find index of a component by name."""
        for i, component in enumerate(form_config.get("components", [])):
            if component.get("name") == component_name:
                return i
        return -1

    def _analyze_component_dependencies(
        self, form_config: dict[str, Any], component_name: str
    ) -> list[str]:
        """Analyze dependencies for a component."""
        dependencies = []

        # Check for event bindings that reference this component
        for component in form_config.get("components", []):
            # Skip self-referencing event handlers (component's own handlers)
            if component.get("name") == component_name:
                continue

            event_bindings = component.get("event_bindings", {})
            for handler in event_bindings.values():
                if component_name in handler:
                    dependencies.append(
                        f"Event handler in {component.get('name', 'unknown')}"
                    )

        # Check for data bindings that reference this component
        for component in form_config.get("components", []):
            # Skip self-referencing data bindings
            if component.get("name") == component_name:
                continue

            data_bindings = component.get("data_bindings", [])
            for binding in data_bindings:
                if component_name in binding.get("code", ""):
                    dependencies.append(
                        f"Data binding in {component.get('name', 'unknown')}"
                    )

        return dependencies

    def _get_component_usage_stats(self, component: dict[str, Any]) -> dict[str, Any]:
        """Get usage statistics for a component."""
        return {
            "has_events": bool(component.get("event_bindings")),
            "has_data_bindings": bool(component.get("data_bindings")),
            "property_count": len(component.get("properties", {})),
            "complexity_score": self._calculate_component_complexity(component),
        }

    def _calculate_component_complexity(self, component: dict[str, Any]) -> float:
        """Calculate complexity score for a component."""
        score = 0.0

        # Base complexity by type
        component_type = component.get("type", "")
        if component_type in ["DataGrid", "RepeatingPanel"]:
            score += 0.8
        elif component_type in ["ColumnPanel", "FlowPanel", "GridPanel"]:
            score += 0.6
        else:
            score += 0.3

        # Add complexity for bindings
        if component.get("event_bindings"):
            score += 0.2 * len(component["event_bindings"])
        if component.get("data_bindings"):
            score += 0.3 * len(component["data_bindings"])

        # Add complexity for properties
        score += 0.1 * len(component.get("properties", {}))

        return min(score, 1.0)  # Cap at 1.0
