"""cortex/types/records.py — Session, episode, cornerstone, and misc record types."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Optional


# ---------------------------------------------------------------------------
# Cornerstone Memory
# ---------------------------------------------------------------------------

@dataclass
class CornerstoneMemory:
    """An identity-forming memory sealed with hash-based integrity protection.

    Cornerstones are the "soul" of the agent — facts like "I am Eva" or
    "My creator is Andrew" that must never drift or be accidentally overwritten.
    They are always injected at the top of the context window (highest priority
    in the token budget).
    """
    id: str
    owner_id: str
    label: str
    content: str
    golden_copy: str
    golden_hash: str
    current_hash: str
    drift_score: float = 0.0
    last_drift_check: Optional[str] = None
    token_count: int = 0
    injection_order: int = 0
    sealed_at: Optional[str] = None
    sealed_by: str = 'operator'
    revision: int = 1
    revision_history: str = '[]'
    status: str = 'active'
    category: Optional[str] = 'memory'
    created_at: Optional[str] = None
    updated_at: Optional[str] = None


# ---------------------------------------------------------------------------
# Evolution Proposal
# ---------------------------------------------------------------------------

@dataclass
class EvolutionProposal:
    """A proposed evolution for a cornerstone memory, pending operator review.

    Created by CornerstoneGuardian.propose_evolution() when new evidence suggests
    a cornerstone should be updated.
    """
    id: str
    cornerstone_id: str
    owner_id: str
    new_evidence: str
    proposed_content: str
    diff: str
    reasoning: str
    confidence: float = 0.0
    status: str = "pending"
    created_at: Optional[str] = None
    applied_at: Optional[str] = None


# ---------------------------------------------------------------------------
# Session
# ---------------------------------------------------------------------------

@dataclass
class SessionRecord:
    """Tracks an agent wake/sleep lifecycle (L2 — session layer).

    A session spans from wake() to sleep(). During that time, all episode
    events and extracted claims are tagged with the session_id for provenance.
    """
    id: str
    owner_id: str
    session_id: str
    started_at: str
    ended_at: Optional[str] = None
    status: str = 'awake'
    duration_seconds: Optional[int] = None
    fatigue_score: float = 0.0
    compaction_count: int = 0
    turn_count: int = 0
    summary: Optional[str] = None
    sleep_report: Optional[str] = None
    dream_report: Optional[str] = None
    memories_created: int = 0
    memories_promoted: int = 0
    memories_pruned: int = 0
    created_at: Optional[str] = None


# ---------------------------------------------------------------------------
# Episode Event (L3 — immutable evidence)
# ---------------------------------------------------------------------------

@dataclass
class EpisodeEvent:
    """An immutable record of something that happened (L3 — evidence layer).

    Episode events are append-only — they can never be modified or deleted.
    They serve as the provenance chain for semantic claims.
    """
    id: str
    owner_id: str
    actor_id: str
    ts: str
    kind: str
    session_id: Optional[str] = None
    raw_text: Optional[str] = None
    tool_trace_ref: Optional[str] = None
    source_uri: Optional[str] = None
    metadata_json: Optional[str] = None
    created_at: Optional[str] = None


# ---------------------------------------------------------------------------
# Procedure Memory (L5)
# ---------------------------------------------------------------------------

@dataclass
class ProcedureMemory:
    """How-to knowledge — repeatable procedures and workflows (L5).

    Procedures capture "how to do X" knowledge that doesn't fit the
    subject-predicate-object triple format.
    """
    id: str
    owner_id: str
    name: str
    kind: str
    trigger_desc: Optional[str] = None
    content_text: Optional[str] = None
    content_json: Optional[str] = None
    success_count: int = 0
    failure_count: int = 0
    last_used_at: Optional[str] = None
    source_type: Optional[str] = None
    created_at: Optional[str] = None
    updated_at: Optional[str] = None


# ---------------------------------------------------------------------------
# Memory Edge (inter-memory graph)
# ---------------------------------------------------------------------------

@dataclass
class MemoryEdge:
    """A directed edge in the inter-memory graph linking any two memory items.

    Unlike BrainGraphEdge (which links nodes within a single brain graph),
    MemoryEdge links across memory types: claim→entity, entity→entity, etc.
    """
    id: str
    owner_id: str
    source_type: str
    source_id: str
    target_type: str
    target_id: str
    edge_type: str
    confidence: float = 1.0
    metadata_json: Optional[str] = None
    created_at: Optional[str] = None


# ---------------------------------------------------------------------------
# Memory Feedback
# ---------------------------------------------------------------------------

@dataclass
class MemoryFeedback:
    """User/operator feedback on a retrieved memory's quality.

    Feedback is queued as 'pending' and applied during dream cycles.
    """
    id: str
    owner_id: str
    target_type: str
    target_id: str
    feedback_type: str
    feedback_value: Optional[str] = None
    source: str = 'operator'
    status: str = 'pending'
    created_at: Optional[str] = None
    applied_at: Optional[str] = None


# ---------------------------------------------------------------------------
# Search result types (not persisted, returned from queries)
# ---------------------------------------------------------------------------

@dataclass
class VectorResult:
    """A single result from vector similarity search (L1 — storage primitive)."""
    item_type: str
    item_id: str
    score: float          # cosine similarity, higher = more similar
    model_id: Optional[str] = None


@dataclass
class FTSResult:
    """A single result from BM25 full-text search (L1 — storage primitive)."""
    item_id: str          # claim_id or event_id depending on table searched
    content: Optional[str]
    rank: float           # BM25 rank from FTS5 (negative, lower = better match)
