"""Component operation models for Hephaestus."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

from .project_context import ProjectContext


@dataclass
class ComponentOperation:
    """Base class for component operations."""

    operation_type: str
    form_path: str
    component_name: str
    component_type: str
    timestamp: str = ""
    project_context: ProjectContext | None = None
    metadata: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        if not self.timestamp:
            from datetime import datetime

            self.timestamp = datetime.now().isoformat()


@dataclass
class AddComponentOperation(ComponentOperation):
    """Operation to add a component to a form."""

    position: str = ""
    properties: dict[str, Any] = field(default_factory=dict)
    layout_properties: dict[str, Any] = field(default_factory=dict)
    event_bindings: dict[str, str] = field(default_factory=dict)
    data_bindings: list[dict[str, Any]] = field(default_factory=list)

    def __post_init__(self) -> None:
        self.operation_type = "add"
        super().__post_init__()


@dataclass
class UpdateComponentOperation(ComponentOperation):
    """Operation to update component properties."""

    old_properties: dict[str, Any] = field(default_factory=dict)
    new_properties: dict[str, Any] = field(default_factory=dict)
    impact_analysis: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        self.operation_type = "update"
        super().__post_init__()


@dataclass
class RemoveComponentOperation(ComponentOperation):
    """Operation to remove a component from a form."""

    removed_component: dict[str, Any] = field(default_factory=dict)
    dependencies: list[str] = field(default_factory=list)
    impact_analysis: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        self.operation_type = "remove"
        super().__post_init__()


@dataclass
class MoveComponentOperation(ComponentOperation):
    """Operation to move a component to a new position."""

    old_position: str = ""
    new_position: str = ""
    layout_constraints: dict[str, Any] = field(default_factory=dict)

    def __post_init__(self) -> None:
        self.operation_type = "move"
        super().__post_init__()


@dataclass
class ComponentOperationResult:
    """Result of a component operation."""

    success: bool
    operation: ComponentOperation
    message: str
    errors: list[str] = field(default_factory=list)
    warnings: list[str] = field(default_factory=list)
    rollback_data: dict[str, Any] = field(default_factory=dict)
    execution_time: float = 0.0

    def has_issues(self) -> bool:
        """Check if operation has any issues."""
        return bool(self.errors or self.warnings)

    def get_summary(self) -> str:
        """Get operation summary."""
        if self.success:
            if self.has_issues():
                return (
                    f"✅ {self.operation.operation_type.title()} completed with issues"
                )
            else:
                return (
                    f"✅ {self.operation.operation_type.title()} completed successfully"
                )
        else:
            return f"❌ {self.operation.operation_type.title()} failed"


@dataclass
class ComponentDependency:
    """Represents a dependency between components."""

    source_component: str
    target_component: str
    dependency_type: str  # "event", "data_binding", "layout"
    description: str = ""
    strength: float = 1.0  # 0.0 to 1.0, how strong the dependency is

    def __str__(self) -> str:
        return f"{self.source_component} → {self.target_component} ({self.dependency_type})"


@dataclass
class ComponentInventory:
    """Inventory of components in a form."""

    form_path: str
    components: list[dict[str, Any]] = field(default_factory=list)
    dependencies: list[ComponentDependency] = field(default_factory=list)
    statistics: dict[str, Any] = field(default_factory=dict)
    analysis_timestamp: str = ""

    def __post_init__(self) -> None:
        if not self.analysis_timestamp:
            from datetime import datetime

            self.analysis_timestamp = datetime.now().isoformat()
        self._calculate_statistics()

    def get_components_by_type(self, component_type: str) -> list[dict[str, Any]]:
        """Get all components of a specific type."""
        return [comp for comp in self.components if comp.get("type") == component_type]

    def get_component_dependencies(
        self, component_name: str
    ) -> list[ComponentDependency]:
        """Get dependencies for a specific component."""
        return [
            dep for dep in self.dependencies if dep.target_component == component_name
        ]

    def get_component_dependents(
        self, component_name: str
    ) -> list[ComponentDependency]:
        """Get components that depend on a specific component."""
        return [
            dep for dep in self.dependencies if dep.source_component == component_name
        ]

    def get_critical_components(self) -> list[str]:
        """Get components that are critical (have dependents)."""
        critical = set()
        for dep in self.dependencies:
            critical.add(dep.target_component)
        return list(critical)

    def _calculate_statistics(self) -> None:
        """Calculate inventory statistics."""
        self.statistics = {
            "total_components": len(self.components),
            "component_types": {},
            "components_with_events": 0,
            "components_with_data_bindings": 0,
            "total_dependencies": len(self.dependencies),
            "dependency_types": {},
        }

        for component in self.components:
            # Count component types
            comp_type = component.get("type", "Unknown")
            self.statistics["component_types"][comp_type] = (
                self.statistics["component_types"].get(comp_type, 0) + 1
            )

            # Count components with bindings
            if component.get("event_bindings"):
                self.statistics["components_with_events"] += 1
            if component.get("data_bindings"):
                self.statistics["components_with_data_bindings"] += 1

        # Count dependency types
        for dep in self.dependencies:
            dep_type = dep.dependency_type
            self.statistics["dependency_types"][dep_type] = (
                self.statistics["dependency_types"].get(dep_type, 0) + 1
            )


@dataclass
class RollbackPlan:
    """Plan for rolling back a component operation."""

    operation: ComponentOperation
    rollback_steps: list[dict[str, Any]] = field(default_factory=list)
    is_possible: bool = True
    confidence: float = 1.0
    risks: list[str] = field(default_factory=list)

    def add_rollback_step(
        self,
        step_type: str,
        description: str,
        data: dict[str, Any] | None = None,
    ) -> None:
        """Add a rollback step."""
        step = {
            "type": step_type,
            "description": description,
            "data": data or {},
        }
        self.rollback_steps.append(step)

    def get_rollback_summary(self) -> str:
        """Get rollback plan summary."""
        if not self.is_possible:
            return "❌ Rollback not possible"

        if self.confidence < 0.5:
            return f"⚠️  Rollback risky ({self.confidence:.0%} confidence)"
        elif self.risks:
            return f"⚠️  Rollback possible with {len(self.risks)} risks"
        else:
            return f"✅ Rollback safe ({len(self.rollback_steps)} steps)"


@dataclass
class OperationBatch:
    """Batch of component operations."""

    operations: list[ComponentOperation] = field(default_factory=list)
    batch_id: str = ""
    description: str = ""
    created_at: str = ""

    def __post_init__(self) -> None:
        if not self.batch_id:
            import uuid

            self.batch_id = str(uuid.uuid4())
        if not self.created_at:
            from datetime import datetime

            self.created_at = datetime.now().isoformat()

    def add_operation(self, operation: ComponentOperation) -> None:
        """Add an operation to the batch."""
        self.operations.append(operation)

    def get_operation_types(self) -> list[str]:
        """Get unique operation types in the batch."""
        return list({op.operation_type for op in self.operations})

    def get_affected_forms(self) -> list[str]:
        """Get list of forms affected by this batch."""
        return list({op.form_path for op in self.operations})

    def get_affected_components(self) -> list[str]:
        """Get list of components affected by this batch."""
        return list({op.component_name for op in self.operations})
