import discord
from discord import ui
from discord.ext.commands import Bot
from pytimeparse2 import disable_dateutil, parse
from redbot.core import Config, app_commands, commands

class Shortmute(commands.Cog):
    """Allows staff members to shortmute individuals for up to 30 minutes, using Discord's Timeouts feature."""

    def __init__(self, bot) -> None:
        self.bot = bot
        self.config = Config.get_conf(self, identifier=25781647388294, force_registration=True)
        self.config.register_guild(
            dm = True,
            confirm = True,
            logging_channels = [],
            immune_roles = [],
            blacklisted_users = []
        )

    @app_commands.command()
    @app_commands.rename(target='member')
    async def shortmute(self, interaction: discord.Interaction, target: discord.Member, duration: int, reason: str, evidence_link: str = None, evidence_image: discord.Attachment = None, skip_confirmation: bool = None):
        """Shortmute someone for up to 30m.

        Parameters
        -----------
        target: discord.Member
            The member to shortmute
        duration: int
            The duration of the shortmute
        reason: str
            The reason for the shortmute
        evidence_link: str = None
            An image link to evidence for the shortmute, do not use with evidence_image
        evidence_image: discord.Attachment = None
            An image file used as evidence for the shortmute, do not use with evidence_link
        skip_confirmation: bool = None
            This allows you skip the confirmation prompt and immediately shortmute the user.
            """
        disable_dateutil()
        timedelta = parse(f'{duration} minutes', as_timedelta=True)
        if evidence_image and evidence_link:
            await interaction.response.send_message(content="You've provided both the `evidence_image` and the `evidence_link` arguments! Please only use one or the other.", ephemeral=True)
            return
        if evidence_link:
            evidence = evidence_link
        elif evidence_image:
            evidence = str(evidence_image)
        else:
            evidence = None
        if skip_confirmation is None:
            skip_confirmation = not bool(await self.config.guild(interaction.guild).confirm())
        passed_info = {
            "target": target,
            "timedelta": timedelta,
            "reason": reason,
            "interaction": interaction,
            "color": await self.bot.get_embed_color(None),
            "evidence": evidence
        }
        blacklisted_users_list = await self.config.guild(interaction.guild).blacklisted_users()
        for user_id in blacklisted_users_list:
            if user_id == interaction.user.id:
                await interaction.response.send_message(content="You are blacklisted from `/shortmute`!", ephemeral=True)
                return
        if target.bot is True:
            await interaction.response.send_message(content="You cannot shortmute bots!", ephemeral=True)
            return
        if interaction.user.guild_permissions.administrator is False:
            immune_roles_list = await self.config.guild(interaction.guild).immune_roles()
            for role_id in immune_roles_list:
                role = interaction.guild.get_role(role_id)
                if role in target.roles:
                    await interaction.response.send_message(content="You're trying to shortmute someone who is immune from shortmuting.", ephemeral=True)
                    return
        if target.guild_permissions.administrator is True:
            await interaction.response.send_message(content="You cannot shortmute people with the Administrator permission!", ephemeral=True)
            return
        if duration in (1, -1):
            readable_duration = f"{duration} minute"
        else:
            readable_duration =  f"{duration} minutes"
        passed_info.update({
            "readable_duration": readable_duration
        })
        if duration > 30:
            await interaction.response.send_message(content=f"{readable_duration} is longer than the 30 minutes you are allowed to shortmute users for.", ephemeral=True)
            return
        if duration < 1:
            await interaction.response.send_message(content=f"Please shortmute the user for longer than {readable_duration}! The maximum duration is 30 minutes.", ephemeral=True)
            return
        if skip_confirmation is False:
            embed = discord.Embed(title="Are you sure?", description=f"**Moderator:** {interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=await self.bot.get_embed_color(None))
            embed.set_footer(text="/shortmute")
            if evidence:
                embed.set_image(url=evidence)
            await interaction.response.send_message(embed=embed, view=self.ShortmuteButtons(timeout=180, passed_info=passed_info), ephemeral=True)
        elif skip_confirmation is True:
            edit_embed = discord.Embed(title="Shortmute confirmed!", description=f"**Moderator:** {interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=await self.bot.get_embed_color(None))
            edit_embed.set_footer(text="/shortmute")
            if evidence:
                edit_embed.set_image(url=evidence)
            message = await interaction.response.send_message(embed=edit_embed, ephemeral=True)
            await target.timeout(timedelta, reason=f"User shortmuted for {readable_duration} by {interaction.user.name} ({interaction.user.id}) for: {reason}")
            shortmute_msg = await interaction.channel.send(content=f"{target.mention} was shortmuted for {readable_duration} by {interaction.user.mention} for: `{reason}`")
            if await self.config.guild(interaction.guild).dm() is True:
                dm_embed = discord.Embed(title=f"You've been shortmuted in {interaction.guild.name}!", description=f"**Moderator:** {interaction.user.mention}\n**Target:** {target.mention}\n**Message:** {shortmute_msg.jump_url}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=await self.bot.get_embed_color(None))
                dm_embed.set_footer(text="/shortmute")
                if evidence:
                    dm_embed.set_image(url=evidence)
                try:
                    await target.send(embed=dm_embed)
                except discord.HTTPException:
                    await message.edit(content="Could not message the target, user most likely has Direct Messages disabled.")
            logging_channels_list = await self.config.guild(interaction.guild).logging_channels()
            if logging_channels_list:
                logging_embed = discord.Embed(title="User Shortmuted", description=f"**Moderator:** {interaction.user.mention} ({interaction.user.id})\n**Target:** {target.mention} ({target.id})\n**Message:** {shortmute_msg.jump_url}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`\n**Confirmation Skipped:** True", color=await self.bot.get_embed_color(None))
                logging_embed.set_footer(text="/shortmute")
                if evidence:
                    logging_embed.set_image(url=evidence)
                for channel_id in logging_channels_list:
                    channel_obj = interaction.guild.get_channel(channel_id)
                    await channel_obj.send(embed=logging_embed)

    class ShortmuteButtons(ui.View):
        def __init__(self, timeout, passed_info: dict):
            super().__init__()
            self.timeout = timeout
            self.passed_info = passed_info
            self.config = Config.get_conf(None, cog_name='Shortmute', identifier=25781647388294)

        @ui.button(label="Yes", style=discord.ButtonStyle.success)
        async def shortmute_button_yes(self, button: ui.Button, interaction: discord.Interaction): # pylint: disable=unused-argument
            disable_dateutil()
            target: discord.Member = self.passed_info['target']
            readable_duration = self.passed_info['readable_duration']
            reason: str = self.passed_info['reason']
            old_interaction: discord.Interaction = self.passed_info['interaction']
            color = self.passed_info['color']
            timedelta = self.passed_info['timedelta']
            evidence = self.passed_info['evidence']
            edit_embed = discord.Embed(title="Shortmute confirmed!", description=f"**Moderator:** {old_interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=color)
            if evidence:
                edit_embed.set_image(url=evidence)
            old_message = await old_interaction.edit_original_response(embed=edit_embed, view=None)
            await target.timeout(timedelta, reason=f"User shortmuted for {readable_duration} by {old_interaction.user.name} ({old_interaction.user.id}) for: {reason}")
            await old_interaction.channel.send(content=f"{target.mention} was shortmuted for {readable_duration} by {old_interaction.user.mention} for: `{reason}`")
            if await self.config.guild(old_interaction.guild).dm() is True:
                dm_embed = discord.Embed(title=f"You've been shortmuted in {old_interaction.guild.name}!", description=f"**Moderator:** {old_interaction.user.mention}\n**Target:** {target.mention}\n**Duration:** {readable_duration}\n**Reason:** `{reason}`", color=color)
                dm_embed.set_footer(text="/shortmute")
                if evidence:
                    dm_embed.set_image(url=evidence)
                try:
                    await target.send(embed=dm_embed)
                except discord.HTTPException:
                    await old_message.edit(content="Could not message the target, user most likely has Direct Messages disabled.")
            logging_channels_list = await self.config.guild(old_interaction.guild).logging_channels()
            if logging_channels_list:
                logging_embed = discord.Embed(title="User Shortmuted", description=f"**Moderator:** {old_interaction.user.mention} ({old_interaction.user.id})\n**Target:** {target.mention} ({target.id})\n**Duration:** {readable_duration}\n**Reason:** `{reason}`\n**Confirmation Skipped:** False", color=color)
                logging_embed.set_footer(text="/shortmute")
                if evidence:
                    logging_embed.set_image(url=evidence)
                for channel_id in logging_channels_list:
                    channel_obj = old_interaction.guild.get_channel(channel_id)
                    await channel_obj.send(embed=logging_embed)

        @ui.button(label="No", style=discord.ButtonStyle.danger)
        async def shortmute_button_no(self, button: ui.Button, interaction: discord.Interaction): # pylint: disable=unused-argument
            message: discord.Message = await self.passed_info['interaction'].edit_original_response(content="Command cancelled.", view=None, embed=None)
            await message.delete(delay=3)

    @commands.group(name='shortmuteset', autohelp=True)
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config(self, ctx: commands.Context):
        """Used to configure the /shortmute command."""

    @shortmute_config.group(name='channel', invoke_without_command=True, aliases=['channels'])
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_channel(self, ctx: commands.Context):
        """Manages /shortmute logging."""
        current_list = await self.config.guild(ctx.guild).logging_channels()
        already_in_list = []
        for channel_id in current_list:
            channel_obj = ctx.guild.get_channel(channel_id)
            if channel_obj:
                already_in_list.append(channel_obj.mention)
        if already_in_list:
            await ctx.send("Channels already in the list:\n" + "\n".join(already_in_list))
        else:
            await ctx.send("No channels are currently in the logging list.")

    @shortmute_config_channel.command(name='add')
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_channel_add(self, ctx: commands.Context, channel: discord.TextChannel = None):
        """Adds a channel to the logging channels list."""
        current_list: list = await self.config.guild(ctx.guild).logging_channels()
        if channel:
            if channel.id in current_list:
                await ctx.send("This channel is already in the logging channel list!")
            else:
                current_list.append(channel.id)
                await self.config.guild(ctx.guild).logging_channels.set(current_list)
                await ctx.send(f"{channel.mention} has been added to the logging channels list.")
        else:
            await ctx.send("Please provide a valid channel!")

    @shortmute_config_channel.command(name='remove')
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_channel_remove(self, ctx: commands.Context, channel: discord.TextChannel = None):
        """Removes a channel from the logging channels list."""
        current_list = await self.config.guild(ctx.guild).logging_channels()
        if channel.id in current_list:
            current_list.remove(channel.id)
            await self.config.guild(ctx.guild).logging_channels.set(current_list)
            await ctx.send(f"{channel.mention} has been removed from the logging channels list.")
        else:
            await ctx.send("Please provide a valid channel that exists in the logging channels list.")

    @shortmute_config.group(name='role', invoke_without_command=True, aliases=['roles'])
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_role(self, ctx: commands.Context):
        """Manages the immune roles list."""
        current_list = await self.config.guild(ctx.guild).immune_roles()
        already_in_list = []
        for role_id in current_list:
            role_obj = ctx.guild.get_role(role_id)
            if role_obj:
                already_in_list.append(role_obj.mention)
        if already_in_list:
            await ctx.send("Roles already in the immune roles list:\n" + "\n".join(already_in_list), allowed_mentions = discord.AllowedMentions(roles=False))
        else:
            await ctx.send("No roles are currently in the immune roles list.")

    @shortmute_config_role.command(name='add')
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_role_add(self, ctx: commands.Context, role: discord.Role = None):
        """Adds roles to the immune roles list."""
        current_list = await self.config.guild(ctx.guild).immune_roles()
        if role:
            if role.id in current_list:
                await ctx.send("This role is already in the immune roles list!")
            else:
                current_list.append(role.id)
                await self.config.guild(ctx.guild).immune_roles.set(current_list)
                await ctx.send(f"{role.mention} has been added to the immune roles list.", allowed_mentions = discord.AllowedMentions(roles=False))
        else:
            await ctx.send("Please provide a valid role.")

    @shortmute_config_role.command(name='remove')
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_role_remove(self, ctx: commands.Context, role: discord.Role = None):
        """Removes roles from the immune roles list."""
        current_list = await self.config.guild(ctx.guild).immune_roles()
        if role.id in current_list:
            current_list.remove(role.id)
            await self.config.guild(ctx.guild).immune_roles.set(current_list)
            await ctx.send(f"{role.mention} has been removed from the immune roles list.", allowed_mentions = discord.AllowedMentions(roles=False))
        else:
            await ctx.send("Please provide a valid role that exists in the immune roles list.")

    @shortmute_config.group(name='blacklist', invoke_without_command=True)
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_blacklist(self, ctx: commands.Context):
        """Manages the blacklist."""
        current_list = await self.config.guild(ctx.guild).blacklisted_users()
        already_in_list = []
        for user_id in current_list:
            user_obj = await Bot.fetch_user(user_id) # pylint: disable=no-value-for-parameter
            if user_obj:
                already_in_list.append(user_obj.mention)
        if already_in_list:
            await ctx.send("Users already blacklisted:\n" + "\n".join(already_in_list), allowed_mentions = discord.AllowedMentions(users=False))
        else:
            await ctx.send("No users are currently blacklisted.")

    @shortmute_config_blacklist.command(name='add')
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_blacklist_add(self, ctx: commands.Context, user: discord.User = None):
        """Adds users to the /shortmute blacklist."""
        current_list = await self.config.guild(ctx.guild).blacklisted_users()
        if user:
            if user.id in current_list:
                await ctx.send("That user is already in the blacklisted users list!")
            else:
                current_list.append(user.id)
                await self.config.guild(ctx.guild).blacklisted_users.set(current_list)
                await ctx.send(f"{user.mention} has been blacklisted from using `/shortmute`.", allowed_mentions = discord.AllowedMentions(users=False))
        else:
            await ctx.send("Please provide a valid user.")

    @shortmute_config_blacklist.command(name='remove')
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_blacklist_remove(self, ctx: commands.Context, user: discord.User = None):
        """Removes users from the /shortmute blacklist."""
        current_list = await self.config.guild(ctx.guild).blacklisted_users()
        if user.id in current_list:
            current_list.remove(user.id)
            await self.config.guild(ctx.guild).blacklisted_users.set(current_list)
            await ctx.send(f"{user.mention} has been removed from the `/shortmute` blacklist.", allowed_mentions = discord.AllowedMentions(users=False))
        else:
            await ctx.send("Please provide a valid user who is blacklisted from `/shortmute`.")

    @shortmute_config.command(name='message')
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_message(self, ctx: commands.Context, enabled: bool = None):
        """Manages if /shortmute Direct Messages its target.

        Parameters
        ------------
        enabled: bool (optional)
            This parameter, if set, will toggle this setting to either True or False."""
        old_value = await self.config.guild(ctx.guild).dm()
        if enabled is None:
            await ctx.send(content=f"Shortmute Direct Messages are currently {'enabled' if old_value else 'disabled'}!")
        else:
            await self.config.guild(ctx.guild).dm.set(enabled)
            await ctx.send(content=f"Shortmute Direct Message setting changed!\nOld value: `{old_value}`\nNew value: `{enabled}`")

    @shortmute_config.command(name='confirmation', aliases=['confirm'])
    @commands.guild_only()
    @commands.admin()
    async def shortmute_config_confirmation(self, ctx: commands.Context, enabled: bool = None):
        """Manages if /shortmute has a confirmation prompt by default.

        Parameters
        ------------
        enabled: bool (optional)
            This parameter, if set, will toggle this setting to either True or False."""
        old_value = await self.config.guild(ctx.guild).confirm()
        if enabled is None:
            await ctx.send(content=f"Shortmute Confirmations are currently {'enabled' if old_value else 'disabled'} by default!")
        else:
            await self.config.guild(ctx.guild).confirm.set(enabled)
            await ctx.send(content=f"Shortmute Confirmation setting changed!\nOld value: `{old_value}`\nNew value: `{enabled}`")
