import json

from sysactions import (
    StopAction,
    action,
    get_model,
    show_any_dialog,
    show_messagebox,
    translate_message,
)

from mw_helper import show_filtered_list_box_dialog
from pos_model import TableOperationMode
from typing import (
    Any,
    Dict,
    List,
    Tuple,
    Union,
)

from .. import (
    logger,
    mb_context,
)
from actions.models.user_levels import UserLevels
from operator_by_sector import (
    get_sectors,
    get_operator_sector_info,
)
from userhelper import UserHelper

ALL_OPERATORS = []
ALL_SECTORS = "$ALL_SECTORS"


def _select_sector(
    pos_id,     # type: str
):
    # type: (...) -> Tuple[str,str]

    sectors = get_sectors(pos_id=pos_id)

    selected_index = show_filtered_list_box_dialog(
        pos_id=pos_id,
        options=sectors,
        title="$SELECT_ONE_SECTOR",
        mask="NOFILTER",
    )
    if selected_index is None:
        raise StopAction()

    selected_sector = sectors[selected_index]
    if selected_sector.startswith('$'):
        model = get_model(posid=pos_id)
        selected_sector = translate_message(
            model=model,
            message_key=str(selected_sector[1:]),
        )

    return selected_sector, sectors[selected_index]


def _get_all_operators():
    # type: (...) -> List[Dict]

    global ALL_OPERATORS
    if ALL_OPERATORS:
        return ALL_OPERATORS

    with UserHelper(mb_context) as user_helper:
        all_operators = user_helper.get_all_users()
        ALL_OPERATORS = []
        for operator_id in sorted(all_operators, key=lambda x: int(x)):
            operator = all_operators.get(operator_id)
            if int(operator[1]) < UserLevels.MANAGER.value:
                user_info = dict(
                    id=int(operator_id),
                    name=operator[0],
                )
                ALL_OPERATORS.append(user_info)

        return ALL_OPERATORS


def _filter_operators(
    all_operators,          # type: List[Dict[str, Any[Union[str, int]]]]
    sector_operators_ids,   # type: List[int]
):
    # type: (...) -> List[Dict[str, Any[Union[str, int]]]]

    sector_operators = []
    for operator in all_operators:
        if operator.get("id") in sector_operators_ids:
            sector_operators.append(operator)
    return sector_operators


def _get_sector_operators(
    pos_id,     # type: str
    sector,     # type: str
):
    # type: (...) -> List[Dict[str, Any[Union[str, int]]]]

    all_sector_operators = get_operator_sector_info(
        pos_id=pos_id,
        repeat_in_sub_sector=False,
    )
    if sector != ALL_SECTORS and sector not in all_sector_operators:
        return []

    all_operators = _get_all_operators()
    if sector != ALL_SECTORS:
        return _filter_operators(
            all_operators=all_operators,
            sector_operators_ids=all_sector_operators.get(sector),
        )

    all_sectors = get_sectors(pos_id=pos_id)
    sectors_name = all_sector_operators.keys()
    if len(all_sectors) - 1 != len(sectors_name):
        return []

    current_operators = all_sector_operators.get(sectors_name[0])
    if len(sectors_name) > 1:
        for sector_name in sectors_name[1:]:
            current_operators = list(set(current_operators) & set(all_sector_operators.get(sector_name)))

    return _filter_operators(
        all_operators=all_operators,
        sector_operators_ids=current_operators,
    )


def _get_available_operators(
    operators_to_ignore,    # type: List[int]
):
    # type: (...) -> List[Dict[str, Any[Union[str, int]]]]

    operators = []
    all_operators = _get_all_operators()
    for operator in all_operators:
        if operator.get("id") not in operators_to_ignore:
            operators.append(operator)

    return operators


@action
def open_service_sector(
    pos_id,     # type: str
):
    # type: (...) -> None

    from table_actions import table_operation_mode
    if table_operation_mode not in [TableOperationMode.INDIVIDUAL_SECTOR, TableOperationMode.SHARED_SECTOR]:
        show_messagebox(
            posid=pos_id,
            message="$NOT_VALID_TABLE_OPERATION_MODE",
            title="$INFORMATION",
        )
        raise StopAction()

    try:
        selected_sector, original_selected_sector = _select_sector(pos_id=pos_id)
        sector_operators = _get_sector_operators(
            pos_id=pos_id,
            sector=original_selected_sector,
        )
        available_operators = _get_available_operators(
            operators_to_ignore=list(map(lambda s: s.get("id"), sector_operators)),
        )
    except Exception as e:
        logger.exception('[rupture_items] Exception {}'.format(e))
        show_messagebox(
            posid=pos_id,
            message="$ERROR_GETTING_DATA",
            title="$INFORMATION",
            buttons="$EXIT",
        )
        raise StopAction()

    dialog_contents = {
        "type": "service_sector",
        "config": {
            "selectedSector": original_selected_sector,
            "leftTitle": "$OPERATORS",
            "rightTitle": selected_sector,
            "confirmTitle": "$CONFIRM_UPDATE_OPERATORS_BY_SECTOR",
            "confirmLeftTitle": "$LEAVE_THE_SECTOR|{0}".format(selected_sector),
            "confirmRightTitle": "$ENTER_THE_SECTOR|{0}".format(selected_sector)
        },
        "availableItems": available_operators,
        "selectedItems": sector_operators
    }

    info_text = json.dumps(dialog_contents)
    show_any_dialog(
        posid=pos_id,
        dlgtype="enableItemsDialog",
        message="",
        title="$MANAGE_SERVICE_SECTOR",
        infotext=info_text,
        buttons="",
        icon="",
        timeout=6000000,
        mask="",
        defvalue="",
        minvalue="",
        maxvalue="",
        contents="",
        asynch=False,
    )
