from datetime import datetime
from logging import Logger

from production.model import Item
from typing import (
    Optional,
    List,
)

from ._OrderChangerProductionBox import OrderChangerProductionBox
from ..model import (
    ProductionOrder,
    StateEvent,
    create_states_from_state,
)

timestamp_format = "%Y-%m-%dT%H:%M:%S.%f"


class FilterDeletedItemsNotSentToKitchenBox(OrderChangerProductionBox):

    def __init__(
        self,                            # type: FilterDeletedItemsNotSentToKitchenBox
        name,                            # type: str
        sons,                            # type: object
        state_to_delete_voided_items,    # type: str
        logger=None,                     # type: Optional[Logger]
    ):
        super(FilterDeletedItemsNotSentToKitchenBox, self).__init__(name, sons, logger)

        self.state_to_delete_voided_items = create_states_from_state(state=state_to_delete_voided_items)

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

        self._remove_deleted_items_in_last_in_progress_state(order=order)
        return order

    def _remove_deleted_items_in_last_in_progress_state(
        self,     # type: FilterDeletedItemsNotSentToKitchenBox
        order,    # type: ProductionOrder
    ):
        # type: (...) -> None

        filtered_states = self._get_filtered_states(order=order)
        last_state_datetime = datetime.strptime(
            order.created_at,
            timestamp_format,
        )
        for i, state in enumerate(filtered_states):
            state_datetime = datetime.strptime(
                state.timestamp_gmt,
                timestamp_format,
            )
            self._remove_empty_items_before_last_state(
                items=order.items,
                last_state_datetime=last_state_datetime,
                current_state_datetime=state_datetime,
            )
            last_state_datetime = state_datetime

    def _remove_empty_items_before_last_state(
        self,                       # type: FilterDeletedItemsNotSentToKitchenBox
        items,                      # type: List[Item]
        last_state_datetime,        # type: datetime
        current_state_datetime,     # type: datetime
    ):
        # type: (...) -> None

        for item in items[:]:
            if item.qty == 0:
                line_created_at = datetime.strptime(
                    item.created_at,
                    timestamp_format,
                )

                if line_created_at >= last_state_datetime:
                    line_last_updated = datetime.strptime(
                        item.last_updated,
                        timestamp_format + "Z",
                    )

                    if line_last_updated <= current_state_datetime:
                        items.remove(item)

            self._remove_empty_items_before_last_state(
                items=item.items,
                last_state_datetime=last_state_datetime,
                current_state_datetime=current_state_datetime,
            )

    @staticmethod
    def _get_next_state_datetime(
        current_index,    # type: int
        states,           # type: List[StateEvent]
    ):
        # type: (...) -> Optional[datetime]

        if current_index + 1 < len(states):
            next_state = states[current_index + 1]
            return datetime.strptime(
                next_state.timestamp_gmt,
                timestamp_format,
            )

        return None

    def _get_filtered_states(
        self,   # type: FilterDeletedItemsNotSentToKitchenBox
        order,  # type: ProductionOrder
    ):
        # type: (...) -> List[StateEvent]

        filtered_states = []
        for state in order.state_history:
            if state.state in self.state_to_delete_voided_items:
                filtered_states.append(state)

        return sorted(
            filtered_states,
            key=lambda item: item.timestamp_gmt,
        )
