import hashlib
import platform
import subprocess
import uuid
import os
from typing import Optional


class DeviceIDGenerator:
    """
    Windows设备唯一ID生成器
    通过收集多个硬件特征来生成稳定的设备唯一标识符
    """
    
    def __init__(self, use_cache: bool = True, cache_file: str = ".device_id"):
        """
        初始化设备ID生成器
        
        Args:
            use_cache: 是否使用本地缓存
            cache_file: 缓存文件名
        """
        self.use_cache = use_cache
        self.cache_file = cache_file
    
    def _run_wmic_command(self, command: str) -> Optional[str]:
        """
        执行WMIC命令并返回结果
        
        Args:
            command: WMIC命令
            
        Returns:
            命令执行结果，失败则返回None
        """
        try:
            result = subprocess.run(
                command, 
                shell=True, 
                capture_output=True, 
                text=True, 
                timeout=10
            )
            if result.returncode == 0 and result.stdout.strip():
                return result.stdout.strip()
        except (subprocess.TimeoutExpired, Exception):
            pass
        return None
    
    def _get_motherboard_serial(self) -> Optional[str]:
        """获取主板序列号"""
        return self._run_wmic_command("wmic baseboard get serialnumber /value")
    
    def _get_cpu_id(self) -> Optional[str]:
        """获取CPU ID"""
        return self._run_wmic_command("wmic cpu get processorid /value")
    
    def _get_bios_serial(self) -> Optional[str]:
        """获取BIOS序列号"""
        return self._run_wmic_command("wmic bios get serialnumber /value")
    
    def _get_disk_serial(self) -> Optional[str]:
        """获取系统盘序列号"""
        return self._run_wmic_command("wmic diskdrive get serialnumber /value")
    
    def _get_machine_guid(self) -> Optional[str]:
        """获取Windows机器GUID"""
        try:
            result = subprocess.run(
                'reg query "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography" /v MachineGuid',
                shell=True,
                capture_output=True,
                text=True,
                timeout=10
            )
            if result.returncode == 0:
                for line in result.stdout.split('\n'):
                    if 'MachineGuid' in line:
                        return line.split()[-1]
        except Exception:
            pass
        return None
    
    def _extract_value(self, wmic_output: str) -> str:
        """从WMIC输出中提取实际值"""
        if not wmic_output:
            return ""
        
        lines = wmic_output.split('\n')
        for line in lines:
            if '=' in line and not line.strip().endswith('='):
                return line.split('=', 1)[1].strip()
        return ""
    
    def _collect_hardware_info(self) -> dict:
        """
        收集硬件信息
        
        Returns:
            包含各种硬件信息的字典
        """
        hardware_info = {}
        
        # 主板序列号
        motherboard = self._get_motherboard_serial()
        hardware_info['motherboard'] = self._extract_value(motherboard) if motherboard else ""
        
        # CPU ID
        cpu_id = self._get_cpu_id()
        hardware_info['cpu'] = self._extract_value(cpu_id) if cpu_id else ""
        
        # BIOS序列号
        bios = self._get_bios_serial()
        hardware_info['bios'] = self._extract_value(bios) if bios else ""
        
        # 硬盘序列号
        disk = self._get_disk_serial()
        hardware_info['disk'] = self._extract_value(disk) if disk else ""
        
        # Windows机器GUID
        machine_guid = self._get_machine_guid()
        hardware_info['machine_guid'] = machine_guid if machine_guid else ""
        
        # 计算机名称
        hardware_info['computer_name'] = platform.node()
        
        # MAC地址（作为备用）
        hardware_info['mac_address'] = ':'.join(['{:02x}'.format((uuid.getnode() >> elements) & 0xff) 
                                                 for elements in range(0, 2*6, 2)][::-1])
        
        return hardware_info
    
    def _generate_device_id(self, hardware_info: dict) -> str:
        """
        基于硬件信息生成设备ID
        
        Args:
            hardware_info: 硬件信息字典
            
        Returns:
            32位十六进制设备ID
        """
        # 过滤掉空值，并按键排序确保一致性
        filtered_info = {k: v for k, v in hardware_info.items() if v and v.strip()}
        
        # 如果没有任何硬件信息，使用MAC地址作为后备方案
        if not filtered_info:
            filtered_info = {'mac_address': hardware_info.get('mac_address', str(uuid.getnode()))}
        
        # 将所有信息连接成字符串
        info_string = '|'.join(f"{k}:{v}" for k, v in sorted(filtered_info.items()))
        
        # 使用SHA256生成哈希值
        hash_object = hashlib.sha256(info_string.encode('utf-8'))
        device_id = hash_object.hexdigest()
        
        return device_id
    
    def _load_cached_device_id(self) -> Optional[str]:
        """从缓存文件加载设备ID"""
        try:
            if os.path.exists(self.cache_file):
                with open(self.cache_file, 'r', encoding='utf-8') as f:
                    cached_id = f.read().strip()
                    if len(cached_id) == 64:  # SHA256哈希长度
                        return cached_id
        except Exception:
            pass
        return None
    
    def _save_device_id_to_cache(self, device_id: str) -> None:
        """将设备ID保存到缓存文件"""
        try:
            with open(self.cache_file, 'w', encoding='utf-8') as f:
                f.write(device_id)
        except Exception:
            pass
    
    def get_device_id(self) -> str:
        """
        获取设备唯一ID
        
        Returns:
            64字符的十六进制设备ID
        """
        # 如果启用缓存，先尝试从缓存加载
        if self.use_cache:
            cached_id = self._load_cached_device_id()
            if cached_id:
                return cached_id
        
        # 收集硬件信息
        hardware_info = self._collect_hardware_info()
        
        # 生成设备ID
        device_id = self._generate_device_id(hardware_info)
        
        # 保存到缓存
        if self.use_cache:
            self._save_device_id_to_cache(device_id)
        
        return device_id
    
    def get_device_id_short(self, length: int = 16) -> str:
        """
        获取短版本的设备ID
        
        Args:
            length: 返回ID的长度
            
        Returns:
            指定长度的设备ID
        """
        full_id = self.get_device_id()
        return full_id[:length]
    
    def get_hardware_info(self) -> dict:
        """
        获取硬件信息（用于调试）
        
        Returns:
            硬件信息字典
        """
        return self._collect_hardware_info()


# 使用示例
def main():
    """使用示例"""
    # 创建设备ID生成器实例
    device_generator = DeviceIDGenerator()
    
    # 获取完整设备ID（64字符）
    device_id = device_generator.get_device_id()
    print(f"完整设备ID: {device_id}")
    
    # 获取短版本设备ID（16字符）
    short_id = device_generator.get_device_id_short(16)
    print(f"短设备ID: {short_id}")
    
    # 查看硬件信息（调试用）
    hardware_info = device_generator.get_hardware_info()
    print("\n硬件信息:")
    for key, value in hardware_info.items():
        print(f"  {key}: {value}")


if __name__ == "__main__":
    main()