from core.chat_blob import ChatBlob
from core.command_param_types import Any, Options
from core.db import DB
from core.decorators import instance, command
from core.text import Text


@instance()
class WhatBuffsController:
    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.command_alias_service = registry.get_instance("command_alias_service")

    def pre_start(self):
        self.db.load_sql_file(self.module_dir + "/" + "item_buffs.sql", pre_optimized=True)
        self.db.create_view("item_buffs")
        self.db.load_sql_file(self.module_dir + "/" + "item_types.sql", pre_optimized=True)
        self.db.create_view("item_types")
        self.db.load_sql_file(self.module_dir + "/" + "skills.sql", pre_optimized=True)
        self.db.create_view("skills")

    def start(self):
        self.command_alias_service.add_alias("buffs", "whatbuffs")

    @command(command="whatbuffs", params=[], access_level="member",
             description="Find items or nanos that buff a skill (or ability)")
    def whatbuffs_list_cmd(self, _):
        data = self.db.query("SELECT name FROM skills ORDER BY name")
        blob = ""
        for row in data:
            blob += self.text.make_tellcmd(row.name, f"whatbuffs {row.name}") + "\n"

        blob += self.get_footer()
        return ChatBlob("Whatbuffs Skill List", blob)

    @command(command="whatbuffs",
             params=[
                 Any("skill"),
                 Options(["arms", "back", "chest", "deck", "feet", "fingers",
                          "hands", "head", "hud", "legs", "nanoprogram",
                          "neck", "shoulders", "unknown", "util", "weapon", "wrists", "all"])],
             access_level="member",
             description="Find items or nanos that buff a skill (or ability) for a particular item type")
    def whatbuffs_detail_cmd(self, _, skill_name, item_type):
        item_type = item_type.capitalize()

        return self.show_search_results(item_type, skill_name)

    @command(command="whatbuffs", params=[Any("skill")], access_level="member",
             description="Find items or nanos that buff a skill (or ability)")
    def whatbuffs_skill_cmd(self, _, skill_name):
        skills = self.search_for_skill(skill_name)
        if len(skills) == 0:
            return "Could not find skill <highlight>%s</highlight>." % skill_name
        elif len(skills) == 1:
            skill = skills.pop()

            data = self.db.query("SELECT i.item_type, COUNT(1) AS cnt "
                                 "FROM aodb "
                                 "JOIN item_types i ON aodb.highid = i.item_id "
                                 "JOIN item_buffs b ON aodb.highid = b.item_id "
                                 "JOIN skills s ON b.attribute_id = s.id "
                                 "WHERE s.id = ? "
                                 "GROUP BY item_type "
                                 "HAVING cnt > 0 "
                                 "ORDER BY item_type", [skill.id])

            blob = ""
            total_count = 0
            for row in data:
                total_count += row.cnt
            for row in data:
                blob += f'{self.text.zfill(row.cnt, total_count)} - ' \
                        f'{self.text.make_tellcmd(row.item_type, f"whatbuffs {skill.name} {row.item_type}")}\n'

            blob += self.get_footer()
            return ChatBlob(f"Whatbuffs {skill.name} - Choose Type", blob)
        else:
            blob = "Choose a skill:\n\n"
            for skill in skills:
                blob += self.text.make_tellcmd(skill.name, f"whatbuffs {skill.name}") + "\n"

            blob += self.get_footer()
            return ChatBlob("Whatbuffs - Choose Skill", blob)

    def search_for_skill(self, skill_name):
        skill_name = skill_name.lower()

        data = self.db.query(
            "SELECT id, name FROM skills WHERE name <EXTENDED_LIKE=0> ? OR common_name <EXTENDED_LIKE=1> ?",
            [skill_name, skill_name], extended_like=True)

        # check for exact match first, in order to disambiguate between Bow and Bot Special Attack
        for row in data:
            if row.name.lower() == skill_name:
                return [row]

        return data

    def show_search_results(self, item_type, skill_name):
        skills = self.search_for_skill(skill_name)

        if len(skills) == 0:
            return "Could not find skill <highlight>%s</highlight>." % skill_name
        elif len(skills) == 1:
            skill = skills.pop()
            return self.get_search_results(item_type, skill)
        else:
            blob = ""
            for skill in skills:
                blob += self.text.make_tellcmd(skill.name, "whatbuffs %s %s" % (skill.name, item_type)) + "\n"

            return ChatBlob("Whatbuffs - Choose Skill", blob)

    def get_search_results(self, item_type, skill):
        data = self.db.query("SELECT aodb.*, b.amount, i.item_type "
                             "FROM aodb "
                             "JOIN item_types i ON aodb.highid = i.item_id "
                             "JOIN item_buffs b ON aodb.highid = b.item_id "
                             "JOIN skills s ON b.attribute_id = s.id "
                             "WHERE i.item_type LIKE ? AND s.id = ? "
                             "ORDER BY item_type, amount DESC", ["%" if item_type == "All" else item_type, skill.id])

        if len(data) == 0:
            return f"No items found of type <highlight>{item_type}</highlight> " \
                   f"that buff <highlight>{skill.name}</highlight>."
        else:
            current_item_type = ""
            blob = ""

            for row in data:
                if current_item_type != row.item_type:
                    blob += f"\n\n<header2>{row.item_type}</header2>\n"
                    current_item_type = row.item_type
                blob += f"{self.text.zfill(row.amount, data[0].amount)} - " \
                        f"{self.text.make_item(row.lowid, row.highid, row.highql, row.name)}\n"

            blob += self.get_footer()

            return ChatBlob(f"Whatbuffs - {skill.name} {item_type} ({len(data):d})", blob)

    def get_footer(self):
        return "\nItem DB Extraction Info provided by Unk"
