from mw_helper import ensure_list, convert_to_dict
from production.model import ProductionOrder, Item
from typing import Union, List, Any, Callable, Optional


class AllowedForbiddenFilter(object):
    def __init__(
        self,
        allowed_values,             # type: Union[Optional[str], List[str]]
        forbidden_values,           # type: Union[Optional[str], List[str]]
        keep_son_parts="false",     # type: Optional[str]
        inherit_comments="false",   # type: Optional[str]
    ):
        # type: (...) -> None

        self.allowed_values = None
        if allowed_values is not None:
            self.allowed_values = convert_to_dict(ensure_list(allowed_values))

        self.forbidden_values = None
        if forbidden_values is not None:
            self.forbidden_values = convert_to_dict(ensure_list(forbidden_values))

        self.keep_son_parts = str(keep_son_parts).lower() == "true"
        self.inherit_comments = str(inherit_comments).lower() == "true"

    def filter_items(self, order, item_value_retriever):
        # type: (ProductionOrder, Callable[[Item], Any]) -> ProductionOrder

        new_items = []
        for item in order.items:
            self.add_item(item, item_value_retriever, new_items)

        order.items = new_items

        return order

    def add_item(self, item, item_value_retriever, new_items):
        values = ensure_list(item_value_retriever(item))
        forbidden_item = False
        if self.forbidden_values is not None:
            list_to_validate = self.forbidden_values
            if self._has_value_in_list(list_to_validate, values):
                forbidden_item = True

        if self.allowed_values is not None:
            list_to_validate = self.allowed_values
            if not self._has_value_in_list(list_to_validate, values):
                forbidden_item = True

        must_ignore_sons = not self.keep_son_parts or len(item.items) == 0
        if forbidden_item and must_ignore_sons:
            return

        son_items = []
        for son in item.items:
            self.add_item(son, item_value_retriever, son_items)

        if forbidden_item:
            self._fix_sons_quantity(item, son_items)
            new_items.extend(son_items)
        else:
            item.items = son_items
            new_items.append(item)

    @staticmethod
    def _has_value_in_list(list_to_validate, values):
        for v in values:
            if v in list_to_validate:
                return True

        return False

    def _fix_sons_quantity(
        self,
        parent,
        sons,
    ):
        for son in sons:
            son.handle_remove_father(
                father=parent,
                inherit_comments=self.inherit_comments,
            )
