"""
Versioning Models - Data models for version control operations.

Defines dataclasses for version info, branch info, field-level changes,
diffs, and merge results.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any


class FieldChangeType(str, Enum):
    """Types of field-level changes."""

    ADDED = "added"
    REMOVED = "removed"
    MODIFIED = "modified"


@dataclass
class VersionInfo:
    """
    Metadata about a single version.

    Attributes:
        version_id: Unique version identifier
        contract_id: Contract this version belongs to
        parent_id: Previous version ID (None for root)
        branch: Branch name (None for main)
        message: Commit-like message
        author: Who created this version
        created_at: When this version was created
    """

    version_id: str
    contract_id: str
    parent_id: str | None = None
    branch: str | None = None
    message: str = ""
    author: str = ""
    created_at: str | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "version_id": self.version_id,
            "contract_id": self.contract_id,
            "parent_id": self.parent_id,
            "branch": self.branch,
            "message": self.message,
            "author": self.author,
            "created_at": self.created_at,
        }


@dataclass
class BranchInfo:
    """
    Metadata about a branch.

    Attributes:
        branch_id: Unique branch identifier
        contract_id: Contract this branch belongs to
        name: Branch name
        base_version_id: Version this branch was created from
        status: Branch status (open, merged, closed)
        created_at: When this branch was created
        created_by: Who created this branch
    """

    branch_id: str
    contract_id: str
    name: str
    base_version_id: str | None = None
    status: str = "open"
    created_at: str | None = None
    created_by: str | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "branch_id": self.branch_id,
            "contract_id": self.contract_id,
            "name": self.name,
            "base_version_id": self.base_version_id,
            "status": self.status,
            "created_at": self.created_at,
            "created_by": self.created_by,
        }


@dataclass
class FieldChange:
    """
    A single field-level change between ontology versions.

    Attributes:
        field_name: Name of the changed field
        change_type: Whether the field was added, removed, or modified
        old_value: Previous field ontology dict (None for additions)
        new_value: New field ontology dict (None for removals)
    """

    field_name: str
    change_type: FieldChangeType
    old_value: dict[str, Any] | None = None
    new_value: dict[str, Any] | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "field_name": self.field_name,
            "change_type": self.change_type.value,
            "old_value": self.old_value,
            "new_value": self.new_value,
        }


@dataclass
class OntologyDiff:
    """
    Detailed diff between two ontology versions.

    Attributes:
        changes: All field-level changes detected
    """

    changes: list[FieldChange] = field(default_factory=list)

    @property
    def additions(self) -> list[FieldChange]:
        """Get only added fields."""
        return [c for c in self.changes if c.change_type == FieldChangeType.ADDED]

    @property
    def removals(self) -> list[FieldChange]:
        """Get only removed fields."""
        return [c for c in self.changes if c.change_type == FieldChangeType.REMOVED]

    @property
    def modifications(self) -> list[FieldChange]:
        """Get only modified fields."""
        return [c for c in self.changes if c.change_type == FieldChangeType.MODIFIED]

    @property
    def has_changes(self) -> bool:
        """Whether any changes were detected."""
        return len(self.changes) > 0

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "changes": [c.to_dict() for c in self.changes],
            "additions": [c.to_dict() for c in self.additions],
            "removals": [c.to_dict() for c in self.removals],
            "modifications": [c.to_dict() for c in self.modifications],
            "total_changes": len(self.changes),
        }


@dataclass
class OntologyMergeResult:
    """
    Result of a three-way merge between ontology versions.

    Attributes:
        merged: The merged ontology content (None if conflicts)
        conflicts: List of unresolvable conflicts
        auto_resolved: List of automatically resolved changes
        success: Whether the merge completed without conflicts
    """

    merged: dict[str, Any] | None = None
    conflicts: list[dict[str, Any]] = field(default_factory=list)
    auto_resolved: list[dict[str, Any]] = field(default_factory=list)

    @property
    def success(self) -> bool:
        """Whether the merge completed without conflicts."""
        return len(self.conflicts) == 0

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "merged": self.merged,
            "conflicts": self.conflicts,
            "auto_resolved": self.auto_resolved,
            "success": self.success,
        }
