import disnake
from disnake.ext import commands
import sqlite3
import os
from datetime import datetime, timedelta
import re
from src.logger import kuby_logger
from utils.premium import check_premium_tier

class ModReasonModal(disnake.ui.Modal):
    def __init__(self, cog, action_type, member):
        self.cog = cog
        self.action_type = action_type
        self.member = member
        
        self.reason_input = disnake.ui.TextInput(
            label="Raison",
            placeholder="Entrez la raison ici...",
            required=True,
            max_length=500,
            custom_id="reason"
        )
        
        components = [self.reason_input]
        
        if action_type == "TIMEOUT":
            self.duration_input = disnake.ui.TextInput(
                label="Durée (ex: 1h, 30m, 1d)",
                placeholder="1h",
                required=True,
                max_length=10,
                custom_id="duration"
            )
            components.append(self.duration_input)

        super().__init__(title=f"Raison pour {action_type}", components=components)

    async def callback(self, interaction: disnake.ModalInteraction):
        reason = interaction.text_values["reason"]
        member = self.member
        
        if self.action_type == "WARN":
            await self.cog.warn(interaction, member, reason)
        elif self.action_type == "TIMEOUT":
            duration = interaction.text_values["duration"]
            await self.cog.timeout(interaction, member, duration, reason)
        elif self.action_type == "KICK":
            await self.cog.kick(interaction, member, reason)
        elif self.action_type == "BAN":
            await self.cog.ban(interaction, member, reason)
        
        await self.cog.send_modpanel_v2(interaction, member, edit=True)

class ModConfigModal(disnake.ui.Modal):
    def __init__(self, field_name, current_value):
        self.field_name = field_name
        self.input_field = disnake.ui.TextInput(
            label=field_name,
            value=str(current_value),
            placeholder="Entrez une valeur numérique...",
            required=True,
            custom_id="value"
        )
        super().__init__(title=f"Modifier {field_name}", components=[self.input_field])

    async def callback(self, interaction: disnake.ModalInteraction):
        value = interaction.text_values["value"]
        cog = interaction.bot.get_cog("Moderation")
        
        mapping = {
            "Limite Timeout": "warn_limit_timeout",
            "Limite Kick": "warn_limit_kick",
            "Limite Ban": "warn_limit_ban",
            "Durée Timeout (s)": "timeout_duration"
        }
        
        if not value.isdigit():
            return await interaction.response.send_message("❌ Veuillez entrer un nombre valide.", ephemeral=True)
        
        db_field = mapping.get(self.field_name)
        conn = sqlite3.connect(cog.db_path)
        cursor = conn.cursor()
        cursor.execute(f"UPDATE mod_config SET {db_field} = ? WHERE guild_id = ?", (int(value), interaction.guild_id))
        conn.commit()
        conn.close()
        
        await interaction.response.send_message(f"✅ {self.field_name} mis à jour.", ephemeral=True)
        await cog.send_modconfig_v2(interaction, edit=True)

class Moderation(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.db_path = os.path.join(os.path.dirname(__file__), "..", "config.db")
        self._init_db()

    def _init_db(self):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('''CREATE TABLE IF NOT EXISTS sanctions (id INTEGER PRIMARY KEY AUTOINCREMENT, guild_id INTEGER, user_id INTEGER, moderator_id INTEGER, type TEXT, reason TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, duration INTEGER, status TEXT DEFAULT 'ACTIVE')''')
        cursor.execute('''CREATE TABLE IF NOT EXISTS mod_config (
            guild_id INTEGER PRIMARY KEY,
            log_channel_id INTEGER,
            board_channel_id INTEGER,
            appeal_channel_id INTEGER,
            warn_limit_timeout INTEGER DEFAULT 3,
            warn_limit_kick INTEGER DEFAULT 5,
            warn_limit_ban INTEGER DEFAULT 10,
            timeout_duration INTEGER DEFAULT 3600
        )''')
        try: cursor.execute("ALTER TABLE mod_config ADD COLUMN board_channel_id INTEGER")
        except: pass
        try: cursor.execute("ALTER TABLE mod_config ADD COLUMN appeal_channel_id INTEGER")
        except: pass
        conn.commit(); conn.close()

    def parse_duration(self, duration_str: str) -> int:
        if not duration_str: return 0
        units = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400, 'w': 604800}
        total_seconds = 0
        matches = re.findall(r'(\d+)([smhdw])', duration_str.lower())
        for value, unit in matches: total_seconds += int(value) * units[unit]
        return total_seconds

    def _type_to_emoji(self, s_type: str) -> str:
        return {"WARN": "⚠️", "TIMEOUT": "⏳", "KICK": "👢", "BAN": "🔨"}.get(s_type, "🛡️")

    def _type_to_action_name(self, s_type: str) -> str:
        return {"WARN": "Avertissement", "TIMEOUT": "Timeout", "KICK": "Expulsion", "BAN": "Ban"}.get(s_type, "Sanction")

    def _format_duration(self, seconds: int) -> str:
        if seconds >= 86400:
            return f"{seconds // 86400} jour(s)"
        elif seconds >= 3600:
            return f"{seconds // 3600} heure(s)"
        elif seconds >= 60:
            return f"{seconds // 60} minute(s)"
        return f"{seconds} seconde(s)"

    async def send_sanction_dm(self, user, s_type: str, reason: str, moderator, guild, duration: int = None) -> bool:
        """Envoie un DM détaillé à l'utilisateur sanctionné. Retourne True si envoyé."""
        from commandes.modules_security.rules import load_settings as load_rules_settings

        emoji = self._type_to_emoji(s_type)
        action_name = self._type_to_action_name(s_type)

        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('SELECT appeal_channel_id FROM mod_config WHERE guild_id = ?', (guild.id,))
        res = cursor.fetchone()
        conn.close()

        rules_settings = load_rules_settings(guild.id)
        appeal_channel = guild.get_channel(res[0]) if res and res[0] else None
        rules_channel = guild.get_channel(rules_settings.get("rules_channel_id")) if rules_settings.get("rules_channel_id") else None

        embed = disnake.Embed(
            title=f"{emoji} {action_name} sur **{guild.name}**",
            color=disnake.Color.red() if s_type in ("BAN", "KICK") else disnake.Color.orange()
        )
        embed.set_thumbnail(url=guild.icon.url if guild.icon else None)

        embed.add_field(name="📋 Action", value=action_name, inline=True)
        embed.add_field(name="👤 Modérateur", value=f"**{moderator}**", inline=True)
        if duration:
            embed.add_field(name="⏱️ Durée", value=self._format_duration(duration), inline=True)

        embed.add_field(name="📝 Raison", value=f"*{reason if reason else 'Aucune raison spécifiée'}*", inline=False)

        if appeal_channel:
            embed.add_field(name="🔗 Contester cette sanction", value=f"Vous pouvez contester cette mesure dans {appeal_channel.mention}.", inline=False)

        if rules_channel:
            embed.add_field(name="📜 Règlement", value=f"[Voir le règlement](https://discord.com/channels/{guild.id}/{rules_channel.id})", inline=False)

        try:
            await user.send(embed=embed)
            return True
        except disnake.Forbidden:
            kuby_logger.warning(f"Impossible d'envoyer un DM à {user} (DMs bloqués)")
            return False

    def build_sanction_board_components(self, *, s_type: str, user, moderator, reason, timestamp, s_id, duration=None) -> list:
        ts_int = int(datetime.fromisoformat(str(timestamp)).timestamp()) if not isinstance(timestamp, datetime) else int(timestamp.timestamp())
        emoji = self._type_to_emoji(s_type)
        
        children = [
            disnake.ui.Section(f"{emoji} **SANCTION : {s_type}**", accessory=disnake.ui.Thumbnail(user.display_avatar.url)),
            disnake.ui.Separator(divider=True),
            disnake.ui.TextDisplay(f"- **Membre sanctionné** : {user.mention}"),
            disnake.ui.TextDisplay(f"- **Modérateur** : {moderator.mention}"),
            disnake.ui.TextDisplay(f"- **Raison** : “ *{reason if reason else 'Aucune raison spécifiée'}* ”"),
            disnake.ui.TextDisplay(f"- **Date** : <t:{ts_int}:F>")
        ]
        
        if s_type == "TIMEOUT" and duration:
            children.append(disnake.ui.TextDisplay(f"- **Durée** : `{duration}s`"))
            
        children.extend([
            disnake.ui.Separator(divider=True),
            disnake.ui.TextDisplay(f"🆔 **ID** : `{s_id}`")
        ])
        
        return [disnake.ui.Container(*children)]

    async def send_mod_log(self, guild, components):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('SELECT log_channel_id FROM mod_config WHERE guild_id = ?', (guild.id,))
        res = cursor.fetchone(); conn.close()
        if res and res[0]:
            chan = guild.get_channel(res[0])
            if chan: await chan.send(components=components)

    async def send_sanction_board(self, guild, components):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('SELECT board_channel_id FROM mod_config WHERE guild_id = ?', (guild.id,))
        res = cursor.fetchone(); conn.close()
        if res and res[0]:
            chan = guild.get_channel(res[0])
            if chan: await chan.send(components=components)

    async def send_modpanel_v2(self, interaction: disnake.Interaction, member: disnake.Member, edit=False):
        self._init_db()
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('SELECT COUNT(*) FROM sanctions WHERE guild_id = ? AND user_id = ? AND type = "WARN" AND status = "ACTIVE"', (interaction.guild_id, member.id))
        warn_count = cursor.fetchone()[0]
        cursor.execute('SELECT type, reason, timestamp FROM sanctions WHERE guild_id = ? AND user_id = ? AND status = "ACTIVE" ORDER BY timestamp DESC LIMIT 3', (interaction.guild_id, member.id))
        rows = cursor.fetchall(); conn.close()

        children = [
            disnake.ui.Section(f"🛡️ Panel : {member.name}", accessory=disnake.ui.Thumbnail(member.display_avatar.url)),
            disnake.ui.Separator(divider=True),
            disnake.ui.TextDisplay(f"👤 **Membre :** {member.mention} (`{member.id}`)"),
            disnake.ui.TextDisplay(f"⚠️ **Avertissements actifs :** {warn_count}"),
            disnake.ui.Separator(divider=True),
            disnake.ui.Section("⚠️ Infliger un avertissement", accessory=disnake.ui.Button(label="Warn", style=disnake.ButtonStyle.secondary, custom_id=f"modpan_warn:{member.id}")),
            disnake.ui.Section("⏳ Mettre en sourdine", accessory=disnake.ui.Button(label="Timeout", style=disnake.ButtonStyle.secondary, custom_id=f"modpan_timeout:{member.id}")),
            disnake.ui.Section("👢 Expulser du serveur", accessory=disnake.ui.Button(label="Kick", style=disnake.ButtonStyle.secondary, custom_id=f"modpan_kick:{member.id}")),
            disnake.ui.Section("🔨 Bannir définitivement", accessory=disnake.ui.Button(label="Ban", style=disnake.ButtonStyle.danger, custom_id=f"modpan_ban:{member.id}")),
            disnake.ui.Separator(divider=True),
            disnake.ui.Section("🧹 Réinitialiser les warns", accessory=disnake.ui.Button(label="Clear", style=disnake.ButtonStyle.danger, custom_id=f"modpan_clear:{member.id}"))
        ]
        
        if rows:
            children.append(disnake.ui.Separator(divider=True))
            children.append(disnake.ui.TextDisplay("📌 **Dernières sanctions :**"))
            for t, r, ts in rows:
                ts_int = int(datetime.fromisoformat(str(ts)).timestamp()) if not isinstance(ts, datetime) else int(ts.timestamp())
                children.append(disnake.ui.TextDisplay(f"• {self._type_to_emoji(t)} **{t}** — {r} (<t:{ts_int}:R>)"))

        components = [disnake.ui.Container(*children)]

        if edit:
            if not interaction.response.is_done(): await interaction.response.edit_message(content=None, components=components)
            else: await interaction.edit_original_response(content=None, components=components)
        else:
            await interaction.response.send_message(components=components, ephemeral=True)

    @commands.slash_command(name="modpanel", description="Ouvre le panel de modération")
    @check_premium_tier()
    @commands.has_permissions(moderate_members=True)
    async def modpanel(self, interaction: disnake.ApplicationCommandInteraction, member: disnake.Member):
        if member.top_role >= interaction.user.top_role and interaction.user.id != interaction.guild.owner_id:
            return await interaction.response.send_message("❌ Permissions insuffisantes.", ephemeral=True)
        await self.send_modpanel_v2(interaction, member)

    async def send_modconfig_v2(self, interaction: disnake.Interaction, edit=False):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('SELECT log_channel_id, board_channel_id, appeal_channel_id, warn_limit_timeout, warn_limit_kick, warn_limit_ban, timeout_duration FROM mod_config WHERE guild_id = ?', (interaction.guild_id,))
        res = cursor.fetchone(); conn.close()
        if not res: return

        children = [
            disnake.ui.Section("⚙️ Configuration Modération", accessory=disnake.ui.Thumbnail(interaction.guild.icon.url if interaction.guild.icon else None)),
            disnake.ui.Separator(divider=True),
            disnake.ui.TextDisplay(f"📁 **Logs internes :** <#{res[0]}>" if res[0] else "📁 **Logs :** Non défini"),
            disnake.ui.TextDisplay(f"📢 **Affichage public :** <#{res[1]}>" if res[1] else "📢 **Affichage :** Non défini"),
            disnake.ui.TextDisplay(f"🔗 **Contestation :** <#{res[2]}>" if res[2] else "🔗 **Contestation :** Non défini"),
            disnake.ui.TextDisplay(f"⚖️ **Paliers :** T:{res[3]} | K:{res[4]} | B:{res[5]}"),
            disnake.ui.TextDisplay(f"⏱️ **Timeout auto :** {res[6]}s"),
            disnake.ui.Separator(divider=True),
            disnake.ui.Section("📁 Salon des logs", accessory=disnake.ui.Button(label="Logs", style=disnake.ButtonStyle.primary, custom_id="modcfg_logs")),
            disnake.ui.Section("📢 Salon d'affichage", accessory=disnake.ui.Button(label="Public", style=disnake.ButtonStyle.primary, custom_id="modcfg_board")),
            disnake.ui.Section("🔗 Salon de contestation", accessory=disnake.ui.Button(label="Contester", style=disnake.ButtonStyle.primary, custom_id="modcfg_appeal")),
            disnake.ui.Section("⚖️ Modifier paliers", accessory=disnake.ui.Button(label="Paliers", style=disnake.ButtonStyle.secondary, custom_id="modcfg_limits")),
            disnake.ui.Section("⏱️ Durée timeout", accessory=disnake.ui.Button(label="Durée", style=disnake.ButtonStyle.secondary, custom_id="modcfg_duration"))
        ]
        
        components = [disnake.ui.Container(*children)]
        
        if edit:
            if not interaction.response.is_done(): await interaction.response.edit_message(content=None, components=components)
            else: await interaction.edit_original_response(content=None, components=components)
        else:
            await interaction.response.send_message(components=components, ephemeral=True)

    @commands.slash_command(name="sanctions", description="Voir l'historique des sanctions d'un membre")
    @check_premium_tier()
    @commands.has_permissions(moderate_members=True)
    async def sanctions(self, interaction: disnake.ApplicationCommandInteraction, member: disnake.Member):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('SELECT type, reason, timestamp, moderator_id, duration FROM sanctions WHERE guild_id = ? AND user_id = ? ORDER BY timestamp DESC LIMIT 10', (interaction.guild_id, member.id))
        rows = cursor.fetchall(); conn.close()

        if not rows:
            return await interaction.response.send_message(f"Aucune sanction trouvée pour {member.mention}.", ephemeral=True)

        children = [
            disnake.ui.Section(f"📋 Historique : {member.name}", accessory=disnake.ui.Thumbnail(member.display_avatar.url)),
            disnake.ui.Separator(divider=True),
        ]

        for t, r, ts, mod_id, dur in rows:
            ts_int = int(datetime.fromisoformat(str(ts)).timestamp()) if not isinstance(ts, datetime) else int(ts.timestamp())
            moderator = interaction.guild.get_member(mod_id)
            mod_name = moderator.name if moderator else f"Modérateur #{mod_id}"
            dur_str = f" ({self._format_duration(dur)})" if dur else ""
            children.append(disnake.ui.TextDisplay(f"{self._type_to_emoji(t)} **{t}{dur_str}** par **{mod_name}** — {r or 'Sans raison'} (<t:{ts_int}:R>)"))

        components = [disnake.ui.Container(*children)]
        await interaction.response.send_message(components=components, ephemeral=True)

    @commands.slash_command(name="modconfig", description="Configuration de la modération")
    @check_premium_tier()
    @commands.has_permissions(administrator=True)
    async def modconfig(self, interaction: disnake.ApplicationCommandInteraction):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('INSERT OR IGNORE INTO mod_config (guild_id) VALUES (?)', (interaction.guild_id,))
        conn.commit(); conn.close()
        await self.send_modconfig_v2(interaction)

    @commands.Cog.listener("on_message_interaction")
    async def on_mod_interaction(self, interaction: disnake.MessageInteraction):
        cid = interaction.data.custom_id
        if not cid: return
        
        if cid.startswith("modpan_"):
            action, mid = cid.replace("modpan_", "").split(":")
            member = interaction.guild.get_member(int(mid))
            if not member: return await interaction.response.send_message("❌ Membre introuvable.", ephemeral=True)
            
            # Vérifications des permissions et de la hiérarchie
            if member.top_role >= interaction.user.top_role and interaction.user.id != interaction.guild.owner_id:
                return await interaction.response.send_message("❌ Permissions insuffisantes : ce membre a un rôle supérieur ou égal au vôtre.", ephemeral=True)
                
            perms = interaction.user.guild_permissions
            if action == "ban" and not perms.ban_members:
                return await interaction.response.send_message("❌ Vous n'avez pas la permission de bannir des membres.", ephemeral=True)
            elif action == "kick" and not perms.kick_members:
                return await interaction.response.send_message("❌ Vous n'avez pas la permission d'expulser des membres.", ephemeral=True)
            elif action in ["timeout", "warn", "clear"] and not perms.moderate_members:
                return await interaction.response.send_message("❌ Vous n'avez pas la permission de gérer les sanctions (moderate_members).", ephemeral=True)

            if action == "clear":
                await self.clearwarns(interaction, member, "Nettoyage Panel")
                await self.send_modpanel_v2(interaction, member, edit=True)
            else:
                await interaction.response.send_modal(ModReasonModal(self, action.upper(), member))
        elif cid.startswith("modcfg_"):
            if not interaction.user.guild_permissions.administrator:
                return await interaction.response.send_message("❌ Vous devez être administrateur pour modifier cette configuration.", ephemeral=True)
                
            act = cid.replace("modcfg_", "")
            if act in ["logs", "board"]:
                col = "log_channel_id" if act == "logs" else "board_channel_id"
                view = disnake.ui.View()
                sel = disnake.ui.ChannelSelect(placeholder="Choisir salon...", channel_types=[disnake.ChannelType.text])
                async def sel_cb(i):
                    c = sel.values[0]
                    conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
                    cursor.execute(f"UPDATE mod_config SET {col} = ? WHERE guild_id = ?", (c.id, i.guild_id))
                    conn.commit(); conn.close()
                    await i.response.send_message(f"✅ Salon mis à jour.", ephemeral=True)
                    await self.send_modconfig_v2(interaction, edit=True)
                sel.callback = sel_cb; view.add_item(sel)
                await interaction.response.send_message(f"Sélectionnez le salon pour {act} :", view=view, ephemeral=True)
            elif act == "limits":
                conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
                cursor.execute("SELECT warn_limit_timeout, warn_limit_kick, warn_limit_ban FROM mod_config WHERE guild_id = ?", (interaction.guild_id,))
                res = cursor.fetchone(); conn.close()
                view = disnake.ui.View()
                b1 = disnake.ui.Button(label=f"Timeout ({res[0]})"); b1.callback = lambda i: i.response.send_modal(ModConfigModal("Limite Timeout", res[0]))
                b2 = disnake.ui.Button(label=f"Kick ({res[1]})"); b2.callback = lambda i: i.response.send_modal(ModConfigModal("Limite Kick", res[1]))
                b3 = disnake.ui.Button(label=f"Ban ({res[2]})"); b3.callback = lambda i: i.response.send_modal(ModConfigModal("Limite Ban", res[2]))
                view.add_item(b1); view.add_item(b2); view.add_item(b3)
                await interaction.response.send_message("Modifier quel palier ?", view=view, ephemeral=True)
            elif act == "duration":
                conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
                cursor.execute("SELECT timeout_duration FROM mod_config WHERE guild_id = ?", (interaction.guild_id,))
                res = cursor.fetchone(); conn.close()
                await interaction.response.send_modal(ModConfigModal("Durée Timeout (s)", res[0]))
            elif act == "appeal":
                view = disnake.ui.View()
                sel = disnake.ui.ChannelSelect(placeholder="Choisir salon...", channel_types=[disnake.ChannelType.text])
                async def sel_cb(i):
                    c = sel.values[0]
                    conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
                    cursor.execute("UPDATE mod_config SET appeal_channel_id = ? WHERE guild_id = ?", (c.id, i.guild_id))
                    conn.commit(); conn.close()
                    await i.response.send_message(f"✅ Salon de contestation mis à jour.", ephemeral=True)
                    await self.send_modconfig_v2(interaction, edit=True)
                sel.callback = sel_cb; view.add_item(sel)
                await interaction.response.send_message("Sélectionnez le salon pour la contestation :", view=view, ephemeral=True)

    async def warn(self, interaction, member, reason):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('INSERT INTO sanctions (guild_id, user_id, moderator_id, type, reason) VALUES (?, ?, ?, ?, ?)', (interaction.guild_id, member.id, interaction.user.id, 'WARN', reason))
        cursor.execute('SELECT COUNT(*) FROM sanctions WHERE guild_id = ? AND user_id = ? AND type = "WARN" AND status = "ACTIVE"', (interaction.guild_id, member.id))
        count = cursor.fetchone()[0]
        cursor.execute('SELECT warn_limit_timeout, warn_limit_kick, warn_limit_ban, timeout_duration FROM mod_config WHERE guild_id = ?', (interaction.guild_id,))
        cfg = cursor.fetchone()
        cursor.execute('SELECT id, timestamp FROM sanctions WHERE guild_id = ? AND user_id = ? AND type = "WARN" ORDER BY id DESC LIMIT 1', (interaction.guild_id, member.id))
        s_id, ts = cursor.fetchone(); conn.commit(); conn.close()
        
        if not interaction.response.is_done(): await interaction.response.send_message(f"✅ {member.mention} averti ({count}).", ephemeral=True)
        await self.send_mod_log(interaction.guild, [disnake.ui.Container(disnake.ui.Section(f"⚠️ Warn : {member}", accessory=disnake.ui.Thumbnail(member.display_avatar.url)), disnake.ui.Separator(divider=True), disnake.ui.TextDisplay(f"Raison: {reason}"), disnake.ui.TextDisplay(f"Total: {count}"))])
        await self.send_sanction_board(interaction.guild, self.build_sanction_board_components(s_type="WARN", user=member, moderator=interaction.user, reason=reason, timestamp=ts, s_id=s_id))
        dm_sent = await self.send_sanction_dm(member, "WARN", reason, interaction.user, interaction.guild)
        if not dm_sent:
            kuby_logger.warning(f"DM non envoyé à {member} (DMs peut-être bloqués)")
        if cfg:
            lt, lk, lb, dur = cfg
            if count >= lb: await member.ban(reason=f"Auto: {count} warns")
            elif count >= lk: await member.kick(reason=f"Auto: {count} warns")
            elif count >= lt: await member.timeout(duration=timedelta(seconds=dur), reason=f"Auto: {count} warns")

    async def timeout(self, interaction, member, duration_str, reason):
        secs = self.parse_duration(duration_str)
        if secs <= 0: return await interaction.response.send_message("❌ Durée invalide.", ephemeral=True)
        await member.timeout(duration=timedelta(seconds=secs), reason=reason)
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('INSERT INTO sanctions (guild_id, user_id, moderator_id, type, reason, duration) VALUES (?, ?, ?, ?, ?, ?)', (interaction.guild_id, member.id, interaction.user.id, 'TIMEOUT', reason, secs))
        cursor.execute('SELECT id, timestamp FROM sanctions WHERE guild_id = ? AND user_id = ? AND type = "TIMEOUT" ORDER BY id DESC LIMIT 1', (interaction.guild_id, member.id))
        s_id, ts = cursor.fetchone(); conn.commit(); conn.close()
        if not interaction.response.is_done(): await interaction.response.send_message(f"✅ {member.mention} timeout.", ephemeral=True)
        await self.send_sanction_board(interaction.guild, self.build_sanction_board_components(s_type="TIMEOUT", user=member, moderator=interaction.user, reason=reason, timestamp=ts, s_id=s_id, duration=secs))
        await self.send_sanction_dm(member, "TIMEOUT", reason, interaction.user, interaction.guild, duration=secs)

    async def kick(self, interaction, member, reason):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('INSERT INTO sanctions (guild_id, user_id, moderator_id, type, reason) VALUES (?, ?, ?, ?, ?)', (interaction.guild_id, member.id, interaction.user.id, 'KICK', reason))
        cursor.execute('SELECT id, timestamp FROM sanctions WHERE guild_id = ? AND user_id = ? AND type = "KICK" ORDER BY id DESC LIMIT 1', (interaction.guild_id, member.id))
        s_id, ts = cursor.fetchone(); conn.commit(); conn.close()
        await self.send_sanction_dm(member, "KICK", reason, interaction.user, interaction.guild)
        await member.kick(reason=reason)
        if not interaction.response.is_done(): await interaction.response.send_message(f"✅ {member.name} expulsé.", ephemeral=True)
        await self.send_sanction_board(interaction.guild, self.build_sanction_board_components(s_type="KICK", user=member, moderator=interaction.user, reason=reason, timestamp=ts, s_id=s_id))

    async def ban(self, interaction, user, reason):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('INSERT INTO sanctions (guild_id, user_id, moderator_id, type, reason) VALUES (?, ?, ?, ?, ?)', (interaction.guild_id, user.id, interaction.user.id, 'BAN', reason))
        cursor.execute('SELECT id, timestamp FROM sanctions WHERE guild_id = ? AND user_id = ? AND type = "BAN" ORDER BY id DESC LIMIT 1', (interaction.guild_id, user.id))
        s_id, ts = cursor.fetchone(); conn.commit(); conn.close()
        await self.send_sanction_dm(user, "BAN", reason, interaction.user, interaction.guild)
        await interaction.guild.ban(user, reason=reason)
        if not interaction.response.is_done(): await interaction.response.send_message(f"✅ {user.name} banni.", ephemeral=True)
        await self.send_sanction_board(interaction.guild, self.build_sanction_board_components(s_type="BAN", user=user, moderator=interaction.user, reason=reason, timestamp=ts, s_id=s_id))

    async def clearwarns(self, interaction, member, reason):
        conn = sqlite3.connect(self.db_path); cursor = conn.cursor()
        cursor.execute('UPDATE sanctions SET status = "REVOKED" WHERE guild_id = ? AND user_id = ? AND type = "WARN"', (interaction.guild_id, member.id))
        conn.commit(); conn.close()
        if not interaction.response.is_done(): await interaction.response.send_message(f"✅ Warns effacés.", ephemeral=True)

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