import hjson

from core.command_param_types import Any
from core.command_service import CommandService
from core.decorators import instance, command, event
from core.dict_object import DictObject
from core.logger import Logger
from core.setting_service import SettingService
from core.setting_types import BooleanSettingType, TextSettingType, NumberSettingType
from core.translation_service import TranslationService


@instance()
class SystemController:
    SHUTDOWN_EVENT = "shutdown"
    MESSAGE_SOURCE = "shutdown_notice"

    def __init__(self):
        self.logger = Logger(__name__)

    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.setting_service: SettingService = registry.get_instance("setting_service")
        self.event_service = registry.get_instance("event_service")
        self.character_service = registry.get_instance("character_service")
        self.ts: TranslationService = registry.get_instance("translation_service")
        self.message_hub_service = registry.get_instance("message_hub_service")
        self.getresp = self.ts.get_response

    def pre_start(self):
        self.event_service.register_event_type(self.SHUTDOWN_EVENT)
        self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)

    def start(self):
        self.ts.register_translation("module/system", self.load_system_msg)

        self.setting_service.register(self.module_name, "expected_shutdown", True, BooleanSettingType(),
                                      "Helps bot to determine if last shutdown was expected or due to a problem")
        self.setting_service.register(self.module_name, "symbol", "!",
                                      TextSettingType(["!", "#", "*", "@", "$", "+", "-"]),
                                      "Symbol for executing bot commands")
        self.setting_service.register(self.module_name, "org_channel_max_page_length", 7500,
                                      NumberSettingType([4500, 6000, 7500, 9000, 10500, 12000]),
                                      "Maximum size of blobs in org channel")
        self.setting_service.register(self.module_name, "private_message_max_page_length", 7500,
                                      NumberSettingType([4500, 6000, 7500, 9000, 10500, 12000]),
                                      "Maximum size of blobs in private messages")
        self.setting_service.register(self.module_name, "private_channel_max_page_length", 7500,
                                      NumberSettingType([4500, 6000, 7500, 9000, 10500, 12000]),
                                      "Maximum size of blobs in private channel")

        self.setting_service.register(self.module_name, "accept_commands_from_slave_bots", True, BooleanSettingType(),
                                      "Accept and respond to commands sent to slave bots (only applies if you have "
                                      "added slave bots in the config)")

    def load_system_msg(self):
        with open("modules/core/system/system.msg", mode="r", encoding="utf-8") as f:
            return hjson.load(f)

    def expected_shutdown(self):
        return self.setting_service.get("expected_shutdown")

    @command(command="shutdown", params=[Any("reason", is_optional=True)], access_level="superadmin",
             description="Shutdown the bot")
    def shutdown_cmd(self, request, reason):
        if request.channel not in [CommandService.ORG_CHANNEL, CommandService.PRIVATE_CHANNEL]:
            request.reply(self._format_message(False, reason))
        self.shutdown(False, reason)

    @command(command="restart", params=[Any("reason", is_optional=True)], access_level="admin",
             description="Restart the bot")
    def restart_cmd(self, request, reason):
        if request.channel not in [CommandService.ORG_CHANNEL, CommandService.PRIVATE_CHANNEL]:
            request.reply(self._format_message(True, reason))
        self.shutdown(True, reason)

    @event(event_type="connect", description="Notify superadmin that bot has come online")
    def connect_event(self, _, _1):
        if self.expected_shutdown().get_value():
            msg = self.getresp("module/system", "expected_online")
        else:
            self.logger.warning("The bot has recovered from an unexpected shutdown or restart")
            msg = self.getresp("module/system", "unexpected_online")

        self.bot.send_org_message(msg, fire_outgoing_event=False)
        self.bot.send_private_channel_message(msg, fire_outgoing_event=False)

        self.expected_shutdown().set_value(False)

    def shutdown(self, should_restart, reason=None):
        self.event_service.fire_event(self.SHUTDOWN_EVENT, DictObject({"restart": should_restart, "reason": reason}))
        # set expected flag
        self.expected_shutdown().set_value(True)
        self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None,
                                              self._format_message(should_restart, reason))
        if should_restart:
            self.bot.restart()
        else:
            self.bot.shutdown()

    def _format_message(self, restart, reason):
        if restart:
            if reason:
                return self.getresp("module/system", "restart") + self.getresp("module/system", "reason",
                                                                               {"reason": reason})
            return self.getresp("module/system", "restart") + ".."
        if reason:
            return self.getresp("module/system", "shutdown") + self.getresp("module/system", "reason",
                                                                            {"reason": reason})
        return self.getresp("module/system", "shutdown") + ".."
