from logging import Logger
from mw_helper import ensure_list
from mwrepository import ProductRepository
from production.model import ProductionOrder, Item
from production.view import ProductionView
from production.box._OrderChangerProductionBox import OrderChangerProductionBox
from typing import List


class ItemSorterBox(OrderChangerProductionBox):
    def __init__(self, name, sons, product_repository, sort_order, item_property_sorters, logger):
        # type: (str, ProductionView, ProductRepository, List[str], List[str], Logger) -> None

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

        self.sort_order = None
        self.item_property_sorters = ensure_list(item_property_sorters)
        self.logger = logger

        if sort_order is not None:
            self.sort_order = {line: product_repository.get_part_codes_of_jit_lines([line]) for line in sort_order}

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

        order = self.sort_order_items(order)
        if self.item_property_sorters is None or len(order.items) == 0:
            return order

        self._sort_order_items_by_attributes(order)
        return order

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

        try:
            order.items = sorted(order.items, key=lambda item: self._manager_item_filter(item))
        except Exception as _:
            self.logger.exception("Error item sorter box")

    def _manager_item_filter(self, item):
        # type: (Item) -> ()

        return [self._parse_value(getattr(item, property_name)) for property_name in self.item_property_sorters]

    @staticmethod
    def _parse_value(property_value):
        # type: (str) -> ()

        try:
            return int(property_value) if property_value.isdigit() else property_value
        except ValueError:
            return property_value

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

        if self.sort_order is None:
            return order

        order_items = order.items
        order.items = []
        for jit_line in self.sort_order:
            items_to_remove = []
            for item in order_items:
                if item.level > 0:
                    continue

                if item.part_code in self.sort_order[jit_line]:
                    order.items.append(item)
                    items_to_remove.append(item)

            for item in items_to_remove:
                order_items.remove(item)

        for item in order_items:
            order.items.append(item)

        return order
