import time

import hjson
import requests

from core.aochat.BaseModule import BaseModule
from core.chat_blob import ChatBlob
from core.command_param_types import Any, Const, Options, Int
from core.db import DB
from core.decorators import instance, command, timerevent
from core.logger import Logger
from core.lookup.character_service import CharacterService
from core.lookup.org_pork_service import OrgPorkService
from core.private_channel_service import PrivateChannelService
from core.translation_service import TranslationService
from core.igncore import IgnCore
from modules.core.accounting.services.account_service import AccountService
from modules.core.ban.ban_service import BanService


@instance()
class OrgBanController(BaseModule):
    single_org_uri = "https://people.anarchy-online.com/org/stats/d/5/name/%d/basicstats.xml?data_type=json"

    def __init__(self):
        self.logger = Logger(__name__)

    def inject(self, registry):
        self.bot: IgnCore = registry.get_instance("bot")
        self.db: DB = registry.get_instance("db")
        self.text = registry.get_instance("text")
        self.util = registry.get_instance("util")
        self.ban_service: BanService = registry.get_instance("ban_service")
        self.command_alias_service = registry.get_instance("command_alias_service")
        self.ts: TranslationService = registry.get_instance("translation_service")
        self.character_service: CharacterService = registry.get_instance("character_service")
        self.pork: OrgPorkService = registry.get_instance("character_service")
        self.getresp = self.ts.get_response
        self.account_service: AccountService = registry.get_instance("account_service")
        self.priv: PrivateChannelService = registry.get_instance("private_channel_service")

    def start(self):
        self.ts.register_translation("module/ban", self.load_ban_msg)

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

    @command(command="orgban", params=[Const("list", is_optional=True)], access_level="admin",
             description="Show the ban list")
    def ban_list_cmd(self, _, _1):
        query = self.db.query("SELECT * from ban_org_list b "
                              "left join all_orgs a on a.org_id = b.org_id")
        blob = ""
        for row in query:

            blob += f"<highlight>{row.org_name}</highlight> (<highlight>{row.org_id}</highlight> " \
                    f"with <highlight>{row.member_count}</highlight> members) by " \
                    f"{self.character_service.resolve_char_to_name(row.sender_char_id)}\n"
            if row.sender_char_id != 0 and row.sender_char_id is not None:
                blob += f"<tab>Added at: <highlight>{self.util.format_datetime(row.created_at)}</highlight>\n"
                blob += f"<tab>Reason: {row.reason or 'None given'}\n"
            blob += "\n"
        return ChatBlob("Banned Organisations", blob)

    @command(command="orgban", params=[Options(["rem", "remove"]), Int("Organisation")], access_level="admin",
             description="Remove an org from the ban list")
    def ban_remove_cmd(self, _, _1, org):
        if self.db.query("SELECT * from ban_org_list where org_id=?", [org]):
            self.db.exec("DELETE FROM ban_org_list where org_id = ?", [org])
            return f"Successfully unbanned org <highlight>{org}</highlight> - " \
                   f"Beware, all players are still banned using an account ban; " \
                   f"It can be lifted using !account add <name>"

    @command(command="orgban", params=[Options(["rem", "remove"]), Any("Organisation")], access_level="admin",
             description="Remove an org from the ban list")
    def ban_remove_cmd_name(self, request, _, org: str):
        orgs = self.db.query(
            "SELECT * from all_orgs where org_name LIKE ? and org_id in (SELECT org_id from ban_org_list)",
            ["%" + org.replace(" ", "%") + "%"])
        if len(orgs) == 1:
            self.ban_remove_cmd(request, _, orgs[0].org_id)
        elif len(orgs) == 0:
            return "No orgs matching your search found."
        elif len(orgs) > 1:
            blob = "Your search had multiple results; please pick an org:<br>"
            for org in orgs:
                blob += "[%s] <highlight>%s<end> (<highlight>%s<end>) <%s>%s<end> [<highlight>%s<end> " \
                        "members]<br><pagebreak>" \
                        % (self.text.make_chatcmd("Unban", "/tell <myname> orgban remove %s" % org.org_id),
                           # self.text.make_chatcmd("More", "/tell <myname> org info %s" % org.org_id),
                           org.org_name, org.org_id, org.faction.lower(), org.faction, org.member_count)
            return ChatBlob("Pick an Org", blob)

    @command(command="orgban", params=[Const("add", is_optional=True), Int("Organisation"),
                                       Any("reason", is_optional=True)], access_level="admin",
             description="Add an org to the ban list")
    def ban_add_cmd(self, request, _, org, reason):
        if self.db.query("SELECT * from ban_org_list where org_id=?", [org]):
            return f"Organisation with the ID <highlight>{org}</highlight> is already banned."
        if self.db.exec(
                "INSERT INTO ban_org_list(org_id, sender_char_id, created_at, finished_at, reason, ended_early) "
                "VALUES (?, ?, ?, 0, ?, 0)",
                [org, request.sender.char_id, time.time(), reason or ""]):
            self.fetch_single(org, request)
            # return f"Organisation with the ID <highlight>{org}</highlight> has been banned."

    @command(command="orgban",
             params=[Options(["add"], is_optional=True), Any("Organisation")],
             access_level="admin",
             description="Add an org from the ban list")
    def ban_add_cmd_name(self, request, _, org: str):
        orgs = self.db.query("SELECT * from all_orgs where org_name LIKE ? order by org_name",
                             ["%" + org.replace(" ", "%") + "%"])
        if len(orgs) == 1:
            self.ban_add_cmd(request, _, orgs[0].org_id, "")
        elif len(orgs) == 0:
            return " No orgs matching your search found."
        elif len(orgs) > 1:
            blob = "Your search had multiple results; please pick an org:<br>"
            for org in orgs:
                blob += "[%s] <highlight>%s<end> (<highlight>%s<end>) <%s>%s<end> [<highlight>%s<end> " \
                        "members]<br><pagebreak>" \
                        % (self.text.make_chatcmd("Add Ban", "/tell <myname> orgban add %s" % org.org_id),
                           org.org_name, org.org_id, org.faction.lower(), org.faction, org.member_count)
            return ChatBlob("Pick an Org", blob)

    def fetch_single(self, org_id, sender: object):
        start = time.time()
        data = []
        accounts = []
        count = 0
        result = requests.get(self.single_org_uri % org_id).json()
        for char_info in result[1]:
            data.append((char_info["CHAR_INSTANCE"], char_info["NAME"], char_info["FIRSTNAME"],
                         char_info["LASTNAME"],
                         char_info["LEVELX"], char_info["BREED"],
                         char_info["SEX"], result[0]["SIDE_NAME"], char_info["PROF"],
                         char_info["PROF_TITLE"], char_info["DEFENDER_RANK_TITLE"], char_info["ALIENLEVEL"],
                         result[0]["ORG_INSTANCE"], result[0]["NAME"], char_info["RANK_TITLE"],
                         char_info["RANK"], char_info["CHAR_DIMENSION"], char_info["HEADID"],
                         0, char_info["PVPTITLE"], "roster", int(time.time())))

            accounts.append((char_info["CHAR_INSTANCE"], char_info["CHAR_INSTANCE"], -1, start, start))
            self.priv.kick(char_info['CHAR_INSTANCE'])
            count += 1
        with self.db.pool.get_connection() as conn:
            with conn.cursor() as cur:
                cur.executemany(
                    "REPLACE INTO player(char_id, name, first_name, last_name, level, breed, gender, faction, "
                    "profession, profession_title, ai_rank, ai_level, org_id, org_name, org_rank_name, "
                    "org_rank_id, dimension, head_id, pvp_rating, pvp_title, source, last_updated) "
                    "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                    data)
        self.account_service.create_users(accounts, disable=True)
        if sender:
            sender.reply(
                f"Org with ID <highlight>{org_id}</highlight> has been banned. "
                f"Runtime: {time.time() - start:.2f} seconds.")

    @timerevent(budatime="24h", description="Refresh orgbans")
    def refresh_orgban(self, _, _1):
        banned_orgs = self.db.query("SELECT * from ban_org_list")
        # for org in [1456129, 391173,1136642, 1011713]:
        #     if org not in banned_orgs:
        #         self.messagehub.send_message("system_logger", None, f"**WARN** Rebanning {org}",
        #         f"**WARN** Rebanning {org}")
        #         self.ban_add_cmd(None, None, org, 'AUTO-BAN')
        #         banned_orgs.append(org)
        for org in banned_orgs:
            self.fetch_single(org.org_id, None)
            self.logger.info(f"Refreshed bans for org {org.org_id}")
