from typing import Dict, Optional, Union

from messagebus import HttpRequestMessage, HttpResponseMessage
from messageprocessor import MessageProcessor
from messageprocessorutil import UuidMessageProcessor
from simplehttprouter import Route, SimpleHttpRouter
from ._RouterProcessorBuilder import RouterProcessorBuilder

from ._ApiRequest import ApiRequest
from ._RouteNotMapped import RouteNotMapped
from ._SimpleHttpRouterRouterProcessorBuilder import SimpleHttpRouterRouterProcessorBuilder


class HttpMessageProcessor(UuidMessageProcessor):
    def __init__(self, route_processor, event_name=None):
        # type: (Union[Dict[Route, MessageProcessor], RouterProcessorBuilder], str) -> None
        super(HttpMessageProcessor, self).__init__(event_name)
        if isinstance(route_processor, RouterProcessorBuilder):
            self.route_processor_builder = route_processor
        else:
            self.route_processor_builder = SimpleHttpRouterRouterProcessorBuilder(route_processor)

        self.processor = None
        self.route_name = None

    def get_processor_name(self):
        if self.route_name is not None:
            return self.route_name
        return super(HttpMessageProcessor, self).get_processor_name()

    def parse_data(self, message):
        # type: (HttpRequestMessage) -> object
        try:
            route_param = Route(message.method, message.url)
            found_route, self.processor = self.route_processor_builder.get_processor(route_param)
            self.route_name = "{}${}${}".format(super(HttpMessageProcessor, self).get_processor_name(),
                                                found_route.route.method,
                                                found_route.route.path)
            api_request = ApiRequest(
                message.method,
                found_route.route.path,
                found_route.path_parameters,
                message.query,
                message.http_headers,
                message.body)

            return self.processor.parse_data(api_request, None)
        except AttributeError:
            raise RouteNotMapped(message.method, message.url)

    def call_business(self, obj):
        return self.processor.call_business(obj)

    def format_response(self, message_bus, message, event, input_obj, result):
        self.processor.format_response(message_bus, message, event, input_obj, result)

    def format_exception(self, message_bus, message, event, input_obj, exception):
        self.processor.format_exception(message_bus, message, event, input_obj, exception)

    def format_parse_exception(self, message_bus, message, event, data, exception):
        if isinstance(exception, RouteNotMapped):
            message_bus.reply_message(message, HttpResponseMessage(404))
        elif self.processor is None:
            message_bus.reply_message(message, HttpResponseMessage(500))
        else:
            self.processor.format_parse_exception(message_bus, message, event, data, exception)
