
import psutil
import sys
from typing import Dict, Any

import platform
import subprocess
import os
from typing import Optional

from .devices_utils import get_hardware_identifier
from .encry.HashUtils import HashUtils


class SystemUtils:
    @staticmethod
    def system_get_cpu_info() -> dict:
        """
        获取CPU详细信息

        Returns:
            dict: 包含CPU信息的字典
        """
        cpu_info = {
            'model': 'Unknown',
            'cores': 0,
            'threads': 0,
            'architecture': platform.machine(),
            'frequency': 'Unknown'
        }

        try:
            system = platform.system().lower()

            if system == "windows":
                # Windows系统获取CPU信息
                try:
                    # 获取CPU型号
                    result = subprocess.run(
                        ['wmic', 'cpu', 'get', 'Name', '/value'],
                        capture_output=True, text=True
                    )
                    if result.returncode == 0:
                        lines = result.stdout.strip().split('\n')
                        for line in lines:
                            if 'Name=' in line:
                                cpu_info['model'] = line.split('=')[1].strip()
                                break

                    # 获取CPU核心数
                    result = subprocess.run(
                        ['wmic', 'cpu', 'get', 'NumberOfCores', '/value'],
                        capture_output=True, text=True
                    )
                    if result.returncode == 0:
                        lines = result.stdout.strip().split('\n')
                        for line in lines:
                            if 'NumberOfCores=' in line:
                                cpu_info['cores'] = int(line.split('=')[1].strip())
                                break

                    # 获取逻辑处理器数
                    result = subprocess.run(
                        ['wmic', 'cpu', 'get', 'NumberOfLogicalProcessors', '/value'],
                        capture_output=True, text=True
                    )
                    if result.returncode == 0:
                        lines = result.stdout.strip().split('\n')
                        for line in lines:
                            if 'NumberOfLogicalProcessors=' in line:
                                cpu_info['threads'] = int(line.split('=')[1].strip())
                                break

                except Exception:
                    # 回退到platform.processor()
                    cpu_info['model'] = platform.processor() or 'Unknown'

            elif system == "linux":
                # Linux系统获取CPU信息
                try:
                    # 从/proc/cpuinfo获取CPU型号
                    with open('/proc/cpuinfo', 'r') as f:
                        cpuinfo = f.read()

                    # 查找CPU型号
                    for line in cpuinfo.split('\n'):
                        if 'model name' in line:
                            cpu_info['model'] = line.split(':')[1].strip()
                            break

                    # 获取核心数
                    cores = set()
                    for line in cpuinfo.split('\n'):
                        if 'core id' in line:
                            core_id = line.split(':')[1].strip()
                            cores.add(core_id)

                    cpu_info['cores'] = len(cores) if cores else 1

                    # 获取线程数
                    thread_count = 0
                    for line in cpuinfo.split('\n'):
                        if 'processor' in line and ':' in line:
                            thread_count += 1

                    cpu_info['threads'] = thread_count if thread_count > 0 else 1

                except Exception:
                    pass

            elif system == "darwin":
                # macOS系统获取CPU信息
                try:
                    # 获取CPU型号
                    result = subprocess.run(
                        ['sysctl', '-n', 'machdep.cpu.brand_string'],
                        capture_output=True, text=True
                    )
                    if result.returncode == 0:
                        cpu_info['model'] = result.stdout.strip()

                    # 获取核心数
                    result = subprocess.run(
                        ['sysctl', '-n', 'hw.physicalcpu'],
                        capture_output=True, text=True
                    )
                    if result.returncode == 0:
                        cpu_info['cores'] = int(result.stdout.strip())

                    # 获取逻辑核心数
                    result = subprocess.run(
                        ['sysctl', '-n', 'hw.logicalcpu'],
                        capture_output=True, text=True
                    )
                    if result.returncode == 0:
                        cpu_info['threads'] = int(result.stdout.strip())

                except Exception:
                    pass

            # 如果还是Unknown，尝试使用platform.processor()
            if cpu_info['model'] == 'Unknown':
                cpu_info['model'] = platform.processor() or 'Unknown'

        except Exception:
            pass

        return cpu_info

    @staticmethod
    def system_get_cpu_model() -> str:
        """
        获取CPU型号

        Returns:
            str: CPU型号字符串
        """
        try:
            cpu_info = SystemUtils.system_get_cpu_info()
            return cpu_info.get('model', 'Unknown')
        except Exception:
            return 'Unknown'

    @staticmethod
    def system_get_cpu_cores() -> int:
        """
        获取CPU物理核心数

        Returns:
            int: CPU物理核心数
        """
        try:
            cpu_info = SystemUtils.system_get_cpu_info()
            return cpu_info.get('cores', 0)
        except Exception:
            return 0

    @staticmethod
    def system_get_cpu_threads() -> int:
        """
        获取CPU逻辑线程数

        Returns:
            int: CPU逻辑线程数
        """
        try:
            cpu_info = SystemUtils.system_get_cpu_info()
            return cpu_info.get('threads', 0)
        except Exception:
            return 0

    @staticmethod
    def system_empty_recycle_bin(confirm: bool = True) -> bool:
        """
        清空回收站

        Args:
            confirm (bool): 是否弹出询问框，默认为True（弹出询问框）
                            True表示弹出系统确认对话框
                            False表示直接清空不询问

        Returns:
            bool: 成功清空回收站返回True，失败返回False
        """
        try:
            system = platform.system().lower()

            if system == "windows":
                # Windows系统清空回收站
                try:
                    import ctypes
                    from ctypes import wintypes

                    # Windows API常量
                    SHERB_NOCONFIRMATION = 0x00000001
                    SHERB_NOPROGRESSUI = 0x00000002
                    SHERB_NOSOUND = 0x00000004

                    # 加载shell32.dll
                    shell32 = ctypes.windll.shell32

                    # 设置标志位
                    flags = 0
                    if not confirm:
                        flags |= SHERB_NOCONFIRMATION  # 不显示确认对话框

                    # 调用Windows API清空回收站
                    # 参数说明：
                    # hwnd: 父窗口句柄，0表示无父窗口
                    # pszRootPath: 回收站路径，None表示所有驱动器
                    # dwFlags: 标志位
                    result = shell32.SHEmptyRecycleBinW(0, None, flags)

                    # 返回值为0表示成功
                    return result == 0

                except Exception:
                    # 如果ctypes方法失败，尝试使用PowerShell命令
                    try:
                        if confirm:
                            # 弹出确认对话框
                            cmd = [
                                "powershell",
                                "-Command",
                                "Add-Type -AssemblyName Microsoft.VisualBasic; "
                                "[Microsoft.VisualBasic.Interaction]::MsgBox('确定要清空回收站吗？', 'OKCancel', '确认清空回收站') | Out-Null; "
                                "Clear-RecycleBin -Force"
                            ]
                        else:
                            # 直接清空不询问
                            cmd = [
                                "powershell",
                                "-Command",
                                "Clear-RecycleBin -Force"
                            ]

                        result = subprocess.run(cmd, capture_output=True, text=True)
                        return result.returncode == 0
                    except Exception:
                        return False

            elif system == "darwin":  # macOS
                # macOS系统清空废纸篓
                try:
                    # 使用AppleScript清空废纸篓
                    if confirm:
                        # 弹出确认对话框
                        script = '''
                        display dialog "确定要清空废纸篓吗？" buttons {"取消", "确定"} default button "取消"
                        if button returned of result is "确定" then
                            tell application "Finder"
                                empty trash
                            end tell
                        end if
                        '''
                    else:
                        # 直接清空不询问
                        script = '''
                        tell application "Finder"
                            empty trash
                        end tell
                        '''

                    cmd = ["osascript", "-e", script]
                    result = subprocess.run(cmd, capture_output=True, text=True)
                    return result.returncode == 0

                except Exception:
                    return False

            elif system == "linux":
                # Linux系统清空回收站
                try:
                    import shutil
                    import glob

                    # Linux回收站路径通常在 ~/.local/share/Trash/
                    trash_path = os.path.expanduser("~/.local/share/Trash/")

                    if os.path.exists(trash_path):
                        if confirm:
                            # 简单的命令行确认
                            response = input("确定要清空回收站吗？(y/N): ")
                            if response.lower() not in ['y', 'yes']:
                                return False

                        # 清空files目录（实际文件）
                        files_dir = os.path.join(trash_path, "files")
                        if os.path.exists(files_dir):
                            for item in os.listdir(files_dir):
                                item_path = os.path.join(files_dir, item)
                                try:
                                    if os.path.isfile(item_path) or os.path.islink(item_path):
                                        os.unlink(item_path)
                                    elif os.path.isdir(item_path):
                                        shutil.rmtree(item_path)
                                except Exception:
                                    continue

                        # 清空info目录（元数据）
                        info_dir = os.path.join(trash_path, "info")
                        if os.path.exists(info_dir):
                            for item in os.listdir(info_dir):
                                item_path = os.path.join(info_dir, item)
                                try:
                                    os.unlink(item_path)
                                except Exception:
                                    continue

                        return True
                    else:
                        return False

                except Exception:
                    return False
            else:
                # 不支持的操作系统
                return False

        except Exception:
            return False

    @staticmethod
    def get_devices_md5(uppercase: bool = False) -> str:

        """
        对硬件信息字典排序并生成MD5值
        :param uppercase: MD5结果是否大写（默认小写）
        :return: 32位MD5字符串
        """
        # 1. 按key升序排序，生成有序键值对列表
        hardware_info = get_hardware_identifier()
        sorted_items = sorted(hardware_info.items(), key=lambda x: x[0])

        # 2. 格式化：将None转为"未知"，拼接为"key:value|key:value"格式
        formatted_str = "|".join([f"{k}:{v if v is not None else '未知'}" for k, v in sorted_items])

        # 3. 生成MD5（统一使用utf-8编码，避免跨平台编码问题）
        md5_obj = HashUtils.hash_md5_string(formatted_str)

        # 4. 可选：转为大写
        if uppercase:
            return md5_obj.upper()
        
        return md5_obj

    @staticmethod
    def system_get_version() -> Dict[str, Any]:
        """
        获取系统版本信息

        Returns:
            dict: 包含系统版本信息的字典
        """
        try:
            # 获取系统信息
            system_info = {
                'system': platform.system(),  # 操作系统名称
                'release': platform.release(),  # 操作系统发行版本
                'version': platform.version(),  # 操作系统版本
                'machine': platform.machine(),  # 机器类型
                'processor': platform.processor(),  # 处理器信息
                'architecture': platform.architecture()[0],  # 系统架构
                'node': platform.node(),  # 网络节点名称
                'platform': platform.platform(),  # 平台信息
                'python_version': sys.version,  # Python版本
                'python_compiler': platform.python_compiler()  # Python编译器
            }

            # 根据不同操作系统获取更详细的版本信息
            if system_info['system'].lower() == 'windows':
                # Windows系统额外信息
                try:
                    import subprocess
                    # 获取Windows版本详细信息
                    result = subprocess.run(
                        ['wmic', 'os', 'get', 'Caption,Version,BuildNumber', '/value'],
                        capture_output=True, text=True
                    )
                    if result.returncode == 0:
                        lines = result.stdout.strip().split('\n')
                        for line in lines:
                            if 'Caption=' in line:
                                system_info['windows_caption'] = line.split('=')[1]
                            elif 'Version=' in line:
                                system_info['windows_version'] = line.split('=')[1]
                            elif 'BuildNumber=' in line:
                                system_info['windows_build'] = line.split('=')[1]
                except Exception:
                    pass

            elif system_info['system'].lower() in ['linux', 'darwin']:
                # Unix/Linux/macOS系统额外信息
                try:
                    import subprocess
                    if system_info['system'].lower() == 'linux':
                        # Linux系统获取发行版信息
                        result = subprocess.run(['lsb_release', '-d'], capture_output=True, text=True)
                        if result.returncode == 0:
                            system_info['distribution'] = result.stdout.strip().split(':')[1].strip()
                    else:
                        # macOS系统获取版本信息
                        result = subprocess.run(['sw_vers', '-productVersion'], capture_output=True, text=True)
                        if result.returncode == 0:
                            system_info['macos_version'] = result.stdout.strip()
                except Exception:
                    pass

            return system_info

        except Exception as e:
            # 发生异常时返回基本系统信息
            return {
                'system': platform.system(),
                'release': platform.release(),
                'version': platform.version(),
                'error': str(e)
            }

    @staticmethod
    def system_get_simple_version() -> str:
        """
        获取简化版系统版本信息

        Returns:
            str: 简化版系统版本信息
        """
        try:
            return platform.platform()
        except Exception:
            return f"{platform.system()} {platform.release()}"

    @staticmethod
    def system_is_windows() -> bool:
        """
        检查是否为Windows系统

        Returns:
            bool: 是Windows系统返回True，否则返回False
        """
        return platform.system().lower() == 'windows'

    @staticmethod
    def system_is_linux() -> bool:
        """
        检查是否为Linux系统

        Returns:
            bool: 是Linux系统返回True，否则返回False
        """
        return platform.system().lower() == 'linux'

    @staticmethod
    def system_is_macos() -> bool:
        """
        检查是否为macOS系统

        Returns:
            bool: 是macOS系统返回True，否则返回False
        """
        return platform.system().lower() == 'darwin'

    @staticmethod
    def process_kill_by_pid(pid: int, force: bool = False) -> bool:
        """
        根据PID结束进程

        Args:
            pid (int): 进程ID
            force (bool): 是否强制结束进程，默认为False（正常结束）
                         True表示强制结束（SIGKILL），False表示正常结束（SIGTERM）

        Returns:
            bool: 成功结束进程返回True，失败返回False
        """
        try:
            # 检查PID是否有效
            if not isinstance(pid, int) or pid <= 0:
                raise ValueError("PID必须是正整数")

            # 获取进程对象
            process = psutil.Process(pid)

            # 结束进程
            if force:
                # 强制结束进程
                process.kill()  # SIGKILL
            else:
                # 正常结束进程
                process.terminate()  # SIGTERM

            # 等待进程结束
            process.wait(timeout=3)
            return True

        except psutil.NoSuchProcess:
            # 进程不存在
            return False
        except psutil.AccessDenied:
            # 权限不足
            return False
        except psutil.TimeoutExpired:
            # 进程未在指定时间内结束，如果需要可以强制结束
            if not force:
                try:
                    process.kill()
                    process.wait(timeout=1)
                    return True
                except Exception:
                    return False
            return False
        except Exception:
            # 其他异常
            return False

    @staticmethod
    def process_kill_by_name(name: str, force: bool = False) -> int:
        """
        根据进程名结束进程

        Args:
            name (str): 进程名
            force (bool): 是否强制结束进程，默认为False

        Returns:
            int: 成功结束的进程数量
        """
        killed_count = 0

        try:
            # 遍历所有进程
            for process in psutil.process_iter(['pid', 'name']):
                try:
                    # 检查进程名是否匹配
                    if process.info['name'].lower() == name.lower():
                        # 结束进程
                        if SystemUtils.process_kill_by_pid(process.info['pid'], force):
                            killed_count += 1
                except (psutil.NoSuchProcess, psutil.AccessDenied):
                    # 进程已不存在或权限不足，跳过
                    continue

        except Exception:
            pass

        return killed_count

    @staticmethod
    def port_check_process(port: int, protocol: str = 'tcp') -> Optional[Dict[str, Any]]:
        """
        检查端口被哪个程序占用

        Args:
            port (int): 端口号
            protocol (str): 协议类型，'tcp' 或 'udp'，默认为 'tcp'

        Returns:
            dict or None: 如果端口被占用，返回包含进程信息的字典；否则返回None
        """
        try:
            # 检查端口是否有效
            if not isinstance(port, int) or port < 0 or port > 65535:
                raise ValueError("端口号必须是0-65535之间的整数")

            # 检查协议类型
            protocol = protocol.lower()
            if protocol not in ['tcp', 'udp']:
                raise ValueError("协议类型必须是'tcp'或'udp'")

            # 遍历所有网络连接
            for conn in psutil.net_connections(kind=protocol):
                # 检查端口是否匹配
                if conn.laddr.port == port:
                    # 获取进程信息
                    try:
                        process = psutil.Process(conn.pid)
                        return {
                            'pid': conn.pid,
                            'name': process.name(),
                            'exe': process.exe(),
                            'cmdline': ' '.join(process.cmdline()),
                            'status': process.status(),
                            'port': port,
                            'protocol': protocol,
                            'local_address': f"{conn.laddr.ip}:{conn.laddr.port}",
                            'remote_address': f"{conn.raddr.ip}:{conn.raddr.port}" if conn.raddr else "N/A"
                        }
                    except (psutil.NoSuchProcess, psutil.AccessDenied):
                        # 如果无法获取进程信息，返回基本连接信息
                        return {
                            'pid': conn.pid,
                            'name': "Unknown",
                            'exe': "Unknown",
                            'cmdline': "Unknown",
                            'status': "Unknown",
                            'port': port,
                            'protocol': protocol,
                            'local_address': f"{conn.laddr.ip}:{conn.laddr.port}",
                            'remote_address': f"{conn.raddr.ip}:{conn.raddr.port}" if conn.raddr else "N/A"
                        }

            # 端口未被占用
            return None

        except Exception as e:
            # 发生异常时返回None
            return None

    @staticmethod
    def port_get_processes(port: int) -> list:
        """
        获取占用指定端口的所有进程信息

        Args:
            port (int): 端口号

        Returns:
            list: 占用该端口的进程信息列表
        """
        processes = []

        try:
            # 检查TCP连接
            tcp_result = SystemUtils.port_check_process(port, 'tcp')
            if tcp_result:
                processes.append(tcp_result)

            # 检查UDP连接
            udp_result = SystemUtils.port_check_process(port, 'udp')
            if udp_result:
                processes.append(udp_result)

        except Exception:
            pass

        return processes

    @staticmethod
    def system_shutdown(delay: int = 0, message: str = "") -> bool:
        """
        关闭计算机系统

        Args:
            delay (int): 延迟关机时间（秒），默认为0（立即关机）
            message (str): 关机前显示的消息，默认为空

        Returns:
            bool: 成功发起关机命令返回True，失败返回False
        """
        try:
            system = platform.system().lower()

            if system == "windows":
                # Windows系统关机命令
                if delay > 0:
                    cmd = ["shutdown", "/s", "/t", str(delay)]
                else:
                    cmd = ["shutdown", "/s", "/f", "/t", "0"]

                if message:
                    cmd.extend(["/c", message])

            elif system in ["linux", "darwin"]:  # Linux or macOS
                # Unix/Linux/macOS系统关机命令
                if delay > 0:
                    # 使用at命令实现延迟关机
                    minutes = delay // 60
                    if minutes > 0:
                        cmd = ["sudo", "shutdown", "-h", f"+{minutes}"]
                    else:
                        cmd = ["sudo", "shutdown", "-h", "now"]
                else:
                    cmd = ["sudo", "shutdown", "-h", "now"]

                if message:
                    cmd.append(message)
            else:
                return False

            # 执行关机命令
            result = subprocess.run(cmd, capture_output=True, text=True)
            return result.returncode == 0

        except Exception:
            return False

    @staticmethod
    def system_restart(delay: int = 0, message: str = "") -> bool:
        """
        重启计算机系统

        Args:
            delay (int): 延迟重启时间（秒），默认为0（立即重启）
            message (str): 重启前显示的消息，默认为空

        Returns:
            bool: 成功发起重启命令返回True，失败返回False
        """
        try:
            system = platform.system().lower()

            if system == "windows":
                # Windows系统重启命令
                if delay > 0:
                    cmd = ["shutdown", "/r", "/t", str(delay)]
                else:
                    cmd = ["shutdown", "/r", "/f", "/t", "0"]

                if message:
                    cmd.extend(["/c", message])

            elif system in ["linux", "darwin"]:  # Linux or macOS
                # Unix/Linux/macOS系统重启命令
                if delay > 0:
                    # 使用at命令实现延迟重启
                    minutes = delay // 60
                    if minutes > 0:
                        cmd = ["sudo", "shutdown", "-r", f"+{minutes}"]
                    else:
                        cmd = ["sudo", "shutdown", "-r", "now"]
                else:
                    cmd = ["sudo", "reboot"]

                if message:
                    cmd.append(message)
            else:
                return False

            # 执行重启命令
            result = subprocess.run(cmd, capture_output=True, text=True)
            return result.returncode == 0

        except Exception:
            return False

    @staticmethod
    def system_cancel_shutdown() -> bool:
        """
        取消已计划的关机或重启操作

        Returns:
            bool: 成功取消返回True，失败返回False
        """
        try:
            system = platform.system().lower()

            if system == "windows":
                # Windows系统取消关机命令
                cmd = ["shutdown", "/a"]
            elif system in ["linux", "darwin"]:
                # Unix/Linux/macOS系统取消关机命令
                cmd = ["sudo", "shutdown", "-c"]
            else:
                return False

            # 执行取消命令
            result = subprocess.run(cmd, capture_output=True, text=True)
            return result.returncode == 0

        except Exception:
            return False



