import json

from application.model import AsyncUuidMessageProcessor

from messagebus import (
    DataType,
    Message,
    MessageBus,
    AckMessage,
    Event,
    InternalErrorMessage,
)
from typing import (
    Any,
    Optional,
    Dict,
)
from application.interactor.get_coupons_on_payment import GetBenefitOnPaymentInteractor
from application.interactor.get_coupons_on_payment.dto import (
    GetBenefitOnPaymentRequest,
    PaymentInfo,
)


class GetBenefitOnPaymentProcessor(AsyncUuidMessageProcessor):
    def __init__(
        self,          # type: GetBenefitOnPaymentProcessor
        interactor,    # type: GetBenefitOnPaymentInteractor
    ):
        # type: (...) -> None

        super(GetBenefitOnPaymentProcessor, self).__init__()
        self.interactor = interactor

    def parse_data(
        self,          # type: GetBenefitOnPaymentProcessor
        data,          # type: str
        event_type,    # type: str
    ):
        # type: (...) -> GetBenefitOnPaymentRequest

        request_json = json.loads(data.decode('utf-8'))
        pos_id = request_json["posId"]
        loyalty_customer_id = request_json["customerId"]
        payment_info = json.loads(request_json["paymentPicture"])

        return GetBenefitOnPaymentRequest(
            pos_id=pos_id,
            loyalty_customer_id=loyalty_customer_id,
            payment_info=PaymentInfo(
                tender_id=int(payment_info["tenderId"]),
                tender_amount=float(payment_info["tenderAmount"]),
                tender_desc=payment_info["tenderDescr"],
                tender_type=int(payment_info["tenderType"]),
                tender_detail="{}",
                change_amount=float(payment_info.get("changeAmount")),
            ),
        )

    def call_business(
        self,       # type: GetBenefitOnPaymentProcessor
        request,    # type: GetBenefitOnPaymentRequest
    ):
        # type: (...) -> str

        return self.interactor.get_benefit_on_payment(request=request)

    def format_response(
        self,           # type: GetBenefitOnPaymentProcessor
        message_bus,    # type: MessageBus
        message,        # type: Message
        event,          # type: Optional[Event]
        request,        # type: Optional[Any]
        response,       # type: Optional[Dict]
    ):
        # type: (...) -> None

        data = b""
        if response is not None:
            data = json.dumps(response).encode("utf-8")

        message_bus.reply_message(
            message=message,
            reply_message=AckMessage(
                data_type=DataType.string,
                data=data,
            )
        )

    def format_exception(
        self,           # type: GetBenefitOnPaymentProcessor
        message_bus,    # type: MessageBus
        message,        # type: Message
        event,          # type: Optional[Event]
        input_obj,      # type: Optional[Any]
        exception,      # type: Exception
    ):
        # type: (...) -> None

        message_bus.reply_message(
            message=message,
            reply_message=InternalErrorMessage(exception)
        )

    def format_parse_exception(
        self,           # type: GetBenefitOnPaymentProcessor
        message_bus,    # type: MessageBus
        message,        # type: Message
        event,          # type: Event
        data,           # type: Any
        exception,      # type: Exception
    ):
        # type: (...) -> None

        self.format_exception(
            message_bus=message_bus,
            message=message,
            event=event,
            input_obj=data,
            exception=exception,
        )
