import json

from logging import Logger
from typing import (
    Any,
    Optional,
    Union,
)

from helper import remove_accents
from posot import OrderTaker

from model.config import Config
from model.repository import PosRepositoryModel
from model.services import (
    OrderServiceModel,
)
from model.error_type import PosValidationErrorsType
from model.exception import ValidationError
from model.order_detail import OrderDetail
from interactor.route.order.apply_benefit.dto import (
    ApplyBenefitRequest,
)
from validation_util import (
    check_if_pos_id_is_valid,
    validate_api_key,
    check_if_order_is_in_progress_or_totaled,
)


class ApplyBenefitInteractor(object):
    def __init__(
        self,               # type: ApplyBenefitInteractor
        logger,             # type: Logger
        config,             # type: Config
        pos_repository,     # type: PosRepositoryModel
        order_service,      # type: OrderServiceModel
    ):
        # type: (...) -> None

        self.logger = logger
        self.config = config
        self.pos_repository = pos_repository
        self.order_service = order_service
        self.model = None
        self.pos_ot = None  # type: Optional[OrderTaker]

    def execute(
        self,       # type: ApplyBenefitInteractor
        request,    # type: ApplyBenefitRequest
    ):
        # type: (...) -> Optional[Union[OrderDetail, str]]

        pos_id = validate_api_key(
            request=request,
            secure_api_key_list=self.config.api_key_mapping,
        )
        check_if_pos_id_is_valid(
            repository=self.pos_repository,
            pos_id=pos_id,
        )
        self.model = self.pos_repository.get_model(pos_id=pos_id)
        self.pos_ot = self.pos_repository.get_pos_ot(model=self.model)

        if self.pos_repository.has_current_order(model=self.model):
            check_if_order_is_in_progress_or_totaled(
                repository=self.pos_repository,
                model=self.model,
            )

        user_auth_level = int(self.model.find("Operator[@state='LOGGEDIN']").get("level") or -1)
        applied_benefit_dto = self.pos_repository.apply_benefit(
            pos_id=pos_id,
            benefit=request.benefit,
            user_auth_level=user_auth_level,
        )

        if applied_benefit_dto.benefit_applied:
            self.logger.info("Success benefit applied")
            order = self.pos_repository.get_current_order(model=self.model)
            order_id = order.get('orderId')
            order = self.pos_repository.get_order_details(
                pos_id=pos_id,
                order_id=order_id,
                pos_ot=self.pos_ot,
            )
            if order:
                return self.order_service.convert_mw_order_to_order_detail(order=order)

            return applied_benefit_dto.response_detail

        else:
            self._raise_custom_error(benefit_data=applied_benefit_dto.response_detail)

    def _raise_custom_error(
        self,
        benefit_data,    # type: Any[Union[str, json]]
    ):
        # type: (...) -> None

        if '\0' in benefit_data:
            error_code, message = benefit_data.split('\0')
        else:
            error_code = benefit_data
            message = ""

        self.logger.info("Error applying benefit. BenefitResponse: {}|{}".format(error_code, message))

        raise ValidationError(
            PosValidationErrorsType.CannotApplyBenefit,
            message,
        )

