import json
from copy import deepcopy
from datetime import datetime

from sysactions import action
from typing import (
    Any,
    Dict,
    List,
    Optional,
    Union,
)

from .. import mb_context
from application.interactor import SectorOperatorInteractor


ALL_SECTORS = "$ALL_SECTORS"
SECTORS = []
OPERATORS_BY_SECTORS = {}
PARSED_OPERATORS_BY_SECTORS = {}


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

    global SECTORS
    if SECTORS:
        return SECTORS

    from msgbusboundary import MsgBusTableService as tableService

    sector_operator_interactor = SectorOperatorInteractor(table_service=tableService())
    SECTORS = sector_operator_interactor.get_sectors(pos_id=pos_id)
    if ALL_SECTORS not in SECTORS:
        SECTORS.insert(0, ALL_SECTORS)

    return SECTORS


def get_operator_sector_info(
    pos_id,                     # type: Any[Union[int, str]]
    repeat_in_sub_sector=True,  # type: Optional[bool]
):
    # type: (...) -> Dict[str, List[int]]

    from msgbusboundary import MsgBusTableService as tableService

    global OPERATORS_BY_SECTORS
    global PARSED_OPERATORS_BY_SECTORS

    if not repeat_in_sub_sector and OPERATORS_BY_SECTORS:
        return OPERATORS_BY_SECTORS

    if repeat_in_sub_sector and PARSED_OPERATORS_BY_SECTORS:
        return PARSED_OPERATORS_BY_SECTORS

    sector_operator_interactor = SectorOperatorInteractor(table_service=tableService())
    operators_by_sectors = sector_operator_interactor.get_operator_sector_info(pos_id=pos_id)
    OPERATORS_BY_SECTORS = json.loads(operators_by_sectors or "{}")
    PARSED_OPERATORS_BY_SECTORS = _add_sector_operator_into_sub_sectors(
        operators_by_sector=OPERATORS_BY_SECTORS,
        pos_id=pos_id,
    )

    return PARSED_OPERATORS_BY_SECTORS if repeat_in_sub_sector else OPERATORS_BY_SECTORS


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

    try:
        operator_sector_info = get_operator_sector_info(pos_id=pos_id)
        operator_sector_info = json.dumps(operator_sector_info)
    except (Exception,):
        return ''

    return operator_sector_info


@action
def update_operator_sector_info(
    pos_id,         # type: Any[Union[int, str]]
    update_info,    # type: Dict
):
    # type: (...) -> None

    global OPERATORS_BY_SECTORS
    global PARSED_OPERATORS_BY_SECTORS

    from msgbusboundary import MsgBusTableService as tableService

    sector_operator_interactor = SectorOperatorInteractor(table_service=tableService())
    updated_operator_sector_info = sector_operator_interactor.update_operator_sector_info(
        pos_id=pos_id,
        update_info=update_info,
    )
    OPERATORS_BY_SECTORS = json.loads(updated_operator_sector_info or "{}")
    OPERATORS_BY_SECTORS = json.loads(updated_operator_sector_info or "{}")
    PARSED_OPERATORS_BY_SECTORS = _add_sector_operator_into_sub_sectors(
        operators_by_sector=OPERATORS_BY_SECTORS,
        pos_id=pos_id,
    )

    mb_context.MB_EasyEvtSend(
        subject="SECTOR_INFO_MODIFIED",
        type="",
        xml=str(datetime.now())
    )


def _add_sector_operator_into_sub_sectors(
    operators_by_sector,    # type: Dict[str, List[int]]
    pos_id,                 # type: int
):
    # type: (...) -> Dict[str, List[int]]

    modified_operators_by_sector = deepcopy(operators_by_sector)

    all_sectors = get_sectors(pos_id=pos_id)
    for sector in modified_operators_by_sector.keys():
        if sector.startswith("$") or "/" in sector:
            continue
        if not modified_operators_by_sector.get(sector, []):
            continue

        for current_sector in all_sectors:
            if current_sector.startswith(sector) and sector != current_sector:
                current_operators = modified_operators_by_sector.get(current_sector, [])
                current_operators.extend(modified_operators_by_sector[sector])
                current_operators = list(set(current_operators))
                modified_operators_by_sector[current_sector] = current_operators

    return modified_operators_by_sector
