import json

from messagebus import DefaultToken, Event, Message, MessageBus
from messageprocessorutil.sender import Sender


class BaseSender(Sender):
    """Base sender that dispatches via reply (sync) or publish (async)."""

    def send(self, message_bus: MessageBus, original_event: Event, data: dict, original_payload: dict) -> None:
        """Wraps data with the report-id and dispatches the response.

        Args:
            message_bus: Bus used to dispatch the message.
            original_event: Event received by the processor.
            data: Already-serialized response data.
            original_payload: Original message payload (provides report-id and sync flag).
        """
        event_data = {
            "report-id": original_payload.get("report-id"),
            "data": data,
        }
        self._dispatch(
            message_bus=message_bus,
            original_event=original_event,
            event_data=event_data,
            original_payload=original_payload,
        )

    def send_error(self, message_bus: MessageBus, original_event: Event, data: dict, original_payload: dict) -> None:
        """Dispatches a pre-built error response.

        Args:
            message_bus: Bus used to dispatch the message.
            original_event: Event received by the processor.
            data: Already-serialized error response.
            original_payload: Original message payload (provides sync flag).
        """
        self._dispatch(
            message_bus=message_bus, original_event=original_event, event_data=data, original_payload=original_payload
        )

    def send_parser_error(
        self, message_bus: MessageBus, original_event: Event, data: dict, original_payload: dict
    ) -> None:
        """Dispatches a pre-built parser-error response.

        Args:
            message_bus: Bus used to dispatch the message.
            original_event: Event received by the processor.
            data: Already-serialized parser-error response.
            original_payload: Original message payload (may be empty when parsing failed before assignment).
        """
        self._dispatch(
            message_bus=message_bus, original_event=original_event, event_data=data, original_payload=original_payload
        )

    def _dispatch(
        self, message_bus: MessageBus, original_event: Event, event_data: dict, original_payload: dict
    ) -> None:
        encoded = json.dumps(event_data, default=str).encode("utf-8")
        if original_payload.get("sync"):
            message_bus.reply_event(original_event, Message(DefaultToken.TK_SYS_ACK, data=encoded))
        else:
            message_bus.publish_event(Event("ProcessReportResponse", data=encoded))
