from typing import Dict, Optional

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

from ._ApiRequest import ApiRequest
from ._RouteNotMapped import RouteNotMapped


class HttpMessageProcessor(UuidMessageProcessor):
    def __init__(self, route_processor, event_name=None):
        # type: (Dict[Route, MessageProcessor], str) -> None
        super(HttpMessageProcessor, self).__init__(event_name)
        self.route_processor = route_processor
        self.router = SimpleHttpRouter(list(self.route_processor.keys()))

        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, request, event_type):
        # type: (HttpRequestMessage, Optional[str]) -> object
        try:
            route_param = Route(request.method, request.url)
            route = self.router.get_route(route_param)
            api_request = ApiRequest(
                request.method,
                route.route.path,
                route.path_parameters,
                request.query,
                request.http_headers,
                request.body)
            self.processor = self.route_processor.get(route.route)
            self.route_name = "{}${}${}".format(super(HttpMessageProcessor, self).get_processor_name(), route.route.method, route.route.path)
            return self.processor.parse_data(api_request, None)
        except AttributeError:
            raise RouteNotMapped(request.method, request.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))
        else:
            self.processor.format_parse_exception(message_bus, message, event, data, exception)

