import json

from typing import (
    Dict,
    Optional,
)

from xml.etree import cElementTree as eTree

from sysactions import (
    show_any_dialog,
    get_model,
    get_posot,
)

from application.repository.impl import MwI18nRepository
from application.domain import (
    TableService,
    I18nImpl,
)


class ChooseLineSeatInteractor(object):

    def __init__(
        self,           # type: ChooseLineSeatInteractor
        pos_id,         # type: int
        table_service,  # type: TableService
    ):
        # type: (...) -> None

        self.table_service = table_service
        self.i18n = I18nImpl(MwI18nRepository(pos_id))
        self.pos_id = pos_id
        model = get_model(pos_id)
        self.pos_ot = get_posot(model)

    def execute(
        self,                   # type: ChooseLineSeatInteractor
        selected_sale_line,     # type: Dict
        seat=None,              # type: Optional[int]
    ):
        # type: (...) -> None

        table_info = self.table_service.get_table_info(self.pos_id, selected_sale_line["tableId"])
        table_info_xml = eTree.XML(table_info)

        if seat is None:
            seat = self._get_new_seat(self.pos_id, table_info_xml)
            if seat is None:
                return

        order_id = selected_sale_line.get("orderId")
        if not order_id:
            current_order = table_info_xml.findall(".//ServiceOrder[@state='IN_PROGRESS']")[0]
            order_id = current_order.get("orderId")

        order_picture = eTree.XML(self.pos_ot.orderPicture(self.pos_id, order_id))
        sale_lines = order_picture.findall(".//SaleLine")
        line_number = str(selected_sale_line["lineNumber"])
        item_id = selected_sale_line["itemId"]
        current_sale_line = [x for x in sale_lines if x.get("lineNumber") == line_number and x.get("itemId") == item_id]
        current_sale_line = current_sale_line[0]
        current_relation_line_number = self._get_relation_line_number(current_sale_line)
        for sale_line in sale_lines:
            if sale_line.get("level") != "0":
                continue

            relation_line_number = self._get_relation_line_number(sale_line)
            is_selected_line_number = sale_line.get("lineNumber") == str(selected_sale_line["lineNumber"])
            has_parent_relation = sale_line.get("lineNumber") == current_relation_line_number
            has_child_relation = relation_line_number == current_sale_line.get("lineNumber")
            has_sibling_relation = relation_line_number != "-1" and relation_line_number == current_relation_line_number
            if has_parent_relation or has_child_relation or is_selected_line_number or has_sibling_relation:
                self.table_service.set_sale_line_seat(
                    pos_id=self.pos_id,
                    seat_number=seat,
                    order_id=selected_sale_line.get("orderId"),
                    sale_line=sale_line,
                )

    def _get_new_seat(self, pos_id, table_info_xml):
        # type: (int, eTree.XML) -> Optional[int]

        seats_count = self.table_service.get_service_seats_count(table_info_xml)
        labels = self.i18n.internationalize(["$NO_SEAT", "$SEAT"])
        options = [labels["$NO_SEAT"]]
        for i in range(1, seats_count + 1):
            options.append(labels["$SEAT"].format(str(i)))

        selected = show_any_dialog(pos_id, "filteredListBox", "", "$SELECT_SEAT_FOR_LINE", "|".join(options),
                                   "$OK|$CANCEL", "", 600000, "NOFILTER", "", "", "", None, False)
        if selected is None:
            return None

        return int(selected)

    @staticmethod
    def _get_relation_line_number(sale_line):
        # type: (eTree.XML) -> int

        sale_line_properties_json = sale_line.get("customProperties")
        if not sale_line_properties_json:
            return -1

        sale_line_properties = json.loads(sale_line_properties_json)
        return sale_line_properties.get("relationLineNumber", '-1')
