"""Reactive Page Generator.

Generates complete reactive pages with routing integration for modern Anvil apps.
"""

from pathlib import Path
from typing import Dict, List, Tuple, Any
from dataclasses import dataclass
import json

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


@dataclass
class PageConfig:
    """Configuration for a reactive page."""

    name: str
    route_path: str
    title: str
    description: str
    layout_type: str  # "main", "detail", "settings", "auth"
    components: List[Dict[str, Any]]
    data_sources: List[Dict[str, Any]]
    state_management: Dict[str, Any]
    navigation_config: Dict[str, Any]
    permissions: List[str]
    seo_config: Dict[str, Any]


@dataclass
class ReactivePageSpec:
    """Complete specification for a reactive page."""

    page_config: PageConfig
    form_yaml: Dict[str, Any]
    route_class: str
    store_integration: Dict[str, Any]
    model_bindings: List[Dict[str, Any]]
    performance_config: Dict[str, Any]


class ReactivePageGenerator:
    """Generate complete reactive pages with routing integration."""

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

    def create_reactive_page(
        self, page_config: PageConfig, project_context: ProjectContext, output_path: str
    ) -> Tuple[bool, str]:
        """Create a complete reactive page with routing integration."""
        try:
            # Generate page specification
            page_spec = self._create_page_spec(page_config, project_context)

            # Generate form YAML
            self._generate_form_yaml(page_spec, output_path)

            # Generate route class
            self._generate_route_class(page_spec, output_path)

            # Generate store integration
            self._generate_store_integration(page_spec, output_path)

            # Generate model bindings
            self._generate_model_bindings(page_spec, output_path)

            # Generate performance optimizations
            self._generate_performance_config(page_spec, output_path)

            return True, f"Reactive page '{page_config.name}' created successfully"

        except Exception as e:
            return False, f"Error creating reactive page: {str(e)}"

    def _create_page_spec(
        self, page_config: PageConfig, project_context: ProjectContext
    ) -> ReactivePageSpec:
        """Create complete page specification."""

        # Generate form YAML based on layout type
        form_yaml = self._generate_form_yaml_config(page_config, project_context)

        # Generate route class name
        route_class = self._generate_route_class_name(page_config.name)

        # Create store integration
        store_integration = self._create_store_integration(page_config, project_context)

        # Create model bindings
        model_bindings = self._create_model_bindings(page_config, project_context)

        # Performance configuration
        performance_config = self._create_performance_config(
            page_config, project_context
        )

        return ReactivePageSpec(
            page_config=page_config,
            form_yaml=form_yaml,
            route_class=route_class,
            store_integration=store_integration,
            model_bindings=model_bindings,
            performance_config=performance_config,
        )

    def _generate_form_yaml_config(
        self, page_config: PageConfig, project_context: ProjectContext
    ) -> Dict[str, Any]:
        """Generate form YAML configuration."""

        base_structure = {
            "container": {
                "type": "ColumnPanel",
                "properties": {
                    "spacing": "medium",
                    "padding": "20px",
                    "role": "main-content",
                },
                "event_bindings": {
                    "refreshing_data_bindings": "form_refreshing_data_bindings"
                },
            }
        }

        # Add components based on layout type
        components = []

        if page_config.layout_type == "main":
            components.extend(
                [
                    {
                        "name": "page_header",
                        "type": "LinearPanel",
                        "properties": {
                            "align": "space_between",
                            "spacing": "medium",
                            "role": "header",
                        },
                        "components": [
                            {
                                "name": "page_title",
                                "type": "Label",
                                "properties": {
                                    "text": page_config.title,
                                    "role": "headline-medium",
                                    "font_weight": "bold",
                                },
                            },
                            {
                                "name": "page_actions",
                                "type": "LinearPanel",
                                "properties": {"align": "right", "spacing": "small"},
                                "components": [
                                    {
                                        "name": "refresh_button",
                                        "type": "Button",
                                        "properties": {
                                            "text": "Refresh",
                                            "role": "outlined-button",
                                            "icon": "fa:refresh",
                                        },
                                        "event_bindings": {
                                            "click": "refresh_button_click"
                                        },
                                    }
                                ],
                            },
                        ],
                    }
                ]
            )

        elif page_config.layout_type == "detail":
            components.extend(
                [
                    {
                        "name": "back_button",
                        "type": "Button",
                        "properties": {
                            "text": "Back",
                            "role": "text-button",
                            "icon": "fa:arrow-left",
                        },
                        "event_bindings": {"click": "back_button_click"},
                    },
                    {
                        "name": "detail_card",
                        "type": "Card",
                        "properties": {
                            "role": "outlined-card",
                            "title": page_config.title,
                        },
                    },
                ]
            )

        elif page_config.layout_type == "settings":
            components.extend(
                [
                    {
                        "name": "settings_header",
                        "type": "Label",
                        "properties": {
                            "text": page_config.title,
                            "role": "headline-large",
                            "font_weight": "bold",
                        },
                    },
                    {
                        "name": "settings_form",
                        "type": "ColumnPanel",
                        "properties": {"spacing": "large"},
                    },
                ]
            )

        # Add custom components
        components.extend(page_config.components)

        # Add loading indicator
        components.append(
            {
                "name": "loading_indicator",
                "type": "LinearPanel",
                "properties": {
                    "align": "center",
                    "justify": "center",
                    "height": "200px",
                    "visible": False,
                },
                "components": [
                    {
                        "name": "loading_spinner",
                        "type": "Spinner",
                        "properties": {"role": "primary"},
                    },
                    {
                        "name": "loading_text",
                        "type": "Label",
                        "properties": {"text": "Loading...", "margin_top": "10px"},
                    },
                ],
            }
        )

        base_structure["container"]["components"] = components

        return base_structure

    def _generate_route_class_name(self, page_name: str) -> str:
        """Generate route class name from page name."""
        # Convert to PascalCase and add Route suffix
        return (
            "".join(
                word.capitalize()
                for word in page_name.replace("_", " ").replace("-", " ").split()
            )
            + "Route"
        )

    def _create_store_integration(
        self, page_config: PageConfig, project_context: ProjectContext
    ) -> Dict[str, Any]:
        """Create store integration configuration."""

        integration = {
            "store_name": f"{page_config.name}_store",
            "signals": [],
            "computed_properties": [],
            "actions": [],
            "subscriptions": [],
        }

        # Add signals based on data sources
        for data_source in page_config.data_sources:
            signal_name = f"{data_source['name']}_data"
            integration["signals"].append(
                {
                    "name": signal_name,
                    "type": data_source.get("type", "list"),
                    "default_value": data_source.get("default", []),
                }
            )

        # Add computed properties
        if page_config.layout_type == "main":
            integration["computed_properties"].extend(
                [
                    {
                        "name": "is_loading",
                        "dependencies": ["loading"],
                        "compute": "lambda: self.loading.get()",
                    },
                    {
                        "name": "has_data",
                        "dependencies": ["main_data"],
                        "compute": "lambda: len(self.main_data.get()) > 0",
                    },
                ]
            )

        # Add actions
        integration["actions"].extend(
            [
                {
                    "name": "load_data",
                    "parameters": ["force_refresh"],
                    "implementation": f"_load_{page_config.name}_data",
                },
                {
                    "name": "refresh_data",
                    "parameters": [],
                    "implementation": f"_refresh_{page_config.name}_data",
                },
            ]
        )

        return integration

    def _create_model_bindings(
        self, page_config: PageConfig, project_context: ProjectContext
    ) -> List[Dict[str, Any]]:
        """Create model bindings for the page."""

        bindings = []

        for data_source in page_config.data_sources:
            if data_source.get("model_class"):
                bindings.append(
                    {
                        "component": data_source["name"],
                        "property": "items",
                        "model": data_source["model_class"],
                        "query": data_source.get("query", {}),
                        "writeback": data_source.get("writeback", False),
                        "reactive": True,
                    }
                )

        return bindings

    def _create_performance_config(
        self, page_config: PageConfig, project_context: ProjectContext
    ) -> Dict[str, Any]:
        """Create performance optimization configuration."""

        return {
            "lazy_loading": page_config.layout_type != "main",
            "virtual_scrolling": len(page_config.data_sources) > 0
            and any(ds.get("type") == "large_list" for ds in page_config.data_sources),
            "caching": {
                "enabled": True,
                "ttl": 300,  # 5 minutes
                "key_prefix": f"{page_config.name}_",
            },
            "batching": {"enabled": True, "batch_size": 50, "debounce_ms": 300},
            "preloading": {
                "enabled": page_config.layout_type == "main",
                "preload_routes": page_config.navigation_config.get(
                    "preload_routes", []
                ),
            },
        }

    def _generate_form_yaml(
        self, page_spec: ReactivePageSpec, output_path: str
    ) -> None:
        """Generate form YAML file."""

        base_path = Path(output_path)
        form_name = f"{page_spec.page_config.name.title()}Form"

        # Convert to YAML string
        yaml_content = self._build_yaml_from_dict(page_spec.form_yaml)

        self.file_system.write_text(str(base_path / f"{form_name}.yaml"), yaml_content)

    def _generate_route_class(
        self, page_spec: ReactivePageSpec, output_path: str
    ) -> None:
        """Generate route class with reactive integration."""

        base_path = Path(output_path)
        route_class_name = page_spec.route_class

        route_code = f'''"""{page_spec.page_config.title} Route with reactive integration."""

import anvil
from anvil import routing
from anvil.reactive import signal, computed, reactive_class, bind
from ..stores.{page_spec.store_integration["store_name"]} import {page_spec.store_integration["store_name"].title()}
from ..models import User

@reactive_class
@routing.route("{page_spec.page_config.route_path}")
class {route_class_name}({route_class_name}):
    """{page_spec.page_config.description}"""
    
    def __init__(self, routing_context=None, **properties):
        self.routing_context = routing_context or {{}}
        self.store = {page_spec.store_integration["store_name"].title()}()
        self.loading = signal(False)
        self.error = signal(None)
        self.init_components(**properties)
        self._load_data()
    
    def _load_data(self, force_refresh=False):
        """Load page data."""
        try:
            self.loading.set(True)
            self.error.set(None)
            
            # Load data using store
            self.store.load_data(force_refresh)
            
        except Exception as e:
            self.error.set(str(e))
            print(f"Error loading {page_spec.page_config.name} data: {{e}}")
        finally:
            self.loading.set(False)
    
    @computed
    def is_loading(self):
        """Computed loading state."""
        return self.loading.get() or self.store.loading.get()
    
    @computed
    def has_error(self):
        """Computed error state."""
        return self.error.get() is not None or self.store.error.get() is not None
    
    @computed
    def error_message(self):
        """Computed error message."""
        return self.error.get() or self.store.error.get()
    
    def form_show(self, **event_args):
        """Handle form show event."""
        self._load_data()
    
    def form_refreshing_data_bindings(self, **event_args):
        """Handle data binding refresh."""
        self._load_data(force_refresh=True)
    
    def refresh_button_click(self, **event_args):
        """Handle refresh button click."""
        self._load_data(force_refresh=True)
    
    {self._generate_event_handlers(page_spec)}
    
    {self._generate_lifecycle_methods(page_spec)}
'''

        self.file_system.write_text(
            str(base_path / f"{page_spec.page_config.name}_route.py"), route_code
        )

    def _generate_event_handlers(self, page_spec: ReactivePageSpec) -> str:
        """Generate event handlers for the page."""

        handlers = []

        # Add navigation handlers
        if page_spec.page_config.layout_type == "detail":
            handlers.append('''
    def back_button_click(self, **event_args):
        """Handle back button click."""
        from anvil import routing
        routing.go_back()''')

        # Add component-specific handlers
        for component in page_spec.page_config.components:
            if component.get("event_bindings"):
                for event, handler in component["event_bindings"].items():
                    handlers.append(f'''
    def {handler}(self, **event_args):
        """Handle {event} event for {component["name"]}."""
        # TODO: Implement {handler} logic
        pass''')

        return "\n".join(handlers)

    def _generate_lifecycle_methods(self, page_spec: ReactivePageSpec) -> str:
        """Generate lifecycle methods for the page."""

        methods = []

        # Add cleanup method
        methods.append('''
    def form_hide(self, **event_args):
        """Handle form hide event."""
        # Cleanup subscriptions and timers
        if hasattr(self, 'store'):
            self.store.cleanup()''')

        # Add performance monitoring
        if page_spec.performance_config.get("caching", {}).get("enabled"):
            methods.append('''
    def _cache_data(self, key, data):
        """Cache data with TTL."""
        import time
        cache = getattr(self, '_cache', {{}})
        cache[key] = {{
            'data': data,
            'timestamp': time.time()
        }}
    
    def _get_cached_data(self, key, ttl=300):
        """Get cached data if valid."""
        cache = getattr(self, '_cache', {{}})
        if key in cache:
            entry = cache[key]
            if time.time() - entry['timestamp'] < ttl:
                return entry['data']
        return None''')

        return "\n".join(methods)

    def _generate_store_integration(
        self, page_spec: ReactivePageSpec, output_path: str
    ) -> None:
        """Generate store integration file."""

        base_path = Path(output_path)
        store_name = page_spec.store_integration["store_name"]

        store_code = f'''"""Store for {page_spec.page_config.name} page."""

import anvil
from anvil.reactive import signal, computed, reactive_class
from ...models import User
from ...services.user_service import get_user_profile

@reactive_class
class {store_name.title()}:
    """Reactive store for {page_spec.page_config.name} page."""
    
    def __init__(self):
        # Signals
        {self._generate_signal_declarations(page_spec.store_integration["signals"])}
        
        # State
        self.loading = signal(False)
        self.error = signal(None)
        
        # Initialize data
        self._initialize_data()
    
    def _initialize_data(self):
        """Initialize store data."""
        try:
            self._load_data()
        except Exception as e:
            self.error.set(str(e))
    
    def _load_data(self, force_refresh=False):
        """Load data from server."""
        try:
            self.loading.set(True)
            self.error.set(None)
            
            {self._generate_data_loading_code(page_spec.page_config.data_sources)}
            
        except Exception as e:
            self.error.set(str(e))
            print(f"Error loading {page_spec.page_config.name} data: {{e}}")
        finally:
            self.loading.set(False)
    
    {self._generate_computed_properties(page_spec.store_integration["computed_properties"])}
    
    {self._generate_actions(page_spec.store_integration["actions"])}
    
    def cleanup(self):
        """Cleanup store resources."""
        # Clear timers, subscriptions, etc.
        pass
'''

        self.file_system.write_text(str(base_path / f"{store_name}.py"), store_code)

    def _generate_signal_declarations(self, signals: List[Dict[str, Any]]) -> str:
        """Generate signal declarations."""

        declarations = []
        for signal in signals:
            default_value = signal.get("default_value", "[]")
            declarations.append(
                f"        self.{signal['name']} = signal({default_value})"
            )

        return "\n".join(declarations)

    def _generate_data_loading_code(self, data_sources: List[Dict[str, Any]]) -> str:
        """Generate data loading code."""

        loading_code = []
        for data_source in data_sources:
            if data_source.get("service_method"):
                loading_code.append(f"""
            # Load {data_source["name"]}
            if data_source.get("service_method"):
                {data_source["name"]}_data = {data_source["service_method"]}()
                self.{data_source["name"]}_data.set({data_source["name"]}_data)""")

        return "\n".join(loading_code)

    def _generate_computed_properties(
        self, computed_props: List[Dict[str, Any]]
    ) -> str:
        """Generate computed properties."""

        properties = []
        for prop in computed_props:
            dependencies = ", ".join(prop["dependencies"])
            properties.append(f'''
    @computed
    def {prop["name"]}(self):
        """Computed {prop["name"]} property."""
        return {prop["compute"]}''')

        return "\n".join(properties)

    def _generate_actions(self, actions: List[Dict[str, Any]]) -> str:
        """Generate action methods."""

        methods = []
        for action in actions:
            params = ", ".join(action["parameters"])
            methods.append(f'''
    def {action["name"]}(self{f", {params}" if params else ""}):
        """{action["name"]} action."""
        return self.{action["implementation"]}({params})''')

        return "\n".join(methods)

    def _generate_model_bindings(
        self, page_spec: ReactivePageSpec, output_path: str
    ) -> None:
        """Generate model bindings configuration."""

        base_path = Path(output_path)

        bindings_config = {
            "page": page_spec.page_config.name,
            "bindings": page_spec.model_bindings,
            "reactive": True,
            "auto_refresh": True,
        }

        self.file_system.write_text(
            str(base_path / "model_bindings.json"),
            json.dumps(bindings_config, indent=2, default=str),
        )

    def _generate_performance_config(
        self, page_spec: ReactivePageSpec, output_path: str
    ) -> None:
        """Generate performance optimization configuration."""

        base_path = Path(output_path)

        config = page_spec.performance_config
        config["page_name"] = page_spec.page_config.name
        config["generated_at"] = "2024-01-01T00:00:00Z"

        self.file_system.write_text(
            str(base_path / "performance_config.json"),
            json.dumps(config, indent=2, default=str),
        )

    def _build_yaml_from_dict(self, data: Dict[str, Any]) -> str:
        """Build YAML string from dictionary with proper formatting."""
        import yaml

        return yaml.dump(data, default_flow_style=False, indent=2, sort_keys=False)
