import os
import platform
import threading
import time
from threading import Thread

import psutil

from core.buddy_service import BuddyService
from core.chat_blob import ChatBlob
from core.command_alias_service import CommandAliasService
from core.command_param_types import Const
from core.db import DB
from core.decorators import instance, command
from core.lookup.pork_service import PorkService
from core.message_hub_service import MessageHubService
from core.text import Text
from core.igncore import IgnCore
from core.util import Util
from modules.core.accounting.services.access_service import AccessService


# noinspection DuplicatedCode
@instance()
class StatController:
    threads = {}
    letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
               "v", "w", "x", "y", "z", "others", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
    pork_uri = "https://people.anarchy-online.com/people/lookup/orgs.html?l=%s"
    single_org_uri = "https://people.anarchy-online.com/org/stats/d/5/name/%d/basicstats.xml?data_type=json"

    def inject(self, registry):
        self.bot: IgnCore = registry.get_instance("bot")
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.util: Util = registry.get_instance("util")
        self.pork: PorkService = registry.get_instance("pork_service")
        self.org_pork: PorkService = registry.get_instance("org_pork_service")
        self.command_alias_service: CommandAliasService = registry.get_instance("command_alias_service")
        self.buddy_service: BuddyService = registry.get_instance("buddy_service")
        self.access_service: AccessService = registry.get_instance("access_service")
        self.relay_hub_service: MessageHubService = registry.get_instance("message_hub_service")

    # noinspection LongLine
    @command(command="debug", params=[Const("verbose", is_optional=True)], access_level="admin",
             description="Display debugging statistics about igncom")
    def debug_output(self, _, verbose):
        def adjust_size(size):
            factor = 1024
            for i in [" B", " KB", " MB", " GB", " TB"]:
                if size > factor:
                    size /= factor
                else:
                    return f"{size:.3f}{i}"

        threads = ""
        for thread in threading.enumerate():
            thread: Thread
            threads += f" - {thread.name} [Deamon: {'YES' if thread.daemon else 'NO'}] [Alive: {'YES' if thread.is_alive() else 'NO'}]\n"
        uname = platform.uname()
        virtual_mem = psutil.virtual_memory()
        blob = f" <header>::: Summary :::</header>\n" \
               f" - Tracked orgs: {self.db.query_single('SELECT count(*) as count from orgs').count}\n" \
               f"<tab>- Tracked characters: {self.db.query_single('SELECT count(*) as count from account a where member>1').count}\n" \
               f"<tab>- Registered alts: {self.db.query_single('SELECT count(*) as count from account where char_id != main').count}\n" \
               f"<tab>- Registered mains: {self.db.query_single('SELECT count(*) as count from (SELECT main from account where char_id != main group by main) a').count}\n" \
               f"<tab>- Banned players: {self.db.query_single('SELECT count(*) as count from account where disabled=1').count}\n" \
               f"<tab>- Online players: {self.db.query_single('SELECT count(*) as count from online where char_id not in (SELECT char_id from org_bots)').count}\n" \
               f"<tab>- Online bots: {self.db.query_single('SELECT count(*) as count from online where char_id in (SELECT char_id from org_bots)').count}\n" \
               f"<tab><tab>- Registered bots: {self.db.query_single('SELECT count(*) as count from org_bots').count}\n" \
               f" - Active discord accounts: {self.db.query_single('SELECT count(*) as count from account where discord_joined=1').count}\n" \
               f""" - Inactive discord accounts: {self.db.query_single("SELECT count(*) as count from account where discord_joined=0 and discord_id != 0 and member>1").count}\n""" \
               f" - Commands issued: {self.db.query_single('SELECT count(*) as count from command_usage').count} [since last reset]\n" \
               f"<tab>- Most used command: {self.db.query_single('SELECT COUNT(*) AS count, command from command_usage GROUP BY command ORDER BY count desc;').command} [since last reset]\n" \
               f" - Cached players: {self.db.query_single('SELECT count(*) as count from player').count}\n" \
               f" - Cached orgs: {self.db.query_single('SELECT count(*) as count from all_orgs').count}\n" \
               f"\n" \
               f" <header>::: Bot :::</header>\n" \
               f" - Memory usage: {adjust_size(psutil.Process(os.getpid()).memory_info().rss)}\n" \
               f" - Thread count: {len(threading.enumerate())}\n" \
               f" - Slaves: {len(self.bot.conns)}\n" \
               f" - Runtime: {self.util.time_to_readable(int(time.time()) - self.bot.start_time, max_levels=None)}\n" \
               f"\n" \
               f" <header>::: System :::</header>\n" \
               f" - System: {uname.system}\n" \
               f" - Release: {uname.release}\n" \
               f" - Version: {uname.version}\n" \
               f" - Processor: {uname.processor} ({psutil.cpu_count(logical=False)}C / {psutil.cpu_count()}T)\n" \
               f" - CPU Usage: {psutil.cpu_percent()}%\n" \
               f" - Memory (Total): {adjust_size(virtual_mem.total)}\n" \
               f" - Memory (Avail): {adjust_size(virtual_mem.available)}\n" \
               f" - Memory (Used): {adjust_size(virtual_mem.used)}\n" \
               f" - Database: {self.db.get_type()} using {self.db.pool_size} connections\n" \
               f"\n"
        if verbose:
            blob += f" <header>::: Threads :::</header>\n" \
                    f"{threads}\n" \
                    f"\n"
        return ChatBlob(f"{self.bot.get_char_name()}'s debugging stats", blob)
