"""
Harmonic State Receipt — Organism health pulse.

Emitted per DecisionEnvelope after computing Ωᴴ (Harmonic Coherence Scalar).
Captures the fused health metric plus component breakdown for audit.

Part of the constitutional physics layer that unifies:
- ΔC (semantic coherence)
- Tension (contradiction pressure)
- Vitality (information density)
- Trust (proof strength)
- Lineage stability (DAG health)
- Entropy (decision volatility)
"""
from __future__ import annotations

from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Literal

from pydantic import Field, field_validator, model_validator

from core.omega_h import HarmonicStatus, OmegaHResult
from receipts.base import BaseReceipt, _normalise_utc_millis


class HarmonicStateReceipt(BaseReceipt):
    """
    Receipt capturing Ωᴴ (Harmonic Coherence Scalar) for an envelope.
    
    Emitted after Guardian/ToolSafety, before learning/persistence.
    Provides organism-wide health metric for routing, gating, and observability.
    
    Tri-temporal:
    - event_time: When the underlying event occurred
    - observed_at: When ExecutionSpine processed it
    - ts (receipt_at): When this receipt was created
    
    Lineage:
    - parent_ids: Links to GuardianReceipt, ProviderReceipt, etc.
    - envelope_id: The DecisionEnvelope this measures
    - envelope_hash: Hash of the envelope for verification
    """

    receipt_type: Literal["HarmonicStateReceipt"] = "HarmonicStateReceipt"
    domain: str = "organism"
    organ: str = "harmonic_field"

    # Envelope identity
    envelope_id: str
    envelope_hash: Optional[str] = None

    # Tri-temporal (event_time and observed_at for full tri-temporal)
    event_time: Optional[datetime] = None
    observed_at: Optional[datetime] = None

    # The scalar [-1, 1]
    omega_h: float = Field(description="Harmonic scalar in [-1, 1]")

    # Status classification
    status: HarmonicStatus = HarmonicStatus.STABLE

    # Component breakdown for interpretability (may include floats + metadata strings)
    components: Dict[str, Any] = Field(default_factory=dict)

    # Serialized inputs for audit trail
    inputs: Dict[str, Any] = Field(default_factory=dict)

    # Context
    profile: Optional[str] = None
    mode: Optional[str] = None
    domain_name: Optional[str] = None  # "clinical", "markets", etc.
    body: Optional[str] = None

    # Thresholds used for classification (for audit)
    thresholds: Dict[str, float] = Field(default_factory=dict)

    # Alert flag (mirrors OmegaHResult.should_alert)
    should_alert: bool = False
    
    # Constitutional gate statuses (ΔC, ECE, EVHD)
    gate_statuses: Dict[str, Any] = Field(
        default_factory=dict,
        description="Status of constitutional gates: coherence, calibration, evhd"
    )

    @field_validator("omega_h")
    @classmethod
    def _clamp_omega(cls, value: float) -> float:
        """Clamp omega_h to [-1, 1]."""
        return max(-1.0, min(1.0, value))

    @field_validator("event_time", "observed_at", mode="before")
    @classmethod
    def _normalize_time(cls, value: Optional[datetime]) -> Optional[datetime]:
        """Ensure timestamps are UTC-aware and millisecond-normalized."""
        if value is None:
            return None
        return _normalise_utc_millis(value)

    @model_validator(mode="after")
    def _enforce_temporal_order(self) -> "HarmonicStateReceipt":
        """Ensure tri-temporal ordering: event_time <= observed_at <= ts."""
        event_time = self.event_time
        observed_at = self.observed_at
        ts = self.ts

        if event_time and observed_at and event_time > observed_at:
            object.__setattr__(self, "event_time", observed_at)
        if observed_at and ts and observed_at > ts:
            object.__setattr__(self, "observed_at", ts)
        return self

    @classmethod
    def from_result(
        cls,
        *,
        envelope_id: str,
        omega_h_result: OmegaHResult,
        envelope_hash: Optional[str] = None,
        event_time: Optional[datetime] = None,
        observed_at: Optional[datetime] = None,
        parent_ids: Optional[List[str]] = None,
        profile: Optional[str] = None,
        mode: Optional[str] = None,
        domain_name: Optional[str] = None,
        body: Optional[str] = None,
        thresholds: Optional[Dict[str, float]] = None,
        gate_statuses: Optional[Dict[str, Any]] = None,
        ts: Optional[datetime] = None,
    ) -> "HarmonicStateReceipt":
        """
        Build a HarmonicStateReceipt from an OmegaHResult.
        """
        ts = _normalise_utc_millis(ts or datetime.now(timezone.utc))
        receipt_id = f"harmonic_{envelope_id[:12]}_{ts.strftime('%Y%m%d%H%M%S%f')}"

        # Prefer thresholds from result, fall back to provided dict
        threshold_payload: Dict[str, float] = thresholds or getattr(omega_h_result, "thresholds", {}) or {}

        return cls(
            receipt_id=receipt_id,
            envelope_id=envelope_id,
            envelope_hash=envelope_hash,
            event_time=event_time,
            observed_at=observed_at,
            omega_h=omega_h_result.omega_h,
            status=omega_h_result.status,
            components=omega_h_result.components,
            inputs=omega_h_result.inputs_snapshot,
            profile=profile,
            mode=mode,
            domain_name=domain_name,
            body=body,
            thresholds=threshold_payload,
            should_alert=omega_h_result.should_alert,
            gate_statuses=gate_statuses or {},
            parent_ids=parent_ids or [],
            ts=ts,
        )

    def to_dict(self) -> Dict[str, Any]:
        """Serialize to a dict with ISO timestamps for external consumers."""
        return {
            "receipt_id": self.receipt_id,
            "receipt_type": self.receipt_type,
            "domain": self.domain,
            "organ": self.organ,
            "envelope_id": self.envelope_id,
            "envelope_hash": self.envelope_hash,
            "parent_ids": self.parent_ids,
            "event_time": self.event_time.isoformat() if self.event_time else None,
            "observed_at": self.observed_at.isoformat() if self.observed_at else None,
            "ts": self.ts.isoformat(),
            "omega_h": self.omega_h,
            "status": self.status.value,
            "components": self.components,
            "inputs": self.inputs,
            "profile": self.profile,
            "mode": self.mode,
            "domain_name": self.domain_name,
            "body": self.body,
            "thresholds": self.thresholds,
            "should_alert": self.should_alert,
            "gate_statuses": self.gate_statuses,
        }

    @property
    def is_critical(self) -> bool:
        """Check if status is CRITICAL."""
        return self.status == HarmonicStatus.CRITICAL

    @property
    def is_stable(self) -> bool:
        """Check if status is STABLE."""
        return self.status == HarmonicStatus.STABLE

    @property
    def is_elevated(self) -> bool:
        """Check if status is ELEVATED_TENSION."""
        return self.status == HarmonicStatus.ELEVATED_TENSION


def emit_harmonic_state_receipt(
    envelope_id: str,
    omega_h_result: Any,  # OmegaHResult from core.omega_h or a dict
    envelope_hash: Optional[str] = None,
    event_time: Optional[datetime] = None,
    observed_at: Optional[datetime] = None,
    parent_ids: Optional[List[str]] = None,
    profile: Optional[str] = None,
    mode: Optional[str] = None,
    domain_name: Optional[str] = None,
    body: Optional[str] = None,
    config: Optional[Any] = None,  # OmegaHConfig
    gate_statuses: Optional[Dict[str, Any]] = None,  # Constitutional gate statuses
) -> HarmonicStateReceipt:
    """
    Create a HarmonicStateReceipt from an OmegaHResult.
    
    Convenience function to build the receipt from compute_omega_h() output.
    
    Args:
        envelope_id: The DecisionEnvelope ID
        omega_h_result: Result from compute_omega_h()
        envelope_hash: Optional hash of the envelope
        event_time: When the underlying event occurred
        observed_at: When ExecutionSpine processed it
        parent_ids: Receipt IDs this links to (Guardian, Provider, etc.)
        profile: Trust profile name
        mode: Operating mode
        domain_name: Domain (clinical, markets, etc.)
        body: Body/subdivision
        config: OmegaHConfig used (for threshold audit)
    
    Returns:
        HarmonicStateReceipt ready for emission
    """
    # Coerce dict-like payloads to OmegaHResult for compatibility
    if not isinstance(omega_h_result, OmegaHResult):
        payload = getattr(omega_h_result, "to_dict", lambda: omega_h_result)()
        omega_h_result = OmegaHResult(
            omega_h=payload.get("omega_h", 0.0),
            status=HarmonicStatus(payload.get("status", HarmonicStatus.STABLE)),
            components=payload.get("components", {}),
            inputs_snapshot=payload.get("inputs", {}),
            thresholds=payload.get("thresholds", {}),
        )
    
    # Extract thresholds from config for audit trail
    thresholds: Dict[str, float] = {}
    if config is not None:
        thresholds["critical_max"] = getattr(config, "critical_max", -0.3)
        thresholds["elevated_max"] = getattr(config, "elevated_max", 0.1)
    
    return HarmonicStateReceipt.from_result(
        envelope_id=envelope_id,
        omega_h_result=omega_h_result,
        envelope_hash=envelope_hash,
        event_time=event_time,
        observed_at=observed_at,
        parent_ids=parent_ids,
        profile=profile,
        mode=mode,
        domain_name=domain_name,
        body=body,
        thresholds=thresholds or None,
        gate_statuses=gate_statuses,
    )
