import json

from application.processor.add_benefit.dto import AddBenefitValidationErrorCode
from typing import Optional

from application.interactor import AddBenefitToApplyInteractor
from application.model import Configurations
from application.model.exceptions import (
    UserLevelNotAllowedException,
)
from application.model.transactions import AddBenefitToApplyUnitOfWork
from application.service import OrderService, BenefitService
from messagebus import (
    DataType,
    DefaultToken,
    Event,
    Message,
    MessageBus,
    NakMessage,
)
from messageprocessorutil import UuidMessageProcessor


class AddBenefitProcessor(UuidMessageProcessor):
    def __init__(self, configs, interactor, order_service, benefit_service):
        # type: (Configurations, AddBenefitToApplyInteractor, OrderService, BenefitService) -> None

        super(AddBenefitProcessor, self).__init__()
        self.configs = configs
        self.interactor = interactor
        self.order_service = order_service
        self.benefit_service = benefit_service
        self.logger = configs.logger

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

        parsed_data = json.loads(data)
        pos_id = int(parsed_data.get("posId"))
        raw_benefit = parsed_data.get("benefit", {})
        benefit_applier = parsed_data.get("benefit_applier")
        tender_id = parsed_data.get("tender_id")
        user_auth_level = parsed_data.get("user_auth_level")

        return self.benefit_service.get_unit_of_work(
                pos_id,
                raw_benefit,
                benefit_applier=benefit_applier,
                tender_id=tender_id,
                user_auth_level=user_auth_level
        )

    def call_business(self, uow):
        # type: (AddBenefitToApplyUnitOfWork) -> None

        self.interactor.apply(uow)

    def format_response(self, message_bus, message, event, request, response):
        message_bus.reply_message(message, Message(DefaultToken.TK_SYS_ACK, DataType.string, ""))

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

        if isinstance(exception, UserLevelNotAllowedException):
            error_code = AddBenefitValidationErrorCode.NDISCOUNT_ERROR_USER_MIN_LEVEL.name
            message_bus.reply_message(
                message=message,
                reply_message=NakMessage(
                    data=error_code + "\0" + str(exception.min_level_required),
                    data_type=DataType.param,
                ),
            )
        else:
            message_bus.reply_message(
                message=message,
                reply_message=NakMessage(
                    data=str(exception),
                    data_type=DataType.param,
                ),
            )

    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)))
