import disnake
from disnake.ext import commands
import sqlite3
import os
import logging
from typing import Dict, Optional
import asyncio
from utils.premium import check_premium_tier

kuby_logger = logging.getLogger("KubyBot")

class Invites(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.db_path = os.path.join(os.path.dirname(__file__), "..", "config.db")
        self.invite_cache = {} # {guild_id: {code: uses}}
        self.cache_lock = asyncio.Lock()  # Verrou pour éviter les problèmes de concurrence
        self._init_db()

    def _init_db(self):
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS member_invites (
                guild_id INTEGER,
                member_id INTEGER,
                inviter_id INTEGER,
                invite_code TEXT,
                PRIMARY KEY (guild_id, member_id)
            )
        ''')
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS invite_configs (
                guild_id INTEGER PRIMARY KEY,
                log_channel_id INTEGER
            )
        ''')
        conn.commit()
        conn.close()

    async def update_invite_cache(self, guild):
        try:
            invites = await guild.invites()
            async with self.cache_lock:
                self.invite_cache[guild.id] = {invite.code: invite.uses for invite in invites}
        except disnake.Forbidden:
            kuby_logger.warning(f"[Invites] Impossible de mettre à jour le cache des invitations pour {guild.name} (permissions manquantes)")
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de la mise à jour du cache des invitations pour {guild.name}: {e}")

    @commands.Cog.listener()
    async def on_ready(self):
        for guild in self.bot.guilds:
            await self.update_invite_cache(guild)
        kuby_logger.info("✅ [Invites] Cache des invitations initialisé")
        
        # Debug: Lister toutes les commandes slash enregistrées
        slash_cmds = [cmd.name for cmd in self.bot.slash_commands]
        kuby_logger.info(f"🔍 [Debug] Commandes slash enregistrées : {slash_cmds}")

    @commands.Cog.listener()
    async def on_invite_create(self, invite):
        async with self.cache_lock:
            if invite.guild.id not in self.invite_cache:
                self.invite_cache[invite.guild.id] = {}
            self.invite_cache[invite.guild.id][invite.code] = invite.uses

    @commands.Cog.listener()
    async def on_invite_delete(self, invite):
        async with self.cache_lock:
            if invite.guild.id in self.invite_cache:
                self.invite_cache[invite.guild.id].pop(invite.code, None)

    @commands.Cog.listener()
    async def on_member_join(self, member):
        if member.bot: return
        
        self._init_db()
        guild = member.guild
        try:
            old_invites = self.invite_cache.get(guild.id, {})
            new_invites = await guild.invites()
        except disnake.Forbidden:
            kuby_logger.warning(f"[Invites] Impossible de récupérer les invitations pour {guild.name} (permissions manquantes)")
            return
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de la récupération des invitations pour {guild.name}: {e}")
            return

        used_invite = None
        for invite in new_invites:
            if invite.code in old_invites:
                if invite.uses > old_invites[invite.code]:
                    used_invite = invite
                    break
            elif invite.uses > 0:
                # C'est une nouvelle invitation qui a été utilisée
                used_invite = invite
                break

        # Mise à jour du cache
        async with self.cache_lock:
            self.invite_cache[guild.id] = {invite.code: invite.uses for invite in new_invites}

        if used_invite:
            inviter = used_invite.inviter
            if inviter:
                try:
                    self.record_invite(guild.id, member.id, inviter.id, used_invite.code)
                    kuby_logger.info(f"📥 [Invites] {member} invité par {inviter} ({used_invite.code})")
                except Exception as e:
                    kuby_logger.error(f"[Invites] Erreur lors de l'enregistrement de l'invitation pour {member}: {e}")
                
                # Modular join message
                try:
                    conn = sqlite3.connect(self.db_path)
                    cursor = conn.cursor()
                    cursor.execute('SELECT log_channel_id FROM invite_configs WHERE guild_id = ?', (guild.id,))
                    result = cursor.fetchone()
                    conn.close()
                    
                    if result:
                        log_channel = guild.get_channel(result[0])
                        if log_channel:
                            # Determine method
                            method = "invitation standard"
                            if guild.vanity_url_code and used_invite.code == guild.vanity_url_code:
                                method = "lien personnalisé"
                            elif used_invite.max_age == 0:
                                method = "invitation permanente"
                            elif used_invite.temporary:
                                method = "invitation temporaire"
                            elif used_invite.max_uses == 1:
                                method = "invitation à usage unique"
                            
                            # Récupérer les statistiques de l'inviteur
                            total_invites, current_invites = self.get_invite_stats(guild.id, inviter.id)
                            
                            components = [
                                disnake.ui.Container(
                                    disnake.ui.Section(
                                        f"Nouveau membre via invitation",
                                        accessory=disnake.ui.Thumbnail(member.display_avatar.url)
                                    ),
                                    disnake.ui.Separator(divider=True),
                                    disnake.ui.TextDisplay(f"👤 {member.mention} vient de nous rejoindre !"),
                                    disnake.ui.TextDisplay(f"🤝 Grâce à {inviter.mention}"),
                                    disnake.ui.TextDisplay(f"📊 Invitations : {current_invites} membres présents / {total_invites} total"),
                                    disnake.ui.TextDisplay(f"🔗 Via **{method}**")
                                )
                            ]
                            await log_channel.send(components=components)
                except Exception as e:
                    kuby_logger.error(f"[Invites] Erreur lors de l'envoi du message de log pour {member}: {e}")

    def record_invite(self, guild_id, member_id, inviter_id, code):
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute('''
                INSERT INTO member_invites (guild_id, member_id, inviter_id, invite_code)
                VALUES (?, ?, ?, ?)
                ON CONFLICT(guild_id, member_id) DO UPDATE SET inviter_id=excluded.inviter_id, invite_code=excluded.invite_code
            ''', (guild_id, member_id, inviter_id, code))
            conn.commit()
            conn.close()
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de l'enregistrement de l'invitation dans la base de données: {e}")

    def get_inviter_info(self, guild_id, member_id):
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute('SELECT inviter_id FROM member_invites WHERE guild_id = ? AND member_id = ?', (guild_id, member_id))
            result = cursor.fetchone()
            conn.close()
            return result[0] if result else None
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de la récupération de l'inviteur pour le membre {member_id}: {e}")
            return None

    def get_invite_stats(self, guild_id, user_id):
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute('SELECT member_id FROM member_invites WHERE guild_id = ? AND inviter_id = ?', (guild_id, user_id))
            invited_ids = [row[0] for row in cursor.fetchall()]
            conn.close()

            guild = self.bot.get_guild(guild_id)
            if not guild: return 0, 0

            current_present = 0
            for mid in invited_ids:
                member = guild.get_member(mid)
                if member is not None:
                    # "membres présents" doit refléter la présence réelle : on considère présent
                    # uniquement les membres qui sont encore sur le serveur.
                    current_present += 1
                else:
                    kuby_logger.debug(f"[Invites] Membre invité {mid} non trouvé dans le serveur {guild_id}")

            # Total = tous les invités enregistrés pour cet inviteur.
            # "présents" = ceux qui sont encore sur le serveur (donc baisse quand quelqu'un quitte).
            return len(invited_ids), current_present
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de la récupération des statistiques d'invitations pour {user_id}: {e}")
            return 0, 0

    @commands.Cog.listener()
    async def on_member_remove(self, member):
        if member.bot: return
        
        guild = member.guild
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute('DELETE FROM member_invites WHERE guild_id = ? AND member_id = ?', (guild.id, member.id))
            conn.commit()
            conn.close()
            kuby_logger.info(f"🗑️ [Invites] Enregistrement de l'invitation supprimé pour {member.name} (ID: {member.id}) car il a quitté le serveur.")
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de la suppression de l'enregistrement de l'invitation pour {member.name}: {e}")

    @commands.Cog.listener()
    async def on_member_ban(self, guild, user):
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute('DELETE FROM member_invites WHERE guild_id = ? AND member_id = ?', (guild.id, user.id))
            conn.commit()
            conn.close()
            kuby_logger.info(f"🗑️ [Invites] Enregistrement de l'invitation supprimé pour {user.name} (ID: {user.id}) car il a été banni.")
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de la suppression de l'enregistrement de l'invitation pour {user.name}: {e}")

    @commands.slash_command(name="setinvitechannel", description="Définit le salon des logs d'invitations")
    @check_premium_tier()
    @commands.has_permissions(administrator=True)
    async def set_invite_channel(self, interaction: disnake.ApplicationCommandInteraction, channel: disnake.TextChannel):
        try:
            conn = sqlite3.connect(self.db_path)
            cursor = conn.cursor()
            cursor.execute('''
                INSERT INTO invite_configs (guild_id, log_channel_id)
                VALUES (?, ?)
                ON CONFLICT(guild_id) DO UPDATE SET log_channel_id=excluded.log_channel_id
            ''', (interaction.guild_id, channel.id))
            conn.commit()
            conn.close()
            
            components = [
                disnake.ui.Container(
                    disnake.ui.TextDisplay(f"✅ Salon des logs d'invitations défini sur {channel.mention}")
                )
            ]
            await interaction.response.send_message(components=components, ephemeral=True)
        except Exception as e:
            kuby_logger.error(f"[Invites] Erreur lors de la configuration du salon des logs d'invitations: {e}")
            await interaction.response.send_message("❌ Une erreur est survenue lors de la configuration du salon des logs d'invitations.", ephemeral=True)

    @commands.command(name="invitations_debug")
    async def invites_prefix(self, ctx, user: disnake.Member = None):
        user = user or ctx.author
        total, current = self.get_invite_stats(ctx.guild.id, user.id)
        await ctx.send(f"📊 **{user.display_name}** : {total} total, {current} présents.")

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