import json
import logging.config
import os
from typing import Any, Optional

from cfgtools import Configuration
from helper import config_logger
from msgbus import (
    MBEasyContext,
    TK_SYS_ACK,
    TK_STORECFG_GET,
    FM_PARAM,
    TK_HV_GLOBALRESTART, MBMessage,
)
from systools import sys_parsefilepath
from ._BaseRepository import BaseRepository
from ._HvLogHandler import HvLogHandler
from ._PosModelRetriever import PosModelRetriever


def find_value_with_vars(
    cfg,                 # type: Configuration
    path,                # type: str
    default_value=None,  # type: Any
):
    # type: (...) -> Optional[str]
    value = cfg.find_value(path, default_value)
    if value is None:
        return value

    for variable_name in os.environ:
        variable_format = "{{{}}}".format(variable_name)
        if variable_format in value:
            value = value.replace(variable_format, os.environ[variable_name])
            if variable_name in ("BUNDLEDIR", "HVDATADIR"):
                value = value.replace("/./", os.sep).replace("//", os.sep).replace("/", os.sep)

    return value


def config_logger_parse_file_name(
    loader_path,              # type: str
    log_name='component',     # type: str
    configure_root=False,     # type: bool
    root_level=logging.WARN,  # type: int
    max_files=5,              # type: int
    max_size=5242880,         # type: int
    add_error_handler=False,  # type: bool
):
    # type: (...) -> None

    real_path = os.path.realpath(loader_path)
    if os.path.isfile(real_path) and real_path.endswith(".json"):
        with open(real_path, "rb") as f:
            json_loads = json.loads(f.read().decode("utf-8"))
            handlers = json_loads.get("handlers")
            if handlers:
                for handler in handlers:
                    file_name = sys_parsefilepath(handlers[handler].get("filename", ""))
                    if file_name:
                        handlers[handler]["filename"] = file_name

                loader_path = json_loads

    config_logger(loader_path, log_name, configure_root, root_level, max_files, max_size, add_error_handler)


def config_logger_with_hv_logger(
    loader_path,              # type: str
    log_name='component',     # type: str
    configure_root=True,      # type: bool
    root_level=logging.WARN,  # type: int
    max_files=5,              # type: int
    max_size=5242880,         # type: int
    add_error_handler=False,  # type: bool
):
    # type: (...) -> None

    config_logger(loader_path, log_name, configure_root, root_level, max_files, max_size, add_error_handler)

    if _is_old_log(loader_path):
        comp_logger = logging.getLogger(log_name)
        comp_logger.addHandler(HvLogHandler())

        if configure_root:
            root_logger = logging.getLogger()
            root_logger.addHandler(HvLogHandler())


def read_sw_config(
    mb_context,   # type: MBEasyContext
    key,          # type: str
):
    # type: (...) -> str

    reply = mb_context.MB_EasySendMessage("StoreWideConfig", token=TK_STORECFG_GET, format=FM_PARAM, data=key)
    if reply.token != TK_SYS_ACK:
        return None

    return str(reply.data)


def restart_system(
        mb_context,             # type: MBEasyContext
        event_type,             # type: str
        pos_id="",              # type: str
        menu_manager_user="",   # type: str
):
    # type: (...) -> MBMessage

    _notify_global_restart(event_type, mb_context, menu_manager_user, pos_id)

    return mb_context.MB_SendMessage(
        destination=mb_context.hv_service,
        token=TK_HV_GLOBALRESTART,
    )


def _notify_global_restart(
        event_type,         # type: str
        mb_context,         # type: MBEasyContext
        menu_manager_user,  # type: str
        pos_id              # type: str
):
    event_xml = '''<GLOBALRESTART posId="{}" userId="{}"/>'''
    data = event_xml.format(pos_id, menu_manager_user)
    mb_context.MB_EasyEvtSend(
        subject="GLOBAL_RESTART",
        type=event_type,
        xml=data,
        synchronous=True,
        timeout=-1,
    )


def _is_old_log(
    loader_path,  # type: str
):
    # type(...) -> bool

    real_path = os.path.realpath(loader_path)
    return not os.path.isfile(real_path) or not real_path.endswith(".json")
