import json
from typing import Any, Optional

from messagebus import Event, Message, MessageBus

from ..data_serializer import DataSerializer, FunctionDataSerializer, IdentityDataSerializer, SerializerLike
from ..parser import FunctionParser, Parser, ParserLike
from ..sender import Sender
from ._UuidMessageProcessor import UuidMessageProcessor


class JsonUtf8EventProcessor(UuidMessageProcessor):
    """Base for event processors that delegate parsing, business logic, and sending to pluggable components.

    The sender is optional: when absent the processor operates in fire-and-forget mode
    (only logs success and failure). When provided, serializes the result and sends
    the response via sender.

    Parser accepts a Parser instance or callable; if None, parse_data returns None.
    Serializer accepts a DataSerializer instance or callable; if None and sender is provided, uses IdentityDataSerializer.
    """

    def __init__(
        self,
        interactor: Optional[Any] = None,
        parser: Optional[ParserLike] = None,
        serializer: Optional[SerializerLike] = None,
        sender: Optional[Sender] = None,
    ):
        """Args:
        interactor: Object with execute(request). Used by the default call_business implementation.
        parser: Parser or callable (data: dict, event_type: str) -> request. If None, parse_data returns None.
        serializer: DataSerializer or callable (result: Any) -> dict. If None and sender provided, uses IdentityDataSerializer.
        sender: Custom sender. If None, processor operates in fire-and-forget mode.
        """
        super().__init__()
        self.interactor = interactor
        self.sender = sender
        self.original_payload: dict = {}

        if parser is None:
            self.parser = None
        elif isinstance(parser, Parser):
            self.parser = parser
        else:
            self.parser = FunctionParser(parser)

        if sender is not None:
            self.serializer: DataSerializer = (
                IdentityDataSerializer()
                if serializer is None
                else serializer if isinstance(serializer, DataSerializer) else FunctionDataSerializer(serializer)
            )
        else:
            self.serializer = None

    def parse_data(self, data: bytes, event_type: str) -> Any:
        if not data:
            self.original_payload = {}
        else:
            self.original_payload = json.loads(data.decode("utf-8"))

        if self.parser is None:
            return None
        return self.parser.parse(data=self.original_payload, event_type=event_type)

    def call_business(self, request: Any) -> Any:
        return self.interactor.execute(request)

    def format_response(
        self, message_bus: MessageBus, message: Message, event: Event, input_obj: Any, result: Any
    ) -> None:
        if self.sender is not None:
            self.sender.send(
                message_bus=message_bus,
                original_event=event,
                data=self.serializer.serialize(result),
                original_payload=self.original_payload,
            )

    def format_exception(
        self, message_bus: MessageBus, message: Message, event: Event, input_obj: Any, exception: Exception
    ) -> None:
        if self.sender is not None:
            self.sender.send_error(
                message_bus=message_bus,
                original_event=event,
                data=self.serializer.serialize_error(input_obj=input_obj, exception=exception, original_payload=self.original_payload),
                original_payload=self.original_payload,
            )

    def format_parse_exception(
        self, message_bus: MessageBus, message: Message, event: Event, data: bytes, exception: Exception
    ) -> None:
        if self.sender is not None:
            self.sender.send_parser_error(
                message_bus=message_bus,
                original_event=event,
                data=self.serializer.serialize_parser_error(data=data, exception=exception),
                original_payload=self.original_payload,
            )