import json
import logging
from typing import (
    List,
    Optional,
)

from httpclient import (
    HttpRequest,
    HttpResponse,
)
from httpmessagehandler import HttpMessageHandler
from messagebus import (
    Event,
    Message,
    MessageBus,
)
from messagehandler import (
    MessageHandler,
    MessageHandlerBuilder,
)

logger = logging.getLogger(name=__name__)


class EventHttpMessageHandler(MessageHandler):

    def __init__(
        self,
        message_bus: MessageBus,
        message_handler_builder: MessageHandlerBuilder,
        fields_to_pass_through: Optional[List[str]] = None
    ) -> None:

        self.fields_to_pass_through = fields_to_pass_through or []

        self.http_message_handler = HttpMessageHandler(
            message_handler_builder=message_handler_builder,
            message_bus=message_bus,
        )

    def handle_event(
        self,
        message_bus: MessageBus,
        event: Event,
    ) -> None:

        logger.info(f"Received: {event}")
        http_request = self._transform_event_into_http_request(event=event)
        http_response = self.http_message_handler.handle_request(request=http_request)

        out_event = self._transform_http_response_in_event(
            http_response=http_response,
            input_event=event,
            http_request=http_request,
        )
        message_bus.publish_event(event=out_event)
        logger.info(f"Published: {out_event}")

    def handle_message(
        self,
        message_bus: MessageBus,
        message: Message,
    ) -> None:

        raise NotImplementedError()

    @staticmethod
    def _transform_event_into_http_request(
        event: Event,
    ) -> HttpRequest:

        request = json.loads(s=event.data.decode())
        body = None
        if "body" in request and request["body"] is not None:
            body = json.dumps(request["body"])

        return HttpRequest(
            url=request["path"],
            method=request["method"],
            body=body,
            headers=request["headers"],
        )

    def _transform_http_response_in_event(
        self,
        http_response: HttpResponse,
        input_event: Event,
        http_request: HttpRequest,
    ) -> Event:

        http_response.headers.update(http_request.headers)
        response = {
            "statusCode": http_response.status_code,
            "headers": http_response.headers,
            "body": json.loads(http_response.body.decode()) if http_response.body else None,
        }
        original_request_json = json.loads(s=input_event.data.decode())
        for field in self.fields_to_pass_through:
            if field in original_request_json:
                response[field] = original_request_json[field]

        return Event(
            subject="ApiEventResponse",
            data=json.dumps(obj=response).encode(),
        )
