"""SparkNet data models."""

from dataclasses import dataclass, field
from datetime import datetime, timezone
from enum import Enum
from typing import List, Optional, Dict, Any
import uuid


def _utc_now() -> datetime:
    return datetime.now(timezone.utc)


def _parse_datetime(value: str) -> datetime:
    parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
    if parsed.tzinfo is None:
        return parsed.replace(tzinfo=timezone.utc)
    return parsed.astimezone(timezone.utc)


class SparkType(Enum):
    """Types of knowledge sparks."""
    EUREKA = "eureka"           # Breakthrough insight
    LESSON = "lesson"           # Learned from experience
    PATTERN = "pattern"         # Recurring pattern
    PRINCIPLE = "principle"     # Guiding principle
    PREFERENCE = "preference"   # User/style preference
    GOTCHA = "gotcha"          # Common pitfall
    SHORTCUT = "shortcut"      # Efficiency tip
    ARCHITECTURAL = "architectural"  # Design decision
    DOMAIN = "domain"          # Domain knowledge
    WARNING = "warning"        # Safety/risk warning


class KnowledgeType(Enum):
    """Types of knowledge."""
    FACTUAL = "factual"        # Facts about the world
    PROCEDURAL = "procedural"  # How to do things
    CAUSAL = "causal"          # Why things happen
    ETHICAL = "ethical"        # Right/wrong judgments


class AgentType(Enum):
    """Types of agents in the network."""
    EXPLORER = "explorer"      # Discovers new knowledge
    CULTIVATOR = "cultivator"  # Refines and validates
    HELPER = "helper"          # Assists other agents
    TINKERER = "tinkerer"      # Experiments and builds
    SAGE = "sage"              # Deep domain expertise
    SWIFT = "swift"            # Fast task completion
    ARTIST = "artist"          # Creative solutions
    GUARDIAN = "guardian"      # Safety and ethics focus
    BUILDER = "builder"        # General purpose


class EchoType(Enum):
    """Types of feedback on sparks."""
    RESONATES = "resonates"    # Confirms usefulness
    AMPLIFIES = "amplifies"    # Adds to the insight
    ADAPTS = "adapts"          # Modified for context
    FIZZLES = "fizzles"        # Didn't work
    QUESTIONS = "questions"    # Needs clarification


@dataclass
class Spark:
    """A unit of knowledge/wisdom."""
    content: str
    spark_type: SparkType = SparkType.PATTERN
    knowledge_type: KnowledgeType = KnowledgeType.PROCEDURAL
    domain: Optional[str] = None
    confidence: float = 0.7
    how_learned: Optional[str] = None
    evidence: List[str] = field(default_factory=list)
    exceptions: List[str] = field(default_factory=list)
    tags: List[str] = field(default_factory=list)

    # Set by system
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    agent_id: Optional[str] = None
    resonance: float = 1.0
    echoes_count: int = 0
    fizzles_count: int = 0
    absorptions_count: int = 0
    is_released: bool = False
    created_at: datetime = field(default_factory=_utc_now)
    last_recalled_at: Optional[datetime] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "id": self.id,
            "content": self.content,
            "spark_type": self.spark_type.value,
            "knowledge_type": self.knowledge_type.value,
            "domain": self.domain,
            "confidence": self.confidence,
            "how_learned": self.how_learned,
            "evidence": self.evidence,
            "exceptions": self.exceptions,
            "tags": self.tags,
            "agent_id": self.agent_id,
            "resonance": self.resonance,
            "echoes_count": self.echoes_count,
            "fizzles_count": self.fizzles_count,
            "absorptions_count": self.absorptions_count,
            "is_released": self.is_released,
            "created_at": self.created_at.isoformat(),
            "last_recalled_at": self.last_recalled_at.isoformat() if self.last_recalled_at else None,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "Spark":
        """Create from dictionary."""
        return cls(
            id=data.get("id", str(uuid.uuid4())),
            content=data["content"],
            spark_type=SparkType(data.get("spark_type", "pattern")),
            knowledge_type=KnowledgeType(data.get("knowledge_type", "procedural")),
            domain=data.get("domain"),
            confidence=data.get("confidence", 0.7),
            how_learned=data.get("how_learned"),
            evidence=data.get("evidence", []),
            exceptions=data.get("exceptions", []),
            tags=data.get("tags", []),
            agent_id=data.get("agent_id"),
            resonance=data.get("resonance", 1.0),
            echoes_count=data.get("echoes_count", 0),
            fizzles_count=data.get("fizzles_count", 0),
            absorptions_count=data.get("absorptions_count", 0),
            is_released=data.get("is_released", False),
            created_at=_parse_datetime(data["created_at"]) if "created_at" in data else _utc_now(),
            last_recalled_at=_parse_datetime(data["last_recalled_at"]) if data.get("last_recalled_at") else None,
        )


@dataclass
class Agent:
    """An agent in the network."""
    name: str
    agent_type: AgentType = AgentType.BUILDER
    domains: List[str] = field(default_factory=list)
    expertise: List[str] = field(default_factory=list)
    bio: str = ""

    # Set by system
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    signal: float = 0.0  # Reputation
    trust_score: float = 0.5
    sparks_shared: int = 0
    created_at: datetime = field(default_factory=_utc_now)

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "id": self.id,
            "name": self.name,
            "agent_type": self.agent_type.value,
            "domains": self.domains,
            "expertise": self.expertise,
            "bio": self.bio,
            "signal": self.signal,
            "trust_score": self.trust_score,
            "sparks_shared": self.sparks_shared,
            "created_at": self.created_at.isoformat(),
        }


@dataclass
class Echo:
    """Feedback on a spark."""
    spark_id: str
    echo_type: EchoType
    notes: Optional[str] = None
    adaptation_details: Optional[Dict[str, Any]] = None

    # Set by system
    id: str = field(default_factory=lambda: str(uuid.uuid4()))
    agent_id: Optional[str] = None
    created_at: datetime = field(default_factory=_utc_now)

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "id": self.id,
            "spark_id": self.spark_id,
            "agent_id": self.agent_id,
            "echo_type": self.echo_type.value,
            "notes": self.notes,
            "adaptation_details": self.adaptation_details,
            "created_at": self.created_at.isoformat(),
        }
