import os
import sys
import subprocess
import psutil
import platform
import shutil
import socket
from datetime import datetime


class SystemControl:
    def __init__(self):
        self.os_type = platform.system().lower()

    def get_system_info(self):
        info = {
            "platform": platform.system(),
            "platform_release": platform.release(),
            "platform_version": platform.version(),
            "architecture": platform.machine(),
            "hostname": platform.node(),
            "processor": platform.processor(),
            "python_version": sys.version,
        }
        return info

    def get_cpu_info(self):
        return {
            "cpu_percent": psutil.cpu_percent(interval=1),
            "cpu_count_physical": psutil.cpu_count(logical=False),
            "cpu_count_logical": psutil.cpu_count(logical=True),
            "cpu_freq": psutil.cpu_freq()._asdict() if psutil.cpu_freq() else None,
        }

    def get_memory_info(self):
        mem = psutil.virtual_memory()
        return {
            "total": self._bytes_to_gb(mem.total),
            "available": self._bytes_to_gb(mem.available),
            "used": self._bytes_to_gb(mem.used),
            "percent": mem.percent,
        }

    def get_disk_info(self):
        partitions = []
        for part in psutil.disk_partitions():
            try:
                usage = psutil.disk_usage(part.mountpoint)
                partitions.append(
                    {
                        "device": part.device,
                        "mountpoint": part.mountpoint,
                        "fstype": part.fstype,
                        "total": self._bytes_to_gb(usage.total),
                        "used": self._bytes_to_gb(usage.used),
                        "free": self._bytes_to_gb(usage.free),
                        "percent": usage.percent,
                    }
                )
            except PermissionError:
                continue
        return partitions

    def get_battery_info(self):
        battery = psutil.sensors_battery()
        if battery:
            return {
                "percent": battery.percent,
                "plugged_in": battery.power_plugged,
                "time_left": battery.secsleft / 60 if battery.secsleft > 0 else "N/A",
            }
        return {"error": "No battery detected"}

    def get_network_info(self):
        net_io = psutil.net_io_counters()
        return {
            "bytes_sent": self._bytes_to_mb(net_io.bytes_sent),
            "bytes_recv": self._bytes_to_mb(net_io.bytes_recv),
            "packets_sent": net_io.packets_sent,
            "packets_recv": net_io.packets_recv,
        }

    def get_internet_connectivity(self):
        try:
            socket.create_connection(("8.8.8.8", 53), timeout=1)
            return "Connected"
        except OSError:
            pass
        return "Disconnected"

    def get_bluetooth_status(self):
        if self.os_type == "linux":
            try:
                result = subprocess.run(["rfkill", "list", "bluetooth"], capture_output=True, text=True)
                if "Soft blocked: yes" in result.stdout or "Hard blocked: yes" in result.stdout:
                    return "Disabled"
                elif result.stdout.strip():
                    return "Enabled"
                return "Not Found"
            except FileNotFoundError:
                return "Unknown (rfkill missing)"
        return "Unknown"

    def get_network_configs(self):
        configs = {}
        for interface, addrs in psutil.net_if_addrs().items():
            for addr in addrs:
                if addr.family == socket.AF_INET:
                    configs[interface] = addr.address
        return configs

    def get_processes(self, limit=10):
        processes = []
        for proc in sorted(
            psutil.process_iter(["pid", "name", "cpu_percent", "memory_percent"]),
            key=lambda x: x.info["cpu_percent"] or 0,
            reverse=True,
        )[:limit]:
            try:
                processes.append(proc.info)
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue
        return processes

    def kill_process(self, pid):
        try:
            proc = psutil.Process(pid)
            proc.kill()
            return f"Process {pid} terminated"
        except psutil.NoSuchProcess:
            return f"Process {pid} not found"
        except psutil.AccessDenied:
            return f"Access denied to process {pid}"

    def open_app(self, app_name):
        if self.os_type == "linux":
            try:
                subprocess.Popen([app_name])
                return f"Opened {app_name}"
            except FileNotFoundError:
                return f"{app_name} not found"
        elif self.os_type == "windows":
            try:
                os.startfile(app_name)
                return f"Opened {app_name}"
            except Exception as e:
                return str(e)
        return "Unsupported OS"

    def open_url(self, url):
        import webbrowser

        webbrowser.open(url)
        return f"Opened {url}"

    def get_environment_vars(self):
        return dict(os.environ)

    def get_startup_programs(self):
        if self.os_type == "linux":
            autostart_path = os.path.expanduser("~/.config/autostart")
            if os.path.exists(autostart_path):
                return os.listdir(autostart_path)
            return []
        elif self.os_type == "windows":
            import winreg

            programs = []
            try:
                key = winreg.OpenKey(
                    winreg.HKEY_CURRENT_USER,
                    r"Software\Microsoft\Windows\CurrentVersion\Run",
                )
                i = 0
                while True:
                    try:
                        programs.append(winreg.EnumValue(key, i)[0])
                        i += 1
                    except OSError:
                        break
            except Exception:
                pass
            return programs
        return []

    def take_screenshot(self, filename=None):
        import pyautogui

        if not filename:
            filename = f"screenshot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
        pyautogui.screenshot(filename)
        return f"Screenshot saved as {filename}"

    def get_temperature(self):
        temps = {}
        try:
            temps["cpu"] = (
                psutil.sensors_temperatures()
                .get("cpu_thermal", [{}])[0]
                .get("current", "N/A")
            )
        except Exception:
            temps["cpu"] = "N/A"
        return temps

    def shutdown(self, delay=0):
        if self.os_type == "linux":
            os.system(f"shutdown -h +{delay}" if delay > 0 else "shutdown -h now")
        elif self.os_type == "windows":
            os.system(f"shutdown /s /t {delay}" if delay > 0 else "shutdown /s /t 0")
        return f"Shutting down{' in ' + str(delay) + ' minutes' if delay > 0 else ''}"

    def restart(self, delay=0):
        if self.os_type == "linux":
            os.system(f"shutdown -r +{delay}" if delay > 0 else "shutdown -r now")
        elif self.os_type == "windows":
            os.system(f"shutdown /r /t {delay}" if delay > 0 else "shutdown /r /t 0")
        return f"Restarting{' in ' + str(delay) + ' minutes' if delay > 0 else ''}"

    def sleep(self):
        if self.os_type == "linux":
            os.system("systemctl suspend")
        elif self.os_type == "windows":
            os.system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0")
        return "Putting system to sleep"

    def lock_screen(self):
        if self.os_type == "linux":
            os.system("loginctl lock-session")
        elif self.os_type == "windows":
            os.system("rundll32.exe user32.dll,LockWorkStation")
        return "Screen locked"

    def empty_trash(self):
        if self.os_type == "linux":
            os.system("trash-empty")
        return "Trash emptied"

    def get_services(self):
        if self.os_type == "linux":
            result = subprocess.run(
                ["systemctl", "list-units", "--type=service", "--state=running"],
                capture_output=True,
                text=True,
            )
            return result.stdout
        return "Services info not available"

    def _bytes_to_gb(self, bytes_val):
        return round(bytes_val / (1024**3), 2)

    def _bytes_to_mb(self, bytes_val):
        return round(bytes_val / (1024**2), 2)
