from typing import Any, Optional
from messagebus import MessageBus, Message, Event
from abc import ABCMeta, abstractmethod


class MessageProcessor(object):
    """The methods of this interface are called based on the lifecycle of the default message handling process"""
    __metaclass__ = ABCMeta

    @abstractmethod
    def get_processor_name(self):
        # type: () -> str
        """
        This method is called to inform callbacks the name of the processor that is being executed
        :return: the name of the processor that is being processed
        """
        raise NotImplementedError()

    @abstractmethod
    def generate_unique_id(self):
        # type: () -> str
        """
        This method is called so that the Processor can generate an unique id for the processing. The value generated
        by this method is passed to callbacks to inform about the request that is being processed
        :return: the unique id generated by the processor
        """
        raise NotImplementedError()

    @abstractmethod
    def parse_data(self, data, event_type):
        # type: (bytes, Optional[str]) -> Any
        """
        This is the first method called. It received the message data and is responsible for parsing it and returning
        the parsed object. In case of parsing errors, an exception must be raised and it must he handled in the
        format_parse_exception method
        :param data: the data of the message
        :param event_type: if handling an event and this event has a type, this will be the type of the event
        :return: the parsed object
        """
        raise NotImplementedError()

    @abstractmethod
    def call_business(self, obj):
        # type: (Any) -> Any
        """
        This method is responsible for executing the request. It should call business objects with the parsed parameter
        and return the value to be formatted
        :param obj: the object parsed by the parse_data method
        :return: the result of the operation
        """
        raise NotImplementedError()

    @abstractmethod
    def format_response(self, message_bus, message, event, input_obj, result):
        # type: (MessageBus, Optional[Message], Optional[Event], Any, Any) -> None
        """
        This method is responsible for formatting a response. It receives the object parsed by the parse_data and the
        result returned by the call_business and must interact with the message bus to produce a response
        :param message_bus: the interface of the message bus
        :param message: the message that is being processed or None if an event is being processed
        :param event:  the event that is being processed or None if a message is being processed
        :param input_obj: the object that was parsed by the parse_data method
        :param result: the value returned by the call_business
        """
        raise NotImplementedError()

    def format_exception(self, message_bus, message, event, input_obj, exception):
        # type: (MessageBus, Optional[Message], Optional[Event], Any, BaseException) -> None
        """
        This method is responsible for formatting a response in case of any exception produced by the previous steps
        after the data ir parsed.
        :param message_bus: the interface to the message bus
        :param message: the message that is being processed or None if an event is being processed
        :param event:  the event that is being processed or None if a message is being processed
        :param input_obj: the object that was parsed by the parse_data method
        :param exception: the exception produced by validate_data or call_business methods
        """
        raise NotImplementedError()

    def format_parse_exception(self, message_bus, message, event, data, exception):
        # type: (MessageBus, Optional[Message], Optional[Event], bytes, BaseException) -> None
        """
        This method is responsible for formatting a response in case of any exception produced by the parse_data method.
        :param message_bus: the interface to the message bus
        :param message: the message that is being processed or None if an event is being processed
        :param event:  the event that is being processed or None if a message is being processed
        :param data: the data received by the parse_data method
        :param exception: the exception produced by validate_data or call_business methods
        """
        raise NotImplementedError()
