from datetime import date, datetime
from xml.etree import cElementTree as eTree

from model.order_detail import OrderDetail, AdditionalProperty, Tender, Item, \
    StateHistory
from model.services import OrderServiceModel
from iso8601 import parse_date
from typing import List


class OrderService(OrderServiceModel):

    def convert_mw_order_to_order_detail(self, order):
        # type: (eTree) -> OrderDetail

        order_detail = OrderDetail()

        order = order.find("Order") or order
        order_detail.order_id = int(order.get("orderId"))
        order_detail.sale_type = order.get("saleTypeDescr")
        order_detail.state = order.get("state")
        order_detail.total_amount = float(order.get("totalGross"))
        order_detail.total_tender = float(order.get("totalTender"))
        order_detail.due_amount = float(order.get("dueAmount"))
        order_detail.created_at = self._parse_timestamp(order.get("createdAt"))
        order_detail.state_history = self._build_state_history(order)
        order_detail.tenders = self._build_tenders(order)
        order_detail.additional_properties = self._build_additional_properties(order)
        order_detail.items = self._build_items(order)

        return order_detail

    def _build_tenders(self, order):
        # type: (eTree) -> List[Tender]

        tenders_list = []
        tenders = order.findall(".//Tender")
        for tender in tenders:
            tender_object = Tender()

            tender_object.sequence_id = int(tender.get("tenderId"))
            tender_object.type_id = int(tender.get("tenderType"))
            tender_object.type_name = tender.get("tenderDescr")
            tender_object.timestamp = self._parse_timestamp(tender.get("timestamp"))
            tender_object.amount = float(tender.get("tenderAmount"))

            tenders_list.append(tender_object)

        return tenders_list

    def _build_state_history(self, order):
        # type: (eTree) -> List[StateHistory]

        state_history_list = []
        states = order.findall(".//State")
        for state in states:
            state_object = StateHistory()

            state_object.state_name = state.get("state")
            state_object.timestamp = self._parse_timestamp(state.get("timestamp"))

            state_history_list.append(state_object)

        return state_history_list

    @staticmethod
    def _build_items(order):
        # type: (eTree) -> List[Item]

        items_list = []
        items = order.findall(".//SaleLine")
        for item in items:
            item_object = Item()

            item_object.context = item.get("itemId")
            item_object.part_code = int(item.get("partCode"))
            item_object.level = int(item.get("level"))
            item_object.line_number = int(item.get("lineNumber"))
            item_object.product_name = item.get("productName")
            item_object.item_type = item.get("itemType")
            item_object.added_price = float(item.get("addedUnitPrice")) if item.get("addedUnitPrice") else None
            item_object.unit_price = float(item.get("unitPrice")) if item.get("unitPrice") else None
            item_object.quantity = int(float(item.get("qty")))
            item_object.default_quantity = int(item.get("defaultQty") or 0)

            items_list.append(item_object)

        return items_list

    @staticmethod
    def _build_additional_properties(order):
        # type: (eTree) -> List[AdditionalProperty]

        additional_properties_list = []
        additional_properties = order.findall(".//OrderProperty")
        for additional_property in additional_properties:
            key = additional_property.get("key")
            value = additional_property.get("value")
            additional_property_object = AdditionalProperty(key, value)
            additional_properties_list.append(additional_property_object)

        return additional_properties_list

    def _parse_timestamp(self, timestamp):
        # type: (str) -> str

        timestamp = parse_date(timestamp)
        converted_time = self._convert_to_utc(timestamp)

        return converted_time.isoformat()

    @staticmethod
    def _convert_to_utc(local_datetime):
        # type: (date) -> date

        time_diff = datetime.utcnow() - datetime.now()
        converted_time = local_datetime + time_diff

        return converted_time
