"""
Impulse Receipts — Audit trail for spontaneous initiative.

These receipts document the organism's autonomous decision-making:
- ImpulseAttemptReceipt: when impulse generation was attempted
- ImpulseGeneratedReceipt: when an impulse was successfully generated
- ImpulseBlockedReceipt: when an impulse was blocked by a safety gate

This allows answering questions like:
- "When did Loom want to do more self-maintenance but was blocked?"
- "Which drive was high when it triggered exploration impulses?"
- "Are we over-blocking a particular drive?"
"""

from typing import Any, Dict, List, Optional
from datetime import datetime, timezone
import uuid
from pydantic import BaseModel, Field
from receipts.models import BaseReceipt, Domain


# ─────────────────────────────────────────────────────────────────────
# Impulse Receipts
# ─────────────────────────────────────────────────────────────────────

class ImpulseAttemptReceipt(BaseReceipt):
    """
    Emitted when impulse generation is attempted.

    Records the state snapshot at the moment of attempt, including
    which gates were checked and their results.
    """
    type: str = Field(default="impulse_attempt", frozen=True)

    # Attempt context
    heartbeat_number: int = Field(description="Heartbeat at attempt time")
    impulse_kind: Optional[str] = Field(default=None, description="Target impulse kind if known")

    # Gate results
    gates_checked: List[str] = Field(default_factory=list, description="Gates that were checked")
    gates_passed: List[str] = Field(default_factory=list, description="Gates that passed")
    gates_failed: List[str] = Field(default_factory=list, description="Gates that failed")

    # State snapshot
    telos_snapshot: Dict[str, Any] = Field(default_factory=dict, description="Telos state at attempt")
    capacity_snapshot: Dict[str, Any] = Field(default_factory=dict, description="Capacity state at attempt")

    # Outcome
    outcome: str = Field(default="unknown", description="generated, blocked, or skipped")
    block_reason: Optional[str] = Field(default=None, description="Why blocked if applicable")

    class Config:
        json_schema_extra = {
            "description": "Impulse generation attempt record",
            "example": {
                "heartbeat_number": 15,
                "impulse_kind": "maintenance",
                "gates_checked": ["safety_level", "pain", "stability", "load", "epoch"],
                "gates_passed": ["safety_level", "pain", "stability", "epoch"],
                "gates_failed": ["load"],
                "telos_snapshot": {"mode": "calm", "dominant_drive": "curiosity"},
                "outcome": "blocked",
                "block_reason": "Cognitive load too high: 0.65",
            }
        }


class ImpulseGeneratedReceipt(BaseReceipt):
    """
    Emitted when an impulse is successfully generated.

    This is the positive case: all gates passed, impulse was created,
    and it was submitted to the action selection engine.
    """
    type: str = Field(default="impulse_generated", frozen=True)

    # Impulse identity
    impulse_id: str = Field(default_factory=lambda: str(uuid.uuid4())[:8])
    impulse_kind: str = Field(description="Kind of impulse generated")
    impulse_type: str = Field(description="Internal impulse type")

    # Impulse content
    goal_text: str = Field(description="The goal/task proposed by the impulse")
    tags: List[str] = Field(default_factory=list, description="Tags for categorization")
    estimated_duration_seconds: int = Field(default=60)
    requires_llm: bool = Field(default=False)

    # State at generation
    telos_snapshot: Dict[str, Any] = Field(default_factory=dict)
    heartbeat_number: int = Field(default=0)

    # Submission
    submitted_to_ase: bool = Field(default=False, description="Whether submitted to ASE")
    ase_candidate_id: Optional[str] = Field(default=None, description="ASE candidate ID if submitted")
    priority: str = Field(default="LOW")

    class Config:
        json_schema_extra = {
            "description": "Successfully generated impulse record",
            "example": {
                "impulse_id": "imp-a1b2c3",
                "impulse_kind": "maintenance",
                "impulse_type": "maintenance",
                "goal_text": "Run light harness on core probes",
                "tags": ["harness", "probes", "health"],
                "estimated_duration_seconds": 30,
                "submitted_to_ase": True,
                "ase_candidate_id": "41447e4d",
                "priority": "LOW",
            }
        }


class ImpulseBlockedReceipt(BaseReceipt):
    """
    Emitted when an impulse is blocked by a safety gate.

    Documents which gate blocked it and the organism's state at that moment.
    Useful for understanding if we're over-blocking certain impulse types.
    """
    type: str = Field(default="impulse_blocked", frozen=True)

    # Block context
    heartbeat_number: int = Field(description="Heartbeat at block time")
    blocking_gate: str = Field(description="The gate that blocked the impulse")
    block_reason: str = Field(description="Human-readable reason for block")

    # State snapshot
    safety_level: str = Field(default="normal")
    pain_level: str = Field(default="NONE")
    cognitive_load: float = Field(default=0.0)
    stability: float = Field(default=1.0)
    vitality: float = Field(default=0.8)
    epoch: str = Field(default="genesis")
    mood: str = Field(default="calm")

    # Telos state
    affective_mode: str = Field(default="calm")
    dominant_drive: str = Field(default="steady")
    internal_tension: float = Field(default=0.0)

    # Gate conditions at block
    gate_conditions: Dict[str, Any] = Field(default_factory=dict)

    class Config:
        json_schema_extra = {
            "description": "Blocked impulse record",
            "example": {
                "heartbeat_number": 12,
                "blocking_gate": "cognitive_load",
                "block_reason": "Cognitive load too high: 0.65",
                "safety_level": "normal",
                "pain_level": "NONE",
                "cognitive_load": 0.65,
                "stability": 0.85,
                "vitality": 0.78,
                "epoch": "growth",
                "mood": "focused",
                "affective_mode": "focused",
                "dominant_drive": "curiosity",
                "gate_conditions": {
                    "safety_level": "normal",
                    "cognitive_load": 0.65,
                    "conflict_pressure": 0.12,
                },
            }
        }


# ─────────────────────────────────────────────────────────────────────
# Helper functions for emitting receipts
# ─────────────────────────────────────────────────────────────────────

def impulse_attempt(
    heartbeat_number: int,
    gates_checked: List[str],
    gates_passed: List[str],
    gates_failed: List[str],
    outcome: str,
    block_reason: Optional[str] = None,
    impulse_kind: Optional[str] = None,
    telos_snapshot: Optional[Dict[str, Any]] = None,
    capacity_snapshot: Optional[Dict[str, Any]] = None,
) -> ImpulseAttemptReceipt:
    """Emit an impulse attempt receipt."""
    receipt = ImpulseAttemptReceipt(
        heartbeat_number=heartbeat_number,
        impulse_kind=impulse_kind,
        gates_checked=gates_checked,
        gates_passed=gates_passed,
        gates_failed=gates_failed,
        outcome=outcome,
        block_reason=block_reason,
        telos_snapshot=telos_snapshot or {},
        capacity_snapshot=capacity_snapshot or {},
    )

    # Persist the receipt
    try:
        from receipts.writer import write_receipt
        write_receipt(receipt)
    except Exception:
        pass

    return receipt


def impulse_generated(
    impulse_id: str,
    impulse_kind: str,
    impulse_type: str,
    goal_text: str,
    heartbeat_number: int,
    tags: Optional[List[str]] = None,
    estimated_duration_seconds: int = 60,
    requires_llm: bool = False,
    submitted_to_ase: bool = False,
    ase_candidate_id: Optional[str] = None,
    priority: str = "LOW",
    telos_snapshot: Optional[Dict[str, Any]] = None,
) -> ImpulseGeneratedReceipt:
    """Emit an impulse generated receipt."""
    receipt = ImpulseGeneratedReceipt(
        impulse_id=impulse_id,
        impulse_kind=impulse_kind,
        impulse_type=impulse_type,
        goal_text=goal_text,
        heartbeat_number=heartbeat_number,
        tags=tags or [],
        estimated_duration_seconds=estimated_duration_seconds,
        requires_llm=requires_llm,
        submitted_to_ase=submitted_to_ase,
        ase_candidate_id=ase_candidate_id,
        priority=priority,
        telos_snapshot=telos_snapshot or {},
    )

    # Persist the receipt
    try:
        from receipts.writer import write_receipt
        write_receipt(receipt)
    except Exception:
        pass

    return receipt


def impulse_blocked(
    heartbeat_number: int,
    blocking_gate: str,
    block_reason: str,
    safety_level: str = "normal",
    pain_level: str = "NONE",
    cognitive_load: float = 0.0,
    stability: float = 1.0,
    vitality: float = 0.8,
    epoch: str = "genesis",
    mood: str = "calm",
    affective_mode: str = "calm",
    dominant_drive: str = "steady",
    internal_tension: float = 0.0,
    gate_conditions: Optional[Dict[str, Any]] = None,
) -> ImpulseBlockedReceipt:
    """Emit an impulse blocked receipt."""
    receipt = ImpulseBlockedReceipt(
        heartbeat_number=heartbeat_number,
        blocking_gate=blocking_gate,
        block_reason=block_reason,
        safety_level=safety_level,
        pain_level=pain_level,
        cognitive_load=cognitive_load,
        stability=stability,
        vitality=vitality,
        epoch=epoch,
        mood=mood,
        affective_mode=affective_mode,
        dominant_drive=dominant_drive,
        internal_tension=internal_tension,
        gate_conditions=gate_conditions or {},
    )

    # Persist the receipt
    try:
        from receipts.writer import write_receipt
        write_receipt(receipt)
    except Exception:
        pass

    return receipt
