"""
EdgeEmitter — Automatic Lattice edge creation from DAG proof artifacts.

When a pgDAG step completes and produces a proof, the EdgeEmitter creates
a PRODUCES edge in the Lattice graph linking the step to its proof hash.
For cross-product handoffs, it creates TRIGGERS edges between templates.

Product-agnostic.  Products provide a LatticeClient (from sbn.lattice)
at runner construction time.  If no client is provided, emission is a no-op.

All emissions are fire-and-forget: errors are logged but never block
the DAG execution pipeline.
"""

from __future__ import annotations

import logging
from typing import Any, Dict, Optional

logger = logging.getLogger(__name__)


class EdgeEmitter:
    """Emit Lattice edges from proof artifacts and handoff envelopes.

    Usage:
        from pgdag.edges import EdgeEmitter

        emitter = EdgeEmitter(lattice_client=sbn.lattice, domain="grid.execution")

        # After a step completes:
        await emitter.emit("seal_run", proof, run_id="run-123", template_name="event_ops")

        # For cross-product handoffs:
        await emitter.emit_handoff(handoff_envelope)
    """

    def __init__(
        self,
        lattice_client: Any = None,
        domain: str = "general",
    ) -> None:
        self._lattice = lattice_client
        self._domain = domain

    @property
    def enabled(self) -> bool:
        """True if a Lattice client is configured."""
        return self._lattice is not None

    async def emit(
        self,
        step_id: str,
        proof: Any,
        *,
        run_id: str,
        template_name: str,
        meta: Optional[Dict[str, Any]] = None,
    ) -> Optional[Dict[str, Any]]:
        """Emit a PRODUCES edge: template.step → proof_hash.

        Args:
            step_id:       The DAG step that produced the proof.
            proof:         A ProofArtifact with .proof_hash and .block_ref.
            run_id:        The DAG run ID.
            template_name: The DAG template name.
            meta:          Optional extra metadata for the edge.

        Returns:
            The Lattice API response dict, or None if emission is disabled/failed.
        """
        if not self._lattice:
            return None

        try:
            return self._lattice.create_edge(
                source_id=f"{template_name}.{step_id}",
                target_id=proof.proof_hash,
                edge_type="PRODUCES",
                weight=1.0,
                meta={
                    "run_id": run_id,
                    "domain": self._domain,
                    "step_id": step_id,
                    "block_ref": proof.block_ref,
                    **(meta or {}),
                },
            )
        except Exception as exc:
            logger.warning(
                "Edge emission failed for %s.%s: %s",
                template_name, step_id, exc,
            )
            return None

    async def emit_handoff(
        self,
        envelope: Any,
        *,
        meta: Optional[Dict[str, Any]] = None,
    ) -> Optional[Dict[str, Any]]:
        """Emit a TRIGGERS edge for a cross-product handoff.

        Args:
            envelope: A HandoffEnvelope with source/target product+template info.
            meta:     Optional extra metadata for the edge.

        Returns:
            The Lattice API response dict, or None if emission is disabled/failed.
        """
        if not self._lattice:
            return None

        try:
            return self._lattice.create_edge(
                source_id=f"{envelope.source_product}.{envelope.source_template}",
                target_id=f"{envelope.target_product}.{envelope.target_template}",
                edge_type="TRIGGERS",
                weight=1.0,
                meta={
                    "handoff_hash": envelope.handoff_hash,
                    "source_run_id": envelope.source_run_id,
                    "source_merkle_root": getattr(envelope, "source_merkle_root", ""),
                    **(meta or {}),
                },
            )
        except Exception as exc:
            logger.warning(
                "Handoff edge emission failed for %s.%s → %s.%s: %s",
                envelope.source_product, envelope.source_template,
                envelope.target_product, envelope.target_template,
                exc,
            )
            return None
