import os
import platform
import subprocess
import socket
import abc

class BasePlatformMetrics(abc.ABC):
    """Abstract Base Class for Platform-Specific Metrics and Capabilities."""
    
    @abc.abstractmethod
    def collect_capabilities(self) -> dict:
        """Collects hardware and OS capabilities."""
        pass

    @abc.abstractmethod
    def get_load_avg(self) -> list:
        """Returns 1, 5, 15 min load averages."""
        pass

class PosixMetrics(BasePlatformMetrics):
    """POSIX (Linux/macOS) Metrics Implementation."""
    
    def collect_capabilities(self) -> dict:
        import platform
        caps = {
            "shell": "v1",
            "arch": platform.machine(),
            "os": platform.system().lower(),
            "os_release": platform.release(),
        }
        
        # Privilege Detection
        try:
            caps["is_root"] = (os.getuid() == 0)
        except:
            caps["is_root"] = False

        if not caps["is_root"]:
            try:
                r = subprocess.run(["sudo", "-n", "true"], capture_output=True, timeout=2)
                caps["has_sudo"] = (r.returncode == 0)
            except:
                caps["has_sudo"] = False
        else:
            caps["has_sudo"] = False

        # GPU Detection
        caps["gpu"] = self._detect_gpu(caps)
        
        # Display Detection
        if caps["os"] == "darwin":
            caps["has_display"] = True
        else:
            caps["has_display"] = bool(os.environ.get("DISPLAY") or os.environ.get("WAYLAND_DISPLAY"))
            
        return caps

    def _detect_gpu(self, caps) -> str:
        try:
            result = subprocess.run(
                ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
                capture_output=True, text=True, timeout=5
            )
            if result.returncode == 0 and result.stdout.strip():
                return result.stdout.strip().split("\n")[0]
        except:
            pass
            
        if caps["os"] == "darwin" and "arm" in caps["arch"].lower():
            return "apple-silicon"
            
        return "none"

    def get_load_avg(self) -> list:
        try:
            return list(os.getloadavg())
        except:
            return [0.0, 0.0, 0.0]


class WindowsMetrics(BasePlatformMetrics):
    """Windows Metrics Implementation."""
    
    def collect_capabilities(self) -> dict:
        import platform
        caps = {
            "shell": "v1",
            "arch": platform.machine(),
            "os": "windows",
            "os_release": platform.release(),
        }
        
        # Admin Detection
        try:
            import ctypes
            caps["is_root"] = bool(ctypes.windll.shell32.IsUserAnAdmin())
        except:
            caps["is_root"] = False
        
        caps["has_sudo"] = False # sudo isn't a thing on Windows usually
        
        # GPU Detection
        gpu_name = "none"
        try:
            # 1. Try nvidia-smi.exe (Discrete NVIDIA GPU)
            result = subprocess.run(
                ["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
                capture_output=True, text=True, timeout=5
            )
            if result.returncode == 0 and result.stdout.strip():
                gpu_name = result.stdout.strip().split("\n")[0]
        except:
            pass # nvidia-smi likely missing

        if gpu_name == "none":
            try:
                # 2. Try WMIC fallback (Integrated Intel/AMD or other)
                wmic_res = subprocess.run(
                    ["wmic", "path", "win32_VideoController", "get", "name"],
                    capture_output=True, text=True, timeout=5
                )
                if wmic_res.returncode == 0:
                    names = [l.strip() for l in wmic_res.stdout.split("\n") if l.strip() and "Name" not in l]
                    # Filter out basic/driver stubs
                    filtered = [n for n in names if "Microsoft" not in n]
                    if filtered:
                        gpu_name = filtered[0]
                    elif names:
                        gpu_name = names[0]
            except:
                pass
        
        caps["gpu"] = gpu_name

        caps["has_display"] = True # Windows usually has a display
        return caps

    def get_load_avg(self) -> list:
        # Windows doesn't have loadavg; approximate using psutil in the caller if needed
        # or just return zero. Hub can derive load from cpu_usage history.
        return [0.0, 0.0, 0.0]


def get_platform_metrics() -> BasePlatformMetrics:
    """Factory to get the platform-appropriate metrics tool."""
    if platform.system() == "Windows":
        return WindowsMetrics()
    else:
        return PosixMetrics()
