import time

from core import command_request
from core.chat_blob import ChatBlob
from core.command_param_types import Const, Character, Options
from core.db import DB
from core.decorators import instance, command
from core.event_service import EventService
from core.lookup.character_service import CharacterService
from core.lookup.pork_service import PorkService
from core.text import Text
from core.translation_service import TranslationService
from core.util import Util
from modules.core.accounting.preference_controller import PreferenceController
from modules.core.accounting.services.access_service import AccessService
from modules.core.accounting.services.account_service import AccountService


@instance()
class AccountController:
    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.buddy_service = registry.get_instance("buddy_service")
        self.util: Util = registry.get_instance("util")
        self.ts: TranslationService = registry.get_instance("translation_service")
        self.db: DB = registry.get_instance("db")
        self.character_service: CharacterService = registry.get_instance("character_service")
        self.account_service: AccountService = registry.get_instance("account_service")
        self.event_service: EventService = registry.get_instance("event_service")
        self.getresp = self.ts.get_response
        self.pork_service: PorkService = registry.get_instance("pork_service")
        self.text: Text = registry.get_instance("text")
        self.preferences: PreferenceController = registry.get_instance("preference_controller")
        self.access_service: AccessService = registry.get_instance("access_service")

    @command(command="account", params=[], access_level="member",
             description="View your account")
    def account(self, request: command_request):
        return self.show_account(request.sender.char_id)

    @command(command="accounts", params=[Const('online', is_optional=True)], access_level="moderator",
             description="View all accounts")
    def accounts(self, request: command_request, online):
        accs = self.account_service.get_all_members(True if online else False)
        main = 0
        main_name = ""
        entries = []
        for entry in accs:
            out = ""
            if main != entry.main:
                main = entry.main
                out += f"\n<{entry.faction.lower()}>{entry.name}</{entry.faction.lower()}>: " \
                       f"[{self.text.make_tellcmd('D', f'account {entry.name}')}]"
                main_name = entry.name
            # n = f"<red>N</red>" if entry.last_seen == 0 else ""
            # out += f"<tab> {self.util.get_prof_icon(entry.profession)}" \
            #        f" {self.text.zfill(entry.level, 220)}/<green>{self.text.zfill(entry.ai_level, 30)}</green> " \
            #        f"<{entry.faction.lower()}>{entry.name}</{entry.faction.lower()}> {n}\n"
            entries.append([main_name, out])
        out = ""
        msg = sorted(entries, key=lambda k: k[0])
        for _, mess in msg:
            out += mess
        self.bot.send_mass_message(request.sender.char_id, ChatBlob(f"All accounts ({len(entries)})", out))

    @command(command="points", params=[], access_level="member",
             description="View your points")
    def points(self, request: command_request):
        alts = self.account_service.get_account(request.sender.char_id)
        self.bot.send_mass_message(request.sender.char_id,
                                   f"So far, you've piled <notice>{alts.points}</notice> points up.")

    @command(command="account", params=[Character("user")],
             access_level="moderator",
             sub_command="moderate", description="Lookup account of another char")
    def display_account(self, _, user):
        if not user.char_id:
            return f"Character <highlight>{user.name}</highlight> not found."
        return self.show_account(user.char_id, True)

    @command(command="account", params=[Const("add"), Character("char")],
             access_level="moderator",
             sub_command="moderate", description="Create a new account for given character",
             extended_description="Potentially breaks in bots using a database generated by an onlinebot. "
                                  "Use with extreme caution.")
    def add_account(self, request: command_request, _, user):
        if not user.char_id:
            return f"Character <highlight>{user.name}</highlight> not found."
        if self.account_service.get_account(user.char_id):
            # Unban the account, if banned
            self.account_service.account_enable(user.char_id)
            # set the memberstatus to 0
            # (-1 is no member,
            # 0 is member,
            # any number above 0 indicates that its an org_member of the same ID)
            self.account_service.account_add_member(user.char_id)
            for char in self.account_service.get_alts(user.char_id):
                self.buddy_service.add_buddy(char.char_id, "member")
            self.account_service.add_log(request.sender.char_id, "system",
                                         f"Opened Account for <highlight>{user.name}</highlight>.",
                                         request.sender.char_id)
            self.account_service.add_log(user.char_id, "system",
                                         f"Account has been reopened by <highlight>{request.sender.name}</highlight>.",
                                         request.sender.char_id)
            return f"There's already an account for character <highlight>{user.name}</highlight>; It has been enabled."
        count = self.account_service.create_users([(user.char_id, user.char_id, 0, time.time(), time.time())])
        if count > 0:
            self.buddy_service.add_buddy(user.char_id, "member")
            self.account_service.add_log(request.sender.char_id, "system",
                                         f"Created Account for <highlight>{user.name}</highlight>.",
                                         request.sender.char_id)
            self.account_service.add_log(user.char_id, "system",
                                         f"Account has been created by <highlight>{request.sender.name}</highlight>.",
                                         request.sender.char_id)
            self.bot.send_mass_message(user.char_id,
                                       f"Your Account has been <green>opened</green> by "
                                       f"<highlight>{request.sender.name}</highlight>.")
            return f"Character <highlight>{user.name}'s</highlight> Account has been created!"
        else:
            return f"There's already an account for character <highlight>{user.name}</highlight>."

    @command(command="account", params=[Const("rem"), Character("char")],
             access_level="moderator",
             sub_command="moderate", description="Disable a new account for given character")
    def rem_account(self, request: command_request, _, user):
        if not user.char_id:
            return f"Character <highlight>{user.name}</highlight> not found."
        if not self.access_service.has_sufficient_access_level(request.sender.char_id, user.char_id):
            return f"The user <highlight>{user.name}</highlight> has a higher rank then you, you cant do that."
        disabled = self.account_service.account_disable(user.char_id)
        if disabled:
            self.buddy_service.remove_buddy(user.char_id, "member")
            self.account_service.add_log(request.sender.char_id, "system",
                                         f"Disabled Account of <highlight>{user.name}</highlight>.",
                                         request.sender.char_id)
            self.account_service.add_log(user.char_id, "system",
                                         f"Account disabled by <highlight>{request.sender.name}</highlight>.",
                                         request.sender.char_id)
            return f"Character <highlight>{user.name}'s</highlight> Account has been disabled!"
        else:
            return f"There's no active account for character <highlight>{user.name}</highlight>."

    @command(command="account", params=[Const("purge"), Character("char")],
             access_level="admin",
             sub_command="modify", description="Purge a user from the database")
    def purge_account(self, request: command_request, _, user):
        if not user.char_id:
            return f"Character <highlight>{user.name}</highlight> not found."
        if not self.access_service.has_sufficient_access_level(request.sender.char_id, user.char_id):
            return f"The user <highlight>{user.name}</highlight> has a higher rank then you, you cant do that."
        account = self.account_service.get_alts(user.char_id)
        if account:
            for alt in account:
                self.buddy_service.remove_buddy(alt.char_id, "member")
                self.db.exec("DELETE FROM notes where char_id=?", [alt.char_id])
            self.db.exec("DELETE FROM account where main=?", [account[0].main])
            self.db.exec("DELETE FROM account_log where char_id=?", [account[0].main])
            self.db.exec("DELETE FROM command_usage where char_id=?", [account[0].main])
            self.db.exec("DELETE FROM pending_accounts where main=? or alt=?", [account[0].main, account[0].main])
            self.db.exec("DELETE FROM mail where recipient=? or sender=?", [account[0].main, account[0].main])
            self.account_service.add_log(request.sender.char_id, "system",
                                         f"Purged the account of <highlight>{user.name}</highlight>.",
                                         request.sender.char_id)
            return f"Character <highlight>{user.name}'s</highlight> Account has been purged!"
        else:
            return f"There's no active account for character <highlight>{user.name}</highlight>."

    @command(command="account",
             params=[Const("rank"), Options(["admin", "moderator", "council", "leader"]), Character("user")],
             access_level="admin", sub_command="modify", description="Add a rank to an Account")
    def set_rank(self, request: command_request, _, rank: str, user):
        if not user.char_id:
            return f"Character <highlight>{user.name}</highlight> not found."
        user = self.account_service.get_main(user.char_id)
        if not user:
            return f"No account for <highlight>{user.name}</highlight> found."
        # is Superadmin
        if rank == "admin" and \
                self.account_service.check_superadmin(self.account_service.get_main(request.sender.char_id).char_id):
            if "admin" in self.account_service.get_ranks(user.char_id):
                return f"<highlight>{user.name}</highlight> already has the rank " \
                       f"<highlight>{rank.capitalize()}</highlight>."
            else:
                self.account_service.add_rank(user.char_id, "admin")
                return f"<highlight>{user.name}</highlight> got promoted to the rank " \
                       f"<highlight>{rank.capitalize()}</highlight>."
        # is Admin
        if self.account_service.check_admin(self.account_service.get_main(request.sender.char_id).char_id) \
                or self.account_service.check_superadmin(self.account_service.get_main(request.sender.char_id).char_id):
            if rank.lower() in self.account_service.get_ranks(user.char_id):
                return f"<highlight>{user.name}</highlight> already has the rank " \
                       f"<highlight>{rank.capitalize()}</highlight>."
            else:
                self.account_service.add_rank(user.char_id, rank.lower())
                return f"<highlight>{user.name}</highlight> got promoted to the rank " \
                       f"<highlight>{rank.capitalize()}</highlight>."
        return "You can't do that."

    @command(command="account",
             params=[Options(["delrank", "remrank"]), Options(["admin", "moderator", "council", "leader"]),
                     Character("user")],
             access_level="admin", sub_command="modify", description="Remove a rank from an Account")
    def rem_rank(self, request: command_request, _, rank: str, user):
        if not user.char_id:
            return f"Character <highlight>{user.name}</highlight> not found."
        user = self.account_service.get_main(user.char_id)
        # is Superadmin
        if rank == "admin" and self.account_service.check_superadmin(
                self.account_service.get_main(request.sender.char_id).char_id):
            if "admin" not in self.account_service.get_ranks(user.char_id):
                return f"<highlight>{user.name}</highlight> is not in the " \
                       f"<highlight>{rank.capitalize()}</highlight> group."
            else:
                self.account_service.del_rank(user.char_id, "admin")
                return f"<highlight>{user.name}</highlight> is nolonger in the " \
                       f"<highlight>{rank.capitalize()}</highlight> group."
        # is Admin
        elif self.account_service.check_admin(self.account_service.get_main(request.sender.char_id).char_id):
            if rank.lower() not in self.account_service.get_ranks(user.char_id):
                return f"<highlight>{user.name}</highlight> is not in the " \
                       f"<highlight>{rank.capitalize()}</highlight> group."
            else:
                self.account_service.del_rank(user.char_id, rank.lower())
                return f"<highlight>{user.name}</highlight> is nolonger in the " \
                       f"<highlight>{rank.capitalize()}</highlight> group."

    def show_account(self, char_id, mod=False) -> str:

        alts = self.account_service.get_alts(char_id)
        if len(alts) < 1:
            return "No Account registered for this user."
        prefs = self.preferences.get_pref_view_small(alts[0])
        response = f"<header>{alts[0].name}'s Account</header>\n\n" \
                   f" Owner: <notice>{alts[0].name}</notice> ({alts[0].char_id}) " \
                   f"[{self.text.make_tellcmd('W', f'whois {alts[0].name}')}] " \
                   f"[{self.text.make_tellcmd('Alts', f'alts {alts[0].name}')}] " \
                   f"({len(alts)})\n"
        if not mod:
            response += f" Options: {prefs}\n"
        response += f" Points: <notice>{alts[0].points}</notice>\n"
        last_seen = {}
        for x in alts:
            if x.last_seen > last_seen.get("last_seen", 0):
                last_seen = x
        access_levels = {f"Member ({alts[0].member})": self.account_service.check_member(alts[0].char_id),
                         "Officer": self.account_service.check_officer(alts[0].char_id),
                         "General": self.account_service.check_general(alts[0].char_id),
                         "President": self.account_service.check_president(alts[0].char_id),
                         "Leader": self.account_service.check_leader(alts[0].char_id),
                         "Council": self.account_service.check_council(alts[0].char_id),
                         "Moderator": self.account_service.check_moderator(alts[0].char_id),
                         "Admin": self.account_service.check_admin(alts[0].char_id)}
        perms = []
        for key, value in access_levels.items():
            if value:
                perms.append(key)
        response += f" Status: {'<green>Open</green>' if alts[0].disabled == 0 else '<red>Closed</red>'}\n"
        response += f" Created at: <notice>{self.util.format_datetime(alts[0].created)}</notice>\n"
        if last_seen:
            response += f" Last seen on <notice>{last_seen.name}</notice> <highlight>{self.util.time_to_readable(time.time() - last_seen.last_seen)}</highlight> ago\n"
        response += f" Permissions: <notice>{', '.join(perms)}</notice>\n"
        if alts[0].discord_joined == 1:
            joined = ' (Joined server)'
        else:
            joined = ' (Left server)' if alts[0].discord_invite != '' else 'Never joined'
        response += f" Discord: <notice>{alts[0].discord_handle}</notice>{joined}\n\n"
        log_types = ['Points', 'Loot', 'Raid', 'Public', 'Admin', 'System']
        response += " Logs: ["
        for i in log_types:
            response += f" {self.text.make_tellcmd(i, f'account log {i.lower()} {alts[0].name} 100')}"
        response += " ]\n\n"

        response += "<header>Last 20 Logs</header>\n"
        rows = self.account_service.get_logs(alts[0].char_id, limit=20)
        for i in rows:
            response += self.account_service.format_entry(i)
        return ChatBlob(f"{alts[0].name}'s Account", response)
