"""System information collection module"""

import os
import platform
import sys
from typing import Dict, Any, Optional


class OSConstants:
    """Operating system constants"""
    WINDOWS = "Windows"
    LINUX = "Linux"
    MACOS = "MacOS"
    UNKNOWN = "Unknown"


class SystemInfo:
    """System information collection class"""
    
    def __init__(self):
        """Initialize system info collector"""
        self.os_type = self._get_os_type()
    
    def _get_os_type(self) -> str:
        """Get current operating system type
        
        Returns:
            str: Operating system type
        """
        system = platform.system()
        if system == "Windows":
            return OSConstants.WINDOWS
        elif system == "Linux":
            return OSConstants.LINUX
        elif system == "Darwin":
            return OSConstants.MACOS
        else:
            return OSConstants.UNKNOWN
    
    def get_os_type(self) -> str:
        """Get current operating system type
        
        Returns:
            str: Operating system type
        """
        return self.os_type
    
    def get_hardware_info(self) -> Dict[str, Any]:
        """Get hardware information
        
        Returns:
            Dict[str, Any]: Hardware information including CPU, memory, and disk info
        """
        hardware_info = {
            "cpu": self._get_cpu_info(),
            "memory": self._get_memory_info(),
            "disk": self._get_disk_info()
        }
        return hardware_info
    
    def _get_cpu_info(self) -> Dict[str, Any]:
        """Get CPU information
        
        Returns:
            Dict[str, Any]: CPU information
        """
        cpu_info = {
            "model": platform.processor(),
            "cores": os.cpu_count()
        }
        
        # Try to get more detailed CPU info based on OS
        if self.os_type == OSConstants.WINDOWS:
            try:
                import wmi
                w = wmi.WMI()
                for cpu in w.Win32_Processor():
                    cpu_info["model"] = cpu.Name
                    cpu_info["cores"] = cpu.NumberOfCores
                    cpu_info["threads"] = cpu.NumberOfLogicalProcessors
                    break
            except ImportError:
                pass
        elif self.os_type == OSConstants.LINUX:
            try:
                with open("/proc/cpuinfo", "r") as f:
                    for line in f:
                        if line.startswith("model name"):
                            cpu_info["model"] = line.split(":")[1].strip()
                            break
            except FileNotFoundError:
                pass
        elif self.os_type == OSConstants.MACOS:
            try:
                import subprocess
                result = subprocess.run(["sysctl", "-n", "machdep.cpu.brand_string"], 
                                      capture_output=True, text=True)
                if result.returncode == 0:
                    cpu_info["model"] = result.stdout.strip()
            except Exception:
                pass
        
        return cpu_info
    
    def _get_memory_info(self) -> Dict[str, Any]:
        """Get memory information
        
        Returns:
            Dict[str, Any]: Memory information
        """
        memory_info = {
            "total": 0,
            "available": 0,
            "model": "Unknown"
        }
        
        if self.os_type == OSConstants.WINDOWS:
            try:
                import wmi
                w = wmi.WMI()
                for memory in w.Win32_ComputerSystem():
                    memory_info["total"] = round(int(memory.TotalPhysicalMemory) / (1024**3), 2)
                for memory in w.Win32_OperatingSystem():
                    memory_info["available"] = round(int(memory.FreePhysicalMemory) / (1024**2), 2)
                # Try to get memory model
                for memory in w.Win32_PhysicalMemory():
                    memory_info["model"] = memory.PartNumber
                    break
            except ImportError:
                pass
        elif self.os_type == OSConstants.LINUX:
            try:
                with open("/proc/meminfo", "r") as f:
                    for line in f:
                        if line.startswith("MemTotal:"):
                            memory_info["total"] = round(int(line.split()[1]) / (1024**2), 2)
                        elif line.startswith("MemAvailable:"):
                            memory_info["available"] = round(int(line.split()[1]) / (1024**2), 2)
            except FileNotFoundError:
                pass
        elif self.os_type == OSConstants.MACOS:
            try:
                import subprocess
                # Get total memory
                result = subprocess.run(["sysctl", "-n", "hw.memsize"], 
                                      capture_output=True, text=True)
                if result.returncode == 0:
                    memory_info["total"] = round(int(result.stdout.strip()) / (1024**3), 2)
                # Get available memory (approximate)
                result = subprocess.run(["vm_stat"], capture_output=True, text=True)
                if result.returncode == 0:
                    for line in result.stdout.splitlines():
                        if "free" in line:
                            free_pages = int(line.split(':')[1].strip().replace(',', ''))
                            memory_info["available"] = round((free_pages * 4096) / (1024**2), 2)
                            break
            except Exception:
                pass
        
        return memory_info
    
    def _get_disk_info(self) -> Dict[str, Any]:
        """Get disk information
        
        Returns:
            Dict[str, Any]: Disk information
        """
        disk_info = {
            "model": "Unknown",
            "total": 0,
            "available": 0,
            "type": "Unknown"
        }
        
        if self.os_type == OSConstants.WINDOWS:
            try:
                import wmi
                w = wmi.WMI()
                # Get disk model
                for disk in w.Win32_DiskDrive():
                    disk_info["model"] = disk.Model
                    break
                # Get disk space for system drive
                system_drive = os.environ.get("SYSTEMDRIVE", "C:")
                total, used, free = self._get_disk_space(system_drive)
                disk_info["total"] = round(total, 2)
                disk_info["available"] = round(free, 2)
                # Get disk type
                for disk in w.Win32_DiskDrive():
                    if "SSD" in disk.Model.upper():
                        disk_info["type"] = "SSD"
                    else:
                        disk_info["type"] = "HDD"
                    break
            except ImportError:
                pass
        elif self.os_type == OSConstants.LINUX:
            try:
                # Get disk model
                with open("/sys/block/sda/device/model", "r") as f:
                    disk_info["model"] = f.read().strip()
                # Get disk space
                total, used, free = self._get_disk_space("/")
                disk_info["total"] = round(total, 2)
                disk_info["available"] = round(free, 2)
                # Try to detect disk type
                try:
                    with open("/sys/block/sda/queue/rotational", "r") as f:
                        rotational = f.read().strip()
                        disk_info["type"] = "HDD" if rotational == "1" else "SSD"
                except FileNotFoundError:
                    pass
            except FileNotFoundError:
                pass
        elif self.os_type == OSConstants.MACOS:
            try:
                import subprocess
                # Get disk info
                result = subprocess.run(["diskutil", "info", "/"], 
                                      capture_output=True, text=True)
                if result.returncode == 0:
                    for line in result.stdout.splitlines():
                        if "Device / Media Name:" in line:
                            disk_info["model"] = line.split(":")[1].strip()
                        elif "Total Size:" in line:
                            size_str = line.split(":")[1].strip()
                            # Extract size in GB
                            import re
                            match = re.search(r'(\d+\.\d+) GB', size_str)
                            if match:
                                disk_info["total"] = float(match.group(1))
                        elif "Volume Free Space:" in line:
                            free_str = line.split(":")[1].strip()
                            match = re.search(r'(\d+\.\d+) GB', free_str)
                            if match:
                                disk_info["available"] = float(match.group(1))
                # Get disk type
                result = subprocess.run(["diskutil", "info", "/"], 
                                      capture_output=True, text=True)
                if result.returncode == 0:
                    if "Solid State" in result.stdout:
                        disk_info["type"] = "SSD"
                    else:
                        disk_info["type"] = "HDD"
            except Exception:
                pass
        
        return disk_info
    
    def _get_disk_space(self, path: str) -> tuple:
        """Get disk space for a given path
        
        Args:
            path: Path to check disk space
            
        Returns:
            tuple: (total, used, free) in GB
        """
        try:
            import shutil
            total, used, free = shutil.disk_usage(path)
            return total / (1024**3), used / (1024**3), free / (1024**3)
        except Exception:
            return 0, 0, 0
    
    def get_full_system_info(self) -> Dict[str, Any]:
        """Get full system information
        
        Returns:
            Dict[str, Any]: Full system information
        """
        return {
            "os": {
                "type": self.os_type,
                "version": platform.version(),
                "release": platform.release(),
                "machine": platform.machine()
            },
            "hardware": self.get_hardware_info()
        }


def get_system_info() -> SystemInfo:
    """Get system info instance
    
    Returns:
        SystemInfo: System info instance
    """
    return SystemInfo()
