"""
HandoffEnvelope — Cross-product proof bridge.

When a business transaction spans multiple products (e.g., Grid slot
completes → Dominion settles → Sonic executes wire), the HandoffEnvelope
bridges the proof chains across product boundaries.

The handoff is TWO channels working together:
  1. SBN (proof chain):  Sealed HandoffEnvelope published as SmartBlock
  2. Signal relay:       Event emitted via NUMA/tower-signals for triggering

The downstream product's first step validates the upstream proof before
proceeding — creating a cryptographic link across products.

Example flow:
  Grid slot #4521 (Merkle: abc123)
    → HandoffEnvelope sealed (links abc123 → Dominion)
      → Dominion batch #891 (first step validates abc123)
        → HandoffEnvelope sealed (links → Sonic)
          → Sonic payout #2233 (first step validates Dominion's proof)
"""

from __future__ import annotations

import hashlib
import json
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any, Dict, Optional

from .artifact import canonical_fingerprint


# ---------------------------------------------------------------------------
# HandoffEnvelope
# ---------------------------------------------------------------------------

@dataclass(frozen=True, slots=True)
class HandoffEnvelope:
    """Cross-product proof bridge.

    Sealed and published as a SmartBlock at the boundary between
    two product DAG runs.

    Attributes:
        source_product:    Product that completed ("grid", "dominion", etc.)
        source_template:   Template that ran ("slot_lifecycle", "payroll_batch")
        source_run_id:     Run ID of the completed execution
        source_slot_id:    SBN slot ID of the completed run
        source_merkle_root: Merkle root of the completed run's proof chain
        target_product:    Product that should pick up ("dominion", "sonic", etc.)
        target_template:   Template to execute downstream
        payload:           Handoff data (amounts, IDs, parameters)
        payload_hash:      SnapChore/SHA-256 hash of the payload
        handoff_hash:      SnapChore seal of this envelope
        block_ref:         SmartBlock that publishes the handoff
    """
    source_product: str
    source_template: str
    source_run_id: str
    source_slot_id: str = ""
    source_merkle_root: str = ""
    target_product: str = ""
    target_template: str = ""
    payload: Dict[str, Any] = field(default_factory=dict)
    payload_hash: str = ""
    handoff_hash: str = ""
    block_ref: str = ""
    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))

    def to_dict(self) -> Dict[str, Any]:
        return {
            "source_product": self.source_product,
            "source_template": self.source_template,
            "source_run_id": self.source_run_id,
            "source_slot_id": self.source_slot_id,
            "source_merkle_root": self.source_merkle_root,
            "target_product": self.target_product,
            "target_template": self.target_template,
            "payload_hash": self.payload_hash,
            "handoff_hash": self.handoff_hash,
            "block_ref": self.block_ref,
            "created_at": self.created_at.isoformat(),
        }


# ---------------------------------------------------------------------------
# Handoff builder
# ---------------------------------------------------------------------------

def build_handoff(
    *,
    source_product: str,
    source_template: str,
    source_run_id: str,
    source_slot_id: str = "",
    source_merkle_root: str = "",
    target_product: str = "",
    target_template: str = "",
    payload: Optional[Dict[str, Any]] = None,
    snapchore: Any = None,
) -> HandoffEnvelope:
    """Build a HandoffEnvelope with computed hashes.

    If a SnapChore client is provided, uses it for sealing.
    Otherwise falls back to local SHA-256.
    """
    _payload = payload or {}
    payload_hash = ""
    handoff_hash = ""

    if snapchore is not None:
        try:
            capture = snapchore.capture(_payload)
            payload_hash = capture.get("hash", "")
        except Exception:
            payload_hash = canonical_fingerprint(_payload)

        envelope_data = {
            "source_product": source_product,
            "source_template": source_template,
            "source_run_id": source_run_id,
            "source_merkle_root": source_merkle_root,
            "target_product": target_product,
            "target_template": target_template,
            "payload_hash": payload_hash,
        }
        try:
            seal_result = snapchore.seal(
                envelope_data,
                domain="handoff",
                block_type="handoff",
            )
            handoff_hash = seal_result.get("hash", seal_result.get("snapchore_hash", ""))
        except Exception:
            handoff_hash = canonical_fingerprint(envelope_data)
    else:
        payload_hash = canonical_fingerprint(_payload)
        envelope_data = {
            "source_product": source_product,
            "source_template": source_template,
            "source_run_id": source_run_id,
            "source_merkle_root": source_merkle_root,
            "target_product": target_product,
            "target_template": target_template,
            "payload_hash": payload_hash,
        }
        handoff_hash = canonical_fingerprint(envelope_data)

    return HandoffEnvelope(
        source_product=source_product,
        source_template=source_template,
        source_run_id=source_run_id,
        source_slot_id=source_slot_id,
        source_merkle_root=source_merkle_root,
        target_product=target_product,
        target_template=target_template,
        payload=_payload,
        payload_hash=payload_hash,
        handoff_hash=handoff_hash,
    )


# ---------------------------------------------------------------------------
# Handoff validation (used as first step in downstream DAG)
# ---------------------------------------------------------------------------

def validate_upstream_proof(
    handoff: HandoffEnvelope,
    *,
    snapchore: Any = None,
) -> bool:
    """Validate an upstream handoff envelope.

    Called as the first step in a downstream product's DAG to verify
    the upstream proof chain is valid before proceeding.

    Returns True if the handoff is valid, False otherwise.
    """
    if not handoff.handoff_hash:
        return False

    # Verify payload hash matches
    if snapchore is not None:
        try:
            capture = snapchore.capture(handoff.payload)
            expected = capture.get("hash", "")
            if expected and expected != handoff.payload_hash:
                return False
        except Exception:
            pass
    else:
        expected = canonical_fingerprint(handoff.payload)
        if expected != handoff.payload_hash:
            return False

    # Optionally verify handoff_hash via SnapChore discover
    if snapchore is not None and hasattr(snapchore, "verify"):
        try:
            result = snapchore.verify(handoff.handoff_hash)
            return result is not None and result.get("verified", False)
        except Exception:
            pass

    # If no SnapChore, trust the hash (local mode)
    return True
