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

import sysactions

from collections import OrderedDict
from bustoken import TK_FISCALWRAPPER_CANCEL_ORDER
from msgbus import (
    FM_PARAM,
    TK_SYS_ACK,
    TK_SLCTRL_OMGR_VOIDORDER
)
from mw_helper import show_filtered_list_box_dialog
from posot import OrderTaker
from utilconfigurations import get_cancel_json
from typing import (
    Any,
    Dict,
    List,
    Optional,
    Union
)

from .. import mb_context
from ..util.get_menu_user_logged import get_menu_manager_authenticated_user


def void_order(
    pos_id,                 # type: Any[Union[int, str]]
    last_paid_order="0",    # type: Optional[str]
    order_id='',            # type: Optional[str]
    abandon=0,              # type: Optional[int]
    void_reason=None,       # type: Optional[Any[int, Dict]]
    pos_ot=None,            # type: Optional[OrderTaker]
    new_order_status=None,  # type: Optional[int]
):
    # type: (...) -> bool

    model = sysactions.get_model(pos_id)
    if pos_ot is None:
        pos_ot = sysactions.get_posot(model)

    order_id = int(order_id) if order_id != "" else ""
    void_order_id = order_id
    if void_reason is None:
        void_reason = get_void_reason_id(
            pos_id,
            "UNDEFINED_REASON",
            authentication_user="SYSTEM"
        )
    elif not isinstance(void_reason, dict):
        void_reason = get_fixed_void_reason(
            void_reason,
            "SYSTEM",
        )

    params = (
        '1' if pos_ot.blkopnotify else '0',
        pos_id,
        '1' if int(last_paid_order) else '0',
        void_order_id,
        '1' if abandon else '0',
        new_order_status,
        json.dumps(void_reason),
    )
    params = "\0".join(str(p) for p in params)
    msg = mb_context.MB_EasySendMessage(
        dest_name="ORDERMGR%d" % int(pos_id),
        token=TK_SLCTRL_OMGR_VOIDORDER,
        format=FM_PARAM,
        data=params,
        timeout=600000000
    )

    return msg.token == TK_SYS_ACK


def void_fiscal_order(
    pos_id,                     # type: int
    order_id,                   # type: int
    pos_id_to_display_message,  # type: int
):
    # type: (...) -> None

    data = "|".join([str(pos_id), str(order_id)])
    msg = mb_context.MB_EasySendMessage("FiscalWrapper", TK_FISCALWRAPPER_CANCEL_ORDER, format=FM_PARAM, data=data)
    if msg.token != TK_SYS_ACK:
        sysactions.show_messagebox(
            posid=pos_id_to_display_message,
            message="$ERROR_CANCEL_FISCAL_ORDER|{}".format(msg.data),
        )
        raise sysactions.StopAction(msg.data)


def get_void_reason_id(
    pos_id,                     # type: str
    selected_reason=None,       # type: Optional[str]
    void_type=None,             # type: Optional[str]
    authentication_user=None,   # type: Optional[str]
):
    # type: (...) -> Optional[Dict]

    if not selected_reason:
        void_reason_options = _get_void_reason_to_show(pos_id=pos_id, void_type=void_type)

        total_void_reasons = len(void_reason_options)
        if total_void_reasons > 1:
            title = "$SELECT_REASON"
            selected_reason = show_filtered_list_box_dialog(
                pos_id=pos_id,
                options=void_reason_options,
                title=title,
                mask="NOFILTER",
            )
        elif total_void_reasons == 1:
            selected_reason = 0

        if selected_reason is None:
            return None

        selected_reason = int(selected_reason)
        void_reason_id = void_reason_options[selected_reason].split('-')[0].strip()
        void_reason_description = void_reason_options[selected_reason].split('-')[1].strip()
        void_reason_dict = {
            'VOID_REASON_ID': void_reason_id,
            'VOID_REASON_DESCR': void_reason_description,
            "VOID_AUTH_USER": authentication_user
        }
    else:
        void_reason_dict = get_fixed_void_reason(
            reason=selected_reason,
            canceled_by=authentication_user,
        )

    return void_reason_dict


def get_fixed_void_reason(
        reason,
        canceled_by,
):
    void_reason = get_void_reason_dict().get(reason)
    void_reason_id = void_reason.get("id")
    void_reason_description = void_reason.get("reasonKey")

    void_reason_dict = {
        'VOID_REASON_ID': void_reason_id,
        'VOID_REASON_DESCR': void_reason_description,
        "VOID_AUTH_USER": canceled_by
    }

    return void_reason_dict


def void_reason_list_to_ordered_dict(void_reasons):
    # type: (...) -> OrderedDict

    void_reasons = sorted(
        void_reasons,
        key=lambda k: k["id"]
    )
    ordered_dict = OrderedDict()
    for item in void_reasons:
        ordered_dict[item["reasonKey"].replace("$", "")] = item

    return ordered_dict


def get_void_reason_dict(
    filtered_items=None,  # type: Optional[List]
):
    # type: (...) -> Dict

    void_reason_list = [
        {"id": 101, "reasonKey": "$CHANGED_YOUR_MIND"},
        {"id": 102, "reasonKey": "$DUPLICATE"},
        {"id": 103, "reasonKey": "$WRONG_SALE"},
        {"id": 104, "reasonKey": "$CANCELLATION"},
        {"id": 105, "reasonKey": "$USER_CANCELLATION"},
        {"id": 106, "reasonKey": "$USER_FISCAL_CANCELLATION"},
        {"id": 107, "reasonKey": "$TIMEOUT_CANCELLATION"},
        {"id": 108, "reasonKey": "$UNDEFINED_REASON"},
        {"id": 109, "reasonKey": "$RECALL_ORDER_TO_OLD"},
        {"id": 110, "reasonKey": "$UNKNOWN_FISCAL_ERROR"},
    ]

    void_reason_list = void_reason_list_to_ordered_dict(void_reason_list)

    return _filter_void_reason_items(void_reason_list, filtered_items)


def _filter_void_reason_items(
    void_reasons,           # type: OrderedDict
    filtered_items=None,    # type: Optional[List]
):
    # type: (...) -> Dict

    if filtered_items:
        return {k: v for k, v in void_reasons.iteritems() if v.get("id") in filtered_items}

    return void_reasons


def _get_void_reason_to_show(
    pos_id,     # type: str
    void_type,  # type: str
):
    # type: (...) -> List[str]

    void_reason_dict = get_void_reason_dict(filtered_items=[101, 102, 103, 104])
    cancel_json = get_cancel_json()
    void_reason_key = {
        "VOID_CURRENT_ORDER": "orderReasons",
        "VOID_PAID_ORDER": "couponReasons",
        "VOID_LINE": "lineReasons",
    }
    if cancel_json and void_reason_key[void_type] in cancel_json:
        void_reason_dict = void_reason_list_to_ordered_dict(cancel_json[void_reason_key[void_type]])

    return _translate_array(pos_id, void_reason_dict)


def _translate_array(
    pos_id,    # type: str
    messages,  # type: dict
):
    # type: (...) -> List[str]

    model = sysactions.get_model(pos_id)
    result = []
    for key, item in messages.items():
        reason_id = item["id"]
        reason = item["reasonKey"].encode('utf-8')
        if reason.startswith("$"):
            reason = sysactions.translate_message(
                model=model,
                message_key=reason.replace("$", ""),
            )
        result.append("{} - {}".format(
            reason_id,
            reason,
        ))

    return result


def get_canceled_by(
    pos_id,       # type: str
    model,        # type: eTree.XML
    auth_user,    # type: str
):
    # type: (...) -> str

    authenticated_manager = get_menu_manager_authenticated_user(int(pos_id))
    if authenticated_manager is not None:
        return str(authenticated_manager)

    if auth_user:
        return str(auth_user)

    operator = model.find("Operator")
    return operator.get("id", "UNDEFINED") if operator is not None else "UNDEFINED"
