from logging import Logger
from typing import (
    List,
    Optional,
    Union,
)

from production.box import ProductionBox
from production.box._OrderChangerProductionBox import OrderChangerProductionBox
from production.model import Item


class ItemFilterBox(OrderChangerProductionBox):
    def __init__(
        self,
        name,                               # type: str
        sons,                               # type: Optional[Union[List[ProductionBox]], ProductionBox]
        allowed_part_codes=None,            # type: Optional[List[int]]
        forbidden_part_codes=None,          # type: Optional[List[int]]
        inherit_comments=False,             # type: Optional[bool]
        logger=None,                        # type: Logger
    ):
        # type: (...) -> None

        super(ItemFilterBox, self).__init__(name, sons, logger)

        self.allowed_part_codes = allowed_part_codes
        self.forbidden_part_codes = forbidden_part_codes
        self.inherit_comments = inherit_comments

    def change_order(self, order):
        filtered_items = []  # type: List[Item]
        for item in order.items:
            self.handle_item(item, filtered_items)

        order.items = filtered_items
        return order

    def handle_item(self, item, filtered_items, father=None):
        sons = []
        if len(item.items) > 0:
            for son in item.items:
                self.handle_item(son, sons, item)

            if item.item_type in ("OPTION",) and not sons:
                return

        self._set_item_tag(item, father)
        if item.has_tag("no-cook"):
            self._fix_sons_quantity(item, sons)
            if self.inherit_comments:
                for son in item.items:
                    son.repeat_comment_from_father(father=item)

            filtered_items.extend(sons)
        else:
            item.items = sons
            filtered_items.append(item)

    def forbidden_part_code(self, item):
        if self.forbidden_part_codes is None:
            return True

        return self.forbidden_part_codes and item.part_code in self.forbidden_part_codes

    def allowed_part_code(self, item):
        if self.allowed_part_codes is None:
            return True

        return self.allowed_part_codes and item.part_code in self.allowed_part_codes

    def _set_item_tag(self, item, father):
        is_ingredient = item.is_ingredient() or (father is not None and father.is_product() and item.is_product())
        father_forbidden = father is not None and self.forbidden_part_code(father)
        if self.forbidden_part_code(item) or (is_ingredient and father_forbidden):
            item.add_tag("no-cook")
            return

        if not self.allowed_part_code(item):
            father_allowed = father is not None and self.allowed_part_code(father)
            if is_ingredient and father_allowed:
                return

            item.add_tag("dont-need-cook")

    @staticmethod
    def _fix_sons_quantity(father, sons):
        for son in sons:
            son.handle_remove_father(father)
