import sys

if sys.version_info[0] < 3:
    import inspect2 as inspect
else:
    import inspect

from typing import Type, Optional, Dict, Any, Union, Tuple

from httpmessageprocessor import ApiRequest
from messagebus import JsonHttpResponseMessage, HttpResponseMessage
from messageprocessorutil import UuidMessageProcessor

from ._ApiRequestParser import ApiRequestParser
from ._ExceptionFormatter import ExceptionFormatter
from ._util import convert_to_json
from .exception import \
    InteractorWithoutExecuteMethod, \
    InteractorWithMoreThanOneParameterOnExecute, \
    ParameterSentToNoParameterInteractor


class AutoMappedMessageProcessor(UuidMessageProcessor):
    def __init__(self,
                 request_type,
                 interactor,
                 exception_map=None,
                 success_status=200,
                 extra_mapping=None,
                 event_name=None,
                 response_content_type=None):
        # type: (Optional[Type], Any, Optional[Dict[type, Union[int, Tuple[int, str]]]], int, dict, Optional[str], Optional[str]) -> None  # noqa
        super(AutoMappedMessageProcessor, self).__init__(event_name)
        self.parser = ApiRequestParser(request_type, extra_mapping)
        self.success_status = success_status
        self.response_content_type = response_content_type

        if not hasattr(interactor, "execute"):
            raise InteractorWithoutExecuteMethod()
        if len(inspect.signature(interactor.execute).parameters) > 1:
            raise InteractorWithMoreThanOneParameterOnExecute()
        self.interactor_has_parameter = False
        if len(inspect.signature(interactor.execute).parameters) == 1:
            self.interactor_has_parameter = True
        self.interactor = interactor

        self.exception_formatter = ExceptionFormatter(exception_map)
        self.exception_map = exception_map

    def parse_data(self, api_request, event_type):
        # type: (ApiRequest, Optional[str]) -> Any
        return self.parser.parse(api_request)

    def call_business(self, obj):
        if obj is not None:
            if not self.interactor_has_parameter:
                raise ParameterSentToNoParameterInteractor()

            return self.interactor.execute(obj)
        else:
            if self.interactor_has_parameter:
                return self.interactor.execute(None)
            else:
                return self.interactor.execute()

    def format_response(self, message_bus, message, event, input_obj, result):
        body = None

        if self.response_content_type is not None:
            headers = {
                "Content-Type": self.response_content_type
            }
            response = HttpResponseMessage(self.success_status, result, headers)
        else:
            if result is not None:
                body = convert_to_json(result)
            response = JsonHttpResponseMessage(self.success_status, body)

        message_bus.reply_message(message, response)

    def format_exception(self, message_bus, message, event, input_obj, exception):
        self.exception_formatter.format(message_bus, message, exception, 500)

    def format_parse_exception(self, message_bus, message, event, data, exception):
        self.exception_formatter.format(message_bus, message, exception, 400)
