import discord
from discord.ext import commands
from utils.util import Pag  # for somereason this throws an error but works fine


class help(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.cmds_per_page = 6  # 6 commnads per page this can be increased/decreased

    def get_command_signature(self, command: commands.Command, ctx: commands.Context):
        aliases = " |".join(command.aliases)  # aliases
        # for more info on a command
        cmd_invoke = f"[{command.name}|{aliases}]" if command.aliases else command.name

        full_invoke = command.qualified_name.replace(command.name, "")

        signature = f"{ctx.prefix}{full_invoke}{cmd_invoke} {command.signature}"
        return signature

    async def return_filtered_commands(self, walkable, ctx):
        filtered = []

        for w in walkable.walk_commands():
            try:
                if w.hidden:  # if command is hidden
                    continue

                elif w.parent:  # if the command is a parent command
                    continue

                await w.can_run(ctx)
                filtered.append(w)
            except commands.CommandError:
                continue

        return self.return_sorted_commands(filtered)  # sorted by alphabet

    def return_sorted_commands(self, commandList):
        return sorted(commandList, key=lambda x: x.name)

    async def setup_help_pag(self, ctx, entity=None, title=None):
        entity = entity or self.bot
        title = title or self.bot.description

        pages = []

        if isinstance(entity, commands.Command):
            filtered_commands = (
                list(set(entity.all_commands.values()))
                if hasattr(entity, "all_commands")
                else []
            )
            filtered_commands.insert(0, entity)

        else:
            filtered_commands = await self.return_filtered_commands(entity, ctx)

        for i in range(0, len(filtered_commands), self.cmds_per_page):
            next_commands = filtered_commands[i: i + self.cmds_per_page]
            commands_entry = ""

            for cmd in next_commands:
                desc = cmd.short_doc or cmd.description
                signature = self.get_command_signature(cmd, ctx)
                subcommand = "" if hasattr(cmd, "all_commands") else ""

                commands_entry += (
                    f"• **__{cmd.name}__**\n```\n{signature}\n```\n{desc}\n"
                    if isinstance(entity, commands.Command)
                    else f"• **__{cmd.name}__**\n{desc}\n    {subcommand}\n"
                )
            pages.append(commands_entry)

        await Pag(title=title, colour=0x37dfca, entries=pages, length=1).start(ctx)

    @commands.command(name="help", aliases=["h", "commands"], description="The help command!")
    async def help_command(self, ctx, *, entity=None):
        if not entity:
            await self.setup_help_pag(ctx)

        else:
            cog = self.bot.get_cog(entity)
            if cog:
                await self.setup_help_pag(ctx, cog, f"{cog.qualified_name}'s commands")

            else:
                command = self.bot.get_command(entity)
                if command:
                    await self.setup_help_pag(ctx, command, command.name)

                else:
                    await ctx.send("Command not found.")


def setup(bot):
    bot.add_cog(help(bot))
