from xml.etree import cElementTree as eTree
from datetime import datetime
from typing import (
    Dict,
    Union,
    List, Optional,
)
from ._Table import Table
from ._ServiceTender import ServiceTender
from order_api.dto import Order as OrderApi
from order_api.dto.order_xml_parser import parse_order


def get_table_attribute_value(
    key,                # type: str
    table_xml_attrib,   # type: Dict[str, str]
    default_value,      # type: Union[str, int, None]
):
    # type: (...) -> Union[str, int, None]

    return table_xml_attrib.get(key, default_value)


def parse_tab_names(
    table_xml,     # type: eTree.Element
):
    # type: (...) -> Dict[str, str]

    service_children = table_xml.findall("ServiceChildren/ServiceChild")
    tabs_names = {}
    for service_child in service_children:
        tabs_names.update({service_child.attrib["tableId"]: service_child.attrib["tabId"]})

    return tabs_names


def parse_table_name(
    table_id,      # type: str
    table_xml,     # type: eTree.Element
):
    # type: (...) -> str

    property_xml = table_xml.findall(".//Properties[@TAB_ID]")
    tab_name = property_xml[0].attrib["TAB_ID"] if property_xml else None
    table_name = table_xml.attrib["name"] if "name" in table_xml.attrib else table_id
    return tab_name if tab_name else table_name


def parse_service_tenders(
    service_tenders,  # type: List[eTree.Element]
):
    # type: (...) ->  List[ServiceTender]

    service_tender_parsed = []      # type: List[ServiceTender]
    for service_tender in service_tenders:
        tender_amount = float(service_tender.get('tenderAmount'))
        if tender_amount > 0:
            service_tender_parsed.append(
                ServiceTender(
                    description=service_tender.get('tenderDescr'),
                    amount=tender_amount,
                )
            )

    return service_tender_parsed


def parse_table(
    table_xml,  # type: eTree.Element
):
    # type: (...) ->  Table

    table_id = table_xml.get("id")
    user_id = table_xml.attrib.get("userId", "")
    status = int(table_xml.attrib.get("status")) if table_xml.attrib.get("status") else 0

    table_name = parse_table_name(
        table_id=table_id,
        table_xml=table_xml,
    )
    tabs_names = parse_tab_names(table_xml=table_xml)

    table_mode = None
    if "MODE" in table_xml.find("Properties").attrib:
        table_mode = table_xml.find("Properties").attrib["MODE"]

    total_amount = float(get_table_attribute_value(
        table_xml_attrib=table_xml.attrib,
        key="totalAmount",
        default_value=0,
    ))
    service_seats = int(get_table_attribute_value(
        table_xml_attrib=table_xml.attrib,
        key="serviceSeats",
        default_value=0,
    ))
    total_per_seat = float(get_table_attribute_value(
        table_xml_attrib=table_xml.attrib,
        key="totalPerSeat",
        default_value=0,
    ))
    total_discounts = float(get_table_attribute_value(
        table_xml_attrib=table_xml.attrib,
        key="discountAmount",
        default_value=0,
    ))
    tip = float(table_xml.get("tip") if table_xml.get("tip") else 0.0)
    tip_rate = float(table_xml.get("tipRate") if table_xml.get("tipRate") else 0.0)

    start_date = get_table_attribute_value(
        table_xml_attrib=table_xml.attrib,
        key="startTS",
        default_value=None,
    )
    start_date = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S") if start_date else None

    service_tenders = table_xml.findall('ServiceTenders/ServiceTender')
    service_tenders = parse_service_tenders(service_tenders=service_tenders)

    orders_xml = table_xml.findall("Orders/Order")
    orders = []     # type: Optional[List[OrderApi]]
    for order_xml in orders_xml:
        order_api = parse_order(order_xml=order_xml)
        orders.append(order_api)

    return Table(
        table_id=table_id,
        user_id=user_id,
        table_name=table_name,
        tabs_names=tabs_names,
        table_mode=table_mode,
        tip_rate=tip_rate,
        tip=tip,
        total_amount=total_amount,
        service_seats=service_seats,
        total_per_seat=total_per_seat,
        total_discounts=total_discounts,
        start_date=start_date,
        service_tenders=service_tenders,
        orders=orders,
        status=status,
    )
