from xml.etree import cElementTree as eTree

from application.service import OrderService, BenefitService
from application.model import Configurations
from typing import Dict, List, Optional


class OnOrderReopenInteractor(object):

    def __init__(
        self,
        configs,                        # type: Configurations
        order_service,                  # type: OrderService
        benefit_service,                # type: BenefitService
        include_table_orders=False,     # type: Optional[bool]
    ):
        # type: (...) -> None

        self.configs = configs
        self.order_service = order_service
        self.benefit_service = benefit_service
        self.include_table_orders = include_table_orders

    def execute(
        self,
        pos_id,         # type: int
        table_id=None,  # type: Optional[str]
    ):
        # type: (...) -> Optional[eTree.XML]

        static_uow = self.benefit_service.get_static_unit_of_work(
            pos_id=pos_id,
            table_id=table_id,
        )

        static_uow.pos_ot.blkopnotify = True
        order_picture = static_uow.order_picture
        order = self.order_service.get_order(
            pos_id=pos_id,
            model=static_uow.model,
            create_order=False,
            order_picture=order_picture,
            static_uow=static_uow,
        )
        if self.include_table_orders is False and order.table_id is not None:
            return

        if self.include_table_orders is True and order.table_id is None:
            return

        state = order_picture.get("state") or "" if order_picture else ""
        if state != "IN_PROGRESS":
            return order_picture

        order = self.order_service.get_order(
            pos_id=pos_id,
            order_picture=order_picture,
            static_uow=static_uow,
        )
        order_picture = order.order_picture

        order_picture = self.benefit_service.save_persistent_benefits(
            pos_id=pos_id,
            order_picture=order_picture,
        )
        static_uow.set_order_picture(order_picture=order_picture)

        order_benefits = self.order_service.get_applied_benefits_from_order_picture(
            pos_id=pos_id,
            order_picture=order_picture,
        )
        if not order_benefits:
            return order_picture

        benefit_pre_total_sequence = self.order_service.get_benefit_pre_total_sequence_from_order_picture(
            pos_id=pos_id,
            order_picture=order_picture,
        )
        benefits_to_remove = self._get_benefits_to_remove(
            order_benefits,
            benefit_pre_total_sequence
        )
        if len(benefits_to_remove) > 0:
            self.benefit_service.remove_benefits(
                pos_id=pos_id,
                benefit_keys=benefits_to_remove,
                static_uow=static_uow,
            )
            return static_uow.order_picture

    def _get_benefits_to_remove(
        self,                           # type: OnOrderReopenInteractor
        applied_benefits,               # type: List
        benefit_pre_total_sequence,     # type: List
    ):
        # type: (...) -> List

        benefits_to_remove = []
        for applied_benefit in applied_benefits:
            benefit_key_to_remove = self._get_benefit_id_to_remove(
                applied_benefit=applied_benefit,
                benefit_pre_total_sequence=benefit_pre_total_sequence
            )
            if benefit_key_to_remove:
                benefits_to_remove.append(benefit_key_to_remove)

        return benefits_to_remove

    @staticmethod
    def _get_benefit_id_to_remove(
        applied_benefit,                # type: Dict
        benefit_pre_total_sequence,     # type: Dict
    ):
        # type: (...) -> Optional[int]

        benefit_applied = applied_benefit.get("benefit_applied")
        if not benefit_applied:
            return None

        benefit = applied_benefit.get("benefit", {})
        is_loyalty_benefit = benefit.get("is_loyalty_benefit", False)
        if (
            applied_benefit.get("benefit_key", "") in benefit_pre_total_sequence
            and benefit.get("automatic", "") != "ON_TOTAL"
            and not is_loyalty_benefit
            and benefit.get("persistent", True)
        ):
            return None

        return applied_benefit.get("benefit_key")
