from logging import Logger

from mw_helper import ensure_iterable
from typing import (
    Dict,
    List,
    Union,
)

from production.model import (
    ProductionOrder,
    Item,
)
from ._OrderChangerProductionBox import OrderChangerProductionBox


class ComboTaggedWhenAllHasTagBox(OrderChangerProductionBox):
    def __init__(
        self,
        name,           # type: object
        sons,           # type: object
        tags,           # type: Union[List, str]
        tag_to_add,     # type: Union[List, str]
        logger=None,    # type: Logger
    ):
        # type: (...) -> None

        super(ComboTaggedWhenAllHasTagBox, self).__init__(name=name, sons=sons, logger=logger)
        self.tags = ensure_iterable(value=tags)
        self.tag_to_add = tag_to_add

    def change_order(
        self,
        order,  # type:  ProductionOrder
    ):
        # type: (...) ->  ProductionOrder

        if not self.tag_to_add:
            for item in order.items:
                self._add_multiple_tags(item=item)
        else:
            for item in order.items:
                if item.item_type == "COMBO" and self.all_sons_have_tags(sons=item.items):
                    item.add_tag(tag=self.tag_to_add)

        return order

    def _add_multiple_tags(
        self,
        item,   # type: Item
    ):
        # type: (...) -> None

        tags_dict = dict([(tag, True) for tag in self.tags])
        self.fill_all_sons_tags(
            sons=item.items,
            tags=tags_dict,
        )

        if item.item_type == "COMBO":
            for tag in tags_dict.keys():
                if tags_dict[tag]:
                    item.add_tag(tag=tag)

    def all_sons_have_tags(
        self,
        sons,   # type: List
    ):
        # type: (...) -> bool

        for son in sons:
            if son.item_type not in ('OPTION', 'COMBO'):
                if not son.has_some_tag(tags=self.tags):
                    return False
            else:
                all_have_tags = self.all_sons_have_tags(sons=son.items)
                if son.item_type == "COMBO" and all_have_tags:
                    son.add_tag(tag=self.tag_to_add)
                if not all_have_tags:
                    return False

        return True

    def fill_all_sons_tags(
        self,
        sons,   # type: List
        tags,   # type: Dict
    ):
        # type: (...) -> None

        for son in sons:
            if son.item_type not in ('OPTION', 'COMBO'):
                for tag in tags.keys():
                    tags[tag] = tags[tag] and son.has_tag(tag=tag)
            else:
                self.fill_all_sons_tags(
                    sons=son.items,
                    tags=tags,
                )
                if son.item_type == "COMBO":
                    for tag in tags.keys():
                        if tags[tag]:
                            son.add_tag(tag=tag)
