import re

import hjson

from core.chat_blob import ChatBlob
from core.command_param_types import Const, Options, Character, Multiple, Any
from core.decorators import instance, command
from core.dict_object import DictObject
from core.sender_obj import SenderObj
from core.setting_service import SettingService
from core.text import Text
from core.translation_service import TranslationService
from core.igncore import IgnCore
from modules.core.accounting.register_controller import RegisterController
from modules.core.accounting.services.account_service import AccountService


@instance()
class AltsController:
    def inject(self, registry):
        self.bot: IgnCore = registry.get_instance("bot")
        self.account_service: AccountService = registry.get_instance("account_service")
        self.buddy_service = registry.get_instance("buddy_service")
        self.util = registry.get_instance("util")
        self.text: Text = registry.get_instance("text")
        self.ts: TranslationService = registry.get_instance("translation_service")
        self.character_service = registry.get_instance("character_service")
        self.getresp = self.ts.get_response
        self.setting_service: SettingService = registry.get_instance("setting_service")
        self.register_controller: RegisterController = registry.get_instance("register_controller")

    def start(self):
        self.ts.register_translation("module/alts", self.load_alts_msg)

    def load_alts_msg(self) -> dict:
        with open("modules/core/accounting/alts.msg", mode="r", encoding="UTF-8") as f:
            return hjson.load(f)

    @command(command="alts", params=[], access_level="member",
             description="Show your alts")
    def alts_list_cmd(self, request):
        alts = self.account_service.get_alts(request.sender.char_id)
        blob = self.format_alt_list(alts)

        return ChatBlob(self.getresp("module/alts", "list", {"char": alts[0].name, "amount": len(alts)}), blob)

    @command(command="alts", params=[Const("setmain")], access_level="member", description="Set a new main",
             extended_description="You must run this from the character you want to be your new main")
    def alts_setmain_cmd(self, request, _):
        msg, result = self.account_service.set_as_main(request.sender.char_id)

        if result:
            return self.getresp("module/alts", "new_main", {"char": request.sender.name})
        elif msg == "not_an_alt":
            return self.getresp("module/alts", "not_an_alt")
        elif msg == "already_main":
            return self.getresp("module/alts", "already_main")
        else:
            raise Exception("Unknown msg: " + msg)

    @command(command="alts", params=[Const("add"), Multiple(Character("character"))], access_level="member",
             description="Add an alt")
    def alts_add_cmd(self, request, _, alt_chars):

        notfound = []
        done = []
        failed = []
        gotalts = []
        main = self.account_service.get_main(request.sender.char_id)
        for alt in alt_chars:
            if not alt.char_id:
                notfound.append(alt.name if type(alt) == SenderObj else alt)
                continue
            if main.char_id == alt.char_id:
                failed.append(self.getresp("module/alts", "add_fail_self"))
                continue
            msg, result = self.account_service.add_alt(main.char_id, alt.char_id)
            if result:
                done.append(alt.name)
                self.bot.send_mass_message(alt.char_id, self.getresp("module/alts", "add_success_target", {"char": main.name}))
            elif msg == "another_main":
                gotalts.append(alt.name)

        reply = ""
        if len(done) > 0:
            reply += self.getresp("module/alts", "add_success_self",
                                  {"char": ", ".join(done)})
        if len(notfound) > 0:
            reply += "\n" if reply != "" else '' + self.getresp("global", "char_not_found", {"char": ", ".join(notfound)})
        if len(gotalts) > 0:
            reply += "\n" if reply != "" else '' + self.getresp("module/alts", "add_fail_already", {"char": ", ".join(gotalts)})
        reply += "\n".join(failed)
        return reply

    @command(command="alts", params=[Options(["rem", "remove"]), Character("character")], access_level="member",
             description="Remove an alt")
    def alts_remove_cmd(self, request, _, alt_char):
        manual = self.setting_service.get_value("alt_verification") == "1"
        if manual:
            return "This command is disabled, you cannot remove alts."

        if not alt_char.char_id:
            return self.getresp("global", "char_not_found", {"char": alt_char.name})

        msg, result = self.account_service.remove_alt(request.sender.char_id, alt_char.char_id)
        if result:
            return self.getresp("module/alts", "rem_success", {"char": alt_char.name})
        elif msg == "not_alt":
            return self.getresp("module/alts", "rem_fail_not", {"char": alt_char.name})
        elif msg == "remove_main":
            return self.getresp("module/alts", "rem_fail_main")
        else:
            raise Exception("Unknown msg: " + msg)

    @command(command="alts", params=[Character("character")], access_level="member",
             description="Show alts of another character", sub_command="show")
    def alts_list_other_cmd(self, _, char):
        if not char.char_id:
            return self.getresp("global", "char_not_found", {"char": char.name})

        alts = self.account_service.get_alts(char.char_id)
        blob = self.format_alt_list(alts)
        if len(alts) < 1:
            return "No alts found"
        return ChatBlob(self.getresp("module/alts", "list", {"char": alts[0].name, "amount": len(alts)}), blob)

    @command(command="altadmin", params=[Const("add"), Character("main"), Any("alts")],
             access_level="admin", description="Add alts to Main")
    def altadmin_add_cmd(self, _, _1, main, altlist):
        alts = re.findall(r"([^ ]+)", altlist)
        notfound = []
        done = []
        failed = []
        gotalts = []
        if alts:
            for alt in alts:
                char_id = self.character_service.resolve_char_to_id(alt)
                if not char_id:
                    notfound.append(alt.name if type(alt) == SenderObj else alt)
                    continue
                alt = DictObject({"char_id": char_id, "name": alt})
                if main.char_id == alt.char_id:
                    failed.append(self.getresp("module/alts", "altadmin_add_same"))

                msg, result = self.account_service.add_alt(main.char_id, alt.char_id)
                if result:
                    done.append(alt.name)
                elif msg == "another_main":
                    gotalts.append(alt.name)
            reply = ""
            if len(done) > 0:
                reply += self.getresp("module/alts", "altadmin_add_success",
                                      {"alt": ", ".join(done),
                                       "main": main.name})
            if len(notfound) > 0:
                reply += "\n" + self.getresp("global", "char_not_found", {"char": ", ".join(notfound)})
            if len(gotalts) > 0:
                reply += "\n" + self.getresp("module/alts", "add_fail_already", {"char": ", ".join(gotalts)})
            reply += "\n".join(failed)
            return reply

    @command(command="altadmin", params=[Options(["rem", "remove"]), Character("main"), Character("alt")],
             access_level="admin",
             description="Remove alts of main")
    def altadmin_remove_cmd(self, _, _1, main, alt):
        if not main.char_id:
            return self.getresp("global", "char_not_found", {"char": main.name})
        if not alt.char_id:
            return self.getresp("global", "char_not_found", {"char": alt.name})

        msg, result = self.account_service.remove_alt(main.char_id, alt.char_id)

        if result:
            return self.getresp("module/alts", "altadmin_rem_success", {"alt": alt.name, "main": main.name})
        elif msg == "not_alt":
            return self.getresp("module/alts", "altadmin_rem_fail_not", {"alt": alt.name, "main": main.name})
        elif msg == "remove_main":
            return self.getresp("module/alts", "altadmin_rem_fail_main")
        else:
            raise Exception("Unknown msg: " + msg)

    def format_alt_list(self, alts) -> str:
        blob = ""
        for alt in alts:
            name = f"{alt.name}"
            blob += f"{self.util.get_prof_icon(alt.profession)} " \
                    f"<yellow>{self.text.zfill(alt.level, 220)}</yellow>:" \
                    f"<green>{self.text.zfill(alt.ai_level, 30)}</green> " \
                    f":: <{alt.faction.lower()}>{name}</{alt.faction.lower()}>"
            if alt.org_name != "":
                blob += f" [<{alt.faction.lower()}>{alt.org_name}</{alt.faction.lower()}> - " \
                        f"<highlight>{alt.org_rank_id + 1}</highlight>]"
            if self.buddy_service.is_online(alt.char_id):
                blob += " [<green>Online</green>]"
            blob += "\n"
        return blob
