"""cortex/types/claims.py — Semantic claims and extraction types."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional


# ---------------------------------------------------------------------------
# Semantic Claim (L4 — entity-linked, lifecycle-managed)
# ---------------------------------------------------------------------------

@dataclass
class SemanticClaim:
    """A single fact stored as a subject-predicate-object triple (L4).

    This is the primary unit of long-term memory in Cortex. Claims are
    extracted from conversations by the ExtractionPipeline (M2), deduplicated
    by the ReconciliationEngine (M4), and served by the RetrievalPipeline (M8).

    Lifecycle: session → (promoted to) long-term → (possibly) superseded → archived.

    Example claim:
        subject="Andrew", predicate="prefers", object_value="dark mode"

    Created by: ReconciliationEngine.reconcile() (M4).
    Read by: RetrievalPipeline (M8), FeedbackSystem (M12).
    Updated by: ReconciliationEngine (confidence bumps, superseding).
    Deleted by: CortexPlugin.forget() (soft-delete to 'archived' by default).
    """
    id: str
    owner_id: str
    subject: str
    predicate: str
    object_value: str
    memory_type: str = 'session'
    subject_entity_id: Optional[str] = None
    object_entity_id: Optional[str] = None
    datatype: str = 'text'
    confidence: float = 0.5
    sensitivity: str = 'normal'
    scope: str = 'user'
    valid_from: Optional[str] = None
    valid_to: Optional[str] = None
    status: str = 'active'
    superseded_by: Optional[str] = None
    last_accessed: Optional[str] = None
    access_count: int = 0
    source_session: Optional[str] = None
    created_at: Optional[str] = None
    updated_at: Optional[str] = None
    # Temporal fields (#573, v12)
    temporal: str = 'current'             # current|past|future|permanent
    temporal_marker: Optional[str] = None # raw time phrase from text ("last week", "March 2026")
    # LoCoMo extraction fields (v10, #516)
    memory_class: str = 'semantic'        # semantic|episodic|procedural|open_loop|transient
    event_date: Optional[str] = None      # ISO YYYY-MM-DD
    sequence_order: Optional[int] = None  # within-conversation ordering
    salience: str = 'medium'              # high|medium|low
    # Causal linking (#518)
    cause: Optional[str] = None
    effect: Optional[str] = None
    # State transitions (#519)
    state_before: Optional[str] = None
    state_after: Optional[str] = None
    # Category (#660 — was in DB schema since v5 but missing from dataclass)
    category: str = 'misc'                # identity|personal|preferences|decisions|goals|behavioral|relational|episodic|misc
    # Explicitness + stability (#609, v13)
    explicitness: str = 'inferred'        # explicit|implied|inferred
    stability: str = 'volatile'           # stable|mutable|volatile
    # Provenance metadata (#748, v15) — JSON blob with source_session_id, etc.
    metadata_json: Optional[str] = None
    # Review queue (#v14)
    flag_reason: Optional[str] = None     # reason for flagging (when status='needs_review')
    # Mention tracking (#924)
    mentions: int = 0                     # how many times this claim has been re-mentioned
    last_mentioned_at: Optional[str] = None  # ISO timestamp of last re-mention
    # Soft-delete (v16 — 90-day retention)
    is_deleted: int = 0                   # 0=active, 1=soft-deleted
    deleted_at: Optional[str] = None      # timestamp when soft-deleted
    # Entity scoping (#923) — sub-owner scoping to specific agents/entities
    entity_id: Optional[str] = None       # e.g. "eva", "kira" — the owning entity within owner_id
    entity_type: str = "agent"            # agent|human|system|tool
    # Source agent (#1396) — which fleet agent created this claim
    source_agent: Optional[str] = None    # e.g. "eva", "kira", "sora"
    # Hotness score (#1343) — memory lifecycle scoring
    hotness_score: float = 0.0            # computed by cortex.core.hotness
    # Source role (#321 — split extraction mode)
    source_role: Optional[str] = None     # 'user' | 'agent' | 'system' — who said the source message


# ---------------------------------------------------------------------------
# Candidate Claim (pre-storage claim from extraction pipeline)
# ---------------------------------------------------------------------------

@dataclass
class CandidateClaim:
    """A claim extracted from raw text, not yet persisted to storage.

    Produced by the ExtractionPipeline (M2) and consumed by the
    ReconciliationEngine (M4) which decides whether to ADD, UPDATE,
    SUPERSEDE, or NOOP against existing SemanticClaims.
    """
    subject: str
    predicate: str
    object_value: str
    confidence: float = 0.5
    source_text: Optional[str] = None
    entity_type: Optional[str] = None
    claim_type: str = "semantic"
    metadata: Optional[dict] = None
    intrinsic_type: str = "fact"
    human_family: Optional[str] = None
    explicitness: str = "inferred"
    stability: str = "volatile"
    sensitivity: str = "normal"
    category: str = "misc"               # identity | personal | preferences | decisions | goals | behavioral | relational | episodic | misc
    # W4: recency precedence
    is_user_explicit: bool = False
    # Temporal marker preserved from extraction
    temporal: str = "current"             # current|past|future|permanent
    temporal_marker: Optional[str] = None # raw time phrase ("last week", "March 2026")
    # --- LoCoMo-aligned fields (v1.3) ---
    memory_class: str = "semantic"        # semantic|episodic|procedural|open_loop|transient
    status: str = "active"               # active|completed|superseded|blocked
    event_date: Optional[str] = None     # ISO 8601 YYYY-MM-DD when parseable
    sequence_order: Optional[int] = None  # within-conversation ordering (1,2,3...)
    salience: str = "medium"             # high|medium|low
    # Causal linking (#518)
    cause: Optional[str] = None           # reason/trigger for this fact
    effect: Optional[str] = None          # outcome/result of the cause
    # State transitions (#519)
    state_before: Optional[str] = None    # previous state being replaced
    state_after: Optional[str] = None     # new state after the change
    # Real-time supersession (#514)
    action: str = "ADD"                   # ADD|UPDATE|DELETE
    # Entity scoping (#923)
    scope_entity_id: Optional[str] = None   # which entity this claim belongs to
    scope_entity_type: str = "agent"        # agent|human|system|tool
    # Coherence check (#722)
    coherence_flags: Optional[List[str]] = None  # cornerstone IDs that flagged conflict
    # Source role (#321 — split extraction mode)
    source_role: Optional[str] = None     # 'user' | 'agent' | 'system' — who said the source message


# ---------------------------------------------------------------------------
# Claim Provenance
# ---------------------------------------------------------------------------

@dataclass
class ClaimProvenance:
    """Links a SemanticClaim to the EpisodeEvent(s) that produced it.

    This is the evidence chain — every claim can be traced back to the
    raw conversation text that originated it.

    Created by: ReconciliationEngine (M4) after storing a new claim.
    Used by: Auditing, debugging extraction pipeline issues.
    """
    id: str
    claim_id: str
    episode_event_id: str
    span_start: Optional[int] = None
    span_end: Optional[int] = None
    extraction_method: Optional[str] = None
    extractor_model_id: Optional[str] = None
    extraction_prompt_ver: Optional[str] = None
    created_at: Optional[str] = None
