import json
import logging

from xml.etree import cElementTree as eTree

from actions.sale_line.set_custom_properties import set_custom_properties
from bustoken import TK_NCOUPON_APPLY_COUPON
from mw_helper import show_keyboard
from sysactions import action, get_model, get_current_order, show_messagebox, get_posot
from msgbus import FM_PARAM, TK_SYS_ACK, MBTimeout, MBException

from actions import mb_context
from custom_sysactions import user_authorized_to_execute_action

logger = logging.getLogger("PosActions")


@action
@user_authorized_to_execute_action
def do_apply_coupons(pos_id, table_id=None, seat=''):
    coupon_code = show_keyboard(pos_id, "$ENTER_COUPON_CODE", defvalue="", title="", numpad=False)
    if coupon_code is None:
        return False

    if seat == '':
        apply_coupon(pos_id, table_id=table_id, coupon_code=coupon_code)
        return

    _apply_coupon_and_set_seat(coupon_code, pos_id, seat, table_id)


def apply_coupon(pos_id, table_id=None, coupon_code=None):
    model = get_model(pos_id)
    order = get_current_order(model)
    message = None
    try:
        coupon_code = coupon_code.upper()
        originator_pos_id = int(order.get("originatorId")[3:]) if order else None
        data = json.dumps(dict(posId=pos_id, originatorPosId=originator_pos_id, voucherId=coupon_code))
        try:
            msg = mb_context.MB_EasySendMessage("nCoupon", TK_NCOUPON_APPLY_COUPON, FM_PARAM, data)
            message = "$SUCCESS_NOT_TOTALED_COUPON_APPLIED"
            if msg.token != TK_SYS_ACK:
                message = "${}".format(msg.data)
                return False
            if msg.token == TK_SYS_ACK and order and order.get('state') == "TOTALED":
                message = "$SUCCESS_COUPON_APPLIED"
                if table_id is not None:
                    from table_actions import process_discount_in_table
                    process_discount_in_table(pos_id, order, table_id)
                return True

        except (MBTimeout, MBException) as _:
            show_messagebox(pos_id, "$ERROR_COUPON_APPLIED")
            logger.exception("Error sending message to nDiscount")
            return False
    except Exception as _:
        show_messagebox(pos_id, "$ERROR_COUPON_APPLIED")
        logger.exception("Error applying coupon")
        return False
    finally:
        if message:
            show_messagebox(pos_id, message)


def _apply_coupon_and_set_seat(coupon_code, pos_id, seat, table_id):
    # type: (str, str, str, str) -> None

    model = get_model(pos_id)
    pos_ot = get_posot(model)
    order_picture = eTree.XML(pos_ot.orderPicture(pos_id))
    order_id = order_picture.get("orderId")
    sale_lines = order_picture.findall(".//SaleLine")
    last_line_number = max([int(x.get("lineNumber")) for x in sale_lines]) if sale_lines else 0
    apply_coupon(pos_id, table_id=table_id, coupon_code=coupon_code)
    _set_custom_properties_for_added_sale_lines(pos_id, pos_ot, order_id, last_line_number, seat)


def _set_custom_properties_for_added_sale_lines(pos_id, pos_ot, order_id, last_line_number, seat):
    order_picture = eTree.XML(pos_ot.orderPicture(pos_id, order_id))
    sale_lines = order_picture.findall(".//SaleLine")
    last_line_number_after_apply_coupon = max([int(x.get("lineNumber")) for x in sale_lines]) if sale_lines else 0
    if last_line_number != last_line_number_after_apply_coupon:
        sale_type = None if order_picture.get("saleTypeDescr") == "EAT_IN" else order_picture.get("saleTypeDescr")

        for sale_line in sale_lines:
            if int(sale_line.get("level")) > 0 or int(sale_line.get("lineNumber")) <= int(last_line_number):
                continue

            set_custom_properties(pos_ot, sale_line, seat, sale_type)
