import copy
import json
import mw_helper

from xml.etree import cElementTree as eTree
from sysactions import get_model, translate_message, set_custom, show_confirmation
from typing import List, Optional, Dict

from application.interactor import ServicePeriodInteractor, NavigationInteractor
from actions.products import getProducts

DEFAULT_NAME = "{}##null##False"


def get_selection_service_period(pos_id):
    # type: (int) -> Optional[Dict]

    services = ServicePeriodInteractor().get_services_period()
    if len(services) == 0:
        mw_helper.show_message_dialog(pos_id, "$ERROR", "$SERVICES_PERIOD_NOT_FOUND")
        return None

    price_lists = _format_price_list_for_special_catalog(pos_id, services)
    data = "|".join(price_lists)
    index = mw_helper.show_filtered_list_box_dialog(pos_id, data, "$SELECT_SERVICE_PERIOD", "", "NOFILTER")
    if index in (None, ''):
        return None

    if index > 0:
        data = services[index - 1]
        service_period_id = int(data.get("id"))
        service_period = data.get("priceListId", "")
        name = data.get("name", "")
        is_valid = data.get("isValid", False)
        abbreviation = data.get("priceListAbbr", "")
        confirmation = _confirm_service_period_schedule(pos_id, is_valid, name)
        if confirmation:
            return {"servicePeriodId": service_period_id, "servicePeriod": service_period, "servicePeriodName": name,
                    "servicePeriodAbbr": abbreviation}
        else:
            return None

    return {}


def _confirm_service_period_schedule(pos_id, is_valid, name):
    # type: (int, bool, str) -> bool

    confirmation = True
    if not is_valid:
        confirmation = show_confirmation(pos_id, message="$SERVICE_PERIOD_OUT_OF_SCHEDULE_RECORDED|{0}".format(name))
    return confirmation


def set_services_period_all_pos(pos_id, service_period):
    # type: (int, Dict) -> None

    from msgbusboundary import MsgBusTableService as tableService

    model = get_model(pos_id)
    if "servicePeriodName" in service_period:
        service_period_name = service_period["servicePeriodName"]
    else:
        service_period_name = translate_message(model, "NONE")
    sectors = _get_sectors_services_period(pos_id, model, service_period_name)
    if sectors is None:
        return

    special_catalog_sectors = dict(zip(sectors, [copy.deepcopy(service_period)] * len(sectors)))

    pos_list = tableService().get_exclusive_pos_list()
    data = _get_json_data_service_period(service_period, special_catalog_sectors)
    for pos_number in pos_list:
        set_custom(pos_number, 'SERVICE_PERIOD', data, True)

    getProducts(pos_id, force=True)
    # TODO: Update all POS uis


def _get_json_data_service_period(service_period, sectors):
    # type: (Dict, Dict) -> str

    service_period = "{}" if service_period == '' else service_period
    service_period_id = service_period.get("servicePeriodId", None)
    data = {}
    if len(sectors) == 0:
        data = service_period
        data["servicePeriodId"] = service_period_id or ''
        data["servicePeriodName"] = data.get("servicePeriodName", None)
        data["servicePeriodAbbr"] = data.get("servicePeriodAbbr", '')
    nav_interactor = NavigationInteractor()
    data["navigationsRestricted"] = nav_interactor.get_navigations_restricted_to_service_period(service_period_id)
    data["sectors"] = sectors

    return json.dumps(data, default=lambda o: getattr(o, '__dict__', str(o)))


def _format_price_list_for_special_catalog(pos_id, services):
    # type: (int, List) -> List

    services_list = ["{}##{}".format(service.get("name"), service.get("isValid")) for service in services]
    model = get_model(pos_id)
    services_list.insert(0, translate_message(model, 'NONE'))
    return services_list


def _get_sectors_services_period(pos_id, model, service_period_name):
    # type: (int, eTree.XML, str) -> Optional[List]

    from msgbusboundary import MsgBusTableService as tableService

    sectors = []
    all_tables = tableService().list_tables(pos_id)
    if len(all_tables) == 0:
        return sectors

    options = _get_options_sectors_services_period(all_tables, model)
    mask = "NO_SALE_PANEL_IN_SERVICE_PERIOD"
    selected = mw_helper.show_check_list_box_dialog(pos_id, options, "$SELECT_SECTORS_SERVICE_PERIOD", mask=mask)
    if not len(selected):
        return None

    all_store = False
    all_sectors = False
    for selected_index in selected:
        if int(selected_index) == 1:
            all_sectors = True
            continue
        if int(selected_index) == 0:
            all_store = True
            break
        sector = options[int(selected_index)]
        sectors.append(sector.split("##")[0])

    if _display_sector_confirmation(pos_id, all_store, all_sectors, sectors, service_period_name):
        return sectors
    return None


def _get_options_sectors_services_period(all_tables, model):
    # type: (List, eTree.XML) -> List

    options = []
    [options.append(table.sector) for table in all_tables if table.sector not in options]
    options.sort(key=lambda item: item)
    for index, sector in enumerate(options):
        name = DEFAULT_NAME.format(sector)
        data = {"index": index + 1, "id": None, "name": name}
        options[index] = data

    title = translate_message(model, "ALL_STORE")
    name = "{}##True".format(DEFAULT_NAME.format(title))
    insert_option(options, -1, name)

    title = translate_message(model, "ALL_SECTORS")
    name = DEFAULT_NAME.format(title)
    insert_option(options, 0, name)

    options.sort(key=lambda x: (x["index"]))
    return ["{0}".format(c["name"]) for c in options]


def insert_option(options, index, name):
    # type: (List, int, str) -> None

    data = {"index": index, "id": None, "name": name}
    options.insert(index, data)


def _display_sector_confirmation(pos_id, all_store, all_sectors, sectors, service_period_name):
    # type: (int, bool, bool, List[str], str) -> bool

    if all_store:
        message = "$SERVICE_PERIOD_WILL_BE_ACTIVATE_FOR_ENTIRE_STORE|{0}".format(service_period_name)
    elif all_sectors:
        message = "$SERVICE_PERIOD_WILL_BE_ACTIVATE_FOR_ALL_SECTORS|{0}".format(service_period_name)
    else:
        sectors_name = ", ".join(sectors)
        message = "$SERVICE_PERIOD_WILL_BE_ACTIVATE_FOR_SECTORS|{0}|{1}".format(service_period_name, sectors_name)
    return show_confirmation(pos_id, message)
