from json import dumps
from typing import Dict, Tuple

from unidecode import unidecode

from ._Action import Action
from ._Conditions import Conditions
from ._Exclusions import Exclusions


class Benefit(object):
    def __init__(self, raw_benefit):
        # type: (Dict) -> None

        self.id = raw_benefit.get("id")
        self.name = unidecode(raw_benefit.get("name"))
        self.user_description = raw_benefit.get("userDescription")
        self.priority = int(raw_benefit.get("priority")) if raw_benefit.get("priority") else None
        self.automatic = raw_benefit.get("automatic")
        self.tip_included = raw_benefit.get("tipIncluded") if raw_benefit.get("tipIncluded") else False
        self.ask_value = bool(raw_benefit.get("askValue"))
        conditions = raw_benefit.get("conditions") if raw_benefit.get("conditions") else {}
        self.conditions = Conditions(conditions)
        actions = [self._get_action(e) for e in raw_benefit.get("actions", {}).items() if self._validate_action(e)]
        self.actions = actions
        exclusions = raw_benefit.get("exclusions") if raw_benefit.get("exclusions") else {}
        self.exclusions = Exclusions(exclusions)
        self.raw = raw_benefit
        self.times_to_apply = raw_benefit.get("timesToApply")
        self.group = raw_benefit.get("group")

    def to_json(self):
        # type: () -> str

        return dumps(self, default=lambda o: o.__dict__ if hasattr(o, '__dict__') else str(o), sort_keys=True)

    def _get_action(
        self,
        e,      # type: Tuple
    ):
        # type: (...) -> Action

        return Action(
            {
                "order": e[0],
                "name": e[1].items()[0][0],
                "value": e[1].items()[0][1],
                "seat": self._get_benefit_seat(e[1].items()),
                "maxValue": e[1]["maxValue"] if "maxValue" in e[1] else None,
            }
        )

    @staticmethod
    def _validate_action(e):
        # type: (Tuple) -> bool

        action_name = e[1].items()[0][0]
        action_value = e[1].items()[0][1]

        if action_name == 'discountAmountOnTotal':
            if action_value == 0:
                return False

        if action_name == 'discountPercentageOnTotal':
            if action_value == 0 or action_value > 100:
                return False

        if action_name == 'itemsToAdd':
            if action_value is None:
                return False

        return True

    @staticmethod
    def _get_benefit_seat(
        benefit_tuple,  # type: Tuple
    ):
        # type: (...) -> str

        seat = None

        if len(benefit_tuple) >= 2 and benefit_tuple[1][0] == "seat":
            seat = benefit_tuple[1][1]
        elif type(benefit_tuple[0][1]) == "list":
            seat = benefit_tuple[0][1][0].get("seat", None)

        return seat
