import discord
from discord.ext import commands, tasks
import psutil
import json
import os
import asyncio
from datetime import datetime
import platform
import subprocess

class RemoteServerMonitoring:
    def __init__(self):
        self.servers = {}
        self.load_servers_config()
    
    def load_servers_config(self):
        """Načte konfiguraci vzdálených serverů"""
        if os.path.exists("servers_config.json"):
            with open("servers_config.json", "r") as f:
                self.servers = json.load(f)
        else:
            self.servers = {}
    
    def save_servers_config(self):
        """Uloží konfiguraci serverů"""
        with open("servers_config.json", "w") as f:
            json.dump(self.servers, f, indent=2)
    
    async def get_remote_server_data(self, server_id):
        """Získá data ze vzdáleného serveru"""
        try:
            server = self.servers.get(server_id)
            if not server:
                return None
            
            import aiohttp
            async with aiohttp.ClientSession() as session:
                url = f"http://{server['host']}:{server['port']}/api/monitoring"
                async with session.get(url, timeout=10) as response:
                    if response.status == 200:
                        data = await response.json()
                        data['server_name'] = server['name']
                        data['server_id'] = server_id
                        return data
            return None
        except Exception as e:
            print(f"Error getting data from {server_id}: {e}")
            return None

class ServerMonitoring(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.alert_channel_id = None
        self.last_alerts = {}
        self.monitoring_data = {}
        self.remote_monitoring = RemoteServerMonitoring()  # NOVÉ
        self.load_config()
        
    def load_config(self):
        """Načtení konfigurace monitoringu"""
        if os.path.exists("monitoring_config.json"):
            with open("monitoring_config.json", "r") as f:
                config = json.load(f)
                self.alert_channel_id = config.get("alert_channel_id")
                self.cpu_threshold = config.get("cpu_threshold", 80)
                self.memory_threshold = config.get("memory_threshold", 85)
                self.disk_threshold = config.get("disk_threshold", 90)
                self.temp_threshold = config.get("temp_threshold", 75)
                self.monitoring_method = config.get("monitoring_method", "auto")
                self.system_override = config.get("system_override", "auto")
        else:
            # Výchozí konfigurace
            self.alert_channel_id = None
            self.cpu_threshold = 80
            self.memory_threshold = 85
            self.disk_threshold = 90
            self.temp_threshold = 75
            self.monitoring_method = "auto"
            self.system_override = "auto"

    def reload_config(self):
        """Znovu načte konfiguraci ze souboru"""
        self.load_config()
        print(f"📊 Monitoring config reloaded - Alert channel: {self.alert_channel_id}")

    def save_config(self):
        """Uložení konfigurace"""
        config = {
            "alert_channel_id": self.alert_channel_id,
            "cpu_threshold": self.cpu_threshold,
            "memory_threshold": self.memory_threshold,
            "disk_threshold": self.disk_threshold,
            "temp_threshold": self.temp_threshold,
            "monitoring_method": self.monitoring_method,
            "system_override": self.system_override
        }
        with open("monitoring_config.json", "w") as f:
            json.dump(config, f, indent=2)

    def get_cpu_frequency(self):
        """Získání CPU frekvence - zjednodušeno"""
        if platform.system() == "Windows":
            try:
                ps_cmd = [
                    'powershell', '-ExecutionPolicy', 'Bypass', '-Command',
                    '(Get-WmiObject -Class Win32_Processor | Select-Object -First 1).MaxClockSpeed'
                ]
                result = subprocess.run(ps_cmd, capture_output=True, text=True, timeout=8, shell=True)
                
                if result.returncode == 0 and result.stdout.strip():
                    freq_str = result.stdout.strip()
                    if freq_str.isdigit():
                        freq = int(freq_str)
                        if freq > 500:
                            return freq
            except:
                pass
        
        elif platform.system() == "Linux":
            try:
                result = subprocess.run(['lscpu'], capture_output=True, text=True, timeout=3)
                if result.returncode == 0:
                    for line in result.stdout.split('\n'):
                        if 'CPU max MHz' in line:
                            freq_str = line.split(':')[1].strip()
                            return float(freq_str)
            except:
                pass
        
        # Fallback na psutil
        try:
            freq = psutil.cpu_freq()
            if freq and freq.max and freq.max > 500:
                return freq.max
        except:
            pass
        
        return None

    def get_system_info_sync(self):
        """Synchronní získání systémových informací"""
        try:
            # Určení systému
            if hasattr(self, 'system_override') and self.system_override != "auto":
                detected_system = self.system_override
            else:
                detected_system = platform.system()
            
            is_windows = detected_system == "Windows"
            
            # CPU měření
            if hasattr(self, 'monitoring_method'):
                if self.monitoring_method == "fast":
                    cpu_percent = psutil.cpu_percent()
                elif self.monitoring_method == "accurate":
                    cpu_percent = psutil.cpu_percent(interval=2.0)
                else:  # auto nebo performance
                    cpu_percent = psutil.cpu_percent(interval=1.0)
            else:
                cpu_percent = psutil.cpu_percent(interval=1.0)
            
            # CPU info
            cpu_count_logical = psutil.cpu_count(logical=True)
            cpu_count_physical = psutil.cpu_count(logical=False)
            cpu_frequency = self.get_cpu_frequency()
            
            # Memory
            memory = psutil.virtual_memory()
            
            # Disk
            if is_windows:
                disk = psutil.disk_usage('C:')
            else:
                disk = psutil.disk_usage('/')
            
            # Network
            try:
                network = psutil.net_io_counters()
            except:
                network = None
            
            # Temperature
            temperature = None
            try:
                temps = psutil.sensors_temperatures()
                if temps:
                    for name, entries in temps.items():
                        if entries and len(entries) > 0:
                            temperature = entries[0].current
                            break
            except:
                pass
            
            # Procesy
            processes = []
            try:
                procs = []
                for proc in psutil.process_iter(['pid', 'name', 'memory_percent']):
                    try:
                        name = proc.info['name']
                        if name and name not in ['System Idle Process', 'System', '']:
                            procs.append({
                                'pid': proc.info['pid'],
                                'name': name[:20],
                                'cpu_percent': 0,
                                'memory_percent': proc.info['memory_percent'] or 0
                            })
                    except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
                        continue
                
                processes = sorted(procs, key=lambda x: x['memory_percent'], reverse=True)[:10]
                
            except Exception as e:
                print(f"Error getting processes: {e}")
                processes = []
            
            result = {
                'cpu': {
                    'percent': round(cpu_percent, 1),
                    'count_logical': cpu_count_logical,
                    'count_physical': cpu_count_physical,
                    'count': cpu_count_physical or cpu_count_logical,
                    'frequency': round(cpu_frequency, 0) if cpu_frequency else None
                },
                'memory': {
                    'total': memory.total,
                    'available': memory.available,
                    'percent': round(memory.percent, 1),
                    'used': memory.used
                },
                'disk': {
                    'total': disk.total,
                    'used': disk.used,
                    'free': disk.free,
                    'percent': round((disk.used / disk.total) * 100, 1)
                },
                'temperature': round(temperature, 1) if temperature else None,
                'processes': processes,
                'timestamp': datetime.now().isoformat(),
                'system': detected_system,
                'method': getattr(self, 'monitoring_method', 'auto')
            }
            
            if network:
                result['network'] = {
                    'bytes_sent': network.bytes_sent,
                    'bytes_recv': network.bytes_recv,
                    'packets_sent': network.packets_sent,
                    'packets_recv': network.packets_recv
                }
            
            return result
            
        except Exception as e:
            print(f"Monitoring error: {e}")
            return None

    async def check_alerts(self, data):
        """Kontrola alertů s debug výpisem"""
        print(f"🔍 Checking alerts - Channel ID: {self.alert_channel_id}")
        
        if not self.alert_channel_id or not data:
            print(f"❌ No alert channel set or no data")
            return
            
        channel = self.bot.get_channel(self.alert_channel_id)
        if not channel:
            print(f"❌ Cannot find channel with ID: {self.alert_channel_id}")
            return
        
        print(f"✅ Found alert channel: {channel.name}")
        
        current_time = datetime.now()
        alerts = []
        
        # CPU Alert
        if data['cpu']['percent'] > self.cpu_threshold:
            print(f"🔥 CPU alert triggered: {data['cpu']['percent']}% > {self.cpu_threshold}%")
            if 'cpu' not in self.last_alerts or (current_time - self.last_alerts['cpu']).seconds > 300:
                alerts.append(f"🔥 **CPU Vysoké zatížení:** {data['cpu']['percent']:.1f}% (limit: {self.cpu_threshold}%)")
                self.last_alerts['cpu'] = current_time
            else:
                print(f"⏳ CPU alert cooldown active")
        
        # Memory Alert
        if data['memory']['percent'] > self.memory_threshold:
            print(f"💾 Memory alert triggered: {data['memory']['percent']}% > {self.memory_threshold}%")
            if 'memory' not in self.last_alerts or (current_time - self.last_alerts['memory']).seconds > 300:
                alerts.append(f"💾 **RAM Vysoké zatížení:** {data['memory']['percent']:.1f}% (limit: {self.memory_threshold}%)")
                self.last_alerts['memory'] = current_time
            else:
                print(f"⏳ Memory alert cooldown active")
        
        # Disk Alert
        if data['disk']['percent'] > self.disk_threshold:
            print(f"💽 Disk alert triggered: {data['disk']['percent']}% > {self.disk_threshold}%")
            if 'disk' not in self.last_alerts or (current_time - self.last_alerts['disk']).seconds > 300:
                alerts.append(f"💽 **Disk Plný:** {data['disk']['percent']:.1f}% (limit: {self.disk_threshold}%)")
                self.last_alerts['disk'] = current_time
            else:
                print(f"⏳ Disk alert cooldown active")
        
        # Temperature Alert
        if data['temperature'] and data['temperature'] > self.temp_threshold:
            print(f"🌡️ Temperature alert triggered: {data['temperature']}°C > {self.temp_threshold}°C")
            if 'temp' not in self.last_alerts or (current_time - self.last_alerts['temp']).seconds > 300:
                alerts.append(f"🌡️ **Vysoká Teplota:** {data['temperature']:.1f}°C (limit: {self.temp_threshold}°C)")
                self.last_alerts['temp'] = current_time
            else:
                print(f"⏳ Temperature alert cooldown active")
        
        # Odeslání alertů
        if alerts:
            print(f"📤 Sending {len(alerts)} alerts to {channel.name}")
            try:
                embed = discord.Embed(
                    title="🚨 Server Alert",
                    description="\n".join(alerts),
                    color=0xff0000,
                    timestamp=current_time
                )
                embed.add_field(
                    name="📊 Aktuální stav", 
                    value=f"CPU: {data['cpu']['percent']:.1f}% | RAM: {data['memory']['percent']:.1f}% | Disk: {data['disk']['percent']:.1f}%", 
                    inline=False
                )
                await channel.send("@here", embed=embed)
                print(f"✅ Alerts sent successfully!")
            except Exception as e:
                print(f"❌ Error sending alert: {e}")
        else:
            print(f"✅ No alerts to send")

    @tasks.loop(minutes=2)
    async def monitor_system(self):
        """Hlavní monitoring loop s automatickým reload konfigurace"""
        try:
            # Reload config před každou kontrolou
            self.reload_config()
            
            loop = asyncio.get_event_loop()
            data = await loop.run_in_executor(None, self.get_system_info_sync)
            
            if data:
                # Uložení dat
                with open("monitoring_data.json", "w") as f:
                    json.dump(data, f, indent=2)
                
                # Kontrola alertů
                await self.check_alerts(data)
            
        except Exception as e:
            print(f"Monitoring loop error: {e}")

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def monitoring(self, ctx):
        """Zobrazí aktuální stav serveru"""
        async with ctx.typing():
            try:
                # Získej nová data
                loop = asyncio.get_event_loop()
                data = await loop.run_in_executor(None, self.get_system_info_sync)
                
                if not data:
                    await ctx.send("❌ Chyba při získávání monitoring dat!")
                    return
                
                embed = discord.Embed(
                    title="📊 Server Monitoring",
                    color=0x5865F2,
                    timestamp=datetime.now()
                )
                
                # CPU Info
                cpu_emoji = "🔥" if data['cpu']['percent'] > self.cpu_threshold else "💚"
                cpu_cores = data['cpu'].get('count_physical', data['cpu'].get('count_logical', 0))
                cpu_threads = data['cpu'].get('count_logical', 0)
                
                cpu_text = f"**{data['cpu']['percent']:.1f}%**\n"
                if cpu_cores != cpu_threads and cpu_cores > 0:
                    cpu_text += f"{cpu_cores} cores, {cpu_threads} threads"
                else:
                    cpu_text += f"{cpu_cores} cores"
                
                if data['cpu']['frequency']:
                    cpu_text += f"\n{data['cpu']['frequency']:.0f} MHz (base)"
                else:
                    cpu_text += f"\n*Frekvence nedostupná*"
                
                embed.add_field(name=f"{cpu_emoji} CPU", value=cpu_text, inline=True)
                
                # Memory Info
                memory_emoji = "🔥" if data['memory']['percent'] > self.memory_threshold else "💚"
                memory_gb = data['memory']['used'] / (1024**3)
                memory_total_gb = data['memory']['total'] / (1024**3)
                embed.add_field(
                    name=f"{memory_emoji} RAM",
                    value=f"**{data['memory']['percent']:.1f}%**\n{memory_gb:.1f}/{memory_total_gb:.1f} GB",
                    inline=True
                )
                
                # Disk Info
                disk_emoji = "🔥" if data['disk']['percent'] > self.disk_threshold else "💚"
                disk_gb = data['disk']['used'] / (1024**3)
                disk_total_gb = data['disk']['total'] / (1024**3)
                embed.add_field(
                    name=f"{disk_emoji} Disk",
                    value=f"**{data['disk']['percent']:.1f}%**\n{disk_gb:.1f}/{disk_total_gb:.1f} GB",
                    inline=True
                )
                
                # Temperature
                if data['temperature']:
                    temp_emoji = "🔥" if data['temperature'] > self.temp_threshold else "❄️"
                    embed.add_field(
                        name=f"{temp_emoji} Teplota",
                        value=f"**{data['temperature']:.1f}°C**",
                        inline=True
                    )
                
                # Top procesy
                if data['processes'] and len(data['processes']) > 0:
                    top_processes = "\n".join([
                        f"`{proc['name'][:12]:12} {proc['memory_percent']:>5.1f}% RAM`"
                        for proc in data['processes'][:5]
                    ])
                    embed.add_field(
                        name="🔝 Top Procesy (RAM)",
                        value=top_processes or "Žádné procesy",
                        inline=False
                    )
                
                # Info footer s odkazem na web
                embed.set_footer(
                    text=f"BuzzHost Server Monitoring • {data.get('system', 'Unknown')} • Konfigurace: http://localhost:5000"
                )
                await ctx.send(embed=embed)
                
            except Exception as e:
                await ctx.send(f"❌ Chyba při monitoring: {e}")
                print(f"Monitoring command error: {e}")

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def reloadmonitoring(self, ctx):
        """Znovu načte monitoring konfiguraci"""
        try:
            self.reload_config()
            
            embed = discord.Embed(
                title="🔄 Monitoring Config Reloaded",
                color=0x00ff00,
                timestamp=datetime.now()
            )
            
            embed.add_field(
                name="📢 Alert Kanál",
                value=f"<#{self.alert_channel_id}>" if self.alert_channel_id else "Nenastaveno",
                inline=False
            )
            
            embed.add_field(
                name="🚨 Thresholds",
                value=f"CPU: {self.cpu_threshold}% | RAM: {self.memory_threshold}% | Disk: {self.disk_threshold}% | Temp: {self.temp_threshold}°C",
                inline=False
            )
            
            await ctx.send(embed=embed)
            
        except Exception as e:
            await ctx.send(f"❌ Chyba při reloadu konfigurace: {e}")

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def testalert(self, ctx):
        """Test alert systému"""
        self.reload_config()
        
        if not self.alert_channel_id:
            await ctx.send("❌ Alert kanál není nastaven!")
            return
        
        channel = self.bot.get_channel(self.alert_channel_id)
        if not channel:
            await ctx.send(f"❌ Kanál s ID {self.alert_channel_id} nenalezen!")
            return
        
        # Pošli test alert
        embed = discord.Embed(
            title="🧪 Test Alert",
            description="Toto je testovací alert ze systému monitoring.",
            color=0xff9900,
            timestamp=datetime.now()
        )
        embed.add_field(name="📢 Kanál", value=channel.mention, inline=False)
        embed.add_field(name="🚨 Status", value="Alert systém funguje správně!", inline=False)
        
        try:
            await channel.send(embed=embed)
            await ctx.send(f"✅ Test alert odeslán do {channel.mention}!")
        except Exception as e:
            await ctx.send(f"❌ Chyba při odesílání: {e}")

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def forcealert(self, ctx):
        """Vynutí odeslání alertu pro test"""
        try:
            # Získej aktuální data
            loop = asyncio.get_event_loop()
            data = await loop.run_in_executor(None, self.get_system_info_sync)
            
            if not data:
                await ctx.send("❌ Chyba při získávání dat!")
                return
            
            # Vynutí alert bez ohledu na thresholds
            self.reload_config()
            
            if not self.alert_channel_id:
                await ctx.send("❌ Alert kanál není nastaven!")
                return
            
            channel = self.bot.get_channel(self.alert_channel_id)
            if not channel:
                await ctx.send(f"❌ Kanál s ID {self.alert_channel_id} nenalezen!")
                return
            
            # Pošli forced alert
            embed = discord.Embed(
                title="🚨 Forced Alert Test",
                description="🔥 **Test CPU Alert:** Vynutí alert pro test systému",
                color=0xff0000,
                timestamp=datetime.now()
            )
            embed.add_field(
                name="📊 Aktuální stav", 
                value=f"CPU: {data['cpu']['percent']:.1f}% | RAM: {data['memory']['percent']:.1f}% | Disk: {data['disk']['percent']:.1f}%", 
                inline=False
            )
            embed.add_field(
                name="⚙️ Nastavené thresholds",
                value=f"CPU: {self.cpu_threshold}% | RAM: {self.memory_threshold}% | Disk: {self.disk_threshold}%",
                inline=False
            )
            
            await channel.send("@here", embed=embed)
            await ctx.send(f"✅ Forced alert odeslán do {channel.mention}!")
            
        except Exception as e:
            await ctx.send(f"❌ Chyba: {e}")

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def addserver(self, ctx, name: str, host: str, port: int = 5000):
        """Přidá nový server pro monitoring"""
        server_id = name.lower().replace(" ", "_")
        
        # Test připojení
        try:
            import aiohttp
            async with aiohttp.ClientSession() as session:
                url = f"http://{host}:{port}/api/monitoring"
                async with session.get(url, timeout=5) as response:
                    if response.status != 200:
                        await ctx.send(f"❌ Server {host}:{port} neodpovídá!")
                        return
        except Exception as e:
            await ctx.send(f"❌ Chyba připojení k {host}:{port}: {e}")
            return
        
        # Přidej server
        self.remote_monitoring.servers[server_id] = {
            "name": name,
            "host": host,
            "port": port,
            "enabled": True,
            "added_at": datetime.now().isoformat()
        }
        self.remote_monitoring.save_servers_config()
        
        embed = discord.Embed(
            title="✅ Server přidán",
            description=f"Server **{name}** byl úspěšně přidán do monitoringu!",
            color=0x00ff00
        )
        embed.add_field(name="🌐 Endpoint", value=f"`{host}:{port}`", inline=False)
        embed.add_field(name="🆔 ID", value=f"`{server_id}`", inline=False)
        
        await ctx.send(embed=embed)

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def removeserver(self, ctx, server_id: str):
        """Odebere server z monitoringu"""
        if server_id not in self.remote_monitoring.servers:
            await ctx.send(f"❌ Server `{server_id}` nenalezen!")
            return
        
        server_name = self.remote_monitoring.servers[server_id]['name']
        del self.remote_monitoring.servers[server_id]
        self.remote_monitoring.save_servers_config()
        
        await ctx.send(f"✅ Server **{server_name}** odebrán z monitoringu!")

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def listservers(self, ctx):
        """Zobrazí seznam monitorovaných serverů"""
        if not self.remote_monitoring.servers:
            await ctx.send("📭 Žádné vzdálené servery nejsou nakonfigurovány!")
            return
        
        embed = discord.Embed(
            title="🌐 Monitorované Servery",
            color=0x5865F2
        )
        
        for server_id, server in self.remote_monitoring.servers.items():
            status = "🟢 Online" if server.get('enabled', True) else "🔴 Offline"
            embed.add_field(
                name=f"{server['name']} ({server_id})",
                value=f"{status}\n`{server['host']}:{server['port']}`",
                inline=True
            )
        
        await ctx.send(embed=embed)

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def monitoring_all(self, ctx):
        """Zobrazí monitoring všech serverů"""
        async with ctx.typing():
            # Lokální server
            local_data = await asyncio.get_event_loop().run_in_executor(None, self.get_system_info_sync)
            
            # Vzdálené servery
            remote_data = {}
            for server_id in self.remote_monitoring.servers:
                data = await self.remote_monitoring.get_remote_server_data(server_id)
                if data:
                    remote_data[server_id] = data
            
            # Vytvoř embed
            embed = discord.Embed(
                title="🌐 Multi-Server Monitoring",
                color=0x5865F2,
                timestamp=datetime.now()
            )
            
            # Lokální server
            if local_data:
                embed.add_field(
                    name="💻 Lokální Server",
                    value=f"CPU: {local_data['cpu']['percent']:.1f}% | RAM: {local_data['memory']['percent']:.1f}% | Disk: {local_data['disk']['percent']:.1f}%",
                    inline=False
                )
            
            # Vzdálené servery
            for server_id, data in remote_data.items():
                server_name = self.remote_monitoring.servers[server_id]['name']
                
                # Status emoji podle zatížení
                cpu_emoji = "🔥" if data['cpu']['percent'] > self.cpu_threshold else "💚"
                ram_emoji = "🔥" if data['memory']['percent'] > self.memory_threshold else "💚"
                disk_emoji = "🔥" if data['disk']['percent'] > self.disk_threshold else "💚"
                
                embed.add_field(
                    name=f"🌐 {server_name}",
                    value=f"{cpu_emoji} CPU: {data['cpu']['percent']:.1f}% | {ram_emoji} RAM: {data['memory']['percent']:.1f}% | {disk_emoji} Disk: {data['disk']['percent']:.1f}%",
                    inline=False
                )
            
            # Offline servery
            offline_servers = []
            for server_id, server in self.remote_monitoring.servers.items():
                if server_id not in remote_data:
                    offline_servers.append(server['name'])
            
            if offline_servers:
                embed.add_field(
                    name="🔴 Offline Servery",
                    value="\n".join([f"❌ {name}" for name in offline_servers]),
                    inline=False
                )
            
            embed.set_footer(text=f"Monitorováno: {len(remote_data) + (1 if local_data else 0)} serverů")
            await ctx.send(embed=embed)

    @commands.Cog.listener()
    async def on_ready(self):
        if not self.monitor_system.is_running():
            self.monitor_system.start()
            print("📊 Server monitoring spuštěn!")

async def setup(bot):
    await bot.add_cog(ServerMonitoring(bot))