from typing import List

import hjson

from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_param_types import Const
from core.db import DB
from core.decorators import instance, command, event
from core.dict_object import DictObject
from core.setting_service import SettingService
from core.text import Text
from core.translation_service import TranslationService
from modules.onlinebot.online.org_alias_controller import OrgAliasController


@instance()
class AdminController:
    def __init__(self):
        pass

    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.pork_service = registry.get_instance("pork_service")
        self.command_alias_service = registry.get_instance("command_alias_service")
        self.buddy_service: BuddyService = registry.get_instance("buddy_service")
        self.ts: TranslationService = registry.get_instance("translation_service")
        self.getresp = self.ts.get_response
        self.db: DB = registry.get_instance("db")
        self.alias_controller: OrgAliasController = registry.get_instance("org_alias_controller")
        self.text: Text = registry.get_instance("text")
        self.settings_service: SettingService = registry.get_instance("setting_service")

    def start(self):
        self.command_alias_service.add_alias("adminlist", "admin")
        self.command_alias_service.add_alias("admins", "admin")
        self.ts.register_translation("module/admin", self.load_admin_msg)

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

    @event(event_type="connect", description="Add admins as buddies")
    def connect_event(self, _, _1):
        for row in self.get_all():
            self.buddy_service.add_buddy(row.char_id, "admin")

    def get_all(self) -> List[DictObject]:
        return self.db.query("SELECT p.*, COALESCE(p.name, t.char_id) AS name, t.rank, t.sort FROM "
                             "("
                             "SELECT a.main as char_id, a.rank, "
                             "CASE WHEN rank = 'admin' THEN 0 "
                             "WHEN rank = 'moderator' THEN 1 "
                             "WHEN rank = 'council' THEN 2 "
                             "WHEN rank = 'leader' THEN 3 END AS sort FROM ranks a) t "
                             "LEFT JOIN player p ON t.char_id = p.char_id "
                             "where rank in ('admin', 'moderator', 'council', 'leader') "
                             "ORDER BY sort, p.name")

    @command(command="admin", params=[Const("all")], access_level="member",
             description="Shows the administrators of the Bot", sub_command="list")
    def show_all_admins(self, _, _1):
        count = []
        # noinspection SqlAggregates
        users = self.db.query("""
                        SELECT r.rank, r.rank_id, a.main, p.*, IF(o.char_id IS NULL, 0, 1) AS online 
                            FROM (SELECT * FROM  (SELECT
                                                CASE when rank = 'admin' then 0
                                                when rank = 'moderator' then 1
                                                when rank = 'council' then 2
                                                when rank = 'leader' then 3
                                                ELSE 99 END AS rank_id, RANK, 
                                                main FROM ranks ORDER BY rank_id, main LIMIT 100000) a 
                                GROUP BY main ORDER BY rank_id) r 
                                LEFT JOIN account a ON  r.main = a.main 
                                LEFT JOIN player p ON a.char_id=p.char_id 
                                LEFT JOIN online o ON a.char_id=o.char_id 
                                WHERE a.disabled=0 
                                GROUP BY char_id 
                                ORDER BY r.rank_id, a.main desc, a.char_id = a.main DESC, p.name;""")
        blob = ""
        main = 0
        rank = ""
        ranks = {'admin': "Administrator's",
                 "moderator": "Moderator's",
                 "council": "Council Member's",
                 "leader": "Raidleader's"}

        for user in users:
            if user.main not in count:
                count.append(user.main)
            if user.rank != rank:
                if rank != "":
                    blob += "<br>"
                rank = user.rank

                blob += f"<notice><tab><tab>:::<tab><header>{ranks[user.rank]}</header><tab>:::</notice><br>"
            if user.online == 0:
                user.online = 1 if self.buddy_service.is_online(user.char_id) else 0
            if main != user.main:
                main = user.main
                blob += self.format_user(user)
            else:
                blob += self.format_user(user, False)

        return ChatBlob("Administrators (%d)" % len(count), blob)

    @command(command="admin", params=[], access_level="member",
             description="Shows the online Administrators of the bot", sub_command="list")
    def show_admin(self, _):
        count = []

        # noinspection SqlAggregates
        users = self.db.query("""
                SELECT r.rank, r.rank_id, a.main, p.*, IF(o.char_id IS NULL, 0, 1) AS online 
                    FROM (SELECT * FROM  (SELECT
                                        CASE when rank = 'admin' then 0
                                        when rank = 'moderator' then 1
                                        when rank = 'council' then 2
                                        when rank = 'leader' then 3
                                        ELSE 99 END AS rank_id, RANK, 
                                        main FROM ranks ORDER BY rank_id, main LIMIT 100000) a 
                        GROUP BY main ORDER BY rank_id) r 
                        LEFT JOIN account a ON  r.main = a.main 
                        LEFT JOIN player p ON a.char_id=p.char_id 
                        LEFT JOIN online o ON a.char_id=o.char_id 
                        WHERE a.disabled=0 and (o.char_id IS NOT NULL or 
                        (a.main = a.char_id and (SELECT count(*) from online 
                        where char_id in 
                        (SELECT char_id from account where main = r.main)) > 0)) 
                        GROUP BY char_id 
                        ORDER BY r.rank_id, a.main desc, a.char_id = a.main DESC, p.name;""")
        blob = ""
        main = 0
        rank = ""
        ranks = {'admin': "Administrator's",
                 "moderator": "Moderator's",
                 "council": "Council Member's",
                 "leader": "Raidleader's"}

        for user in users:
            if user.main not in count:
                count.append(user.main)
            if user.rank != rank:
                if rank != "":
                    blob += "<br>"
                rank = user.rank
                blob += f"<notice><tab><tab>:::<tab><header>{ranks[user.rank]}</header><tab>:::</notice><br>"
                main = ""
            if main != user.main:
                main = user.main
                blob += self.format_user(user)
            else:
                blob += self.format_user(user, False)

        return ChatBlob("Online Administrators (%d)" % len(count), blob)

    # noinspection LongLine
    def format_user(self, user, main=True):
        alias = self.alias_controller.get_alias(user.org_id) if self.settings_service.get_value(
            "is_alliance_bot") == "1" else user.org_name

        if main:
            return f"<br><pagebreak>[{'<red>O</red>' if user.online == 0 else '<green>O</green>'}] <highlight>{user.name}</highlight> ({user.level}/<green>{user.ai_level}</green> - {alias}) {'[' + self.text.make_chatcmd('Tell', '/tell ' + user.name) + ']' if user.online == 1 else ''}<br>"
        return f" └ [{'<red>O</red>' if user.online == 0 else '<green>O</green>'}] <highlight>{user.name}</highlight> ({user.level}/<green>{user.ai_level}</green> - {alias}) {'[' + self.text.make_chatcmd('Tell', '/tell ' + user.name) + ']' if user.online == 1 else ''}<br>"
