from core.chat_blob import ChatBlob
from core.command_param_types import Any, Int, NamedParameters
from core.decorators import instance, command


# noinspection SqlCaseVsIf,SqlAggregates
@instance()
class NanoController:
    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.util = registry.get_instance("util")
        self.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 + "/" + "nanos.sql", pre_optimized=True)
        self.db.create_view("nanos")

    def start(self):
        self.command_alias_service.add_alias("nl", "nanolines")
        self.command_alias_service.add_alias("nanoline", "nanolines")

    @command(command="nano", params=[Any("search"), NamedParameters(["page"])], access_level="member",
             description="Search for a nano")
    def nano_cmd(self, _, search, named_params):
        page = int(named_params.page or "1")
        page_size = 30
        offset = (page - 1) * page_size

        sql = "SELECT n.* " \
              "FROM nanos n " \
              "WHERE n.nano_name <EXTENDED_LIKE=0> ? group by nano_id " \
              "ORDER BY n.profession, n.strain, n.ql DESC, n.crystal_name"
        data = self.db.query(sql, [search], extended_like=True)
        count = len(data)
        paged_data = data[offset:offset + page_size]

        blob = ""
        if count == 0:
            return "No nanos found matching <highlight>%s</highlight>." % search
        elif count == 1:
            row = data[0]
            nano = self.make_nano(row)
            if nano:
                return f"{nano} <highlight>{row.strain.replace('_', ' ')}</highlight>"
            return f"No nanos found matching <highlight>{search}</highlight>."
        elif count > page_size:
            if page > 1 and len(paged_data) > 0:
                blob += "   " + self.text.make_chatcmd(f"<< Page {page - 1:d}",
                                                       self.get_chat_command(search, page - 1))
            if offset + page_size < len(data):
                blob += "   Page " + str(page)
                blob += "   " + self.text.make_chatcmd(f"Page {page + 1:d} >>",
                                                       self.get_chat_command(search, page + 1))
            blob += "\n\n"

        current_nanoline = []
        for row in paged_data:
            if current_nanoline != [row.strain_id, row.profession]:
                if row.strain:
                    nano = self.text.make_tellcmd(row.strain, f"nanolines {row.profession} {row.strain}")
                    blob += f"<pagebreak>\n<header2>{row.profession}</header2> - {nano}\n" if nano else ""
                else:
                    blob += "\n<header2>Unknown/General</header2>\n"
                current_nanoline = [row.strain_id, row.profession]
            nano = self.make_nano(row)
            blob += nano + "\n" if nano else ""
        blob += self.get_footer()

        return ChatBlob(
            f"Nano Search Results for '{search}' ({offset + 1:d} - "
            f"{min(offset + page_size, count):d} of {count:d})",
            blob)

    def format_single_nano(self, row):
        if str(row.crystal_name).startswith("Nano") \
                or str(row.crystal_name).startswith("Shadow") \
                or str(row.crystal_name).startswith("Alien") \
                or str(row.location).startswith("Arete"):
            item = self.text.make_item(row.crystal_id, row.crystal_id, row.ql, str(row.crystal_name).replace('_', ' '))
            return f"QL {row.ql: >3} {item} {row.location}"
        return ""

    @command(command="nanoloc", params=[], access_level="member",
             description="Show all nano locations")
    def nanoloc_list_cmd(self, _):
        data = self.db.query(
            "SELECT location, COUNT(location) AS cnt "
            "FROM (SELECT * FROM nanos group by nano_id order by crystal_name) a "
            "GROUP BY location "
            "ORDER BY location")

        blob = ""
        for row in data:
            blob += "%s (%d)\n" % (self.text.make_tellcmd(row.location, "nanoloc %s" % row.location), row.cnt)
        blob += self.get_footer()

        return ChatBlob("Nano Locations", blob)

    @command(command="nanoloc", params=[Any("location")], access_level="member",
             description="Show nanos by location")
    def nanoloc_show_cmd(self, _, location):
        sql = "SELECT * " \
              "FROM nanos n " \
              "WHERE n.location LIKE ? " \
              "group by n.nano_id ORDER BY n.profession, n.crystal_name"
        data = self.db.query(sql, [location])
        cnt = len(data)

        blob = ""
        prof = ""

        for row in data:
            if prof != row.profession:
                if row.profession:
                    blob += f"<pagebreak>\n<header2>{row.profession.replace('_', ' ')}</header2>\n"
                else:
                    blob += "\n<header2>Unknown/General</header2>\n"
                prof = row.profession

            blob += "<tab>QL %d %s\n" % (row.ql, self.make_nano(row))
        return ChatBlob("Nanos for Location '%s' (%d)" % (location, cnt), blob)

    @command(command="nanolines", params=[], access_level="member",
             description="Show nanos by nanoline")
    def nanolines_list_cmd(self, _):
        data = self.db.query("SELECT DISTINCT profession FROM nanos ORDER BY profession")

        blob = ""
        for row in data:
            blob += self.text.make_tellcmd(row.profession, f"nanolines {row.profession}") + "\n"
        blob += self.get_footer()

        return ChatBlob("Nanolines", blob)

    @command(command="nanolines", params=[Int("nanoline_id")], access_level="member",
             description="Show nanos by nanoline id")
    def nanolines_id_cmd(self, _, nanoline_id):
        nanoline = self.db.query_single("SELECT * FROM nanos WHERE strain_id = ? LIMIT 1", [nanoline_id])

        if not nanoline or nanoline_id == 0:
            return f"Could not find nanoline with ID <highlight>{nanoline_id:d}</highlight>."

        data = self.db.query(
            "SELECT n.crystal_id, n.ql, n.strain, n.crystal_name, n.location "
            "FROM nanos n "
            "where n.strain_id=? "
            "group by n.nano_id "
            "ORDER BY n.ql DESC, n.nano_name",
            [nanoline_id])
        blob = ""
        for row in data:
            item = self.make_nano(row)
            blob += item + "\n" if item else ""
        blob += self.get_footer()

        return ChatBlob(f"{str(nanoline.strain).replace('_', ' ')} Nanos", blob)

    @command(command="nanolines", params=[Any("profession"), Any("nanoline")], access_level="member",
             description="Show nanos by nanoline profession and line name")
    def nanolines_prof_strain(self, _, prof: str, strain: str):
        profession = self.util.get_profession(prof)
        if strain.startswith("Artist"):
            profession = "Martial Artist"
            strain = strain[7:]
        nanoline = self.db.query_single(
            "SELECT * FROM nanos n WHERE n.strain LIKE ? AND profession =? and type='Crystal' LIMIT 1",
            [strain, profession])

        if not nanoline:
            return f"Could not find nanoline with name <highlight>{strain}</highlight>."

        data = self.db.query(
            "SELECT n.* FROM nanos n "
            "where n.strain LIKE ? "
            "and n.profession = ? "
            "and type='Crystal' "
            "group by nano_id "
            "ORDER BY n.strain, n.ql DESC, n.nano_name",
            ["%" + strain.replace(" ", "%") + "%", profession])
        blob = ""
        strain = ""
        for row in data:
            if strain != row.strain:
                if row.strain:
                    blob += f"<pagebreak>\n<header2>{row.strain.replace('_', ' ')}</header2>\n"
                else:
                    blob += "\n<header2>Unknown/General</header2>\n"
                strain = row.strain
            item = self.make_nano(row)
            blob += item + "\n" if item else ""
        blob += self.get_footer()

        return ChatBlob("%s %s Nanos" % (nanoline.profession, str(nanoline.strain).replace("_", " ")), blob)

    @command(command="nanolines", params=[Any("profession")], access_level="member",
             description="Show nanolines by profession")
    def nanolines_profession_cmd(self, _, prof_name):
        profession = self.util.get_profession(prof_name)
        if not profession:
            return "Could not find profession <highlight>%s</highlight>." % prof_name

        data = self.db.query(
            "SELECT CASE WHEN strain = 'Composite' THEN 'Composite' ELSE school END as school, strain, profession "
            "FROM nanos WHERE Profession = ? "
            "and location not like 'No%longer%drops' "
            "and type not in ('Tainted', 'Misc') "
            "GROUP by strain ORDER BY school, strain='Composite', strain", [profession])

        blob = ""
        school = ""
        for row in data:
            if school != row.school:
                if row.strain:
                    blob += f"<pagebreak>\n<header2>{row.school.replace('_', ' ')}</header2>\n"
                else:
                    blob += "\n<header2>Unknown/General</header2>\n"
                school = row.school

            blob += "<tab>" + self.text.make_tellcmd(row.strain, f"nanolines {row.profession} {row.strain}") + "\n"
        blob += self.get_footer()

        return ChatBlob("%s Nanolines" % profession, blob)

    def get_footer(self):
        return "\n\nNano-DB provided by AOIA+ 2019"

    def get_chat_command(self, search, page):
        return "/tell <myname> nano %s --page=%d" % (search, page)

    def make_nano(self, row):
        return f"QL {row.ql: >3} <a href='itemid://53019/{row.nano_id}'>{row.crystal_name}</a> {row.location}"
