"""
Receipt types for Corpus Callosum organ.

The Corpus Callosum emits receipts to record:
1. CorpusStateReceipt — unified state snapshot at key milestones
2. ExpectationReceipt — Brain's predictions before execution
3. RealityAlignmentReceipt — comparison of expectations vs actuality
4. DiscrepancyReceipt — when Eyes and Brain disagree

These receipts enable:
- Constitutional logging of alignment/drift
- Historical analysis of discrepancies
- Debugging of hallucinations
- Learning from mispredictions
"""

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


class AlignmentStatus(str, Enum):
    """Status of Eyes/Brain alignment."""
    ALIGNED = "aligned"
    DRIFTING = "drifting"
    DESYNCHRONIZED = "desynchronized"
    UNKNOWN = "unknown"


class DiscrepancySeverity(str, Enum):
    """Severity of a discrepancy."""
    INFO = "info"           # Interesting but expected
    WARNING = "warning"     # Should investigate
    ERROR = "error"         # Significant problem
    CRITICAL = "critical"   # System health threatened


@dataclass
class CorpusStateReceipt:
    """
    Snapshot of unified cognitive state at a milestone.

    Emitted:
    - At the start of a goal
    - After each major phase (Eyes, Brain, Guardian, Hands)
    - At the end of a goal
    """
    receipt_type: str = "CorpusStateReceipt"
    id: str = ""  # Will be set by receipts writer
    goal_id: str = ""

    # Timestamps
    valid_time: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")
    observed_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")
    transaction_time: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")

    # State snapshot
    phase: str = ""  # "start", "perception", "cognition", "verdict", "execution", "end"
    perception_summary: Dict[str, Any] = field(default_factory=dict)
    cognition_summary: Dict[str, Any] = field(default_factory=dict)
    execution_summary: Dict[str, Any] = field(default_factory=dict)
    semantic_summary: Dict[str, Any] = field(default_factory=dict)

    # Alignment status
    alignment_status: str = AlignmentStatus.UNKNOWN.value
    discrepancies: List[str] = field(default_factory=list)

    # Agent and trace
    agent: str = "organism"
    traceparent: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to JSON-serializable dict."""
        return {
            "receipt_type": self.receipt_type,
            "id": self.id,
            "goal_id": self.goal_id,
            "valid_time": self.valid_time,
            "observed_at": self.observed_at,
            "transaction_time": self.transaction_time,
            "phase": self.phase,
            "perception_summary": self.perception_summary,
            "cognition_summary": self.cognition_summary,
            "execution_summary": self.execution_summary,
            "semantic_summary": self.semantic_summary,
            "alignment_status": self.alignment_status,
            "discrepancies": self.discrepancies,
            "agent": self.agent,
            "traceparent": self.traceparent,
        }


@dataclass
class ExpectationReceipt:
    """
    Record of Brain's prediction before execution.

    Emitted:
    - After Brain generates a plan
    - Before Hands executes actions

    Later matched against RealityAlignmentReceipt to detect errors.
    """
    receipt_type: str = "ExpectationReceipt"
    id: str = ""  # Will be set by receipts writer
    goal_id: str = ""

    # Timestamps
    predicted_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")
    observed_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")

    # Prediction
    expected_frontmost_app: Optional[str] = None
    expected_ax_count_range: tuple = (0, 1000)  # min, max elements
    expected_visual_changes: List[str] = field(default_factory=list)
    expected_execution_steps: List[str] = field(default_factory=list)

    # Confidence
    prediction_confidence: float = 0.5  # 0-1
    model_used: Optional[str] = None
    reasoning_summary: Optional[str] = None

    # Trace
    parent_receipt_id: Optional[str] = None  # Links to PlanReceipt
    agent: str = "brain"
    traceparent: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to JSON-serializable dict."""
        return {
            "receipt_type": self.receipt_type,
            "id": self.id,
            "goal_id": self.goal_id,
            "predicted_at": self.predicted_at,
            "observed_at": self.observed_at,
            "expected_frontmost_app": self.expected_frontmost_app,
            "expected_ax_count_range": self.expected_ax_count_range,
            "expected_visual_changes": self.expected_visual_changes,
            "expected_execution_steps": self.expected_execution_steps,
            "prediction_confidence": self.prediction_confidence,
            "model_used": self.model_used,
            "reasoning_summary": self.reasoning_summary,
            "parent_receipt_id": self.parent_receipt_id,
            "agent": self.agent,
            "traceparent": self.traceparent,
        }


@dataclass
class RealityAlignmentReceipt:
    """
    Comparison of Brain's predictions vs Eyes' observations.

    Emitted:
    - After Eyes recapture state
    - Matched against ExpectationReceipt

    Shows where predictions were accurate and where hallucinations occurred.
    """
    receipt_type: str = "RealityAlignmentReceipt"
    id: str = ""  # Will be set by receipts writer
    goal_id: str = ""

    # Timestamps
    checked_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")
    observed_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")

    # Comparison
    expected_receipt_id: Optional[str] = None  # Links to ExpectationReceipt
    actual_frontmost_app: Optional[str] = None
    actual_ax_count: int = 0
    actual_visual_state: Dict[str, Any] = field(default_factory=dict)

    # Results
    alignment_status: str = AlignmentStatus.UNKNOWN.value
    matches: List[str] = field(default_factory=list)  # What was correct
    mismatches: List[str] = field(default_factory=list)  # What was wrong

    # Analysis
    hallucination_risk: float = 0.0  # 0-1, high if big mismatch
    confidence_reduction: float = 0.0  # How much we should reduce confidence
    suggestions: List[str] = field(default_factory=list)  # How to recover

    # Trace
    parent_receipt_id: Optional[str] = None  # Links to CorpusStateReceipt
    agent: str = "eyes"
    traceparent: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to JSON-serializable dict."""
        return {
            "receipt_type": self.receipt_type,
            "id": self.id,
            "goal_id": self.goal_id,
            "checked_at": self.checked_at,
            "observed_at": self.observed_at,
            "expected_receipt_id": self.expected_receipt_id,
            "actual_frontmost_app": self.actual_frontmost_app,
            "actual_ax_count": self.actual_ax_count,
            "actual_visual_state": self.actual_visual_state,
            "alignment_status": self.alignment_status,
            "matches": self.matches,
            "mismatches": self.mismatches,
            "hallucination_risk": self.hallucination_risk,
            "confidence_reduction": self.confidence_reduction,
            "suggestions": self.suggestions,
            "parent_receipt_id": self.parent_receipt_id,
            "agent": self.agent,
            "traceparent": self.traceparent,
        }


@dataclass
class DiscrepancyReceipt:
    """
    Record when Eyes/Brain/Hands/Memory don't align.

    Emitted:
    - When Corpus Callosum detects interference
    - For constitutional logging and learning

    Enables:
    - Debugging of discrepancies
    - Learning why predictions failed
    - Identifying system drift
    """
    receipt_type: str = "DiscrepancyReceipt"
    id: str = ""  # Will be set by receipts writer
    goal_id: str = ""

    # Timestamps
    detected_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")
    observed_at: str = field(default_factory=lambda: datetime.now(timezone.utc).isoformat() + "Z")

    # The conflict
    discrepancy_type: str = ""  # "prediction_mismatch", "timeline_conflict", etc.
    severity: str = DiscrepancySeverity.INFO.value
    description: str = ""

    # What disagreed
    hemisphere_a: str = ""  # "eyes", "brain", "hands", "memory"
    hemisphere_b: str = ""
    value_a: Any = None
    value_b: Any = None

    # Context
    related_receipt_ids: List[str] = field(default_factory=list)
    magnitude: float = 0.0  # 0-1, how big is the disagreement

    # Response
    automatic_recovery_attempted: bool = False
    recovery_action: Optional[str] = None
    recommended_action: Optional[str] = None

    # Trace
    agent: str = "corpus"
    traceparent: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to JSON-serializable dict."""
        return {
            "receipt_type": self.receipt_type,
            "id": self.id,
            "goal_id": self.goal_id,
            "detected_at": self.detected_at,
            "observed_at": self.observed_at,
            "discrepancy_type": self.discrepancy_type,
            "severity": self.severity,
            "description": self.description,
            "hemisphere_a": self.hemisphere_a,
            "hemisphere_b": self.hemisphere_b,
            "value_a": str(value_a) if self.value_a else None,
            "value_b": str(self.value_b) if self.value_b else None,
            "related_receipt_ids": self.related_receipt_ids,
            "magnitude": self.magnitude,
            "automatic_recovery_attempted": self.automatic_recovery_attempted,
            "recovery_action": self.recovery_action,
            "recommended_action": self.recommended_action,
            "agent": self.agent,
            "traceparent": self.traceparent,
        }
