import zmq
import json

from logging import Logger
from typing import Optional
from messagehandler import MessageHandlerBuilder
from zeromqthreadpool import RepWorkerThread
from messagebus import Event, MessageBus, SwaggerMessage


class HandleRequestWorkerThread(RepWorkerThread, MessageBus):
    def __init__(self, context, worker_address, idle_timeout, message_handler_builder, pub_address, logger=None):
        # type: (zmq.Context, str, int, MessageHandlerBuilder, str, Logger) -> None
        super(HandleRequestWorkerThread, self).__init__(context, worker_address, idle_timeout)
        self.message_handler_builder = message_handler_builder
        self.logger = logger
        self.pub_socket = context.socket(zmq.PUB)
        self.pub_socket.connect(pub_address)

        self.response_data = None

    def do_work(self, data):
        event = self.parse_event(data)
        if event is None:
            return

        try:
            self.response_data = None
            message_handler = self.message_handler_builder.build_message_handler()
            message_handler.handle_event(self, event)
            return self.response_data
        except:
            self.logger.exception("Error handling event")

    def dispose(self):
        self.pub_socket.close()

    def publish_event(self, event):
        data = "{} {}\0{}".format(event.subject, event.event_type, event.data)
        self.pub_socket.send(data)

    def send_message(self, component, message):
        pass

    def subscribe(self, subject):
        pass

    def reply_message(self, message, reply_message):
        pass

    def reply_event(self, event, reply_message):
        self.response_data = reply_message.data
        if reply_message.data is None:
            self.response_data = ""

        if isinstance(reply_message, SwaggerMessage):
            transformed_data = {
                "status": reply_message.status_code
            }

            if reply_message.body is not None:
                transformed_data["body"] = reply_message.body

            if reply_message.headers is not None:
                transformed_data["headers"] = reply_message.headers

            reply_message.data = transformed_data

        if isinstance(reply_message.data, dict):
            self.response_data = json.dumps(reply_message.data)

    def parse_event(self, raw_data):
        # type: (str) -> Optional[Event]
        data_dict = json.loads(raw_data, encoding="utf-8")
        if "subject" not in data_dict or \
                "method" not in data_dict or \
                "apiPath" not in data_dict or \
                "headers" not in data_dict or \
                "query" not in data_dict or \
                "body" not in data_dict:
            return None

        subject = data_dict["subject"]
        type = data_dict["method"]
        event_data = json.dumps({
            "api_path": data_dict["apiPath"],
            "headers": data_dict["headers"],
            "query": data_dict["query"],
            "body": data_dict["body"]
        })

        return Event(subject, type, event_data, 0, True)
