from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Literal, Optional
from models.base import BaseModel


EntityType = Literal['task', 'reward', 'penalty', 'chore', 'kindness']
ActionType = Literal['activated', 'requested', 'redeemed', 'cancelled', 'confirmed', 'approved', 'rejected', 'reset']


@dataclass
class TrackingEvent(BaseModel):
    user_id: Optional[str]
    child_id: str
    entity_type: EntityType
    entity_id: str
    action: ActionType
    points_before: int
    points_after: int
    delta: int
    occurred_at: str  # UTC ISO 8601 timestamp
    metadata: Optional[dict] = None

    def __post_init__(self):
        """Validate invariants after initialization."""
        if self.delta != self.points_after - self.points_before:
            raise ValueError(
                f"Delta invariant violated: {self.delta} != {self.points_after} - {self.points_before}"
            )

    @classmethod
    def from_dict(cls, d: dict):
        return cls(
            user_id=d.get('user_id'),
            child_id=d.get('child_id'),
            entity_type=d.get('entity_type'),
            entity_id=d.get('entity_id'),
            action=d.get('action'),
            points_before=d.get('points_before'),
            points_after=d.get('points_after'),
            delta=d.get('delta'),
            occurred_at=d.get('occurred_at'),
            metadata=d.get('metadata'),
            id=d.get('id'),
            created_at=d.get('created_at'),
            updated_at=d.get('updated_at')
        )

    def to_dict(self):
        base = super().to_dict()
        base.update({
            'user_id': self.user_id,
            'child_id': self.child_id,
            'entity_type': self.entity_type,
            'entity_id': self.entity_id,
            'action': self.action,
            'points_before': self.points_before,
            'points_after': self.points_after,
            'delta': self.delta,
            'occurred_at': self.occurred_at,
            'metadata': self.metadata
        })
        return base

    @staticmethod
    def create_event(
        user_id: Optional[str],
        child_id: str,
        entity_type: EntityType,
        entity_id: str,
        action: ActionType,
        points_before: int,
        points_after: int,
        metadata: Optional[dict] = None
    ) -> 'TrackingEvent':
        """Factory method to create a tracking event with server timestamp."""
        delta = points_after - points_before
        occurred_at = datetime.now(timezone.utc).isoformat()
        
        return TrackingEvent(
            user_id=user_id,
            child_id=child_id,
            entity_type=entity_type,
            entity_id=entity_id,
            action=action,
            points_before=points_before,
            points_after=points_after,
            delta=delta,
            occurred_at=occurred_at,
            metadata=metadata
        )
