"""NEUROVAULT data models - cognitive layer on top of CHRONOS."""

from __future__ import annotations

import hashlib
import time
from dataclasses import dataclass, field
from enum import Enum
from typing import Any, Optional

try:
    import numpy as np
except Exception:  # pragma: no cover
    np = None  # type: ignore


class MemoryTier(str, Enum):
    WORKING = "working"
    SHORT_TERM = "short_term"
    LONG_TERM = "long_term"
    ARCHIVE = "archive"


class EntityType(str, Enum):
    PERSON = "PERSON"
    ORGANIZATION = "ORGANIZATION"
    PROJECT = "PROJECT"
    TECHNOLOGY = "TECHNOLOGY"
    CONCEPT = "CONCEPT"
    LOCATION = "LOCATION"
    DATE = "DATE"
    URL = "URL"
    FILE = "FILE"
    EVENT = "EVENT"
    METRIC = "METRIC"
    EMOTION = "EMOTION"


@dataclass
class EmotionalValence:
    """Emotional coloring of a memory."""

    valence: float = 0.0
    arousal: float = 0.0
    dominance: float = 0.5

    def to_dict(self) -> dict[str, float]:
        return {
            "valence": self.valence,
            "arousal": self.arousal,
            "dominance": self.dominance,
        }

    @classmethod
    def from_dict(cls, d: dict[str, float]) -> "EmotionalValence":
        return cls(d.get("valence", 0.0), d.get("arousal", 0.0), d.get("dominance", 0.5))

    @property
    def importance_modifier(self) -> float:
        return 1.0 + self.arousal * 0.5


@dataclass
class Entity:
    """A named entity in the knowledge graph."""

    name: str
    entity_type: str
    canonical_name: str = ""
    description: str = ""
    embedding: Optional[np.ndarray] = None
    mention_count: int = 1
    first_seen: int = field(default_factory=lambda: int(time.time() * 1000))
    last_seen: int = field(default_factory=lambda: int(time.time() * 1000))
    importance: float = 0.5
    metadata: dict[str, Any] = field(default_factory=dict)
    id: Optional[bytes] = None

    def __post_init__(self) -> None:
        if not self.canonical_name:
            self.canonical_name = self.name.lower().strip()
        if self.id is None:
            payload = f"{self.canonical_name}\x00{self.entity_type}".encode("utf-8")
            self.id = hashlib.sha256(payload).digest()

    @property
    def short_id(self) -> str:
        return self.id.hex()[:6] if self.id else "??????"


@dataclass
class Relationship:
    """A directional relationship between two entities."""

    source_entity_id: bytes
    target_entity_id: bytes
    relation_type: str
    strength: float = 0.5
    evidence_count: int = 1
    first_seen: int = field(default_factory=lambda: int(time.time() * 1000))
    last_seen: int = field(default_factory=lambda: int(time.time() * 1000))
    metadata: dict[str, Any] = field(default_factory=dict)
    id: Optional[bytes] = None

    def __post_init__(self) -> None:
        if self.id is None:
            payload = (
                f"{self.source_entity_id.hex()}\x00"
                f"{self.target_entity_id.hex()}\x00"
                f"{self.relation_type}"
            ).encode("utf-8")
            self.id = hashlib.sha256(payload).digest()


@dataclass
class MemoryCluster:
    """A group of semantically related memories."""

    memory_ids: list[bytes] = field(default_factory=list)
    centroid_embedding: Optional[np.ndarray] = None
    insight_id: Optional[bytes] = None
    created_at: int = field(default_factory=lambda: int(time.time() * 1000))
    updated_at: int = field(default_factory=lambda: int(time.time() * 1000))
    id: Optional[bytes] = None

    def __post_init__(self) -> None:
        if self.id is None:
            content = "".join(m.hex() for m in sorted(self.memory_ids))
            self.id = hashlib.sha256(content.encode("utf-8")).digest()


@dataclass
class ConsolidationReport:
    """Report from a consolidation cycle."""

    entities_extracted: int = 0
    relationships_found: int = 0
    clusters_formed: int = 0
    insights_generated: int = 0
    cross_domain_insights: int = 0
    memories_promoted: int = 0
    memories_decayed: int = 0
    memories_archived: int = 0
    duration_seconds: float = 0.0
    timestamp: int = field(default_factory=lambda: int(time.time() * 1000))


@dataclass
class VaultStatus:
    """Status snapshot of the NEUROVAULT brain."""

    daemon_running: bool
    daemon_pid: Optional[int]
    uptime_seconds: float
    tier_counts: dict[str, int]
    entity_count: int
    relationship_count: int
    concept_count: int
    sensor_status: dict[str, dict]
    last_consolidation: Optional[int]
    insight_count: int
    db_size_bytes: int
    chronos_version: str


@dataclass
class EntityGraph:
    """Traversal result centered on one entity."""

    root_entity: Entity
    nodes: list[Entity] = field(default_factory=list)
    relationships: list[Relationship] = field(default_factory=list)
    depth: int = 2


@dataclass
class AuditReport:
    """Basic audit report for memory operations."""

    generated_at: int
    since: Optional[int]
    total_memories: int
    active_memories: int
    source_counts: dict[str, int] = field(default_factory=dict)
    tier_counts: dict[str, int] = field(default_factory=dict)
    entity_count: int = 0
    relationship_count: int = 0


@dataclass
class MergeResult:
    """Result of importing memories into a vault."""

    imported: int = 0
    skipped: int = 0
    errors: list[str] = field(default_factory=list)
