import datetime
import time
import os
import discord
from discord.ext import commands


async def reload_all(client, ctx):
    """
    Reloads all cogs (modules) in the 'cogs' folder and syncs the command tree.

    Args:
        client (discord.Client): The bot's main client object.
        ctx (commands.Context): The context in which the command was invoked.
    """
    cogs_folder = os.path.abspath(os.path.dirname(__file__))  # Get the cogs folder path
    for filename in os.listdir(cogs_folder):
        if filename.endswith(".py"):
            try:
                await client.reload_extension(f"cogs.{filename[:-3]}")
            except Exception as e:
                print(f"Error reloading {filename}: {e}")
                await client.load_extension(f"cogs.{filename[:-3]}")
    await client.tree.sync()  # Synchronize command tree
    await ctx.reply("Reloaded all cogs.")


class Admin(commands.Cog):
    """Cog that provides administrative commands for bot control and information."""

    def __init__(self, client):
        self.client = client

    @commands.command(
        name="ping",
        brief="Bot Latency",
        description="Displays the bot's latency in milliseconds.",
    )
    async def _ping(self, ctx):
        """
        Responds with the bot's latency (ping time).

        Args:
            ctx (commands.Context): The context in which the command was invoked.
        """
        latency = round(self.client.latency * 1000, 2)  # Convert to ms
        await ctx.reply(f"Pong! 🏓\nLatency: {latency}ms")

    @commands.command(
        name="info",
        brief="Bot Info",
        description="Provides information about the bot's owner and team (if applicable).",
    )
    async def _info(self, ctx):
        """
        Displays information about the bot's owner or team members.

        Args:
            ctx (commands.Context): The context in which the command was invoked.
        """
        app_info = await self.client.application_info()
        if app_info.team:
            team_members = "\n".join(
                f"{member.name}#{member.discriminator} ({'Owner' if member.id == app_info.team.owner_id else 'Member'})"
                for member in app_info.team.members
            )
            await ctx.reply(
                f"Bot is part of the team: {app_info.team.name}\nMembers:\n{team_members}"
            )
        else:
            await ctx.reply(
                f"Bot is owned by {app_info.owner} and is not part of a team."
            )

    @commands.command(
        name="uptime",
        brief="Bot Runtime",
        description="Displays how long the bot has been running since its last restart.",
    )
    async def _uptime(self, ctx):
        """
        Calculates and sends the bot's uptime based on a start timestamp.

        Args:
            ctx (commands.Context): The context in which the command was invoked.
        """
        with open("time.txt", "r") as file:
            start_time = float(file.read())
        uptime = str(
            datetime.timedelta(seconds=int(time.time() - start_time))
        )  # Calculate uptime
        await ctx.send(f"Uptime: {uptime}")

    @commands.hybrid_command(
        name="reload",
        brief="Reload Cog",
        description="Reloads a specific cog or all cogs.",
        aliases=["rl"],
    )
    @commands.is_owner()
    async def _reload(self, ctx, extension: str):
        """
        Reloads a specified cog/module or all modules if 'all' is passed.

        Args:
            ctx (commands.Context): The context in which the command was invoked.
            extension (str): Name of the cog to reload, or 'all' to reload all cogs.
        """
        if extension.lower() == "all":
            await reload_all(self.client, ctx)
            return
        try:
            await self.client.unload_extension(f"cogs.{extension}")
            await self.client.load_extension(f"cogs.{extension}")
            await ctx.send(f"Successfully reloaded {extension}.")
        except commands.ExtensionNotLoaded:
            await ctx.send(f"Extension {extension} was not loaded, loading it now.")
            try:
                await self.client.load_extension(f"cogs.{extension}")
                await ctx.send(f"Successfully loaded {extension}.")
            except Exception as e:
                await ctx.send(f"Failed to load {extension}: {e}")
        except commands.ExtensionNotFound:
            await ctx.send(f"Extension {extension} was not found.")
        except Exception as e:
            await ctx.send(f"Failed to reload {extension}: {e}")

    @commands.hybrid_command(
        name="purge",
        brief="Delete messages",
        description="Deletes a specified number of messages from the current channel (default: 100).",
    )
    @commands.has_permissions(manage_channels=True)
    @commands.cooldown(1, 10, commands.BucketType.user)
    async def _purge(self, ctx, n: int = 100):
        """
        Deletes a specified number of messages from the current channel.

        Args:
            ctx (commands.Context): The context in which the command was invoked.
            n (int, optional): The number of messages to delete. Defaults to 100.
        """
        n += 1
        if n <= 0:
            return
        if n < 100:
            await ctx.channel.purge(limit=n)
            await ctx.channel.send(
                f"Successfully purged last {n-1} messages", delete_after=2
            )
        elif n == 100:
            await ctx.channel.purge()
            await ctx.channel.send(
                "Successfully purged last 100 messages", delete_after=2
            )
        else:  # n > 100
            for i in range(n // 100):
                await ctx.channel.purge()
            await ctx.channel.purge(limit=n % 100)
            await ctx.channel.send(
                f"Successfully purged last {n-1} messages", delete_after=2
            )

    @commands.hybrid_command(
        name="nuke",
        brief="Clear channel",
        description="Deletes all messages by duplicating and deleting the channel.",
    )
    @commands.has_permissions(manage_channels=True)
    @commands.cooldown(1, 30, commands.BucketType.user)
    async def _nuke(self, ctx, channel_name: str = "Current"):
        """
        Duplicates and deletes a specified channel (or the current channel) to clear messages.

        Args:
            ctx (commands.Context): The context in which the command was invoked.
            channel_name (str, optional): Name of the channel to nuke. Defaults to 'Current' (the invoking channel).
        """
        # Determine the channel ID based on the channel_name parameter
        if channel_name.lower() == "current":
            channel_id = ctx.channel.id
        else:
            channel_id = discord.utils.get(ctx.guild.channels, name=channel_name)
            if channel_id is None:
                return await ctx.send(f"Channel **{channel_name}** was not found.")

        existing_channel = self.client.get_channel(channel_id)
        if existing_channel:
            await existing_channel.clone(reason="Channel has been nuked")
            await existing_channel.delete()
            await self._send_embed(
                ctx,
                f"Channel **{existing_channel.name}** has been nuked.",
                discord.Color.red(),
            )
        else:
            await ctx.send(f"No channel with ID {channel_id} was found.")

    @commands.command(
        name="guildids",
        brief="List all guild IDs",
        description="Lists all guild IDs the bot is currently in. Owner only.",
    )
    @commands.is_owner()
    async def _guildids(self, ctx):
        """
        Sends a list of all guild IDs the bot is in to the owner.

        Args:
            ctx (commands.Context): The context in which the command was invoked.
        """
        guild_ids = [str(guild.id) for guild in self.client.guilds]
        guilds_str = "\n".join(guild_ids)
        await ctx.author.send(f"Guild IDs:\n{guilds_str}")
        await ctx.reply("Sent you a DM with all guild IDs.")

    async def _send_embed(self, ctx, description, color=discord.Color.blurple()):
        embed = discord.Embed(description=description, color=color)
        await ctx.send(embed=embed)


async def setup(client):
    """Sets up the Admin cog for the bot."""
    await client.add_cog(Admin(client))
