import disnake
from disnake.ext import commands
from disnake.ui import View, Button
import json
import os
from datetime import datetime
from typing import List, Dict, Optional

class WhitelistMonitor(commands.Cog):
    """Monitors whitelist members for role changes and server leave events."""
    
    def __init__(self, bot):
        self.bot = bot
        self.whitelist_file = "data/whitelist.json"
        self.persistent_views_added = False
        self.big_permissions = [
            "administrator", "manage_guild", "manage_roles", "manage_channels",
            "kick_members", "ban_members", "manage_messages", "moderate_members",
            "manage_nicknames", "manage_emojis", "manage_webhooks", "view_audit_log"
        ]
        
    def load_whitelist(self) -> Dict[str, List[str]]:
        """Load whitelist from JSON file."""
        if not os.path.exists(self.whitelist_file):
            return {}
        try:
            with open(self.whitelist_file, "r", encoding="utf-8") as f:
                raw_data = json.load(f)
                # Convert all user IDs to strings for consistent comparison
                result = {}
                for guild_id, user_ids in raw_data.items():
                    result[str(guild_id)] = [str(uid) for uid in user_ids]
                return result
        except (json.JSONDecodeError, FileNotFoundError):
            return {}
    
    def save_whitelist(self, whitelist: Dict[str, List[str]]):
        """Save whitelist to JSON file."""
        with open(self.whitelist_file, "w", encoding="utf-8") as f:
            json.dump(whitelist, f, ensure_ascii=False, indent=4)
    
    def is_whitelisted(self, guild_id: int, user_id: int) -> bool:
        """Check if user is whitelisted for a specific guild."""
        whitelist = self.load_whitelist()
        guild_key = str(guild_id)
        user_key = str(user_id)
        return guild_key in whitelist and user_key in whitelist[guild_key]
    
    def remove_from_whitelist(self, guild_id: int, user_id: int) -> bool:
        """Remove user from whitelist for a specific guild."""
        whitelist = self.load_whitelist()
        guild_key = str(guild_id)
        user_key = str(user_id)
        
        if guild_key in whitelist and user_key in whitelist[guild_key]:
            whitelist[guild_key].remove(user_key)
            # Clean up empty guild entries
            if not whitelist[guild_key]:
                del whitelist[guild_key]
            self.save_whitelist(whitelist)
            return True
        return False
    
    def has_big_permissions(self, role: disnake.Role) -> bool:
        """Check if role has significant permissions."""
        perms = role.permissions
        return any(getattr(perms, p, False) for p in self.big_permissions)
    
    async def send_whitelist_notification(self, member: disnake.Member, removed_roles: List[disnake.Role]):
        """Send DM notification to user about whitelist member losing roles."""
        try:
            # Find guild administrators to notify
            admins = [m for m in member.guild.members if m.guild_permissions.administrator and not m.bot]
            if not admins:
                return
            
            # Create embed
            embed = disnake.Embed(
                title="⚠️ Whitelist Alert",
                description=f"Un membre whitelisté a perdu des rôles importants dans **{member.guild.name}**.",
                color=disnake.Color.orange(),
                timestamp=datetime.now()
            )
            
            embed.add_field(
                name="👤 Membre concerné",
                value=f"{member.mention} ({member.display_name})",
                inline=False
            )
            
            if removed_roles:
                roles_text = "\n".join([f"• {role.name}" for role in removed_roles])
                embed.add_field(
                    name="🗑️ Rôles retirés",
                    value=roles_text,
                    inline=False
                )
            
            embed.add_field(
                name="📋 Statut whitelist",
                value="✅ Toujours whitelisté",
                inline=True
            )
            
            # Create view with removal button
            view = WhitelistRemovalView(member.id, member.guild.id)
            
            # Send to all admins
            for admin in admins:
                try:
                    await admin.send(embed=embed, view=view)
                except disnake.Forbidden:
                    continue  # User has DMs disabled
                    
        except Exception as e:
            print(f"Error sending whitelist notification: {e}")

    async def cog_load(self):
        """Register persistent views when cog is loaded"""
        await self._register_persistent_views()

    async def _register_persistent_views(self):
        """Register all persistent views for guilds with whitelist alerts"""
        if self.persistent_views_added:
            return
        
        try:
            import json
            security_file = "data/security_settings.json"
            if os.path.exists(security_file):
                with open(security_file, "r", encoding="utf-8") as f:
                    all_settings = json.load(f)
                
                # For each guild with whitelist monitoring, register a default view
                # We'll use a generic view that gets recreated when needed
                # The key is that each unique custom_id needs to be registered once
                view = WhitelistRemovalView(0, 0)  # Placeholder with dummy IDs
                self.bot.add_view(view)
                print(f"[WhitelistMonitor] Persistent view registered")
            
            self.persistent_views_added = True
        except Exception as e:
            print(f"[WhitelistMonitor] Error registering views: {e}")

    @commands.Cog.listener()
    async def on_member_update(self, before: disnake.Member, after: disnake.Member):
        """Monitor role changes for whitelist members."""
        if before.roles == after.roles:
            return
            
        if not self.is_whitelisted(after.guild.id, after.id):
            return
            
        # Find removed roles
        removed_roles = [role for role in before.roles if role not in after.roles]
        
        # Check if any removed roles had big permissions
        important_removed = [role for role in removed_roles if self.has_big_permissions(role)]
        
        if important_removed:
            await self.send_whitelist_notification(after, important_removed)

    @commands.Cog.listener()
    async def on_member_remove(self, member: disnake.Member):
        """Auto-remove from whitelist when member leaves server."""
        if self.is_whitelisted(member.guild.id, member.id):
            removed = self.remove_from_whitelist(member.guild.id, member.id)
            if removed:
                # Log the removal
                try:
                    log_channel_id = self.get_log_channel(member.guild.id)
                    if log_channel_id:
                        log_channel = member.guild.get_channel(log_channel_id)
                        if log_channel:
                            embed = disnake.Embed(
                                title="🗑️ Auto-Whitelist Removal",
                                description=f"{member.mention} a été retiré automatiquement de la whitelist après avoir quitté le serveur.",
                                color=disnake.Color.red(),
                                timestamp=datetime.now()
                            )
                            await log_channel.send(embed=embed)
                except Exception as e:
                    print(f"Error logging whitelist removal: {e}")
    
    def get_log_channel(self, guild_id: int) -> Optional[int]:
        """Get log channel ID from security settings."""
        try:
            security_file = "data/security_settings.json"
            if os.path.exists(security_file):
                with open(security_file, "r") as f:
                    settings = json.load(f)
                    return settings.get(str(guild_id), {}).get("log_channel_id")
        except:
            pass
        return None

class WhitelistRemovalView(View):
    """View with button to remove user from whitelist."""
    
    def __init__(self, user_id: int, guild_id: int):
        super().__init__(timeout=None)  # Persistent view
        self.user_id = user_id
        self.guild_id = guild_id
    
    @disnake.ui.button(
        label="Retirer de la whitelist",
        style=disnake.ButtonStyle.red,
        emoji="🗑️",
        custom_id="whitelist_remove_button"
    )
    async def remove_whitelist(
        self, 
        interaction: disnake.Interaction, 
        button: Button
    ):
        """Remove user from whitelist when button is clicked."""
        try:
            # Get the cog instance
            cog = self.bot.get_cog("WhitelistMonitor")
            if not cog:
                await interaction.response.send_message(
                    "❌ Erreur: Système de whitelist non disponible.",
                    ephemeral=True
                )
                return
            
            # Remove from whitelist
            removed = cog.remove_from_whitelist(self.guild_id, self.user_id)
            
            if removed:
                # Get user info
                try:
                    user = await self.bot.fetch_user(self.user_id)
                    user_mention = user.mention
                except:
                    user_mention = f"<@{self.user_id}>"
                
                # Update button
                button.disabled = True
                button.label = "✅ Retiré"
                button.style = disnake.ButtonStyle.green
                
                await interaction.response.edit_message(view=self)
                
                # Send confirmation
                embed = disnake.Embed(
                    title="✅ Retrait effectué",
                    description=f"{user_mention} a été retiré de la whitelist.",
                    color=disnake.Color.green()
                )
                await interaction.followup.send(embed=embed, ephemeral=True)
                
                # Log the removal
                try:
                    guild = self.bot.get_guild(self.guild_id)
                    if guild:
                        log_channel_id = cog.get_log_channel(self.guild_id)
                        if log_channel_id:
                            log_channel = guild.get_channel(log_channel_id)
                            if log_channel:
                                embed = disnake.Embed(
                                    title="🗑️ Whitelist Manual Removal",
                                    description=f"{user_mention} a été retiré manuellement de la whitelist.",
                                    color=disnake.Color.green(),
                                    timestamp=datetime.now()
                                )
                                embed.set_footer(text=f"Retiré par {interaction.user.display_name}")
                                await log_channel.send(embed=embed)
                except Exception as e:
                    print(f"Error logging manual removal: {e}")
                    
            else:
                await interaction.response.send_message(
                    "ℹ️ L'utilisateur n'était pas dans la whitelist.",
                    ephemeral=True
                )
                
        except Exception as e:
            await interaction.response.send_message(
                f"❌ Erreur lors du retrait: {str(e)}",
                ephemeral=True
            )

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