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

from .ping import ping_command
from .uptime import uptime_command
from .serverinfo import serverinfo_command
from .feedback import feedback_command
from .userinfo import userinfo_command


def _require_group_prefix(context: Context) -> bool:
    if getattr(context, "interaction", None):
        return True
    group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
    if not group:
        return True
    prefix = context.prefix or ""
    content = context.message.content.strip().lower()
    return content.startswith(f"{prefix}{group} ")


@app_commands.allowed_contexts(guilds=True, dms=True, private_channels=True)
@app_commands.allowed_installs(guilds=True, users=True)
class General(commands.GroupCog, name="general"):
    def __init__(self, bot) -> None:
        self.bot = bot
        super().__init__()

    @commands.group(name="general", invoke_without_command=True)
    async def general_group(self, context: Context):
        embed = discord.Embed(
            title="General Commands",
            description="Use `.general <subcommand>` or `/general <subcommand>`.",
            color=0x7289DA,
        )
        embed.set_author(
            name="General", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
        )
        embed.add_field(
            name="Available",
            value="ping, uptime, serverinfo, userinfo, feedback",
            inline=False,
        )
        await context.send(embed=embed)

    async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
        command = self.bot.get_command(name)
        if command is not None:
            await context.invoke(command, **kwargs)
        else:
            await context.send(f"Unknown general command: {name}")

    @general_group.command(name="ping")
    async def general_group_ping(self, context: Context):
        await self._invoke_hybrid(context, "ping")

    @general_group.command(name="uptime")
    async def general_group_uptime(self, context: Context):
        await self._invoke_hybrid(context, "uptime")

    @general_group.command(name="serverinfo")
    async def general_group_serverinfo(self, context: Context):
        await self._invoke_hybrid(context, "serverinfo")

    @general_group.command(name="userinfo")
    async def general_group_userinfo(
        self, context: Context, user: discord.User = None, user_id: str = None
    ):
        await self._invoke_hybrid(context, "userinfo", user=user, user_id=user_id)

    @general_group.command(name="feedback")
    async def general_group_feedback(self, context: Context):
        await self._invoke_hybrid(context, "feedback")

    @commands.check(_require_group_prefix)
    @commands.hybrid_command(
        name="ping",
        description="Check if the bot is alive.",
    )
    async def ping(self, context):
        return await ping_command()(self, context)

    @commands.check(_require_group_prefix)
    @commands.hybrid_command(
        name="uptime",
        description="Check how long the bot has been running.",
    )
    async def uptime(self, context):
        return await uptime_command()(self, context)

    @commands.check(_require_group_prefix)
    @commands.hybrid_command(
        name="serverinfo",
        description="Get some useful (or not) information about the server.",
    )
    async def serverinfo(self, context):
        return await serverinfo_command()(self, context)

    @commands.check(_require_group_prefix)
    @commands.hybrid_command(
        name="userinfo",
        description="Get information on a user.",
    )
    @app_commands.describe(
        user="User to get info for", user_id="User ID to get info for"
    )
    async def userinfo(self, context, user: discord.User = None, user_id: str = None):
        return await userinfo_command()(self, context, user=user, user_id=user_id)

    @commands.check(_require_group_prefix)
    @commands.hybrid_command(
        name="feedback", description="Submit a feedback for the owners of the bot"
    )
    async def feedback(self, context):
        return await feedback_command()(self, context)


async def setup(bot) -> None:
    cog = General(bot)
    await bot.add_cog(cog)

    bot.logger.info("Loaded extension 'general.ping'")
    bot.logger.info("Loaded extension 'general.uptime'")
    bot.logger.info("Loaded extension 'general.serverinfo'")
    bot.logger.info("Loaded extension 'general.userinfo'")
    bot.logger.info("Loaded extension 'general.feedback'")
