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

from xml.etree import cElementTree as eTree
from typing import Optional, List

from sysactions import show_messagebox, StopAction, get_model, get_current_order, get_posot

from actions.coupon.display_coupon import get_benefits_from_order
from actions.eft import finish_eft_transactions
from application.interactor import (
    NDiscountInteractor,
    OrderInteractor,
)


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

    return order


def clean_discounts_and_payments(pos_id, disconnected_discount_component=False):
    model = get_model(pos_id)
    order = get_current_order(model)

    clean_orders_discounts(pos_id, [order], disconnected_discount_component)
    return clean_order_payments(
        pos_id=pos_id,
        order=order,
    )


def has_manual_discounts(
        order   # type: eTree.XML
):
    # 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"))
    return True if benefits["manualBenefitOnTotalSequence"] else False


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

    has_discounts = check_manual_discounts and has_manual_discounts(order)
    order_tenders = filter(
        lambda t: float(t.get("tenderAmount")) > 0,
        order.findall(".//TenderHistory/Tender")
    )
    order_id = order.get('orderId')
    order_interactor = OrderInteractor(pos_id=str(pos_id))
    if len(order_tenders) >= 1:
        if has_discounts:
            message = "$CLEAN_TENDERS_AND_MANUAL_DISCOUNTS_TO_EXECUTE_ACTION"
            message = "$CLEAN_TENDERS_AND_MANUAL_DISCOUNTS_TO_STORE_ORDER" if store else message
            ret = show_messagebox(pos_id, message, buttons="$YES|$NO")
        else:
            message = "$CLEAN_TENDERS_TO_STORE_ORDER" if store else "$CLEAN_TENDERS_TO_EXECUTE_ACTION"
            ret = show_messagebox(pos_id, message, buttons="$YES|$NO")
        if ret != 0:
            raise StopAction()

        finish_eft_transactions(pos_id, order, "0")
        for tender in order_tenders:
            order_interactor.clear_order_tender(
                order_tender_id=tender.get("tenderId"),
                order_id=order_id,
            )
        return True
    if has_discounts:
        message = "$CLEAN_MANUAL_DISCOUNTS_TO_STORE_ORDER" if store else "$CLEAN_MANUAL_DISCOUNTS_TO_EXECUTE_ACTION"
        ret = show_messagebox(pos_id, message, buttons="$YES|$NO")

        if ret != 0:
            raise StopAction()

    return True


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

    model = get_model(pos_id)
    pos_ot = get_posot(model)

    discount_ids = []
    lines_to_void = {}

    for order in orders:
        lines_to_void = _get_lines_with_coupons(order, lines_to_void)
        discount_ids.extend(_get_lines_discount_ids(order))

    if len(lines_to_void) == 0 and not discount_ids:
        return

    ret = show_messagebox(
        pos_id,
        message,
        buttons="$YES|$NO"
    )
    if ret != 0:
        raise StopAction()

    if disconnected_discount_component:
        success = _clean_static_orders_discounts(pos_id, pos_ot, discount_ids, lines_to_void)
        time.sleep(0.5)
        return success
    elif len(discount_ids) > 0:
        success = _clean_discount_with_id(pos_ot, discount_ids)
        return success
    else:
        return NDiscountInteractor.remove_benefits(pos_id)


def _clean_static_orders_discounts(pos_id, pos_ot, discount_ids, lines_to_void):
    # type: (str, object, List, dict) -> bool

    try:
        if len(lines_to_void) > 0:
            pos_ot.blkopnotify = True
            for order_id in lines_to_void:
                pos_ot.voidLine(int(pos_id), "|".join(lines_to_void[order_id]))
            pos_ot.blkopnotify = False

        _clean_discount_with_id(pos_ot, discount_ids)
        return True
    except Exception as e:
        raise e.message


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

    try:
        for discount in list(dict.fromkeys(discount_ids)):
            pos_ot.clearDiscount(discount)
        return True
    except Exception as e:
        raise e.message


def _get_lines_with_coupons(order, lines_to_void=None):
    if lines_to_void is None:
        lines_to_void = {}

    sale_lines = order.findall(".//SaleLine")
    for sale_line in sale_lines:
        item_type = sale_line.get("itemType")
        qty = float(sale_line.get('qty'))
        if item_type == "COUPON" and qty > 0:
            line_number = sale_line.get("lineNumber")
            order_id = int(order.get("orderId"))
            if order_id in lines_to_void:
                lines_to_void[order_id].append(line_number)
            else:
                lines_to_void[order_id] = [line_number]
    return lines_to_void


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
