# -*- coding: utf-8 -*-
import json

from xml.etree import cElementTree as eTree

from thread_local import get_current_model
from typing import (
    Dict,
    List,
    Optional,
)

from sysactions import (
    StopAction,
    get_model,
    get_posot,
    show_messagebox,
)

from actions.coupon.display_coupon import get_benefits_from_order
from actions.eft import finish_eft_transactions
from actions.eft.cancel_eft_transaction import clear_single_tender
from application.interactor import (
    NCouponInteractor,
    OrderInteractor,
)

YES_NO_BUTTONS = "$YES|$NO"


def clean_discounts(pos_id):
    model = get_model(pos_id)
    order = model.find(".//Order")
    clean_orders_discounts(pos_id, [order])

    return order


def is_manual_discount_on_total(
    benefit,    # type: Dict
):
    # type: (...) -> bool

    benefit_detail = benefit.get("benefit")
    automatic_discount = benefit_detail.get("automatic", "")
    if automatic_discount in ["ON_SALE", "ON_TOTAL", "ON_PAYMENT"]:
        return False

    applied_on_order_state = benefit.get("order_state", "")
    if applied_on_order_state != "TOTALED":
        return False

    return benefit_detail.get("persistent", None) in ["", None]


def has_manual_discounts(
    order,  # type: eTree.Element
):
    # type: (...) -> bool

    if not order:
        return False

    custom_properties = order.find(".//CustomOrderProperties")

    benefit_list_custom_property = custom_properties.find(".//OrderProperty[@key='BENEFIT_LIST']")
    if benefit_list_custom_property is None:
        return False

    benefits = json.loads(benefit_list_custom_property.get("value"))
    benefit_list = benefits.get("benefitList", "")
    if not benefit_list:
        return False

    benefit_list = json.loads(benefit_list or "[]")
    for benefit in benefit_list:
        if is_manual_discount_on_total(benefit=benefit):
            return True

    return False


def clean_order_payments(
    pos_id,                         # type: str
    order,                          # type: eTree.XML
    pos_id_to_show_message=None,    # type: str
    check_manual_discounts=False,   # type: Optional[bool]
    store=False,                    # type: Optional[bool]
):
    # type: (...) -> None

    if pos_id_to_show_message is None:
        pos_id_to_show_message = pos_id

    has_discounts = check_manual_discounts and has_manual_discounts(order)
    order_tenders = list(filter(
        lambda t: float(t.get("tenderAmount")) > 0,
        order.findall(".//TenderHistory/Tender")
    ))
    if len(order_tenders) >= 1 or has_discounts:
        if len(order_tenders) >= 1 and has_discounts and not _order_has_only_on_payment_benefits(order):
            message = "$CLEAN_TENDERS_AND_MANUAL_DISCOUNTS_TO_EXECUTE_ACTION"
            message = "$CLEAN_TENDERS_AND_MANUAL_DISCOUNTS_TO_STORE_ORDER" if store else message
        elif not order_tenders:
            message = "$CLEAN_MANUAL_DISCOUNTS_TO_STORE_ORDER" if store else "$CLEAN_MANUAL_DISCOUNTS_TO_EXECUTE_ACTION"
        else:
            message = "$CLEAN_TENDERS_TO_STORE_ORDER" if store else "$CLEAN_TENDERS_TO_EXECUTE_ACTION"

        ret = show_messagebox(
            posid=pos_id_to_show_message,
            message=message,
            buttons=YES_NO_BUTTONS,
        )

        if ret != 0:
            raise StopAction()

        finish_eft_transactions(pos_id, order, "0")
        order_interactor = OrderInteractor(pos_id=pos_id)
        for tender in order_tenders:
            clear_single_tender(
                pos_id=pos_id,
                order=order,
                tender=tender,
                order_interactor=order_interactor,
            )


def _order_has_only_on_payment_benefits(
    order,  # type: eTree.Element
):
    # type: (...) -> bool

    if not order:
        return False

    custom_properties = order.find(".//CustomOrderProperties")
    benefit_property = custom_properties.find(".//OrderProperty[@key='BENEFIT_LIST']")

    if benefit_property is None:
        return False

    benefit_dict = json.loads(benefit_property.attrib["value"])
    benefit_list = json.loads(benefit_dict.get("benefitList"))
    automatic_values = []
    for benefit in benefit_list:
        automatic_values.append(benefit.get("benefit").get("automatic"))

    return len(automatic_values) > 0 and all(automatic == 'ON_PAYMENT' for automatic in automatic_values)


def clean_orders_discounts(
    pos_id,                                 # type: str
    orders,                                 # type: List[eTree.Element]
    message="$CONFIRM_CLEAN_DISCOUNT",      # type: Optional[str]
):
    # type: (...) -> Optional[bool, object]

    model = get_current_model()
    pos_ot = get_posot(model)

    discount_ids = []
    any_order_has_manual_discounts = False

    for order in orders:
        discount_ids.extend(_get_lines_discount_ids(order))
        any_order_has_manual_discounts |= has_manual_discounts(order=order)

    if not discount_ids and not any_order_has_manual_discounts:
        return

    if message:
        ret = show_messagebox(
            pos_id,
            message,
            buttons=YES_NO_BUTTONS
        )
        if ret != 0:
            raise StopAction()

    if len(discount_ids) > 0:
        success = _clean_discount_with_id(pos_ot, discount_ids)
        return success

    return NCouponInteractor.remove_benefits(pos_id=pos_id)


def _clean_discount_with_id(pos_ot, discount_ids):
    # type: (object, List) -> bool

    try:
        discount_list = list(dict.fromkeys(discount_ids))
        pos_ot.clearDiscount(",".join((str(p) for p in discount_list)))
        return True
    except Exception as e:
        raise e.message


def _get_lines_discount_ids(order):
    automatic_discount_ids = _get_automatic_discount_ids(order)
    discounts = []
    sale_lines = order.findall(".//SaleLine")
    for sale_line in sale_lines:
        # discountsApplied is like this in teh CORE: "2:0.9,1:5.00"
        discounts_applied = sale_line.get("discountsApplied")
        if discounts_applied:
            for discount in discounts_applied.split(','):
                discount_id = discount.split(':')[0]
                if discount_id != '2' and int(discount_id) not in automatic_discount_ids:
                    discounts.append(discount_id)

    return discounts


def _get_automatic_discount_ids(order):
    automatic_discount_ids = []
    order_custom_properties = order.find(".//CustomOrderProperties")
    if order_custom_properties:
        benefits = get_benefits_from_order(None, order, order_custom_properties)
        for benefit in benefits:
            automatic_benefit = benefit.get("benefit") and benefit.get("benefit").get("automatic") != 'DISABLED'
            used_discount_ids = benefit.get("used_discount_ids")
            if not automatic_benefit or not used_discount_ids:
                continue

            automatic_discount_ids.extend(benefit["used_discount_ids"])

    return automatic_discount_ids
