import logging

from actions.models import PaymentType
from actions.coupon.apply_coupon import apply_coupon
from actions.discount.clean_discounts import clean_discounts_and_payments
from actions.discount.get_discount import get_visible_discounts
from application.interactor import NDiscountInteractor
from model.customexception import ErrorAddingBenefits
from mw_helper import show_filtered_list_box_dialog, show_numpad_dialog, show_message_dialog
from sysactions import show_messagebox, get_current_order, StopAction, get_model, get_posot, show_keyboard

logger = logging.getLogger("PosActions")


def apply_discount(pos_id):
    try:
        coupons, disconnected_discount_component = get_visible_discounts(pos_id)
        if len(coupons) == 0:
            show_messagebox(pos_id, "$DISCOUNT_NOT_FOUND", icon="warning")
            return

        selected_index = _select_discount(pos_id, coupons)
        if selected_index is None:
            return

        selected_coupon = filter(lambda c: c["index"] == selected_index + 1, coupons)
        if not selected_coupon:
            return

        selected_coupon = selected_coupon[0]
        benefit_id = selected_coupon.get("benefit_id", "")
        coupon = selected_coupon.get("coupon", {})

        if disconnected_discount_component:
            clean_discounts_and_payments(pos_id, disconnected_discount_component)
            model = get_model(pos_id)
            pos_ot = get_posot(model)
            order = get_current_order(model)
            apply_amount_discount(pos_id, pos_ot, order, selected_coupon)
        elif coupon.get("askValue", False):
            coupon["index"] = _get_discount_type(coupon)
            amount = _get_discount_amount(coupon, pos_id)
            if coupon.get("requestJustification", False):
                coupon["justification"] = _get_justification_discount(pos_id)

            return _set_amount_discount(pos_id, coupon, amount)
        else:
            return apply_coupon(pos_id, table_id=None, coupon_code=benefit_id)
    except ErrorAddingBenefits as ex:
        logger.warn("Error applying discount ${}".format(ex.message))
        show_message_dialog(pos_id, "$ERROR", "${}".format(ex.message))
    except Exception as ex:
        logger.exception("Error applying discount")
        show_message_dialog(pos_id, "$ERROR", "${}".format(ex.message))

    return False


def _get_discount_amount(coupon, pos_id):
    model = get_model(pos_id)
    order = get_current_order(model)
    amount, percentage = _ask_discount_amount(pos_id, order, coupon=coupon)
    if percentage is not None:
        amount = percentage

    return amount


def apply_amount_discount(pos_id, pos_ot, order, coupon=None, discount_type=None, discount_value=None):
    amount, _ = _ask_discount_amount(pos_id, order, coupon, discount_type, discount_value)
    pos_ot.applyDiscount(1, amount, forcebyitem=1)


def _ask_discount_amount(pos_id, order, coupon=None, discount_type=None, discount_value=None):
    if not discount_type:
        discount_type = coupon['index']
        title = "$DISCOUNT_VALUE_TITLE" if discount_type == PaymentType.AMOUNT.value else "$DISCOUNT_PERCENTAGE_TITLE"
        mask = "CURRENCY" if discount_type == PaymentType.AMOUNT.value else "NUMBER"
        if not discount_value:
            discount_value = show_numpad_dialog(pos_id, title, "", mask)
            if discount_value is None:
                raise StopAction()

    if discount_type == PaymentType.AMOUNT.value:
        return discount_value, None

    amount = float(order.get("totalGross"))

    return (amount * discount_value) / 100, discount_value


def _select_discount(pos_id, coupons):
    options = ["{0} - {1}".format(coupon["index"], coupon["name"].encode("UTF-8")) for coupon in coupons]
    return show_filtered_list_box_dialog(pos_id, options, "$SELECT_ONE_COUPON", mask="NOFILTER")


def _set_amount_discount(pos_id, coupon, amount):
    coupon = set_coupon_amount(coupon, amount)
    return NDiscountInteractor.add_benefit(pos_id, "", coupon)


def _get_object_json(json_object, key, value):
    return [obj for obj in json_object if obj[key] == value][0]


def set_coupon_amount(coupon, amount):
    if coupon.get("actions", False) and coupon.get("actions").get("0", False):
        action = coupon.get("actions").get("0")
        value_actions = ["discountAmountOnTotal", "discountPercentageOnTotal"]
        group_actions = ["discountPercentageByGroupsOnTotal", "discountAmountByGroupsOnTotal"]
        if any(x for x in value_actions if x in action.keys()):
            action_name = action.keys()[0]
            action[action_name] = amount
            return coupon
        elif any(x for x in group_actions if x in action.keys()):
            action.values()[0][0]["amount"] = amount
            return coupon

    raise StopAction()


def _get_discount_type(coupon):
    if coupon.get("actions", False) and coupon.get("actions").get("0", False):
        action = coupon.get("actions").get("0")
        amount_actions = ["discountAmountOnTotal", "discountAmountByGroupsOnTotal"]
        percentage_actions = ["discountPercentageOnTotal", "discountPercentageByGroupsOnTotal"]
        if any(x for x in amount_actions if x in action.keys()):
            return PaymentType.AMOUNT.value
        elif any(x for x in percentage_actions if x in action.keys()):
            return PaymentType.PERCENTAGE.value

    raise StopAction()


def _get_justification_discount(pos_id):
    # type: (str) -> str

    justification = None
    while justification in (None, "", ".") or len(justification) < 5:
        justification = show_keyboard(pos_id, "$JUSTIFICATION_DISCOUNT", '', timeout=1800000, buttons="$OK")
        if justification:
            return justification.strip()
