from core.chat_blob import ChatBlob
from core.command_param_types import Options
from core.db import DB
from core.decorators import instance, command, setting
from core.setting_service import SettingService
from core.setting_types import BooleanSettingType
from core.text import Text


@instance()
class LootListsController:
    def __init__(self):
        self.categories = {
            "s7": "Sector 7",
            "s13": "Sector 13",
            "s28": "Sector 28",
            "s35": "Sector 35",
            "s42": "Sector 42",
            "db": "DustBrigade",
            "aquarius": "Aquarius",
            "sagittarius": "Sagittarius",
            "taurus": "Taurus",
            "libra": "Libra",
            "capricorn": "Capricorn",
            "gemini": "Gemini",
            "virgo": "Virgo",
            "cancer": "Cancer",
            "pisces": "Pisces",
            "scorpio": "Scorpio",
            "aries": "Aries",
            "leo": "Leo",
            "tnh": "The Night Heart",
            "barmor": "Beast Armor",
            "bweapons": "Beast Weapons",
            "bstars": "Stars",
            "sb": "Shadowbreeds",
            "alba": "Albtraum",
            "samples": "Samples",
            "ancients": "Ancients",
            "c&cm": "Crystals & Crystalised Memories",
            "pbc": "Pocket Boss Crystals",
            "r&pu": "Rings and Preservation Units",
            "symbs": "Symbiants",
            "spirits": "Spirits",
            "pgems": "Profession Gems",
            "gen": "General",
            "db1": "DB1",
            "db2": "DB2",
            "db3": "DB3",
            "ncu": "HUD/NCU",
            "gaunt": "Bastion",
            "mitaar": "Mitaar",
            "12m": "12Man",
            "vortexx": "Vortexx",
            "dbarmor": "DB Armor",
            "util": "Util",
            "poh": "Pyramid of Home",
            "totwh": "Temple of Three Winds (HL)",
            "binyacht": "Binyacht the Faithful",
            "guardian": "Guardian of the Three",
            "summoner": "The Immortal Summoner",
            "lien": "Lien the Memory-Devourer",
            "loremaster": "The Loremaster",
            "nematet": "Nematet the Subjugator of Time",
            "aegis": "Aegis of Tomorrow",
            "gartua": "Gartua the Gate Guardian",
            "aztur": "Aztur the Immortal",
            "khalum": "Khalum the Weaver of Flesh",
            "uklesh": "Uklesh the Beguiling",

            "subh": "Condemned Subway (HL)",
            "shiro": "Eliminator Shiro",
            "eumen": "Eumenides",
            "qets": "Queen of the Slums",
            "psion": "The Psion",
            "pbcr": "Primal Bloodcreeper",
            "aneid": "Vergil Aeneid",
            "abmouth": "Abmouth Supremus",

        }

    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.setting_service: SettingService = registry.get_instance("setting_service")
        self.command_alias_service = registry.get_instance("command_alias_service")

    def start(self):
        self.command_alias_service.add_alias("aries", "pande aries")
        self.command_alias_service.add_alias("aquarius", "pande aquarius")
        self.command_alias_service.add_alias("leo", "pande leo")
        self.command_alias_service.add_alias("virgo", "pande virgo")
        self.command_alias_service.add_alias("cancer", "pande cancer")
        self.command_alias_service.add_alias("gemini", "pande gemini")
        self.command_alias_service.add_alias("libra", "pande libra")
        self.command_alias_service.add_alias("pisces", "pande pisces")
        self.command_alias_service.add_alias("capricorn", "pande capricorn")
        self.command_alias_service.add_alias("scorpio", "pande scorpio")
        self.command_alias_service.add_alias("taurus", "pande taurus")
        self.command_alias_service.add_alias("sagittarius", "pande sagittarius")
        self.command_alias_service.add_alias("tnh", "pande tnh")
        self.command_alias_service.add_alias("barmor", "pande barmor")
        self.command_alias_service.add_alias("bstars", "pande bstars")
        self.command_alias_service.add_alias("bweapons", "pande bweapons")

        self.command_alias_service.add_alias("s7", "apf s7")
        self.command_alias_service.add_alias("s13", "apf s13")
        self.command_alias_service.add_alias("s28", "apf s28")
        self.command_alias_service.add_alias("s35", "apf s35")
        self.command_alias_service.add_alias("s42", "apf s35")

        self.command_alias_service.add_alias("mitaar", "xan mitaar")
        self.command_alias_service.add_alias("12m", "xan 12m")
        self.command_alias_service.add_alias("vortexx", "xan vortexx")

        self.command_alias_service.add_alias("alba", "albtraum")

        self.command_alias_service.add_alias("lt", "loottables")
        # self.command_alias_service.add_alias("raids", "loottables")
        self.command_alias_service.add_alias("ltables", "loottables")
        self.command_alias_service.add_alias("loots", "loottables")

    @setting(name="use_item_icons", value="True", description="Use icons when building loot list")
    def use_item_icons(self):
        return BooleanSettingType()

    @command(command="loottables", params=[], description="Show all Loottables", access_level="member")
    def loottables_cmd(self, _):
        return ChatBlob("Loot Tables", self.build_overview())

    #                   #
    #       APF         #
    #                   #
    @command(command="apf",
             params=[Options(["s7", "s13", "s28", "s35", "s42"])],
             description="Get list of items from APF", access_level="member")
    def apf_loot_cmd(self, _, category):
        add_all = True if category not in ["s7", "s42"] else False
        category = self.get_real_category_name(category)

        items = self.get_items("APF", category)

        if items:
            return ChatBlob(f"{category} loot table", self.build_list(items, "APF", category, add_all))
        else:
            return f"No loot registered for <highlight>{category}<end>."

    @command(command="apf", params=[], description="Get list of items from APF", access_level="member")
    def apf_tables_cmd(self, _):
        return ChatBlob("APF loot tables", self.build_overview("APF", "apf"))

    #               #
    #   Albtraum    #
    #               #
    @command(command="albtraum", params=[],
             description="Get list of items from Albtraum", access_level="member")
    def albtraum_loot_cmd(self, _):
        return ChatBlob("Albtraum loot tables", self.build_overview("Albtraum", "albtraum"))

    @command(command="albtraum", params=[Options(["c&cm", "pbc", "r&pu", "ancients", "samples"])],
             description="Get list of items from Albtraum", access_level="member")
    def albtraum_tables_cmd(self, _, category):
        category = self.get_real_category_name(category)

        items = self.get_items("Albtraum", category)

        if items:
            return ChatBlob(f"{category} loot table", self.build_list(items, "Albtraum", category))
        else:
            return f"No loot registered for <highlight>{category}<end>."

    #               #
    #  Pandemonium  #
    #               #
    @command(command="pande",
             params=[Options(["bweapons", "barmor", "bstars", "aries", "aquarius", "leo",
                              "virgo", "cancer", "gemini", "libra", "pisces", "capricorn",
                              "scorpio", "taurus", "sagittarius", "tnh", "gaunt", "sb"])],
             description="Get list of items from Pandemonium", access_level="member")
    def pande_loot_cmd(self, _, category_name):
        category = self.get_real_category_name(category_name)

        items = self.get_items("Pande", category)

        if items:
            return ChatBlob(f"{category} loot table", self.build_list(items, "Pande", category))
        else:
            return f"No loot registered for <highlight>{category_name}<end>."

    @command(command="pande", params=[], description="Get list of items from Pandemonium", access_level="member")
    def pande_tables_cmd(self, _):
        return ChatBlob("Pandemonium loot tables", self.build_overview("Pande", "pande"))

    #               #
    # Dust Brigade  #
    #               #
    @command(command="db", params=[Options(["db1", "db2", "db3", "dbarmor", "util"])],
             description="Get list of items from DustBrigade", access_level="member")
    def db_loot_cmd(self, _, category):
        category = self.get_real_category_name(category)
        items = self.get_items("DustBrigade", category)
        if items:
            return ChatBlob(f"{category} loot table", self.build_list(items, "DustBrigade", category))
        else:
            return f"No loot registered for <highlight>{category}<end>."

    @command(command="db", params=[], description="Get list of items from DustBrigade", access_level="member")
    def db_tables_cmd(self, _):
        return ChatBlob("DustBrigade loot tables", self.build_overview("DustBrigade", "db"))

    #               #
    #      Xan      #
    #               #
    @command(command="xan", params=[Options(["mitaar", "12m", "vortexx"]),
                                    Options(["gen", "symbs", "spirits", "gem"], is_optional=True)],
             description="Get list of items from Xan", access_level="member")
    def xan_loot_cmd(self, _, category, sub):
        category = self.get_real_category_name(category)
        sub = self.get_real_category_name(sub)
        blob = ""
        if not sub:
            blob += self.build_list(self.get_items(category, "General"), category, "General")
            blob += self.build_list(self.get_items(category, "Symbiants"), category, "Symbiants")
            blob += self.build_list(self.get_items(category, "Spirits"), category, "Spirits")
        else:
            blob += self.build_list(self.get_items(category, sub), category, sub)

        return ChatBlob(f"{category} loot table", blob)

    @command(command="xan", params=[], description="Get list of items from Xan", access_level="member")
    def xan_tables_cmd(self, _):
        blob = ""
        raids = ["Mitaar", "Vortexx", "12Man"]

        for raid in raids:
            show_loot = self.text.make_chatcmd("Loot table",
                                               f"/tell <myname> xan {self.get_real_category_name(raid, True)}")

            sql = "SELECT COUNT(*) AS count FROM raid_loot WHERE raid = ?"
            count = self.db.query_single(sql, [raid]).count

            blob += f"{raid} - {count} items\n"
            blob += f" └ [{show_loot}]\n\n"

        return ChatBlob("Xan loot tables", blob)

    #               #
    # Pyramid of Home#
    #               #
    @command(command="poh", params=[Options(["gen", "ncu"])],
             description="Get list of items from Pyramid of Home", access_level="member")
    def poh_loot_cmd(self, _, category_name):
        category = self.get_real_category_name(category_name)
        items = self.get_items("Pyramid of Home", category)
        if items:
            return ChatBlob(f"{category} loot table", self.build_list(items, "poh", category))
        else:
            return f"No loot registered for <highlight>{category_name}<end>."

    @command(command="poh", params=[], description="Get list of items from Pyramid of Home", access_level="member")
    def poh_tables_cmd(self, _):
        return ChatBlob("Pyramid of Home loot tables", self.build_overview("Pyramid of Home", "poh"))

    #########################################
    #   Temple of Three Winds (Highlevel)   #
    #########################################

    @command(command="totwh", params=[Options(
        ["binyacht", "guardian", "summoner", "loremaster", "nematet", "aegis", "lien", "gartua", "aztur", "khalum",
         "uklesh", "gen", "armor"])],
             description="Get list of items from Temple of Three Winds", access_level="member")
    def totwh_loot_cmd(self, _, category_name):
        category = self.get_real_category_name(category_name)
        items = self.get_items("Temple of Three Winds (HL)", category)
        if items:
            return ChatBlob(f"{category} loot table", self.build_list(items, "totwh", category))
        else:
            return f"No loot registered for <highlight>{category_name}<end>."

    @command(command="totwh", params=[], description="Get list of items from Temple of Three Winds", access_level="member")
    def totwh_tables_cmd(self, _):
        return ChatBlob("Temple of Three Winds (HL) loot tables",
                        self.build_overview("Temple of Three Winds (HL)", "totwh"))

    ###############################
    #   Condemned Subway (raid)   #
    ###############################

    @command(command="subh", params=[Options(["shiro", "eumen", "qets", "psion", "pbcr", "aneid", "abmouth", "gen"])],
             description="Get list of items from Condemned Subway (HL)", access_level="member")
    def subh_loot_cmd(self, _, category_name):
        category = self.get_real_category_name(category_name)
        items = self.get_items("Condemned Subway (HL)", category)
        if items:
            return ChatBlob(f"{category} loot table", self.build_list(items, "subh", category))
        else:
            return f"No loot registered for <highlight>{category_name}<end>."

    @command(command="subh", params=[], description="Get list of items from Condemned Subway (HL)",
             access_level="member")
    def subh_tables_cmd(self, _):
        return ChatBlob("Condemned Subway (HL) loot tables", self.build_overview("Condemned Subway (HL)", "subh"))

    def build_overview(self, name=None, cmd=None):
        blob = ""
        if name and cmd:
            sql = "SELECT category FROM raid_loot WHERE raid = ? GROUP BY category"
            raids = self.db.query(sql, [name])
            for raid in raids:
                show_loot = self.text.make_chatcmd(
                    "Loot table", f"/tell <myname> {cmd} {self.get_real_category_name(raid.category, True)}")

                sql = "SELECT COUNT(*) AS count FROM raid_loot WHERE category = ? and raid=?"
                count = self.db.query_single(sql, [raid.category, name]).count

                blob += f"<highlight>{raid.category}<end> - {count} items\n"
                blob += f" └ [{show_loot}]\n\n"
                blob += "<pagebreak>"
        if not name and not cmd:
            raids = [
                ("Condemned Subway (HL)", "subh"),
                ("Temple of Three Winds (HL)", "totwh"),
                ("12Man", "xan 12m"),
                ("Vortexx", "xan vortexx"),
                ("Mitaar", "xan mitaar"),
                (("APF", "Sector 7"), "apf s7"),
                (("APF", "Sector 13"), "apf s13"),
                (("APF", "Sector 28"), "apf s28"),
                (("APF", "Sector 35"), "apf s35"),
                ("Albtraum", "albtraum"),
                ("DustBrigade", "db"),
                ("Pande", "pande"),
                ("Pyramid of Home", "poh")
            ]
            for raid in raids:
                title = raid[0][1] if isinstance(raid[0], tuple) else raid[0]
                cmd = raid[1]
                show_loot = self.text.make_chatcmd("Loot table", f"/tell <myname> {cmd}")
                blob += f"<highlight>{title}<end>\n"
                blob += f" └ [{show_loot}]\n\n"
                blob += "<pagebreak>"
        return blob

    # Raids available in AO:
    # s7, s10, s13, s28, s35, s42, aquarius, virgo, sagittarius, beastweapons, beastarmor,
    # beaststars, tnh, aries, leo, cancer, gemini, libra, pisces, taurus,
    # capricorn, scorpio, tara, vortexx, mitaar, 12m, db1, db2, db3, poh,
    # biodome, manex (collector), hollow islands, mercenaries
    def build_list(self, items, raid=None, category=None, add_all=False):
        blob = ""

        if add_all:
            blob += f"{self.text.make_chatcmd('Add all', f'/tell <myname> loot addraid {raid} {category}')} items to loot list\n\n"

        blob += f"<header2>{category}<end>\n" if category is not None else ""

        for item in items:
            comment = f" ({item.comment})" if item.comment != "" else ""
            item.id = self.text.make_item(item.low_id, item.high_id, item.ql, item.name + comment)

            if item.multiloot > 1:
                single_link = self.text.make_chatcmd("Add to loot", f"/tell <myname> loot {item.id}")
                single_link1 = self.text.make_chatcmd("Add to auction", f"/tell <myname> auction prepare {item.id} ")
                multi_link = self.text.make_chatcmd(
                    f"Add x{item.multiloot} to loot", f"/tell <myname> loot {item.id} {item.multiloot}")
                multi_link2 = self.text.make_chatcmd(
                    f"Add x{item.multiloot} to auction", f"/tell <myname> auction prepare {item.id} (ALL)")
                add_links = f"└ [{single_link}] [{multi_link}]<br> └ [{single_link1}] [{multi_link2} (ALL) - One Winner]"
            else:
                add_links = f"└ [{self.text.make_chatcmd('Add to loot', f'/tell <myname> loot {item.id}')}]<br> " \
                            f"└ [{self.text.make_chatcmd('Add to auction', f'/tell <myname> auction prepare {item.id}')}]"

            # comment = f" ({item.comment})" if item.comment != "" else ""

            if self.setting_service.get("use_item_icons").get_value():
                item_link = self.text.make_item(item.low_id, item.high_id, item.ql, f"<img src=rdb://{item.icon}>")
                blob += f"{item_link}{item.name}{comment}\n {add_links}\n\n"
            else:
                item_link = self.text.make_item(item.low_id, item.high_id, item.ql, item.name)
                blob += f"{item_link}{comment}\n {add_links}\n\n"
            blob += "<pagebreak>"
        return blob

    def get_items(self, raid, category):
        return self.db.query(
            "SELECT r.raid, r.category, r.id, r.ql, r.name, r.comment, "
            "r.multiloot, a.lowid AS low_id, a.highid AS high_id, a.icon "
            "FROM raid_loot r "
            "LEFT JOIN aodb a "
            "ON (r.high_id = a.highid OR (r.high_id = 0 AND r.name = a.name AND r.ql <= a.highql)) "
            "WHERE r.raid = ? AND r.category = ? "
            "ORDER BY r.name",
            [raid, category]
        )

    def get_real_category_name(self, category, reverse=False):
        if reverse:
            return next((name for name, real_name in self.categories.items() if real_name == category), None)
        else:
            return self.categories[category] if category in list(self.categories.keys()) else None
