"""Context model for the oedix agent framework.

Defines Context items that flow through the AgentQueue pipeline as the
central data structure controlling information flow.
"""

from __future__ import annotations

import uuid
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional


class ContextType(str, Enum):
    """Types of context entries in the pipeline."""

    USER_QUERY = "USER_QUERY"
    INSTRUCTION = "INSTRUCTION"
    ACTION_RESULT = "ACTION_RESULT"
    TOOL_OUTPUT = "TOOL_OUTPUT"
    SUMMARY = "SUMMARY"
    SYSTEM = "SYSTEM"


@dataclass
class Context:
    """A single context entry in the AgentQueue context array.

    Attributes:
        id: Unique identifier (UUID).
        type: Category of this context entry.
        content: Actual text content.
        source_action_id: ID of the Action that produced this entry (for
            restoration tracking).
        is_compressed: Whether this entry has been summarised / compressed.
        original_content: Pre-compression content (kept for potential
            restoration by the organizer).
        priority: Higher values are more likely to be retained during
            compression.  The organizer uses this when deciding what to
            compress or remove.
    """

    type: ContextType
    content: str
    id: str = field(default_factory=lambda: uuid.uuid4().hex)
    source_action_id: Optional[str] = None
    is_compressed: bool = False
    original_content: Optional[str] = None
    priority: int = 0

    # ------------------------------------------------------------------
    # Convenience factories
    # ------------------------------------------------------------------

    @classmethod
    def user_query(cls, content: str) -> Context:
        return cls(type=ContextType.USER_QUERY, content=content, priority=100)

    @classmethod
    def instruction(cls, content: str) -> Context:
        return cls(type=ContextType.INSTRUCTION, content=content, priority=90)

    @classmethod
    def action_result(
        cls,
        content: str,
        source_action_id: Optional[str] = None,
        priority: int = 50,
    ) -> Context:
        return cls(
            type=ContextType.ACTION_RESULT,
            content=content,
            source_action_id=source_action_id,
            priority=priority,
        )

    @classmethod
    def tool_output(
        cls,
        content: str,
        source_action_id: Optional[str] = None,
        priority: int = 50,
    ) -> Context:
        return cls(
            type=ContextType.TOOL_OUTPUT,
            content=content,
            source_action_id=source_action_id,
            priority=priority,
        )

    @classmethod
    def summary(cls, content: str, priority: int = 30) -> Context:
        return cls(type=ContextType.SUMMARY, content=content, priority=priority)

    @classmethod
    def system(cls, content: str, priority: int = 80) -> Context:
        return cls(type=ContextType.SYSTEM, content=content, priority=priority)

    # ------------------------------------------------------------------
    # Compression helpers
    # ------------------------------------------------------------------

    def compress(self, summary: str) -> None:
        """Replace content with a compressed summary, preserving original."""
        if not self.is_compressed:
            self.original_content = self.content
        self.content = summary
        self.is_compressed = True

    def restore(self) -> None:
        """Restore original content if available."""
        if self.is_compressed and self.original_content is not None:
            self.content = self.original_content
            self.original_content = None
            self.is_compressed = False

    # ------------------------------------------------------------------
    # Size helpers
    # ------------------------------------------------------------------

    def size(self) -> int:
        """Return approximate size of content in characters."""
        return len(self.content)

    # ------------------------------------------------------------------
    # Serialisation
    # ------------------------------------------------------------------

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "type": self.type.value,
            "content": self.content,
            "source_action_id": self.source_action_id,
            "is_compressed": self.is_compressed,
            "original_content": self.original_content,
            "priority": self.priority,
        }

    @classmethod
    def from_dict(cls, data: dict) -> Context:
        return cls(
            id=data.get("id", uuid.uuid4().hex),
            type=ContextType(data["type"]),
            content=data["content"],
            source_action_id=data.get("source_action_id"),
            is_compressed=data.get("is_compressed", False),
            original_content=data.get("original_content"),
            priority=data.get("priority", 0),
        )
