"""
Base Entity Abstract Classes

Entity base classes with identity and lifecycle management.
"""

from abc import ABC
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional, Any
from uuid import UUID, uuid4


@dataclass
class BaseEntity(ABC):
    """
    Abstract base class for all domain entities.
    
    Entities have identity that remains constant throughout their lifecycle.
    Two entities are equal if they have the same ID, regardless of other attributes.
    """
    
    id: UUID = field(default_factory=uuid4)
    
    def __eq__(self, other: Any) -> bool:
        """Entities are equal if they have the same ID."""
        if not isinstance(other, BaseEntity):
            return False
        return self.id == other.id
    
    def __hash__(self) -> int:
        """Hash based on entity ID."""
        return hash(self.id)
    
    def __repr__(self) -> str:
        return f"{self.__class__.__name__}(id={self.id})"


@dataclass
class AuditableEntity(BaseEntity):
    """
    Entity with audit trail fields.
    
    Tracks creation and modification metadata.
    """
    
    created_at: datetime = field(default_factory=datetime.utcnow)
    updated_at: Optional[datetime] = None
    created_by: Optional[UUID] = None
    updated_by: Optional[UUID] = None
    
    def mark_updated(self, user_id: Optional[UUID] = None) -> None:
        """
        Mark entity as updated.
        
        Args:
            user_id: ID of the user making the update
        """
        self.updated_at = datetime.utcnow()
        if user_id:
            self.updated_by = user_id


@dataclass
class SoftDeletableEntity(AuditableEntity):
    """
    Entity that supports soft deletion.
    
    Instead of physical deletion, marks as deleted with timestamp.
    """
    
    is_deleted: bool = False
    deleted_at: Optional[datetime] = None
    deleted_by: Optional[UUID] = None
    
    def soft_delete(self, user_id: Optional[UUID] = None) -> None:
        """
        Mark entity as deleted.
        
        Args:
            user_id: ID of the user performing deletion
        """
        self.is_deleted = True
        self.deleted_at = datetime.utcnow()
        if user_id:
            self.deleted_by = user_id
    
    def restore(self) -> None:
        """Restore a soft-deleted entity."""
        self.is_deleted = False
        self.deleted_at = None
        self.deleted_by = None


@dataclass
class TenantEntity(AuditableEntity):
    """
    Entity that belongs to a specific tenant.
    
    Used in multi-tenant systems where data isolation is required.
    """
    
    tenant_id: UUID = field(default_factory=uuid4)
    
    def belongs_to_tenant(self, tenant_id: UUID) -> bool:
        """
        Check if entity belongs to a specific tenant.
        
        Args:
            tenant_id: The tenant ID to check
            
        Returns:
            True if entity belongs to the tenant
        """
        return self.tenant_id == tenant_id


@dataclass
class VersionedEntity(AuditableEntity):
    """
    Entity with optimistic locking support.
    
    Uses version number to detect concurrent modifications.
    """
    
    version: int = 1
    
    def increment_version(self) -> None:
        """Increment version number for optimistic locking."""
        self.version += 1
