import json
from logging import Logger
from xml.etree import cElementTree as eTree

from model.config import Config
from model.repository import PosRepositoryModel
from model.services import (
    CouponServiceModel,
    OrderServiceModel
)
from model.error_type import PosValidationErrorsType
from model.exception import (
    ValidationError,
    ExternalServiceErrors,
)
from validation_util import (
    check_if_pos_id_is_valid,
    validate_api_key,
    check_if_order_is_in_progress_or_totaled,
)
from posot import OrderTaker

from interactor.route.order.get_coupons.dto import GetCouponRequest

from typing import (
    List,
    Optional,
)


class GetCouponInteractor(object):
    def __init__(
        self,
        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]
        self.price_list = None

    def execute(self, request):
        # type: (GetCouponRequest) -> List

        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
            )

        try:
            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
            )
        except Exception as ex:
            error_message = "Error retrieving applied coupons. Pos ID: {}".format(pos_id)
            self.logger.error(
                msg=error_message,
                exc_info=ex,
            )
            raise ExternalServiceErrors(PosValidationErrorsType.CouponValidationError, error_message)

        if order:
            return self._get_applied_coupons_details(order=order)

        error_message = "Error retrieving applied coupons. Order: {}".format(order_id)
        self.logger.error(error_message)
        raise ValidationError(PosValidationErrorsType.CouponValidationError, error_message)

    def _get_applied_coupons_details(
        self,
        order,      # type: eTree
    ):
        # type: (...) -> List

        benefits = order.find(".//OrderProperty[@key=\"BENEFIT_LIST\"]")
        if benefits is not None:
            benefits = json.loads(benefits.get("value"))
            benefits = json.loads(benefits.get("benefitList"))
            benefits_details = []
            for benefit in benefits:
                benefit_dict = {
                    "name": benefit.get("benefit").get("userDescription"),
                    "id": benefit.get("benefit_key"),
                    "value": benefit.get("benefit_total_value"),
                }
                benefits_details.append(benefit_dict)

            self.logger.info("Success retrieving applied coupons. Coupons: {}".format(benefits))
            return benefits_details

        return []
