from application.interactor import OrderInteractor
from typing import (
    Dict,
    List,
    Optional,
)

import sysactions
from utils import (
    get_void_reason_id,
    get_canceled_by,
    do_confirm_void,
    get_fixed_void_reason,
)
from custom_sysactions import user_authorized_to_execute_action
from manager.reports import justification_report
from utilconfigurations import must_require_void_reason
from utilfunctions import (
    is_stored_order,
)
from api.order import get_order_service


@sysactions.action
def do_void_lines(
    pos_id,             # type: str
    line_numbers=None,  # type: Optional[str]
    auth_data=None,     # type: Optional[str]
):
    # type: (...) -> bool

    stored_order = is_stored_order(pos_id=pos_id)
    order_interactor = OrderInteractor(
        pos_id=pos_id,
    )
    in_progress_order = order_interactor.is_order_in_progress()

    if stored_order:
        do_void_lines_stored_order(
            pos_id,
            line_numbers=line_numbers,
            auth_data=auth_data,
        )
    elif in_progress_order:
        do_void_lines_in_progress_order(
            pos_id,
            line_numbers=line_numbers,
            auth_data=auth_data,
        )

    return True


@user_authorized_to_execute_action
def do_void_lines_in_progress_order(
    pos_id,         # type: str
    line_numbers,   # type: str
    auth_data,      # type: str
):
    # type: (...) -> None

    _void_lines(
        pos_id=pos_id,
        line_numbers=line_numbers,
        auth_data=auth_data,
    )


@user_authorized_to_execute_action
def do_void_lines_stored_order(
    pos_id,         # type: str
    line_numbers,   # type: str
    auth_data,      # type: str
):
    # type: (...) -> None

    _void_lines(
        pos_id=pos_id,
        line_numbers=line_numbers,
        auth_data=auth_data,
        stored_order=True,
    )


def _void_lines(
    pos_id,              # type: str
    line_numbers,        # type: str
    auth_data,           # type: str
    stored_order=False,  # type: Optional[bool]
):
    # type: (...) -> bool

    if not line_numbers:
        return False

    model = sysactions.get_model(pos_id)
    sysactions.check_current_order(pos_id, model=model)

    if not sysactions.can_void_line(model, line_numbers):
        sysactions.show_messagebox(pos_id, "$NEED_TO_HAVE_ITEM_TO_VOID")
        return False

    auth_user = auth_data if auth_data is not None else None
    canceled_by_current_operator = get_canceled_by(
        pos_id,
        model,
        auth_user
    )
    canceled_by_auth_user = sysactions.get_custom(model=model, key="last_auth_user")
    void_type = "VOID_LINE_ON_STORED_ORDER" if stored_order else "VOID_LINE"
    if must_require_void_reason(void_type):
        void_reason = get_void_reason_id(
            pos_id=pos_id,
            void_type=void_type,
            authentication_user=canceled_by_auth_user,
            is_void_line=True,
        )
        if void_reason is None:
            return True
    else:
        do_confirm_void(
            pos_id=pos_id,
            message="$CONFIRM_VOID_LINE",
        )
        void_reason = get_fixed_void_reason(
            pos_id=pos_id,
            reason="USER_CANCELLATION",
            canceled_by=canceled_by_auth_user,
            void_type=void_type,
        )

    order = model.find("CurrentOrder/Order")
    order_id = order.get("orderId")

    do_void_lines_justification_report(
        pos_id=pos_id,
        void_reason=void_reason,
        canceled_by=canceled_by_current_operator,
        order_id=order_id,
        stored_order=stored_order,
    )
    order_service = get_order_service(pos_id=pos_id)
    void_custom_properties = _get_voided_custom_properties(
        void_reason=void_reason,
        canceled_by=canceled_by_auth_user,
    )

    order_service.void_lines(
        line_numbers=[line_numbers],
        custom_property=void_custom_properties,
    )

    return True


def do_void_lines_justification_report(
    pos_id,         # type: str
    void_reason,    # type: Dict
    canceled_by,    # type: str
    order_id,       # type: str
    stored_order,   # type: bool
):
    # type: (...) -> None

    justification_type = "VOID_LINE_ON_STORED_ORDER" if stored_order else "VOID_LINE"
    justification_report(
        pos_id=pos_id,
        justification_type=justification_type,
        justification=void_reason['VOID_REASON_DESCR'],
        authorized_by=canceled_by,
        order_id=order_id,
    )


def _get_voided_custom_properties(
    canceled_by,    # type: Optional[str]
    void_reason,    # type: Dict
):
    # type: (...) -> List[Dict[str, str]]

    voided_sale_lines = []

    if canceled_by not in [None, "None"]:
        voided_sale_lines.append({"key": "VOID_AUTH_USER", "value": canceled_by})

    for key, value in void_reason.items():
        properties = {"key": key, "value": str(value)}
        voided_sale_lines.append(properties)

    return voided_sale_lines
