#!/usr/bin/env python3
"""
POPRAVEN CLIENT - So bolsho sobiranje na podatoci
"""

import socket
import os
import platform
import json
import requests
from datetime import datetime
import psutil
import time


class FixedClient:
    def __init__(self, server_ip="192.168.1.13", port=5555):
        self.server_ip = server_ip
        self.port = port
        self.computer_name = socket.gethostname()
        self.user = os.getlogin()

    def get_detailed_info(self):
        """Sobiraј podrobni podatoci"""
        # Osnovni
        info = {
            "computer_name": self.computer_name,
            "user": self.user,
            "ip_address": socket.gethostbyname(self.computer_name),
            "os": f"{platform.system()} {platform.release()} {platform.version()}",
            "architecture": platform.architecture()[0],
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        }

        # Performansi
        info.update(self.get_performance_metrics())

        # Hardver informacii
        info.update(self.get_hardware_info())

        return info

    def get_performance_metrics(self):
        """Metriki za performansi"""
        try:
            # CPU
            cpu_percent = psutil.cpu_percent(interval=1)
            cpu_per_core = psutil.cpu_percent(interval=1, percpu=True)

            # RAM
            ram = psutil.virtual_memory()

            # Disk
            disk = psutil.disk_usage("C:/")

            # Mrezha
            net_io = psutil.net_io_counters()

            return {
                "cpu_usage": cpu_percent,
                "cpu_cores": len(cpu_per_core),
                "cpu_per_core": cpu_per_core,
                "ram_usage": ram.percent,
                "ram_total_gb": round(ram.total / (1024 ** 3), 2),
                "ram_used_gb": round(ram.used / (1024 ** 3), 2),
                "disk_usage": disk.percent,
                "disk_total_gb": round(disk.total / (1024 ** 3), 2),
                "disk_used_gb": round(disk.used / (1024 ** 3), 2),
                "network_sent_mb": round(net_io.bytes_sent / (1024 ** 2), 2),
                "network_recv_mb": round(net_io.bytes_recv / (1024 ** 2), 2),
                "boot_time": datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%m-%d %H:%M:%S")
            }
        except Exception as e:
            print(f"Performance metrics error: {e}")
            return {}

    def get_hardware_info(self):
        """Hardver informacii"""
        try:
            # CPU info
            cpu_info = {
                "cpu_physical_cores": psutil.cpu_count(logical=False),
                "cpu_logical_cores": psutil.cpu_count(logical=True),
                "cpu_freq_current": psutil.cpu_freq().current if hasattr(psutil.cpu_freq(), 'current') else 0,
                "cpu_freq_max": psutil.cpu_freq().max if hasattr(psutil.cpu_freq(), 'max') else 0,
            }

            # Disk info
            partitions = []
            for partition in psutil.disk_partitions():
                try:
                    usage = psutil.disk_usage(partition.mountpoint)
                    partitions.append({
                        "device": partition.device,
                        "mountpoint": partition.mountpoint,
                        "fstype": partition.fstype,
                        "total_gb": round(usage.total / (1024 ** 3), 2),
                        "used_gb": round(usage.used / (1024 ** 3), 2),
                        "percent_used": usage.percent
                    })
                except:
                    continue

            return {
                "cpu_info": cpu_info,
                "disks": partitions,
                "battery_percent": psutil.sensors_battery().percent if hasattr(psutil.sensors_battery(),
                                                                               'percent') else None,
            }
        except Exception as e:
            print(f"Hardware info error: {e}")
            return {}

    def get_detailed_processes(self):
        """Detalni informacii za procesite"""
        processes = []
        try:
            for proc in psutil.process_iter(['pid', 'name', 'username', 'cpu_percent',
                                             'memory_percent', 'create_time', 'status']):
                try:
                    pinfo = proc.info

                    # Dodadi additional info
                    processes.append({
                        "pid": pinfo['pid'],
                        "name": pinfo['name'],
                        "user": pinfo['username'],
                        "cpu_percent": pinfo['cpu_percent'],
                        "memory_mb": round(proc.memory_info().rss / (1024 ** 2), 2),
                        "memory_percent": pinfo['memory_percent'],
                        "create_time": datetime.fromtimestamp(pinfo['create_time']).strftime("%Y-%m-%d %H:%M:%S") if
                        pinfo['create_time'] else None,
                        "status": pinfo['status'],
                        "exe": proc.exe() if hasattr(proc, 'exe') else None,
                        "cmdline": proc.cmdline() if hasattr(proc, 'cmdline') else None,
                    })
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    continue

                # Limit na broј na procesi
                if len(processes) >= 50:
                    break

        except Exception as e:
            print(f"Process error: {e}")

        return processes

    def get_network_connections(self):
        """Aktivni mrezhi konekcii"""
        connections = []
        try:
            for conn in psutil.net_connections(kind='inet'):
                if conn.status == 'ESTABLISHED':
                    connections.append({
                        "pid": conn.pid,
                        "local_address": f"{conn.laddr.ip}:{conn.laddr.port}" if conn.laddr else None,
                        "remote_address": f"{conn.raddr.ip}:{conn.raddr.port}" if conn.raddr else None,
                        "status": conn.status,
                        "family": str(conn.family)
                    })

                if len(connections) >= 20:
                    break

        except:
            pass

        return connections

    def collect_and_send(self):
        """Sobiraј i isprati site podatoci"""
        print(f"\n[{datetime.now().strftime('%H:%M:%S')}] 🔍 Sobiranje podatoci...")

        # Sobiraј site podatoci
        data = {
            "info": self.get_detailed_info(),
            "processes": self.get_detailed_processes(),
            "network_connections": self.get_network_connections(),
            "collection_time": datetime.now().isoformat()
        }

        # Prikazhi osnovni informacii
        info = data["info"]
        print(f"   💻 Kompjuter: {info['computer_name']}")
        print(f"   👤 Korisnik: {info['user']}")
        print(
            f"   📊 CPU: {info.get('cpu_usage', 0)}% | RAM: {info.get('ram_usage', 0)}% | Disk: {info.get('disk_usage', 0)}%")
        print(f"   🔄 Procesi: {len(data['processes'])} | Mrezhi konekcii: {len(data.get('network_connections', []))}")

        # Ispraти gi podatocite
        try:
            response = requests.post(
                f"http://{self.server_ip}:{self.port}/receive",
                json=data,
                timeout=15
            )

            if response.status_code == 200:
                result = response.json()
                print(f"   ✅ Podatocite se uspeshno isprateni!")
                print(f"   📝 Server odgovor: {result.get('message', '')}")
                return True
            else:
                print(f"   ❌ Greshka: {response.status_code}")
                return False

        except Exception as e:
            print(f"   ❌ Problem so serverot: {e}")
            return False


def main():
    """Glavna programa"""
    print("=" * 70)
    print("🖥️  FIXED LAN LOG COLLECTOR")
    print("=" * 70)
    print(f"Computer: {socket.gethostname()}")
    print(f"User: {os.getlogin()}")
    print(f"IP: {socket.gethostbyname(socket.gethostname())}")
    print("=" * 70)
    print("Data will be collected and sent every 30 seconds.")
    print("Press Ctrl+C to stop.")
    print("=" * 70)

    # Proveri dali serverot e dostapen
    server_ip = input("Enter server IP (default 192.168.1.13): ").strip() or "192.168.1.13"

    client = FixedClient(server_ip)

    # Test connection
    print(f"\n🔌 Testiranje na vrska so serverot {server_ip}...")
    try:
        response = requests.get(f"http://{server_ip}:5555/ping", timeout=5)
        if response.status_code == 200:
            print("   ✅ Serverot e dostapen!")
        else:
            print(f"   ⚠️  Serverot odgovora so: {response.status_code}")
            confirm = input("   Sakaš li da prodolzhish? (y/n): ").lower()
            if confirm != 'y':
                return
    except:
        print(f"   ❌ Ne mozam da se povrzam so serverot {server_ip}")
        confirm = input("   Sakaš li da prodolzhish? (y/n): ").lower()
        if confirm != 'y':
            return

    try:
        count = 1
        while True:
            print(f"\n📤 Transmission #{count}")

            success = client.collect_and_send()

            count += 1
            print(f"\n⏳ Chekam 30 sekundi do slednata transmisija...")

            # Countdown
            for i in range(30, 0, -1):
                if i % 5 == 0:
                    print(f"\r   {i} seconds remaining...", end="")
                time.sleep(1)
            print("\r" + " " * 30 + "\r", end="")  # Clear line

    except KeyboardInterrupt:
        print("\n\n🛑 Programata e zaјchana.")
        print(f"📊 Dashboard: http://{server_ip}:5555/")


if __name__ == "__main__":
    try:
        import psutil
        import requests
    except ImportError:
        print("Instaliraј gi modulite:")
        print("pip install psutil requests")
        input("Pritisni ENTER za izlez...")
        exit(1)

    main()