"""Dependency Manager for Modern Anvil Applications.

Handles modern Anvil dependencies and configuration management.
"""

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

from ..dependencies.container import FileSystem


@dataclass
class DependencyConfig:
    """Configuration for a single dependency."""

    name: str
    version: str
    type: str  # "dependency", "dev-dependency", "theme", "routing"
    description: str
    required: bool = True
    compatibility: Dict[str, str] = field(
        default_factory=dict
    )  # Anvil version compatibility


@dataclass
class ProjectDependencies:
    """Complete dependency configuration for a project."""

    project_name: str
    anvil_version: str
    dependencies: List[DependencyConfig]
    dev_dependencies: List[DependencyConfig]
    themes: List[DependencyConfig]
    routing: List[DependencyConfig]

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for JSON serialization."""
        return {
            "project_name": self.project_name,
            "anvil_version": self.anvil_version,
            "dependencies": {
                dep.name: {
                    "version": dep.version,
                    "description": dep.description,
                    "required": dep.required,
                    "compatibility": dep.compatibility,
                }
                for dep in self.dependencies
            },
            "dev_dependencies": {
                dep.name: {
                    "version": dep.version,
                    "description": dep.description,
                    "required": dep.required,
                    "compatibility": dep.compatibility,
                }
                for dep in self.dev_dependencies
            },
            "themes": {
                dep.name: {
                    "version": dep.version,
                    "description": dep.description,
                    "required": dep.required,
                    "compatibility": dep.compatibility,
                }
                for dep in self.themes
            },
            "routing": {
                dep.name: {
                    "version": dep.version,
                    "description": dep.description,
                    "required": dep.required,
                    "compatibility": dep.compatibility,
                }
                for dep in self.routing
            },
        }


class DependencyManager:
    """Manage modern Anvil dependencies and configuration."""

    def __init__(self, file_system: FileSystem) -> None:
        self.file_system: FileSystem = file_system
        self._modern_dependencies: Dict[str, DependencyConfig] = (
            self._load_modern_dependency_catalog()
        )

    def _load_modern_dependency_catalog(self) -> Dict[str, DependencyConfig]:
        """Load catalog of modern Anvil dependencies."""
        return {
            # Material 3 Theme
            "@anvil/material-3": DependencyConfig(
                name="@anvil/material-3",
                version="latest",
                type="theme",
                description="Material Design 3 components and theming system",
                required=True,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Official Routing
            "@anvil/official-routing": DependencyConfig(
                name="@anvil/official-routing",
                version="latest",
                type="routing",
                description="Official client-side routing with data loading",
                required=True,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Reactive Library
            "@anvil/reactive": DependencyConfig(
                name="@anvil/reactive",
                version="latest",
                type="dependency",
                description="Signals-based reactive state management",
                required=True,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Layouts System
            "@anvil/layouts": DependencyConfig(
                name="@anvil/layouts",
                version="latest",
                type="dependency",
                description="Slot-based layout architecture",
                required=True,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Tabulator Integration
            "@anvil/tabulator": DependencyConfig(
                name="@anvil/tabulator",
                version="latest",
                type="dependency",
                description="High-performance reactive data tables",
                required=False,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Testing Framework
            "@anvil/testing": DependencyConfig(
                name="@anvil/testing",
                version="latest",
                type="dev-dependency",
                description="Testing framework for Anvil applications",
                required=False,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Form Builder
            "@anvil/form-builder": DependencyConfig(
                name="@anvil/form-builder",
                version="latest",
                type="dependency",
                description="Dynamic form generation with validation",
                required=False,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Chart Components
            "@anvil/charts": DependencyConfig(
                name="@anvil/charts",
                version="latest",
                type="dependency",
                description="Interactive chart components",
                required=False,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # PDF Generation
            "@anvil/pdf": DependencyConfig(
                name="@anvil/pdf",
                version="latest",
                type="dependency",
                description="PDF generation and manipulation",
                required=False,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
            # Email Templates
            "@anvil/email-templates": DependencyConfig(
                name="@anvil/email-templates",
                version="latest",
                type="dependency",
                description="Professional email template system",
                required=False,
                compatibility={"1.0": "1.0.0", "2.0": "2.0.0"},
            ),
        }

    def create_modern_dependency_config(
        self,
        project_name: str,
        anvil_version: str = "2.0",
        features: Optional[Dict[str, bool]] = None,
    ) -> ProjectDependencies:
        """Create dependency configuration for modern Anvil app."""

        if features is None:
            features = {
                "material_3": True,
                "official_routing": True,
                "reactive": True,
                "layouts": True,
                "tabulator": False,
                "charts": False,
                "pdf": False,
                "email_templates": False,
                "form_builder": False,
                "testing": True,
            }

        # Core modern dependencies (always included)
        dependencies = []
        themes = []
        routing = []
        dev_dependencies = []

        # Material 3 Theme
        if features.get("material_3", True):
            themes.append(self._modern_dependencies["@anvil/material-3"])

        # Official Routing
        if features.get("official_routing", True):
            routing.append(self._modern_dependencies["@anvil/official-routing"])

        # Reactive Library
        if features.get("reactive", True):
            dependencies.append(self._modern_dependencies["@anvil/reactive"])

        # Layouts System
        if features.get("layouts", True):
            dependencies.append(self._modern_dependencies["@anvil/layouts"])

        # Optional dependencies based on features
        if features.get("tabulator", False):
            dependencies.append(self._modern_dependencies["@anvil/tabulator"])

        if features.get("charts", False):
            dependencies.append(self._modern_dependencies["@anvil/charts"])

        if features.get("pdf", False):
            dependencies.append(self._modern_dependencies["@anvil/pdf"])

        if features.get("email_templates", False):
            dependencies.append(self._modern_dependencies["@anvil/email-templates"])

        if features.get("form_builder", False):
            dependencies.append(self._modern_dependencies["@anvil/form-builder"])

        # Development dependencies
        if features.get("testing", True):
            dev_dependencies.append(self._modern_dependencies["@anvil/testing"])

        return ProjectDependencies(
            project_name=project_name,
            anvil_version=anvil_version,
            dependencies=dependencies,
            dev_dependencies=dev_dependencies,
            themes=themes,
            routing=routing,
        )

    def generate_dependency_files(
        self, project_path: str, dependencies: ProjectDependencies
    ) -> Tuple[bool, str]:
        """Generate dependency configuration files."""
        try:
            base_path = Path(project_path)

            # Generate anvil_dependencies.json
            self._generate_anvil_dependencies_json(base_path, dependencies)

            # Generate requirements.txt equivalent
            self._generate_requirements_txt(base_path, dependencies)

            # Generate dependency documentation
            self._generate_dependency_docs(base_path, dependencies)

            # Generate setup configuration
            self._generate_setup_config(base_path, dependencies)

            return True, f"Dependency files generated for {dependencies.project_name}"

        except Exception as e:
            return False, f"Error generating dependency files: {str(e)}"

    def _generate_anvil_dependencies_json(
        self, base_path: Path, dependencies: ProjectDependencies
    ) -> None:
        """Generate anvil_dependencies.json file."""

        config = dependencies.to_dict()

        # Add metadata
        config.update(
            {
                "generated_by": "Hephaestus MCP Server",
                "generated_at": "2024-01-01T00:00:00Z",
                "version": "1.0.0",
                "compatibility": {
                    "anvil_version": dependencies.anvil_version,
                    "python_version": ">=3.8",
                },
            }
        )

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

    def _generate_requirements_txt(
        self, base_path: Path, dependencies: ProjectDependencies
    ) -> None:
        """Generate requirements.txt equivalent for Anvil dependencies."""

        lines = [
            f"# Anvil Dependencies for {dependencies.project_name}",
            f"# Generated by Hephaestus MCP Server",
            f"# Compatible with Anvil {dependencies.anvil_version}",
            "",
        ]

        # Core dependencies
        for dep in dependencies.dependencies:
            lines.append(f"# {dep.description}")
            lines.append(f"{dep.name}=={dep.version}")
            lines.append("")

        # Themes
        for theme in dependencies.themes:
            lines.append(f"# {theme.description}")
            lines.append(f"{theme.name}=={theme.version}")
            lines.append("")

        # Routing
        for routing_dep in dependencies.routing:
            lines.append(f"# {routing_dep.description}")
            lines.append(f"{routing_dep.name}=={routing_dep.version}")
            lines.append("")

        # Development dependencies
        if dependencies.dev_dependencies:
            lines.append("")
            lines.append("# Development Dependencies")
            lines.append("")

            for dev_dep in dependencies.dev_dependencies:
                lines.append(f"# {dev_dep.description}")
                lines.append(f"{dev_dep.name}=={dev_dep.version}")
                lines.append("")

        self.file_system.write_text(
            str(base_path / "requirements.txt"), "\n".join(lines)
        )

    def _generate_dependency_docs(
        self, base_path: Path, dependencies: ProjectDependencies
    ) -> None:
        """Generate dependency documentation."""

        docs = [
            f"# Dependencies Documentation",
            f"",
            f"## Project: {dependencies.project_name}",
            f"**Anvil Version:** {dependencies.anvil_version}",
            f"**Generated:** 2024-01-01T00:00:00Z",
            f"",
            f"## Core Dependencies",
            f"",
        ]

        # Dependencies documentation
        for dep in dependencies.dependencies:
            docs.extend(
                [
                    f"### {dep.name}",
                    f"**Version:** {dep.version}",
                    f"**Description:** {dep.description}",
                    f"**Required:** {dep.required}",
                    f"**Compatibility:** {dep.compatibility}",
                    f"",
                ]
            )

        # Themes documentation
        if dependencies.themes:
            docs.extend([f"## Themes", f""])

            for theme in dependencies.themes:
                docs.extend(
                    [
                        f"### {theme.name}",
                        f"**Version:** {theme.version}",
                        f"**Description:** {theme.description}",
                        f"**Required:** {theme.required}",
                        f"**Compatibility:** {theme.compatibility}",
                        f"",
                    ]
                )

        # Routing documentation
        if dependencies.routing:
            docs.extend([f"## Routing", f""])

            for routing_dep in dependencies.routing:
                docs.extend(
                    [
                        f"### {routing_dep.name}",
                        f"**Version:** {routing_dep.version}",
                        f"**Description:** {routing_dep.description}",
                        f"**Required:** {routing_dep.required}",
                        f"**Compatibility:** {routing_dep.compatibility}",
                        f"",
                    ]
                )

        # Development dependencies
        if dependencies.dev_dependencies:
            docs.extend([f"## Development Dependencies", f""])

            for dev_dep in dependencies.dev_dependencies:
                docs.extend(
                    [
                        f"### {dev_dep.name}",
                        f"**Version:** {dev_dep.version}",
                        f"**Description:** {dev_dep.description}",
                        f"**Required:** {dev_dep.required}",
                        f"**Compatibility:** {dev_dep.compatibility}",
                        f"",
                    ]
                )

        self.file_system.write_text(
            str(base_path / "docs" / "DEPENDENCIES.md"), "\n".join(docs)
        )

    def _generate_setup_config(
        self, base_path: Path, dependencies: ProjectDependencies
    ) -> None:
        """Generate setup configuration for dependencies."""

        setup_py = f'''"""Setup configuration for {dependencies.project_name}."""

# Auto-generated by Hephaestus MCP Server
# This file configures modern Anvil dependencies

import anvil

# Configure Material 3 theme
def setup_material_3_theme():
    """Initialize Material 3 theme system."""
    try:
        # Import and configure Material 3
        from anvil_extras import material_3
        material_3.apply_theme()
        print("Material 3 theme initialized")
    except ImportError:
        print("Material 3 theme not available")
    except Exception as e:
        print(f"Error initializing Material 3 theme: {{e}}")

# Configure Official Routing
def setup_official_routing():
    """Initialize official routing system."""
    try:
        # Import and configure routing
        from anvil import routing
        routing.configure_error_handling()
        print("Official routing initialized")
    except ImportError:
        print("Official routing not available")
    except Exception as e:
        print(f"Error initializing official routing: {{e}}")

# Configure Reactive Library
def setup_reactive_library():
    """Initialize reactive state management."""
    try:
        # Import and configure reactive
        from anvil.reactive import configure
        configure(auto_batch=True)
        print("Reactive library initialized")
    except ImportError:
        print("Reactive library not available")
    except Exception as e:
        print(f"Error initializing reactive library: {{e}}")

# Configure Layouts System
def setup_layouts_system():
    """Initialize layouts system."""
    try:
        # Import and configure layouts
        from anvil.layouts import configure
        configure(responsive=True)
        print("Layouts system initialized")
    except ImportError:
        print("Layouts system not available")
    except Exception as e:
        print(f"Error initializing layouts system: {{e}}")

# Main setup function
def setup_dependencies():
    """Setup all configured dependencies."""
    print(f"Setting up dependencies for {dependencies.project_name}")
    
    # Setup core dependencies
    setup_material_3_theme()
    setup_official_routing()
    setup_reactive_library()
    setup_layouts_system()
    
    print("Dependency setup complete")

# Auto-setup on import
if anvil.server.context:
    setup_dependencies()
'''

        self.file_system.write_text(str(base_path / "setup_dependencies.py"), setup_py)

    def validate_dependencies(
        self, dependencies: ProjectDependencies
    ) -> Tuple[bool, List[str]]:
        """Validate dependency configuration."""
        errors = []

        # Check for required dependencies
        required_types = {"theme", "routing"}
        present_types = set()

        for theme in dependencies.themes:
            present_types.add("theme")

        for routing_dep in dependencies.routing:
            present_types.add("routing")

        missing_types = required_types - present_types
        for missing_type in missing_types:
            errors.append(f"Missing required dependency type: {missing_type}")

        # Check compatibility
        for dep in (
            dependencies.dependencies + dependencies.themes + dependencies.routing
        ):
            if dependencies.anvil_version in dep.compatibility:
                required_version = dep.compatibility[dependencies.anvil_version]
                if dep.version != "latest" and dep.version < required_version:
                    errors.append(
                        f"Dependency {dep.name} version {dep.version} is incompatible with Anvil {dependencies.anvil_version}. "
                        f"Requires {required_version} or later"
                    )

        return len(errors) == 0, errors

    def get_dependency_info(self, dependency_name: str) -> Optional[DependencyConfig]:
        """Get information about a specific dependency."""
        return self._modern_dependencies.get(dependency_name)

    def list_available_dependencies(
        self, dependency_type: str = None
    ) -> List[DependencyConfig]:
        """List available dependencies by type."""
        dependencies = list(self._modern_dependencies.values())

        if dependency_type:
            dependencies = [dep for dep in dependencies if dep.type == dependency_type]

        return dependencies
