import logging

from typing import (
    Any,
    List,
    Dict,
    Optional,
    Tuple,
    Union
)
from xml.etree import cElementTree as eTree

from application.domain import TableService
from pos_model import TableStatus
from sysactions import (
    get_model,
    show_listbox,
    StopAction,
    translate_message,
)


class TableInteractor(object):
    def __init__(
            self,
            pos_id,         # type: str
            table_id,       # type: str
            table_service   # type: TableService
    ):
        # type: (...) -> None

        self.logger = logging.getLogger("PosActions")
        self.table_service = table_service
        self.pos_id = pos_id
        self.table_id = table_id

    def get_related_services(
        self,
        filter_totaled=False    # type: Optional[bool]
    ):
        # type: (...) -> Tuple[List[Dict], List[str]]

        table_picture = eTree.XML(
                self.table_service.get_table_picture(
                        self.pos_id,
                        self.table_id
                )
        )
        model = get_model(self.pos_id)
        related_objects = []
        services_totaled = []
        service_children = table_picture.findall(".//ServiceChildren/ServiceChild")
        for child in service_children:
            child_is_totaled = int(child.get("status") or 0) == TableStatus.TOTALED
            if child_is_totaled:
                services_totaled.append(child.get("tableId"))

            child_is_closed = int(child.get("status") or 0) in [TableStatus.CLOSED, TableStatus.ABANDONED]
            if child_is_closed or (filter_totaled and child_is_totaled):
                continue
            tab_label = ' / '.join([
                data
                for data in [
                    child.get("tabId"),
                    child.get("customerName"),
                    child.get("customerPhone")
                ]
                if data
            ])
            related_objects.append({
                "caption": translate_message(model, "TAB_INFORMATION", tab_label),
                "table_id": child.get("tableId"),
            })

        return related_objects, services_totaled

    def get_selected_related_services(
        self,
        related_objects,        # type: List[Dict]
        show_all_services=False    # type: bool
    ):
        # type: (...) -> str

        if len(related_objects) > 0:
            listbox_options = [e["caption"] for e in related_objects]
            if show_all_services:
                model = get_model(self.pos_id)
                listbox_options.append(translate_message(model, "CLOSE_ALL_TABLES_OR_TABS"))
                related_objects.append({
                    "table_id": "all_services",
                })
            title = "$CLOSE_ALL_TABLES_OR_TABS_TITLE" if show_all_services else "$SELECT_TAB"
            index = show_listbox(
                    self.pos_id,
                    listbox_options,
                    message=title
            )
            if index is None:
                raise StopAction()

            return related_objects[index]["table_id"]

        return self.table_id

    def do_total_table(
        self,
        tip_rate,           # type: str
        selected_to_total   # type: str

    ):
        # type: (...) -> str

        return self.table_service.do_total_table(
            pos_id=self.pos_id,
            table_id=self.table_id,
            tip_rate=tip_rate,
            selected_to_total=selected_to_total
        )

    def select_table_or_related_tab_by_dialog(
        self,
        pos_id,     # type: Any[Union[str, int]]
        table_id    # type: Any[Union[str, int]]
    ):
        # type: (...) -> Any[Union[str, int]]

        related_services, _ = self.get_related_services()
        selected_table_id = self.get_selected_related_services(related_services)
        if selected_table_id != table_id:
            result = self.change_selected_table(pos_id, selected_table_id)
            if result:
                return selected_table_id
            else:
                raise StopAction()

        return selected_table_id

    @staticmethod
    def change_selected_table(
            pos_id,
            selected_table_id
    ):

        from table_actions import (
            deselect_table,
            select_table_or_tab,
        )

        deselect_table(pos_id)
        return select_table_or_tab(pos_id, selected_table_id)
