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


class OnOrderReopenInteractor(object):

    def __init__(self, configs, order_service, benefit_service):
        # type: (Configurations, OrderService, BenefitService) -> None

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

    def execute(self, pos_id):
        # type: (int) -> None

        order_picture = self.order_service.get_order_picture(pos_id)

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

        order = self.order_service.get_order(pos_id, order_picture=order_picture)
        order_picture = order.order_picture
        remove_manual = order.table_id is None

        applied_benefits = self.order_service.get_applied_benefits_from_order_picture(
            pos_id=pos_id,
            order_picture=order_picture,
            return_benefit_pre_total_sequence=True,
        )
        if not applied_benefits:
            return

        benefits_to_remove = self._get_benefits_to_remove(applied_benefits)
        if len(benefits_to_remove) > 0:
            self.benefit_service.remove_benefits(pos_id, benefits_to_remove, order_picture, delete_manual=remove_manual)

        self.benefit_service.unset_applied_benefit(pos_id, ["IN_PROGRESS"])

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

        benefits_to_remove = []
        for applied_benefit in applied_benefits["benefitList"]:
            benefit_key_to_remove = self._get_benefit_id_to_remove(
                applied_benefit=applied_benefit,
                benefit_pre_total_sequence=applied_benefits["benefitPreTotalSequence"]
            )
            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
        ):
            return None

        return applied_benefit.get("benefit_key")
