import time

from core.chat_blob import ChatBlob
from core.command_alias_service import CommandAliasService
from core.command_param_types import Const, Character, Any, Int
from core.db import DB
from core.decorators import instance, command
from core.event_service import EventService
from core.lookup.character_history_service import CharacterHistoryService
from core.lookup.character_service import CharacterService
from core.lookup.pork_service import PorkService
from core.message_hub_service import MessageHubService
from core.setting_service import SettingService
from core.text import Text
from core.igncore import IgnCore
from core.util import Util
from modules.core.accounting.services.account_service import AccountService


@instance()
class RegisterController:
    def inject(self, registry):
        self.bot: IgnCore = registry.get_instance("bot")
        self.buddy_service = registry.get_instance("buddy_service")
        self.util: Util = registry.get_instance("util")
        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.pork_service: PorkService = registry.get_instance("pork_service")
        self.text: Text = registry.get_instance("text")
        self.setting_service: SettingService = registry.get_instance("setting_service")
        self.character_history_service: CharacterHistoryService = registry.get_instance("character_history_service")
        self.command_alias_service: CommandAliasService = registry.get_instance("command_alias_service")
        self.messagehub: MessageHubService = registry.get_instance("message_hub_service")

    def start(self):
        self.command_alias_service.add_alias("pending", "register pending")
        self.command_alias_service.add_alias("recommend", "register recommend")
        self.messagehub.register_message_source("registration")

    @command(command="register", params=[Const("pending"), Int('count', is_optional=True)],
             description="Show the latest Recommendations", sub_command="mng", access_level="admin")
    def register_pending(self, _, _1, limit):
        limit = limit or 25
        latest = self.db.query("SELECT "
                               "main.char_id as main_id, "
                               "alt.char_id as alt_id, "
                               "recommender.char_id as recommender_id, "

                               "main.name as main_name, "
                               "alt.name as alt_name, "
                               "recommender.name as recommender_name, "

                               "main.faction as main_faction, "
                               "alt.faction as alt_faction, "
                               "recommender.faction as recommender_faction, "

                               "main.level as main_level, "
                               "alt.level as alt_level, "
                               "recommender.level as main_level, "

                               "alt.ai_level as alt_ai_level, "
                               "main.ai_level as main_ai_level, "
                               "recommender.ai_level as recommender_ai_level, "

                               "reason "
                               "from pending_accounts p "
                               "left join player alt on alt.char_id = p.alt "
                               "left join player main on main.char_id = p.main "
                               "left join player recommender on recommender.char_id = p.recommender where answered=0 "
                               "order by time desc limit ?", [limit])
        blob = ""
        for entry in latest:
            blob += self.format_pending(entry, buttons=True)

        return ChatBlob("Latest recommendations", blob)

    @command(command="register", params=[Const("pending"), Const('latest'), Int('count', is_optional=True)],
             description="Show the latest Recommendations", sub_command="mng", access_level="admin")
    def register_pending_latest(self, _, _1, _2, limit):
        limit = limit or 25
        latest = self.db.query("SELECT "
                               "main.char_id as main_id, "
                               "alt.char_id as alt_id, "
                               "recommender.char_id as recommender_id, "

                               "main.name as main_name, "
                               "alt.name as alt_name, "
                               "recommender.name as recommender_name, "

                               "main.faction as main_faction, "
                               "alt.faction as alt_faction, "
                               "recommender.faction as recommender_faction, "

                               "main.level as main_level, "
                               "alt.level as alt_level, "
                               "recommender.level as main_level, "

                               "alt.ai_level as alt_ai_level, "
                               "main.ai_level as main_ai_level, "
                               "recommender.ai_level as recommender_ai_level, "

                               "reason "
                               "from pending_accounts p "
                               "left join player alt on alt.char_id = p.alt "
                               "left join player main on main.char_id = p.main "
                               "left join player recommender on recommender.char_id = p.recommender "
                               "order by time desc limit ?", [limit])
        blob = ""
        for entry in latest:
            blob += self.format_pending(entry)

        return ChatBlob("Latest recommendations", blob)

    # noinspection LongLine
    def format_pending(self, entry, buttons=False):
        button = "[<green>" + self.text.make_tellcmd(name="APPROVE", msg=f"pending approve {entry.alt_name}",
                                                     style="style='text-decoration:none'") + "</green>] - [<red>" + self.text.make_tellcmd(
            name="DENY", msg=f"pending deny {entry.alt_name}",
            style="style='text-decoration:none'") + "</red>]" if buttons else ""
        if entry.main_id == entry.alt_id:
            text = f"[<notice>ACC</notice>]  <{entry.main_faction.lower()}>{entry.main_name}</{entry.main_faction.lower()}> ({entry.main_level}/<green>{entry.main_ai_level}</green>) " \
                   f" [{self.text.make_tellcmd('W', f'whois {entry.main_name}')}] " \
                   f"[{self.text.make_tellcmd('H', f'history {entry.main_name}')}]\n" \
                   f"Recommender: <{entry.recommender_faction.lower()}>{entry.recommender_name}</{entry.recommender_faction.lower()}> Why: <notice>{entry.reason}</notice>\n" \
                   f"{button}"
        else:
            account = self.account_service.get_account(entry.main_id)
            text = f"[<notice>ALT</notice>] <{entry.alt_faction.lower()}>{entry.alt_name}</{entry.alt_faction.lower()}> ({entry.alt_level}/<green>{entry.alt_ai_level}</green>) " \
                   f" [{self.text.make_tellcmd('W', f'whois {entry.alt_name}')}] " \
                   f"[{self.text.make_tellcmd('H', f'history {entry.alt_name}')}]\n" \
                   f"Main: <{entry.main_faction.lower()}>{entry.main_name}</{entry.main_faction.lower()}> ({entry.main_level}/<green>{entry.main_ai_level}</green>) [Join: {self.util.format_datetime(account.created)}]" \
                   f" - [{self.text.make_tellcmd('W', f'whois {entry.main_name}')}] " \
                   f"[{self.text.make_tellcmd('H', f'history {entry.main_name}')}]\n" \
                   f"{button}"

        return text + "\n\n"

    @command(command="register", params=[Const("pending"), Const('deny'), Character('character')],
             description="Deny (and disable) a pending account", sub_command="mng", access_level="admin")
    def register_pending_deny(self, request, _1, _2, user):
        pending = self.account_service.is_pending(user.char_id)
        if not pending:
            return f"There's no pending registration for <highlight>{user.name}</highlight>."
        self.account_service.create_users([(pending.alt, pending.alt, -1, time.time(), time.time())])
        self.account_service.add_log(request.sender.char_id, "system",
                                     f"Created <highlight>{user.name}</highlight>'s account.",
                                     request.sender.char_id)
        self.account_service.add_log(user.char_id, "system",
                                     f"Account closed by <highlight>{request.sender.name}</highlight>.",
                                     request.sender.char_id)

        self.db.exec("UPDATE pending_accounts set answered = 1 where alt=?", [pending.alt])
        self.account_service.account_disable(user.char_id)
        self.send_notify(self.Notify.DENIED, user.name, user.name)

    # noinspection LongLine
    @command(command="register", params=[Const("pending"), Const('approve'), Character('character')],
             description="Approve (and activate) a pending account", sub_command="mng", access_level="admin")
    def register_pending_approve(self, request, _1, _2, user):
        pending = self.account_service.is_pending(user.char_id)
        if not pending:
            return f"There's no pending registration for <highlight>{user.name}</highlight>."
        self.account_service.create_users([(pending.alt, pending.alt, 0, time.time(), time.time())])
        if pending.alt == pending.main:
            self.db.exec("UPDATE pending_accounts set answered = 1 where alt=?", [pending.alt])
            self.account_service.add_log(request.sender.char_id, "system",
                                         f"Opened <highlight>{user.name}</highlight>'s account.",
                                         request.sender.char_id)
            self.account_service.add_log(user.char_id, "system",
                                         f"Account opened by <highlight>{request.sender.name}</highlight>.",
                                         request.sender.char_id)
            recommender: str = self.character_service.get_char_name(pending.recommender)
            self.buddy_service.add_buddy(user.char_id, "member")
            self.bot.send_mass_message(user.char_id,
                                       f"Your Account has been <green>opened</green> by "
                                       f"<highlight>{request.sender.name}</highlight>. "
                                       f"<highlight>{recommender.capitalize()}</highlight> has recommended you.")
            self.send_notify(self.Notify.APPROVAL_MAIN, user.name, user.name)
        else:
            msg, typ = self.account_service.add_alt(pending.main, pending.alt, approve=True)
            if msg == "success":
                self.db.exec("UPDATE pending_accounts set answered = 1 where alt=?", [pending.alt])
                self.account_service.add_log(request.sender.char_id, "system",
                                             f"Added <highlight>{user.name}</highlight> as an alt of <highlight>{self.character_service.resolve_char_to_name(pending.main)}</highlight>.",
                                             request.sender.char_id)
                self.account_service.add_log(user.char_id, "system",
                                             f"Request to add <highlight>{user.name}</highlight> as an alt "
                                             f"has been approved by <highlight>{request.sender.name}</highlight>.",
                                             request.sender.char_id)
                self.send_notify(self.Notify.APPROVAL_ALT,
                                 self.character_service.resolve_char_to_name(pending.main),
                                 user.name)
            else:
                return "Something went wrong.."

    @command(command="register", params=[Const('alt'), Character('character')],
             description="Add an alt", access_level="member")
    def register_alt(self, request, _, alt):
        manual = self.setting_service.get_value("alt_verification") == "1"
        if not alt.char_id:
            return "Character does not exist"
        if not manual:
            return "This command is currently disabled, please use <highlight>!alts add</highlight>"
        msg, _ = self.account_service.add_pending_alt(request.sender.char_id, alt.char_id)
        if msg in ["another_main", "already_main"]:
            return f"You cannot add <highlight>{alt.name}</highlight> as an alt, because it already has a main."
        elif msg == "pending_alt":
            return f"There's already a pending registration for the alt <highlight>{alt.name}</highlight>, " \
                   f"please wait for an admin to confirm it."
        elif msg == "success":
            self.send_notify(self.Notify.REQUEST_ALT, request.sender.name, alt.name)
            return f"You requested to add <highlight>{alt.name}</highlight> as an alt."

    @command(command="register", params=[Const('recommend'), Character('character'), Any('reason')],
             description="Recommend someone as a raider", access_level="member")
    def register_account(self, request, _, user, reason):
        if not user.char_id:
            return "Character does not exist"
        if self.account_service.get_account(user.char_id):
            return f"There's already an account for <highlight>{user.name}</highlight> registered."
        msg, _ = self.account_service.add_pending_account(request.sender.char_id, user.char_id, reason)
        if msg in ["another_main", "already_main"]:
            return f"You cannot recommend <highlight>{user.name}</highlight>, " \
                   f"because the character is already registered."
        elif msg == "pending_alt":
            return f"There's already a pending registration for the character <highlight>{user.name}</highlight>, " \
                   f"please wait for an admin to confirm it."
        elif msg == "success":
            self.send_notify(self.Notify.REQUEST_MAIN, user.name, user.name)

    def send_notify(self, notify_type, main, alt):
        message = "[<cyan>PG</cyan>] "
        if notify_type == self.Notify.APPROVAL_MAIN:
            message += f"[<cyan>Main</cyan>] Approved: <highlight>{main}</highlight>'s Account has been opened."
        elif notify_type == self.Notify.APPROVAL_ALT:
            message += f"[<cyan>Alt</cyan>] Approved: <highlight>{alt}</highlight> " \
                       f"has been assigned to <highlight>{main}</highlight>."
        elif notify_type == self.Notify.DENIED:
            message += f"Denied: <highlight>{main}</highlight>'s Account has been closed."
        elif notify_type == self.Notify.REQUEST_ALT:
            message += f"[<cyan>Alt</cyan>] Request: <highlight>{alt}</highlight> => <highlight>{main}</highlight>"
        elif notify_type == self.Notify.REQUEST_MAIN:
            message += f"[<cyan>Main</cyan>] Request: <highlight>{main}</highlight> as a new " \
                       f"<highlight>raider</highlight>"
        self.messagehub.send_message("registration", None, f"{message}", f"{message}")

    class Notify:
        APPROVAL_MAIN = "approval-main"
        APPROVAL_ALT = "approval-alt"
        DENIED = "denied"
        REQUEST_ALT = "req-alt"
        REQUEST_MAIN = "req-main"
