import discord
from discord import app_commands
from discord.ext import commands
from discord.ext.commands import Context


class Help(commands.Cog, name="help"):
    def __init__(self, bot) -> None:
        self.bot = bot

    async def category_autocomplete(
        self,
        interaction: discord.Interaction,
        current: str,
    ) -> list[app_commands.Choice[str]]:
        categories = [
            "general",
            "fun",
            "moderation",
            "owner",
            "sidestore",
            "idevice",
            "melonx",
            "livecontainer",
            "media",
            "miscellaneous",
            "utilities",
            "events",
        ]

        suggestions = []
        for category in categories:
            if current.lower() in category.lower():
                suggestions.append(
                    app_commands.Choice(
                        name=f"{category.capitalize()} Commands", value=category
                    )
                )

        return suggestions[:25]

    @commands.hybrid_command(
        name="help", description="List all commands the bot has loaded."
    )
    @app_commands.allowed_contexts(guilds=True, dms=True, private_channels=True)
    @app_commands.allowed_installs(guilds=True, users=True)
    @app_commands.describe(category="Choose a specific category to view its commands")
    @app_commands.autocomplete(category=category_autocomplete)
    async def help(self, context: Context, category: str = None) -> None:
        category_mapping = {
            "general": "general",
            "fun": "fun",
            "idevice": "idevice",
            "melonx": "melonx",
            "livecontainer": "livecontainer",
            "media": "media",
            "misc": "miscellaneous",
            "miscellaneous": "miscellaneous",
            "moderation": "moderation",
            "sidestore": "sidestore",
            "utils": "utilities",
            "utilities": "utilities",
            "events": "events",
            "sync": "owner",
            "logs": "owner",
            "invite": "owner",
            "load": "owner",
            "unload": "owner",
            "reload": "owner",
            "shutdown": "owner",
            "say": "owner",
        }

        category_descriptions = {
            "general": "General commands",
            "fun": "Fun commands",
            "moderation": "Administration commands",
            "owner": "Owner commands",
            "sidestore": "SideStore troubleshooting commands",
            "idevice": "idevice troubleshooting commands",
            "melonx": "MeloNX troubleshooting commands",
            "livecontainer": "LiveContainer troubleshooting commands",
            "media": "Media commands",
            "utilities": "Utility commands",
            "miscellaneous": "Miscellaneous commands",
            "events": "Events commands",
        }

        if category is None:
            embed = discord.Embed(title="Help", color=0x7289DA)
            embed.set_author(
                name="Help", icon_url="https://yes.nighty.works/raw/T9mnBO.png"
            )

            standalone_commands = []
            botinfo_cmd = self.bot.tree.get_command("botinfo")
            if botinfo_cmd:
                standalone_commands.append(
                    "**/botinfo** » Get information about this bot"
                )

            if standalone_commands:
                embed.add_field(
                    name="", value="".join(standalone_commands) + "\n", inline=False
                )

            available_categories = set()
            for cog_name in self.bot.cogs:
                mapped_category = category_mapping.get(cog_name.lower())
                if mapped_category:
                    available_categories.add(mapped_category)

            category_list = []
            for cat in sorted(available_categories):
                description = category_descriptions.get(
                    cat, f"{cat.capitalize()} commands"
                )
                category_list.append(f"**/help {cat}** » {description}")

            if category_list:
                embed.add_field(name="", value="\n".join(category_list), inline=False)

            if context.interaction:
                await context.interaction.response.send_message(
                    embed=embed, ephemeral=True
                )
            else:
                try:
                    await context.send(embed=embed)
                except (discord.Forbidden, discord.HTTPException):
                    try:
                        await context.author.send(embed=embed)
                    except discord.Forbidden:
                        pass  # User has DMs disabled
            return

        category = category.lower()
        if category not in category_descriptions:
            embed = discord.Embed(
                title="Error",
                description=f"Category '{category}' not found. Use `/help` to see available categories.",
                color=0x7289DA,
            )
            if context.interaction:
                await context.interaction.response.send_message(
                    embed=embed, ephemeral=True
                )
            else:
                try:
                    await context.send(embed=embed)
                except (discord.Forbidden, discord.HTTPException):
                    try:
                        await context.author.send(embed=embed)
                    except discord.Forbidden:
                        pass
            return

        commands_in_category = []
        seen_names = set()
        for cog_name in self.bot.cogs:
            if category_mapping.get(cog_name.lower()) == category:
                cog = self.bot.get_cog(cog_name)
                if cog:
                    commands_list = cog.get_commands()
                    for command in commands_list:
                        has_prefix_subcommands = (
                            hasattr(command, "commands")
                            and len(getattr(command, "commands", [])) > 0
                        )
                        if has_prefix_subcommands:
                            continue
                        name = command.name
                        if name in seen_names:
                            continue
                        description = (
                            command.description.partition("\n")[0]
                            if command.description
                            else "No description available"
                        )
                        commands_in_category.append((name, description))
                        seen_names.add(name)

        for app_command in self.bot.tree.get_commands():
            bound_cog = getattr(app_command, "binding", None)
            if bound_cog is None:
                continue
            bound_cog_name = getattr(bound_cog, "qualified_name", "").lower()
            if category_mapping.get(bound_cog_name) != category:
                continue
            has_subcommands = (
                hasattr(app_command, "commands")
                and len(getattr(app_command, "commands", [])) > 0
            )

            if has_subcommands and category not in ["owner"]:
                for subcommand in app_command.commands:
                    if subcommand.name in seen_names:
                        continue
                    sub_desc = (
                        subcommand.description.partition("\n")[0]
                        if getattr(subcommand, "description", None)
                        else "No description available"
                    )
                    commands_in_category.append(
                        (f"{app_command.name} {subcommand.name}", sub_desc)
                    )
                    seen_names.add(f"{app_command.name} {subcommand.name}")
            else:
                if app_command.name in seen_names:
                    continue
                description = (
                    app_command.description.partition("\n")[0]
                    if getattr(app_command, "description", None)
                    else "No description available"
                )
                commands_in_category.append((app_command.name, description))
                seen_names.add(app_command.name)

        if not commands_in_category:
            embed = discord.Embed(
                title="Error",
                description=f"No commands found in category '{category}'.",
                color=0x7289DA,
            )
            if context.interaction:
                await context.interaction.response.send_message(
                    embed=embed, ephemeral=True
                )
            else:
                try:
                    await context.send(embed=embed)
                except (discord.Forbidden, discord.HTTPException):
                    try:
                        await context.author.send(embed=embed)
                    except discord.Forbidden:
                        pass
            return

        embed = discord.Embed(title=f"/help » {category.lower()}", color=0x7289DA)
        embed.set_author(
            name="Help", icon_url="https://yes.nighty.works/raw/T9mnBO.png"
        )
        data = []
        for command_name, description in sorted(commands_in_category):
            data.append(f"**/{command_name}** » {description}")
        help_text = "\n".join(data)
        embed.add_field(name="", value=help_text, inline=False)
        if context.interaction:
            await context.interaction.response.send_message(embed=embed, ephemeral=True)
        else:
            try:
                await context.send(embed=embed)
            except (discord.Forbidden, discord.HTTPException):
                try:
                    await context.author.send(embed=embed)
                except discord.Forbidden:
                    pass


async def setup(bot) -> None:
    await bot.add_cog(Help(bot))
