"""Form generator for Anvil YAML forms."""

from __future__ import annotations
from typing import Any, Dict, List, Optional, Tuple

from ..dependencies.container import FileSystem
from ..validators.component_validator import ComponentValidator


class FormGenerator:
    """Generate Anvil form YAML with modern patterns and Material 3 support."""

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

    def generate_form(
        self, form_config: Dict[str, Any], output_path: str
    ) -> tuple[bool, str]:
        """Generate Anvil form YAML from configuration."""
        is_valid, errors = self.validator.validate_form_config(form_config)
        if not is_valid:
            return False, f"Validation errors: {'; '.join(errors)}"

        try:
            yaml_content = self._build_yaml(form_config)
            self.file_system.write_text(output_path, yaml_content)
            return True, f"Form generated successfully at {output_path}"
        except Exception as e:
            return False, f"Error generating form: {str(e)}"

    def generate_modern_form(
        self,
        form_config: Dict[str, Any],
        output_path: str,
        theme_config: Optional[Dict[str, Any]] = None,
        reactive_config: Optional[Dict[str, Any]] = None,
        performance_config: Optional[Dict[str, Any]] = None,
    ) -> Tuple[bool, str]:
        """Generate modern Anvil form with Material 3 and reactive patterns."""
        # Enhance form config with modern patterns
        enhanced_config = self._enhance_form_config(
            form_config, theme_config, reactive_config, performance_config
        )

        # Validate enhanced configuration
        is_valid, errors = self.validator.validate_form_config(enhanced_config)
        if not is_valid:
            return False, f"Validation errors: {'; '.join(errors)}"

        try:
            yaml_content = self._build_yaml(enhanced_config)
            self.file_system.write_text(output_path, yaml_content)
            return True, f"Modern form generated successfully at {output_path}"
        except Exception as e:
            return False, f"Error generating modern form: {str(e)}"

    def _enhance_form_config(
        self,
        form_config: Dict[str, Any],
        theme_config: Optional[Dict[str, Any]],
        reactive_config: Optional[Dict[str, Any]],
        performance_config: Optional[Dict[str, Any]],
    ) -> Dict[str, Any]:
        """Enhance form configuration with modern patterns."""
        enhanced = form_config.copy()

        # Apply Material 3 theming
        if theme_config:
            enhanced = self._apply_material_3_theme(enhanced, theme_config)

        # Apply reactive patterns
        if reactive_config:
            enhanced = self._apply_reactive_patterns(enhanced, reactive_config)

        # Apply performance optimizations
        if performance_config:
            enhanced = self._apply_performance_optimizations(
                enhanced, performance_config
            )

        return enhanced

    def _apply_material_3_theme(
        self, form_config: Dict[str, Any], theme_config: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Apply Material 3 theme to form configuration."""
        # Add Material 3 roles and styling
        if "container" in form_config:
            container = form_config["container"]
            if "properties" not in container:
                container["properties"] = {}

            # Apply Material 3 theme properties
            container["properties"].update(
                {
                    "role": "surface-container",
                    "elevation": theme_config.get("elevation", "1"),
                    "background": theme_config.get("surface", "#FAFAFA"),
                }
            )

            form_config["container"] = container

        # Apply Material 3 roles to components
        if "components" in form_config:
            enhanced_components = []
            for component in form_config["components"]:
                enhanced_component = self._apply_component_theme(
                    component, theme_config
                )
                enhanced_components.append(enhanced_component)

            form_config["components"] = enhanced_components

        return form_config

    def _apply_component_theme(
        self, component: Dict[str, Any], theme_config: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Apply Material 3 theme to individual component."""
        enhanced = component.copy()

        if "properties" not in enhanced:
            enhanced["properties"] = {}

        # Apply Material 3 role based on component type
        component_type = enhanced.get("type", "")

        if component_type in ["Button", "Button:raised", "Button:outlined"]:
            enhanced["properties"]["role"] = theme_config.get(
                "button_role",
                "filled-button" if component_type == "Button" else "outlined-button",
            )
            enhanced["properties"]["elevation"] = theme_config.get(
                "button_elevation", "2"
            )

        elif component_type in ["Card", "Card:outlined", "Card:elevated"]:
            enhanced["properties"]["role"] = theme_config.get(
                "card_role",
                "elevated-card"
                if component_type == "Card:elevated"
                else "outlined-card",
            )
            enhanced["properties"]["elevation"] = theme_config.get(
                "card_elevation", "3"
            )

        elif component_type in ["TextBox", "TextArea"]:
            enhanced["properties"]["role"] = theme_config.get(
                "input_role", "outlined-text-field"
            )
            enhanced["properties"]["border_radius"] = theme_config.get(
                "border_radius", "8px"
            )

        elif component_type in ["Label"]:
            enhanced["properties"]["role"] = theme_config.get(
                "text_role",
                "body-large"
                if enhanced.get("properties", {}).get("font_size") == "20px"
                else "body-medium",
            )

        return enhanced

    def _apply_reactive_patterns(
        self, form_config: Dict[str, Any], reactive_config: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Apply reactive patterns to form configuration."""
        enhanced = form_config.copy()

        # Add reactive data bindings
        if "components" in form_config:
            enhanced_components = []
            for component in form_config["components"]:
                enhanced_component = self._apply_component_reactive_patterns(
                    component, reactive_config
                )
                enhanced_components.append(enhanced_component)

            enhanced["components"] = enhanced_components

        # Add reactive event bindings
        if "container" in enhanced:
            container = enhanced["container"]
            if "event_bindings" not in container:
                container["event_bindings"] = {}

            container["event_bindings"]["refreshing_data_bindings"] = (
                "form_refreshing_data_bindings"
            )

        return enhanced

    def _apply_component_reactive_patterns(
        self, component: Dict[str, Any], reactive_config: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Apply reactive patterns to individual component."""
        enhanced = component.copy()

        if "data_bindings" not in enhanced:
            enhanced["data_bindings"] = []

        # Add reactive data binding if enabled
        if reactive_config.get("enable_reactive", True):
            component_name = enhanced.get("name", "")
            if component_name:
                binding = {
                    "property": "text",
                    "code": f"self.{component_name}_text",
                    "writeback": True,
                }
                enhanced["data_bindings"].append(binding)

        return enhanced

    def _apply_performance_optimizations(
        self, form_config: Dict[str, Any], performance_config: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Apply performance optimizations to form configuration."""
        enhanced = form_config.copy()

        # Add lazy loading configuration
        if performance_config.get("lazy_loading", False):
            if "container" in enhanced:
                container = enhanced["container"]
                if "properties" not in container:
                    container["properties"] = {}

                container["properties"]["lazy_loading"] = True
                container["properties"]["load_threshold"] = performance_config.get(
                    "load_threshold", 100
                )

        # Add virtual scrolling for large lists
        if performance_config.get("virtual_scrolling", False):
            if "components" in enhanced:
                enhanced_components = []
                for component in enhanced["components"]:
                    if component.get("type") in ["RepeatingPanel", "DataGrid"]:
                        enhanced_component = self._apply_virtual_scrolling(
                            component, performance_config
                        )
                        enhanced_components.append(enhanced_component)
                    else:
                        enhanced_components.append(component)

                enhanced["components"] = enhanced_components

        return enhanced

    def _apply_virtual_scrolling(
        self, component: Dict[str, Any], performance_config: Dict[str, Any]
    ) -> Dict[str, Any]:
        """Apply virtual scrolling to component."""
        enhanced = component.copy()

        if "properties" not in enhanced:
            enhanced["properties"] = {}

        enhanced["properties"].update(
            {
                "virtual_scrolling": True,
                "item_height": performance_config.get("item_height", "48px"),
                "buffer_size": performance_config.get("buffer_size", 10),
                "window_size": performance_config.get("window_size", 20),
            }
        )

        return enhanced

    def _build_yaml(self, form_config: dict) -> str:
        """Build YAML content from form configuration."""
        lines = []

        container = form_config["container"]
        lines.append("container:")
        lines.append(f"  type: {container['type']}")

        if "properties" in container:
            lines.append("  properties:")
            for key, value in container["properties"].items():
                lines.append(f"    {key}: {self._format_value(value)}")

        if "layout_properties" in container:
            lines.append("  layout_properties:")
            for key, value in container["layout_properties"].items():
                lines.append(f"    {key}: {self._format_value(value)}")

        if "event_bindings" in container:
            lines.append("  event_bindings:")
            for key, value in container["event_bindings"].items():
                lines.append(f"    {key}: {self._format_value(value)}")

        components = form_config.get("components", [])
        if components:
            lines.append("components:")
            for component in components:
                component_yaml = self._build_component_yaml(component)
                lines.extend(
                    f"  {line}" for line in component_yaml.split("\n") if line.strip()
                )

        return "\n".join(lines)

    def _build_component_yaml(self, component: dict) -> str:
        """Build YAML for a single component."""
        lines = []

        lines.append(f"- name: {component['name']}")
        lines.append(f"  type: {component['type']}")

        if "properties" in component:
            lines.append("  properties:")
            for key, value in component["properties"].items():
                lines.append(f"    {key}: {self._format_value(value)}")

        if "layout_properties" in component:
            lines.append("  layout_properties:")
            for key, value in component["layout_properties"].items():
                lines.append(f"    {key}: {self._format_value(value)}")

        if "data_bindings" in component:
            lines.append("  data_bindings:")
            for binding in component["data_bindings"]:
                lines.append(f"    - property: {binding['property']}")
                lines.append(f"      code: {self._format_value(binding['code'])}")
                if "writeback" in binding:
                    lines.append(f"      writeback: {binding['writeback']}")

        if "event_bindings" in component:
            lines.append("  event_bindings:")
            for key, value in component["event_bindings"].items():
                lines.append(f"    {key}: {self._format_value(value)}")

        return "\n".join(lines)

    def _format_value(self, value: Any) -> str:
        """Format a value for YAML output."""
        if isinstance(value, str):
            if any(char in value for char in [" ", ":", "{", "}", "[", "]"]):
                return f'"{value}"'
            return value
        elif isinstance(value, bool):
            return str(value).lower()
        elif isinstance(value, (int, float)):
            return str(value)
        elif isinstance(value, list):
            formatted_items = [self._format_value(item) for item in value]
            return f"[{', '.join(formatted_items)}]"
        elif isinstance(value, dict):
            formatted_pairs = [
                f"{k}: {self._format_value(v)}" for k, v in value.items()
            ]
            return f"{{{', '.join(formatted_pairs)}}}"
        else:
            return f'"{str(value)}"'
