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

from xml.etree import cElementTree as eTree
from functools import wraps
from datetime import datetime

from sysactions import get_model, StopAction, show_messagebox, get_podtype, get_line_product_name, get_posot, get_custom
from systools import sys_log_exception

from actions.config import get_function_authorization_level_from_config
from actions.util import get_user_level, get_authorization
from actions.pos import pos_need_to_be_blocked

configurations = None


def initialize_manager_authorizations(config):
    global configurations
    configurations = config


def user_authorized_to_execute_action(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        user_data = None
        pos_id = _get_pos_id(args, kwargs)
        if not pos_id:
            return False

        try:
            function_level = get_function_authorization_level_from_config(configurations, f.func_name)
            model = get_model(pos_id)
            operator = model.find("./Operator")
            if operator is not None:
                user_id = operator.get("id")
                if get_user_level(user_id) <= function_level:
                    status, user_data = get_authorization(pos_id, function_level, model)

                    if status:
                        _save_authentication_info_on_order(f.func_name, model, pos_id)
                    else:
                        return StopAction()

        except BaseException as ex: # noqa
            error_message = "$GET_USER_AUTHORIZATION_ERROR_" + str(type(ex).__name__).upper()
            sys_log_exception("Error validating user authorization")
            show_messagebox(pos_id, message=error_message, icon="error")
            return False

        if 'auth_data' in inspect.getargspec(f).args:
            kwargs['auth_data'] = user_data

        return f(*args, **kwargs)

    return decorated_function


def block_action_if_pos_is_blocked(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        pos_id = _get_pos_id(args, kwargs)
        if not pos_id:
            return False

        try:
            model = get_model(pos_id)
            pod_type = get_podtype(model)
            if pod_type != 'TT' and pos_need_to_be_blocked(pos_id):
                from msgbusboundary import MsgBusTableService as tableService
                from table_actions import deselect_table
                selected_table = tableService().get_selected_table(pos_id)
                if selected_table is None:
                    deselect_table(pos_id)

                show_messagebox(pos_id, message="$POS_BLOCKED", icon="error")
                return StopAction()
        except BaseException as _:  # noqa
            return False

        return f(*args, **kwargs)

    return decorated_function


def block_action_if_order_items_not_resolved(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        from posactions import list_open_options

        pos_id = _get_pos_id(args, kwargs)
        if not pos_id:
            return False

        model = get_model(pos_id)
        order = model.find("CurrentOrder/Order")

        sale_lines = order.findall("SaleLine")
        active_sale_lines = _get_active_order_lines(sale_lines)
        is_remote_order = order.find("CustomOrderProperties/OrderProperty[@key='REMOTE_ORDER_ID']")
        if not active_sale_lines and is_remote_order is None:
            show_messagebox(pos_id, "$HAS_NO_ITEMS_IN_ORDER", title="")
            return False

        option = list_open_options(order)
        if option is not None:
            prod_name = get_line_product_name(model, int(option.get("lineNumber")))
            show_messagebox(pos_id, message="$NEED_TO_RESOLVE_OPTION|%s" % (prod_name.encode("UTF-8")), icon="error")
            return False

        return f(*args, **kwargs)

    return decorated_function


def _get_pos_id(args, kwargs):
    pos_id = None
    if len(args) > 0:
        pos_id = args[0]
    elif 'pos_id' in kwargs:
        pos_id = kwargs['pos_id']
    elif 'posid' in kwargs:
        pos_id = kwargs['posid']
    else:
        sys_log_exception("PosId not found to authorize")

    return pos_id


def _get_order_deleted_lines(sale_lines):
    return map(lambda x: x.get("lineNumber"), filter(lambda x: x.get("level") == "0" and x.get("qty") == "0", sale_lines))


def _get_active_order_lines(sale_lines):
    deleted_line_numbers = _get_order_deleted_lines(sale_lines)
    return filter(lambda x: x.get("lineNumber") not in deleted_line_numbers, sale_lines)


def _save_authentication_info_on_order(
        executed_function,      # type: str
        model,                  # type: eTree.Element
        pos_id                  # type: int
):
    # type: (...) -> None

    if executed_function is not None:
        if not model:
            model = get_model(pos_id)

        pos_ot = get_posot(model)
        user_id = get_custom(model, 'Last Manager ID')
        order = model.find("CurrentOrder/Order")
        order_id = order.get("orderId") if order else None

        if order_id:
            property_name = "{}: {}".format(executed_function, datetime.now().strftime("%m/%d/%Y %H:%M:%S"))
            pos_ot.setOrderCustomProperty(property_name, user_id, order_id)
