import json

from application.interactor import LockBenefitInteractor
from application.model import AsyncUuidMessageProcessor
from application.model.customexception import ClientCustomError, NotFoundError, InUseError, GoneError
from application.processor.get_and_lock_coupon.dto import GetAndLockCouponErrorCode
from messagebus import (
    DefaultToken,
    DataType,
    Message,
    MessageBus,
    AckMessage,
    Event,
    InternalErrorMessage,
)
from typing import (
    Any,
    Optional,
)
from ..tokens import ResponseToken


class LockBenefitProcessor(AsyncUuidMessageProcessor):
    def __init__(self, interactor):
        # type: (LockBenefitInteractor) -> None

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

    def parse_data(self, data, event_type):
        # type: (str, str) -> Any

        parsed_data = json.loads(data)
        benefit_id = str(parsed_data["benefitId"])
        pos_id = int(parsed_data["posId"])
        return benefit_id, pos_id

    def call_business(self, params):
        # type: ((int, str)) -> None

        benefit_id, pos_id = params

        self.interactor.lock_benefit(
            benefit_id=benefit_id,
            pos_id=pos_id,
        )

    def format_response(
        self,
        message_bus,  # type: MessageBus
        message,      # type: Message
        event,        # type: Optional[Event]
        request,      # type: Optional[Any]
        response,     # type: str
    ):
        message_bus.reply_message(
            message=message,
            reply_message=AckMessage(response)
        )

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

        data = ""
        if isinstance(exception, ClientCustomError):
            data = json.dumps({
                "message": {
                    "pt": exception.message.pt,
                    "en": exception.message.en,
                    "es": exception.message.es,
                }
            }).encode("utf-8")
            error_code = GetAndLockCouponErrorCode.PARTNER_CUSTOM_ERROR
        elif isinstance(exception, NotFoundError):
            error_code = GetAndLockCouponErrorCode.COUPON_NOT_FOUND
        elif isinstance(exception, InUseError):
            error_code = GetAndLockCouponErrorCode.COUPON_LOCKED
        elif isinstance(exception, GoneError):
            error_code = GetAndLockCouponErrorCode.COUPON_ALREADY_USED
        else:
            message_bus.reply_message(
                message=message,
                reply_message=InternalErrorMessage(ex=exception)
            )
            return

        message_bus.reply_message(
            message=message,
            reply_message=Message(
                token=ResponseToken.TK_LOYALTY_ERROR.value,
                data_type=DataType.param,
                data=error_code.name + "\0" + data,
            ),
        )

    def format_parse_exception(self, message_bus, message, event, data, exception):
        message_bus.reply_message(message, Message(DefaultToken.TK_SYS_NAK, DataType.param, str(exception)))
