"""recoil.api.fallback_bridge — BUS-emitting wrapper for canonical sanctioned fallbacks.

The canonical recoil.pipeline._lib.sanctioned_fallbacks is log-only (no BUS
awareness). The API layer needs both log + BUS emission for operator observability
(Law 4 / Tenet 6 prong-2), so this bridge adds BUS.emit_sync on top.

Public surface:
    emit_fallback(name, scope, payload=None)
"""
from __future__ import annotations

import sys
from typing import Any, Optional

from recoil.pipeline._lib.sanctioned_fallbacks import fire_sanctioned_fallback


def emit_fallback(
    name: str,
    scope: str,
    payload: Optional[dict[str, Any]] = None,
) -> None:
    """Fire a named sanctioned fallback with log + BUS emission.

    Wraps fire_sanctioned_fallback (log-only) and adds BUS emission so the
    API's /api/events stream and SSE subscribers see FALLBACK_FIRED in real time.
    Signature mirrors the old api/sanctioned_fallbacks.emit_fallback for drop-in
    compatibility with all api/ consumers.
    """
    ctx: dict[str, Any] = {"scope": scope}
    if payload is not None:
        ctx.update(payload)
    fire_sanctioned_fallback(name, **ctx)

    # BUS emission — import lazily to avoid circular import at module load time.
    merged_payload: dict[str, Any] = {"name": name, **(payload or {})}
    try:
        from recoil.api.eventbus import BUS  # local import — avoid cycle
        BUS.emit_sync(
            severity="fallback",
            scope=scope,
            summary=name,
            payload=merged_payload,
        )
    except Exception as exc:  # noqa: BLE001
        # Last-resort guard: bus failure must not block the calling code path.
        sys.stderr.write(f"[fallback_bridge] BUS.emit_sync failed: {exc}\n")


__all__ = ["emit_fallback"]
