import nextcord
from nextcord.ext import commands
from nextcord import Embed
from nextcord.ext.commands import Cog

from typing import Optional, Set


class HelpDropdown(nextcord.ui.Select):
    def __init__(self, help_cmd: "HelpCommand", options: list[nextcord.SelectOption]):
        super().__init__(placeholder="Choose a cog..", min_values=1, max_values=1, options=options)
        self._help_cmd = help_cmd

    async def callback(self, interaction: nextcord.Interaction):
        embed = (
            await self._help_cmd.cog_help_embed(self._help_cmd.context.bot.get_cog(self.values[0]))
            if self.values[0] != self.options[0].value
            else await self._help_cmd.bot_help_embed(self._help_cmd.get_bot_mapping())
        )
        await interaction.response.edit_message(embed=embed)

class HelpView(nextcord.ui.View):
    def __init__(self, help_cmd: "HelpCommand", options: list[nextcord.SelectOption], *, timeout: Optional[float] = 120.0):
        super().__init__(timeout=timeout)
        self.add_item(HelpDropdown(help_cmd, options))
        self._help_cmd = help_cmd

    async def on_timeout(self):
        self.clear_items()
        await self._help_cmd.response.edit(view=self)

    async def interaction_check(self, interaction: nextcord.Interaction) -> bool:
        return self._help_cmd.context.author == interaction.user

class HelpCommand(commands.MinimalHelpCommand):
    def get_command_signature(self, command):
        return f"{self.context.clean_prefix}{command.qualified_name} {command.signature}"

    async def _cog_select_options(self) -> list[nextcord.SelectOption]:
        options: list[nextcord.SelectOption] = []
        options.append(nextcord.SelectOption(label="Home", emoji="🏠", description="Go back to the home menu",))

        for cog, command_set in self.get_bot_mapping().items():
            filtered = await self.filter_commands(command_set, sort=True)
            if not filtered:
                continue
            emoji = getattr(cog, "COG_EMOJI", None)
            options.append(nextcord.SelectOption(label=cog.qualified_name if cog else "No Category", emoji=emoji, description=cog.description[:100] if cog and cog.description else None))

        return options

    async def _help_embed(self, title: str, description: Optional[str] = None, mapping: Optional[str] = None, command_set: Optional[Set[commands.Command]] = None, set_author: bool = False) -> Embed:
        helpEmbed = Embed(title=title)
        if description:
            helpEmbed.description = description
        if set_author:
            avatar = self.context.bot.user.avatar or self.context.bot.user.default_avatar
            helpEmbed.set_author(name=self.context.bot.user.name, icon_url=avatar.url)
        if command_set:
            filtered = await self.filter_commands(command_set, sort=True)
            for command in filtered:
                helpEmbed.add_field(name=self.get_command_signature(command), value=command.short_doc or "...", inline=False)
        elif mapping:
            for cog, command_set in mapping.items():
                filtered = await self.filter_commands(command_set, sort=True)
                if not filtered:
                    continue
                name = cog.qualified_name if cog else "No category"
                emoji = getattr(cog, "COG_EMOJI", None)
                cog_label = f"{emoji} {name}" if emoji else name
                cmd_list = "\u2002".join(f"`{self.context.clean_prefix}{cmd.name}`" for cmd in filtered)
                value = (f"{cog.description}\n{cmd_list}" if cog and cog.description else cmd_list)
                helpEmbed.add_field(name=cog_label, value=value)

        return helpEmbed

    async def bot_help_embed(self, mapping: dict) -> Embed:
        return await self._help_embed(title="ROGUE's Commands & Cogs", description=self.context.bot.description, mapping=mapping, set_author=True)

    async def send_bot_help(self, mapping: dict):
        helpEmbed = await self.bot_help_embed(mapping)
        options = await self._cog_select_options()
        self.response = await self.get_destination().send(embed=helpEmbed, view=HelpView(self, options))

    async def send_command_help(self, command: commands.Command):
        emoji = getattr(command.cog, "COG_EMOJI", None)
        helpEmbed = await self._help_embed(title=f"{emoji} {command.cog.qualified_name}" if emoji else command.qualified_name, description=command.help, command_set=command.commands if isinstance(command, commands.Group) else None)

        await self.get_destination().send(embed=helpEmbed)

    async def cog_help_embed(self, cog: Optional[commands.Cog]) -> Embed:
        if cog is None:
            return await self._help_embed(title=f"No category", command_set=self.get_bot_mapping()[None])
        emoji = getattr(cog, "COG_EMOJI", None)
        return await self._help_embed(title=f"{emoji} {cog.qualified_name}" if emoji else cog.qualified_name, description=cog.description, command_set=cog.get_commands())

    async def send_cog_help(self, cog: commands.Cog):
        helpEmbed = await self.cog_help_embed(cog)
        await self.get_destination().send(embed=helpEmbed)

    send_group_help = send_command_help


class Help(Cog, name="Help"):
    """Shows information on all of ROGUE's commands"""

    COG_EMOJI = "❔"

    def __init__(self, bot):
        self._original_help_command = bot.help_command
        bot.help_command = HelpCommand()
        bot.help_command.cog = self

    def cog_unload(self):
        self.bot.help_command = self._original_help_command


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