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

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


class StoredOrderUnsplitter(OrderChangerProductionBox):

    def __init__(
        self,                       # type: StoredOrderUnsplitter
        name,                       # type: str
        sons,                       # type: object
        prod_states_clean_cache,    # type: List[str]
        logger=None,                # type: Optional[Logger]
    ):
        # type: (...) -> None

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

        self.prod_states_clean_cache = prod_states_clean_cache

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

        if not order.stored_split_order:
            return order

        cloned_order = self._get_cloned_unsplitted_order(order=order)
        cached_order = self.get_order(order_id=cloned_order.order_id)
        if cached_order is None:
            self.save_order(order=cloned_order)
        else:
            self._update_cached_order(
                cloned_order=cloned_order,
                cached_order=cached_order,
            )

        updated_order = self.get_order(order_id=cloned_order.order_id)
        if updated_order.prod_state in self.prod_states_clean_cache:
            self.delete_order(order_id=updated_order.order_id)

        return updated_order

    def _update_cached_order(
        self,            # type: StoredOrderUnsplitter
        cloned_order,    # type: ProductionOrder
        cached_order,    # type: ProductionOrder
    ):
        # type: (...) -> None

        if cloned_order.prod_state == ProdStates.INVALID and len(cloned_order.items) == 0:
            return

        self._update_cached_items(
            cloned_order=cloned_order,
            cached_order=cached_order,
        )

        if cached_order.state != cloned_order.state or cached_order.prod_state != cloned_order.prod_state:
            cached_order.items.extend(cloned_order.items)
            cloned_order.items = cached_order.items
            self.save_order(order=cloned_order)
        else:
            cached_order.items.extend(cloned_order.items)
            self.save_order(order=cached_order)

    @staticmethod
    def _update_cached_items(
        cloned_order,    # type: ProductionOrder
        cached_order,    # type: ProductionOrder
    ):
        # type: (...) -> None

        items_to_remove_from_cache = []
        for cloned_item in cloned_order.items:
            for cached_item in cached_order.items:
                if cloned_item.get_line_id() == cached_item.get_line_id():
                    items_to_remove_from_cache.append(cached_item)
                    break

        for item_to_remove in items_to_remove_from_cache:
            cached_order.items.remove(item_to_remove)

    @staticmethod
    def _get_cloned_unsplitted_order(
        order,    # type: ProductionOrder
    ):
        # type: (...) -> ProductionOrder

        order_cloned = order.clone(items=order.items)
        split_indexes = order.order_id.split("-")
        if len(split_indexes) == 1:
            order_cloned.order_id = split_indexes[0]
        else:
            order_cloned.order_id = "-".join(split_indexes[:len(split_indexes) - 1])

        order_cloned.stored_split_order = False
        return order_cloned
