"""
Canonical Progress Event for the FMatch pipeline.
Provides a single, versioned format for all progress communication.
"""

from __future__ import annotations

import time
from typing import Any, Dict, Optional, NamedTuple
from enum import Enum


class ProgressPhase(str, Enum):
    """Progress reporting phases."""

    INIT = "init"
    RUN = "run"
    FINAL = "final"
    HEARTBEAT = "heartbeat"


# Using NamedTuple for immutability and better performance
class ProgressEvent(NamedTuple):
    """
    Immutable progress event for pipeline communication.

    Attributes:
        items_delta: Change in items processed since last event
        comparisons_delta: Change in comparisons made since last event
        total_items: Total items to process (always included)
        phase: Current processing phase
        message: Human-readable status message
        timestamp_ns: Monotonic timestamp in nanoseconds
        schema_version: Event schema version for future compatibility
        extras: Additional phase-specific data
    """

    items_delta: int = 0
    comparisons_delta: int = 0
    total_items: int = 0
    phase: str = ProgressPhase.RUN.value
    message: str = ""
    timestamp_ns: int = 0  # Will be set explicitly when creating
    schema_version: int = 1
    extras: Optional[Dict[str, Any]] = (
        None  # Use None as default, convert to {} when needed
    )

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> ProgressEvent:
        """Create ProgressEvent from dictionary, with validation."""
        # Handle schema versioning
        schema_version = data.get("schema_version", 1)

        if schema_version != 1:
            # Future: handle schema migrations here
            pass

        # Extract known fields, ignore unknown ones for forward compatibility
        return cls(
            items_delta=data.get("items_delta", 0),
            comparisons_delta=data.get("comparisons_delta", 0),
            total_items=data.get("total_items", 0),
            phase=data.get("phase", ProgressPhase.RUN.value),
            message=data.get("message", ""),
            timestamp_ns=data.get("timestamp_ns", time.perf_counter_ns()),
            schema_version=schema_version,
            extras=data.get("extras") or {},
        )

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary for serialization."""
        # Use _asdict() from NamedTuple
        return self._asdict()

    def with_updates(self, **kwargs) -> ProgressEvent:
        """Create a new ProgressEvent with updated fields."""
        return self._replace(**kwargs)
