import discord
from discord.ext import commands
import json
import os
import math
from datetime import datetime, timedelta
import asyncio

class Leveling(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.config_file = "leveling_config.json"
        self.data_file = "leveling_data.json"
        self.load_config()
        self.load_data()
        self.last_message = {}  # Anti-spam
        
    def load_config(self):
        """Načte konfiguraci leveling systému"""
        if os.path.exists(self.config_file):
            with open(self.config_file, "r") as f:
                config = json.load(f)
        else:
            config = {
                "enabled": True,
                "xp_per_message": 15,
                "xp_cooldown": 60,
                "level_up_channel": None,
                "level_roles": {},
                "blacklisted_channels": [],
                "multiplier_channels": {},
                "reset_on_leave": False,
                "level_up_message": "🎉 Gratulujeme {user}! Dosáhl jsi **Level {level}**! 🎊",
                "show_level_card": True
            }
            self.save_config(config)
        
        self.config = config
    
    def save_config(self, config=None):
        """Uloží konfiguraci"""
        if config is None:
            config = self.config
        with open(self.config_file, "w") as f:
            json.dump(config, f, indent=2)
    
    def load_data(self):
        """Načte uživatelská data"""
        if os.path.exists(self.data_file):
            with open(self.data_file, "r") as f:
                self.user_data = json.load(f)
        else:
            self.user_data = {}
    
    def save_data(self):
        """Uloží uživatelská data"""
        with open(self.data_file, "w") as f:
            json.dump(self.user_data, f, indent=2)
    
    def calculate_level(self, xp):
        """Vypočítá level na základě XP"""
        return math.floor(0.1 * math.sqrt(xp))
    
    def calculate_xp_needed(self, level):
        """Vypočítá XP potřebné pro daný level"""
        return math.ceil(((level / 0.1) ** 2))
    
    def get_user_data(self, user_id):
        """Získá data uživatele"""
        user_id = str(user_id)
        if user_id not in self.user_data:
            self.user_data[user_id] = {
                "xp": 0,
                "level": 0,
                "messages": 0,
                "last_message": None
            }
        return self.user_data[user_id]
    
    def add_xp(self, user_id, amount):
        """Přidá XP uživateli"""
        user_data = self.get_user_data(user_id)
        old_level = user_data["level"]
        
        user_data["xp"] += amount
        user_data["level"] = self.calculate_level(user_data["xp"])
        user_data["messages"] += 1
        user_data["last_message"] = datetime.now().isoformat()
        
        self.save_data()
        
        # Kontrola level up
        if user_data["level"] > old_level:
            return user_data["level"]
        return None

    # Oprav chybu v on_message - datetime objekty porovnání
    @commands.Cog.listener()
    async def on_message(self, message):
        """Event pro zprávy - přidává XP"""
        if not self.config["enabled"]:
            return
        
        if message.author.bot:
            return
        
        if message.channel.id in self.config["blacklisted_channels"]:
            return
        
        user_id = str(message.author.id)
        current_time = datetime.now()
        
        # OPRAVA: Anti-spam kontrola s datetime objekty
        if user_id in self.last_message:
            time_diff = (current_time - self.last_message[user_id]).total_seconds()
            if time_diff < self.config["xp_cooldown"]:
                return
        
        self.last_message[user_id] = current_time
        
        # Vypočítej XP s multiplikátorem
        base_xp = self.config["xp_per_message"]
        multiplier = self.config["multiplier_channels"].get(str(message.channel.id), 1.0)
        final_xp = int(base_xp * multiplier)
        
        # Přidej XP
        new_level = self.add_xp(message.author.id, final_xp)
        
        # Level up zpráva
        if new_level:
            await self.handle_level_up(message.author, message.channel, new_level)
    
    async def handle_level_up(self, user, channel, level):
        """Zpracuje level up"""
        # Level up zpráva
        if self.config["level_up_channel"]:
            target_channel = self.bot.get_channel(self.config["level_up_channel"])
        else:
            target_channel = channel
        
        if target_channel:
            message = self.config["level_up_message"].format(
                user=user.mention,
                level=level,
                username=user.name
            )
            
            if self.config["show_level_card"]:
                embed = discord.Embed(
                    title="🎉 Level Up!",
                    description=message,
                    color=0x00ff00,
                    timestamp=datetime.now()
                )
                embed.set_thumbnail(url=user.display_avatar.url)
                embed.add_field(name="📊 Nový Level", value=f"**{level}**", inline=True)
                
                user_data = self.get_user_data(user.id)
                next_level_xp = self.calculate_xp_needed(level + 1)
                current_xp = user_data["xp"]
                needed_xp = next_level_xp - current_xp
                
                embed.add_field(name="⭐ Celkové XP", value=f"**{current_xp:,}**", inline=True)
                embed.add_field(name="🎯 Do dalšího levelu", value=f"**{needed_xp:,} XP**", inline=True)
                
                await target_channel.send(embed=embed)
            else:
                await target_channel.send(message)
        
        # Přidej role
        await self.assign_level_role(user, level)
    
    async def assign_level_role(self, user, level):
        """Přiřadí roli na základě levelu"""
        if not isinstance(user, discord.Member):
            return
        
        # Najdi nejvyšší roli pro tento level
        role_to_assign = None
        for level_req, role_id in self.config["level_roles"].items():
            if level >= int(level_req):
                role_to_assign = role_id
        
        if role_to_assign:
            role = user.guild.get_role(int(role_to_assign))
            if role and role not in user.roles:
                try:
                    await user.add_roles(role, reason=f"Level {level} dosažen")
                except discord.Forbidden:
                    print(f"❌ Nemám oprávnění přidat roli {role.name}")

    @commands.command()
    async def rank(self, ctx, user: discord.Member = None):
        """Zobrazí rank kartu uživatele"""
        if user is None:
            user = ctx.author
        
        user_data = self.get_user_data(user.id)
        
        embed = discord.Embed(
            title=f"📊 Rank - {user.display_name}",
            color=0x5865F2,
            timestamp=datetime.now()
        )
        embed.set_thumbnail(url=user.display_avatar.url)
        
        current_level = user_data["level"]
        current_xp = user_data["xp"]
        current_level_xp = self.calculate_xp_needed(current_level) if current_level > 0 else 0
        next_level_xp = self.calculate_xp_needed(current_level + 1)
        
        progress_xp = current_xp - current_level_xp
        needed_xp = next_level_xp - current_level_xp
        progress_percent = (progress_xp / needed_xp) * 100
        
        # Progress bar
        bar_length = 20
        filled_length = int(bar_length * progress_percent / 100)
        bar = "█" * filled_length + "░" * (bar_length - filled_length)
        
        embed.add_field(
            name="📈 Level",
            value=f"**{current_level}**",
            inline=True
        )
        embed.add_field(
            name="⭐ Celkové XP",
            value=f"**{current_xp:,}**",
            inline=True
        )
        embed.add_field(
            name="💬 Zprávy",
            value=f"**{user_data['messages']:,}**",
            inline=True
        )
        embed.add_field(
            name="🎯 Progress do dalšího levelu",
            value=f"`{bar}` {progress_percent:.1f}%\n**{progress_xp:,}** / **{needed_xp:,}** XP",
            inline=False
        )
        
        # Server ranking
        all_users = [(uid, data) for uid, data in self.user_data.items() if data["xp"] > 0]
        all_users.sort(key=lambda x: x[1]["xp"], reverse=True)
        
        try:
            rank = next(i for i, (uid, _) in enumerate(all_users, 1) if uid == str(user.id))
            embed.add_field(
                name="🏆 Rank na serveru",
                value=f"**#{rank}** z {len(all_users)}",
                inline=True
            )
        except StopIteration:
            pass
        
        await ctx.send(embed=embed)

    @commands.command()
    async def leaderboard(self, ctx, page: int = 1):
        """Zobrazí žebříček nejlepších uživatelů"""
        all_users = [(uid, data) for uid, data in self.user_data.items() if data["xp"] > 0]
        all_users.sort(key=lambda x: x[1]["xp"], reverse=True)
        
        if not all_users:
            await ctx.send("📭 Žebříček je prázdný!")
            return
        
        users_per_page = 10
        total_pages = math.ceil(len(all_users) / users_per_page)
        page = max(1, min(page, total_pages))
        
        start_idx = (page - 1) * users_per_page
        end_idx = start_idx + users_per_page
        page_users = all_users[start_idx:end_idx]
        
        embed = discord.Embed(
            title="🏆 Leaderboard",
            description=f"Stránka {page}/{total_pages}",
            color=0xffd700,
            timestamp=datetime.now()
        )
        
        leaderboard_text = ""
        for i, (user_id, data) in enumerate(page_users, start_idx + 1):
            try:
                user = self.bot.get_user(int(user_id))
                if user:
                    emoji = "🥇" if i == 1 else "🥈" if i == 2 else "🥉" if i == 3 else "🔸"
                    leaderboard_text += f"{emoji} **#{i}** {user.display_name}\n"
                    leaderboard_text += f"    Level {data['level']} • {data['xp']:,} XP • {data['messages']:,} zpráv\n\n"
            except:
                continue
        
        embed.description = f"Stránka {page}/{total_pages}\n\n{leaderboard_text}"
        
        if total_pages > 1:
            embed.set_footer(text=f"Použij {ctx.prefix}leaderboard {page+1} pro další stránku")
        
        await ctx.send(embed=embed)

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def addxp(self, ctx, user: discord.Member, amount: int):
        """Přidá XP uživateli (admin)"""
        old_data = self.get_user_data(user.id).copy()
        new_level = self.add_xp(user.id, amount)
        
        embed = discord.Embed(
            title="⭐ XP Přidáno",
            color=0x00ff00
        )
        embed.add_field(name="👤 Uživatel", value=user.mention, inline=True)
        embed.add_field(name="➕ Přidáno XP", value=f"**{amount:,}**", inline=True)
        embed.add_field(name="📊 Nové XP", value=f"**{self.get_user_data(user.id)['xp']:,}**", inline=True)
        
        if new_level:
            embed.add_field(name="🎉 Level Up!", value=f"Level **{new_level}**", inline=False)
        
        await ctx.send(embed=embed)

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def removexp(self, ctx, user: discord.Member, amount: int):
        """Odebere XP uživateli (admin)"""
        user_data = self.get_user_data(user.id)
        old_xp = user_data["xp"]
        old_level = user_data["level"]
        
        user_data["xp"] = max(0, user_data["xp"] - amount)
        user_data["level"] = self.calculate_level(user_data["xp"])
        self.save_data()
        
        embed = discord.Embed(
            title="➖ XP Odebráno",
            color=0xff9900
        )
        embed.add_field(name="👤 Uživatel", value=user.mention, inline=True)
        embed.add_field(name="➖ Odebráno XP", value=f"**{amount:,}**", inline=True)
        embed.add_field(name="📊 Nové XP", value=f"**{user_data['xp']:,}**", inline=True)
        
        if user_data["level"] < old_level:
            embed.add_field(name="📉 Level Down", value=f"Level **{user_data['level']}** (z {old_level})", inline=False)
        
        await ctx.send(embed=embed)

    @commands.group(invoke_without_command=True)
    @commands.has_permissions(administrator=True)
    async def levelconfig(self, ctx):
        """Konfigurace leveling systému"""
        embed = discord.Embed(
            title="⚙️ Leveling Konfigurace",
            color=0x5865F2
        )
        
        prefix = ctx.prefix
        embed.add_field(
            name="🔧 Dostupné příkazy",
            value=f"`{prefix}levelconfig enable/disable` - Zapne/vypne systém\n"
                  f"`{prefix}levelconfig xp <amount>` - Nastaví XP za zprávu\n"
                  f"`{prefix}levelconfig cooldown <seconds>` - Nastaví cooldown\n"
                  f"`{prefix}levelconfig channel <#channel>` - Nastaví kanál pro level up\n"
                  f"`{prefix}levelconfig addrole <level> <@role>` - Přidá level roli\n"
                  f"`{prefix}levelconfig removerole <level>` - Odebere level roli\n"
                  f"`{prefix}levelconfig blacklist <#channel>` - Zakáže XP v kanálu\n"
                  f"`{prefix}levelconfig multiplier <#channel> <multiplier>` - Nastaví multiplikátor\n"
                  f"`{prefix}levelconfig reset <@user>` - Resetuje uživatele",
            inline=False
        )
        
        level_up_channel = self.config['level_up_channel']
        channel_display = f"<#{level_up_channel}>" if level_up_channel else "Nenastaveno"
        
        # OPRAVA: Použij proměnné místo přímého přístupu v f-stringu
        enabled_status = "✅" if self.config['enabled'] else "❌"
        xp_amount = self.config['xp_per_message']
        cooldown_time = self.config['xp_cooldown']
        roles_count = len(self.config['level_roles'])
        blacklisted_count = len(self.config['blacklisted_channels'])
        
        embed.add_field(
            name="📊 Aktuální nastavení",
            value=(
                f"Zapnuto: {enabled_status}\n"
                f"XP za zprávu: {xp_amount}\n"
                f"Cooldown: {cooldown_time}s\n"
                f"Level kanál: {channel_display}\n"
                f"Level role: {roles_count}\n"
                f"Zakázané kanály: {blacklisted_count}"
            ),
            inline=False
        )
        
        await ctx.send(embed=embed)

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def enable(self, ctx):
        """Zapne leveling systém"""
        self.config["enabled"] = True
        self.save_config()
        await ctx.send("✅ Leveling systém zapnut!")

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def disable(self, ctx):
        """Vypne leveling systém"""
        self.config["enabled"] = False
        self.save_config()
        await ctx.send("❌ Leveling systém vypnut!")

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def xp(self, ctx, amount: int):
        """Nastaví XP za zprávu"""
        if amount < 1 or amount > 100:
            await ctx.send("❌ XP musí být mezi 1-100!")
            return
        
        self.config["xp_per_message"] = amount
        self.save_config()
        await ctx.send(f"✅ XP za zprávu nastaveno na {amount}!")

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def cooldown(self, ctx, seconds: int):
        """Nastaví cooldown pro získání XP"""
        if seconds < 0 or seconds > 3600:
            await ctx.send("❌ Cooldown musí být mezi 0-3600 sekund!")
            return
        
        self.config["xp_cooldown"] = seconds
        self.save_config()
        await ctx.send(f"✅ XP cooldown nastaven na {seconds} sekund!")

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def channel(self, ctx, channel: discord.TextChannel = None):
        """Nastaví kanál pro level up zprávy"""
        if channel is None:
            self.config["level_up_channel"] = None
            await ctx.send("✅ Level up kanál resetován!")
        else:
            self.config["level_up_channel"] = channel.id
            await ctx.send(f"✅ Level up kanál nastaven na {channel.mention}!")
        
        self.save_config()

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def addrole(self, ctx, level: int, role: discord.Role):
        """Přidá roli pro určitý level"""
        if level < 1:
            await ctx.send("❌ Level musí být alespoň 1!")
            return
        
        self.config["level_roles"][str(level)] = role.id
        self.save_config()
        await ctx.send(f"✅ Role {role.mention} přidána pro level {level}!")

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def removerole(self, ctx, level: int):
        """Odebere roli pro určitý level"""
        if str(level) in self.config["level_roles"]:
            del self.config["level_roles"][str(level)]
            self.save_config()
            await ctx.send(f"✅ Role pro level {level} odebrána!")
        else:
            await ctx.send(f"❌ Žádná role pro level {level} není nastavena!")

    @commands.Cog.listener()
    async def on_member_remove(self, member):
        """Reset dat při opuštění serveru (pokud je povoleno)"""
        if self.config.get("reset_on_leave", False):
            user_id = str(member.id)
            if user_id in self.user_data:
                del self.user_data[user_id]
                self.save_data()

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def blacklist(self, ctx, channel: discord.TextChannel):
        """Přidá/odebere kanál ze zakázaných"""
        if channel.id in self.config["blacklisted_channels"]:
            self.config["blacklisted_channels"].remove(channel.id)
            await ctx.send(f"✅ Kanál {channel.mention} odebrán ze zakázaných!")
        else:
            self.config["blacklisted_channels"].append(channel.id)
            await ctx.send(f"✅ Kanál {channel.mention} přidán do zakázaných!")
    
        self.save_config()

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def multiplier(self, ctx, channel: discord.TextChannel, multiplier: float):
        """Nastaví XP multiplikátor pro kanál"""
        if multiplier < 0.1 or multiplier > 10.0:
            await ctx.send("❌ Multiplikátor musí být mezi 0.1 - 10.0!")
            return
        
        if multiplier == 1.0:
            # Odstraň multiplikátor
            if str(channel.id) in self.config["multiplier_channels"]:
                del self.config["multiplier_channels"][str(channel.id)]
                await ctx.send(f"✅ Multiplikátor pro {channel.mention} odstraněn!")
        else:
            self.config["multiplier_channels"][str(channel.id)] = multiplier
            await ctx.send(f"✅ Multiplikátor pro {channel.mention} nastaven na {multiplier}x!")
        
        self.save_config()

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def reset(self, ctx, user: discord.Member):
        """Resetuje XP a level uživatele"""
        user_id = str(user.id)
        
        if user_id in self.user_data:
            old_data = self.user_data[user_id].copy()
            self.user_data[user_id] = {
                "xp": 0,
                "level": 0,
                "messages": 0,
                "last_message": None
            }
            self.save_data()
            
            embed = discord.Embed(
                title="🔄 Reset Uživatele",
                description=f"XP a level pro {user.mention} byl resetován!",
                color=0xff9900
            )
            embed.add_field(name="📊 Předchozí data", value=f"Level: {old_data['level']}\nXP: {old_data['xp']:,}\nZprávy: {old_data['messages']:,}", inline=True)
            embed.add_field(name="📊 Nová data", value="Level: 0\nXP: 0\nZprávy: 0", inline=True)
            
            await ctx.send(embed=embed)
        else:
            await ctx.send(f"❌ Uživatel {user.mention} nemá žádná data k resetování!")

    @levelconfig.command()
    @commands.has_permissions(administrator=True) 
    async def listroles(self, ctx):
        """Zobrazí seznam level rolí"""
        if not self.config["level_roles"]:
            await ctx.send("📭 Žádné level role nejsou nastaveny!")
            return
        
        embed = discord.Embed(
            title="🎭 Level Role",
            color=0x5865F2
        )
        
        roles_text = ""
        for level, role_id in sorted(self.config["level_roles"].items(), key=lambda x: int(x[0])):
            role = ctx.guild.get_role(int(role_id))
            if role:
                roles_text += f"**Level {level}:** {role.mention}\n"
            else:
                roles_text += f"**Level {level}:** Neplatná role (ID: {role_id})\n"
        
        embed.description = roles_text or "Žádné role nenalezeny"
        await ctx.send(embed=embed)

    @levelconfig.command()
    @commands.has_permissions(administrator=True)
    async def listchannels(self, ctx):
        """Zobrazí blacklisted kanály a multiplikátory"""
        embed = discord.Embed(
            title="📋 Kanály Konfigurace",
            color=0x5865F2
        )
        
        # Blacklisted channels
        if self.config["blacklisted_channels"]:
            blacklist_text = ""
            for channel_id in self.config["blacklisted_channels"]:
                channel = ctx.guild.get_channel(channel_id)
                if channel:
                    blacklist_text += f"• {channel.mention}\n"
                else:
                    blacklist_text += f"• Neplatný kanál (ID: {channel_id})\n"
            embed.add_field(name="🚫 Zakázané kanály", value=blacklist_text, inline=False)
        
        # Multiplier channels
        if self.config["multiplier_channels"]:
            multiplier_text = ""
            for channel_id, multiplier in self.config["multiplier_channels"].items():
                channel = ctx.guild.get_channel(int(channel_id))
                if channel:
                    multiplier_text += f"• {channel.mention}: **{multiplier}x**\n"
                else:
                    multiplier_text += f"• Neplatný kanál (ID: {channel_id}): **{multiplier}x**\n"
            embed.add_field(name="⚡ Multiplikátory", value=multiplier_text, inline=False)
        
        if not self.config["blacklisted_channels"] and not self.config["multiplier_channels"]:
            embed.description = "Žádné speciální kanály nejsou nakonfigurovány."
        
        await ctx.send(embed=embed)

async def setup(bot):
    await bot.add_cog(Leveling(bot))