"""
一些工具:
    比如复制文件,ADB命令(使用前请看注释!)
    获取桌面位置,获取用户名...
"""
import os
import re
import sys
import time
import signal
import ctypes
import shutil
import winreg
import hashlib
import requests
import platform
import threading
import subprocess
import ctypes.util
from tkinter import *
from pyfiglet import Figlet

close_list = ['normal','sys','decr',' ']


def default(txt,font="larry3d"):
    """
    艺术字(pyfiglet)
    txt:字
    font:字体
    """
    f = Figlet(font=font, width=200)
    #print(f.renderText('CODINGHOU'))
    print(f.renderText(txt))


def download(url, destination, Savelocation,
              Sen = 'get'):
    """
    在互联网上下载文件
    url:下载链接
    destination:下载完成后的名字
    Savelocation:保存位置
    Sen:发送方式,可填'get'和'post',默认get.
    """
    try:
        os.chdir(Savelocation)
        if Sen == 'get':
            response = requests.get(url, stream=True)

        if Sen == 'post':
            response = requests.post(url, stream=True)

        else:
            response = requests.get(url, stream=True)

        response.raise_for_status()

        with open(destination, 'wb') as file:
            for chunk in response.iter_content(chunk_size=8192):
                if chunk:
                    file.write(chunk)

    except Exception as e:
        print(f"Failed to download the file due to error: {e}")


def system():
    """通过调用系统命令识别操作系统"""
    try:
        result = subprocess.run("ver", capture_output=True, text=True, shell=True)
        if "Microsoft" in result.stdout:
            return "Windows"
        
        result = subprocess.run("uname", capture_output=True, text=True, shell=True)
        if "Darwin" in result.stdout:
            return "macOS"
        
        result = subprocess.run("uname", capture_output=True, text=True, shell=True)
        if "Linux" in result.stdout:
            return "Linux"
        
    except Exception as e:
        return f"发生错误: {e}"

    return "未知操作系统"


def desktop():
    """获取桌面位置(Desktop)"""
    return os.path.join(os.path.expanduser("~"), "Desktop")


def username():
    """获取用户名"""

    if platform.system() == "Windows":
        return os.getenv("USERNAME")

    else:
        return os.getenv("USER")


def timecur():
    """获取当前时间"""
    if platform.system() == "Windows":
        return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))

    else:
        return os.popen('date').read().strip()


def timemin(minutes):
    """获取minutes分钟前的时间"""
    return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time() - minutes * 60))


def sleep(seconds):
    """
    暂停程序指定的秒数
    seconds:秒
    """
    event = threading.Event()
    event.wait(timeout=seconds)


def close(method = 'sys'):
    """
    关闭程序
    method:关闭方式
    """
    if system() == 'Windows':
        if method == 'decr':
            raise Exception("程序结束")
        
        elif method == 'sys':
            sys.exit()

        else:
            print('not method')

    else:
        if method == 'decr':
            raise Exception("程序结束")
        
        elif method == 'sys':
            sys.exit()
        
        elif method == 'normal':
            os.kill(os.getpid(), signal.SIGTERM)

        else:
            print('not method')


def route(relative_path):
    """
    从相对路径获取绝对路径
    relative_path:相对路径
    """
    # 检查该路径是否存在
    if os.path.exists(relative_path):
        print("该路径存在。")
    else:
        print("该路径不存在。")

    # 获取对应的绝对路径
    return os.path.abspath(relative_path)


def filehash(file_path):
    """
    计算给定文件的 SHA256 哈希值
    file_path:文件路径
    """
    hash_sha256 = hashlib.sha256()
    with open(file_path, 'rb') as f:
        # 按块读取文件内容以避免占用大量内存
        for byte_block in iter(lambda: f.read(4096), b""):
            hash_sha256.update(byte_block)
            
    return hash_sha256.hexdigest()


def copy(source_file,destination_file):
    """
    复制文件
    source_file:源文件路径,例如 "C:/path/to/source.txt"
    destination_file:目标文件路径,例如 "C:/path/to/destination.txt"
    """
    try:

        with open(source_file, 'rb') as src:
            content = src.read()
            
        with open(destination_file, 'wb') as dest:
            dest.write(content)
        
    except FileNotFoundError:
        print("源文件不存在:", source_file)
    except Exception as e:
        print("发生错误:", e)

def copy_secure(source_file,destination_file):
    """
    更保险的复制文件
    source_file:源文件路径,例如 "C:/path/to/source.txt"
    destination_file:目标文件路径,例如 "C:/path/to/destination.txt"
    """
    try:
        source_hash = filehash(source_file)

        with open(source_file, 'rb') as src, open(destination_file, 'wb') as dest:
            dest.write(src.read())

        destination_hash = filehash(destination_file)

        if source_hash == destination_hash:
            pass

        else:
            print("文件复制完成，但验证失败：内容不匹配。")

    except FileNotFoundError:
        print("源文件不存在:", source_file)
    except Exception as e:
        print("发生错误:", e)

def copy_secure2(source_file,destination_file):
    """
    更更更保险的复制文件
    source_file:源文件路径,例如 "C:/path/to/source.txt"
    destination_file:目标文件路径,例如 "C:/path/to/destination.txt"
    """

    temp_file = destination_file + '.tmp'

    try:
        shutil.copy2(source_file, temp_file)# 使用copy2

        source_hash = filehash(source_file)

        destination_hash = filehash(temp_file)

        if source_hash == destination_hash:
            os.rename(temp_file, destination_file)

        else:
            print("文件复制完成，但验证失败：内容不匹配。")
            os.remove(temp_file)

    except Exception as e:
        print("发生错误:", e)
        if os.path.exists(temp_file):
            os.remove(temp_file)

def execute_command(command):
    """
    执行给定的命令(Android)
    command:命令
    """
    try:
        # 使用 ADB 执行命令
        result = subprocess.run(command, capture_output=True, text=True)
        return result.stdout
    except Exception as e:
        print(f"命令执行失败: {e}")
        return None

def copy3_secure(source_file,destination_file,yes_or_no = False):
    """
    更更更更保险的方式复制文件
    source_file:源文件路径,例如 "C:/path/to/source.txt"
    destination_file:目标文件路径,例如 "C:/path/to/destination.txt"
    yes_or_no:是否覆盖文件,默认不覆盖.False:不覆盖,True:覆盖
    """
    if os.path.exists(destination_file):
        if yes_or_no != False:
            return

    source_hash = filehash(source_file)
    temp_file = destination_file + '.tmp'

    try:
        chunk_size=4096
        with open(temp_file, 'rb') as source_file:
            with open(destination_file, 'wb') as dest_file:
                while True:
                    chunk = source_file.read(chunk_size)
                    if not chunk:
                        break
                    dest_file.write(chunk)

        temp_hash = filehash(temp_file)

        if source_hash == temp_hash:
                os.rename(temp_file, destination_file)
        else:
            print("文件复制完成，但验证失败：内容不匹配。")
            os.remove(temp_file)

    except FileNotFoundError:
        print("源文件不存在:", source_file)
    except Exception as e:
        print("发生错误:", str(e))
        if os.path.exists(temp_file):
            os.remove(temp_file)


def software():
    """获取当前安装的软件列表(实验性)"""
    software_list = []

    # Windows 64-bit 和 32-bit 注册表路径
    registry_keys = [
        r"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
        r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
    ]

    for registry_key in registry_keys:
        try:
            # 打开注册表项
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, registry_key) as key:
                for i in range(0, winreg.QueryInfoKey(key)[0]):
                    try:
                        # 读取每个子键的 DisplayName
                        subkey_name = winreg.EnumKey(key, i)
                        with winreg.OpenKey(key, subkey_name) as subkey:
                            display_name = winreg.QueryValueEx(subkey, "DisplayName")[0]
                            software_list.append(display_name)
                    except FileNotFoundError:
                        continue
        except FileNotFoundError:
            continue

    return software_list

class adb:
    """
    执行ADB命令需要用USB链接安卓设备!!!
    如果没有链接安卓设备ADB命令是无效的!!!
    设备需要 Root 权限:此方法仅在设备已经获得 Root 权限的情况下有效。如果没有 Root 权限，将无法成功切换到 Root 用户。
    电脑需要安装ADB,并且需要存在于环境变量path中ADB命令才有效
    
    安全性:Root 权限将使用户能访问系统的所有文件和资源，这既带来了灵活性，也会提高安全风险。因此要谨慎使用。

    ADB 设置:确保 ADB 已正确安装并与设备成功连接。USB 调试需开启。

    使用风险:使用 Root 权限时需要小心操作，尽量避免侵入系统关键文件或应用，这可能导致系统崩溃或其他技术问题。

    链接安卓设备示例:

    #通过USB链接
    usb()
        
    # 获取设备 IP 地址
    device_ip = getip()
    if device_ip:
        # 通过 Wi-Fi 连接
        wifi(device_ip)
        #尝试切换到root用户(Android最高权限,需要Android已解锁root)
        root()
    """

    def install_apk(apk_path):
        """
        安装指定的 APK 文件
        apk_path:apk文件的路径
        """
        try:
            # 使用 ADB 安装 APK 文件
            subprocess.run(["adb", "install", apk_path], check=True)
            print(f"成功安装 APK: {apk_path}")
        except subprocess.CalledProcessError as e:
            print(f"安装失败: {e}")
        except FileNotFoundError:
            print("未找到 ADB，确保 ADB 已安装并正确配置在 PATH 中。")

    def uninstall_app(package_name):
        """
        卸载指定包名的应用
        package_name:应用名称
        """
        try:
            # 使用 ADB 卸载应用
            subprocess.run(["adb", "uninstall", package_name], check=True)
            print(f"成功卸载应用: {package_name}")
        except subprocess.CalledProcessError as e:
            print(f"卸载失败: {e}")
        except FileNotFoundError:
            print("未找到 ADB，确保 ADB 已安装并正确配置在 PATH 中。")

    def shutdown_device():
        """通过 ADB 命令关闭 Android 设备"""
        try:
            # 使用 ADB 进行关机
            subprocess.run(["adb", "shell", "reboot", "-p"], check=True)
            print("设备正在关机...")
        except subprocess.CalledProcessError as e:
            print(f"关机失败: {e}")
        except FileNotFoundError:
            print("未找到 ADB，确保 ADB 已安装并正确配置在 PATH 中。")

    def reboot_device():
        """通过 ADB 命令重启 Android 设备"""
        try:
            # 使用 ADB 进行关机
            subprocess.run(["adb", "reboot"], check=True)
            print("设备正在关机...")
        except subprocess.CalledProcessError as e:
            print(f"关机失败: {e}")
        except FileNotFoundError:
            print("未找到 ADB，确保 ADB 已安装并正确配置在 PATH 中。")

    def reboot_to_recovery():
        """通过 ADB 命令重启 Android 设备到恢复模式"""
        try:
            # 使用 ADB 进入恢复模式
            subprocess.run(["adb", "reboot", "recovery"], check=True)
            print("设备正在重启到恢复模式...")
        except subprocess.CalledProcessError as e:
            print(f"重启到恢复模式失败: {e}")
        except FileNotFoundError:
            print("未找到 ADB，确保 ADB 已安装并正确配置在 PATH 中。")

    def usb():
        """通过 USB 连接 Android 设备"""
        try:
            result = subprocess.run(["adb", "devices"], capture_output=True, text=True)

            if "device" in result.stdout:
                """设备已通过 USB 连接"""
                pass

            else:
                print("没有找到已连接的设备，请确认 USB 调试已开启。")
        except FileNotFoundError:
            print("未找到 ADB，确保 ADB 已安装并正确配置在 PATH 中。")

    def getip():
        """获取设备的 IP 地址"""
        try:
            result = subprocess.run(["adb", "shell", "ip", "route"], capture_output=True, text=True)
            # 使用正则表达式提取 IP 地址
            ip_address = re.search(r'(\d+\.\d+\.\d+\.\d+)', result.stdout)
            if ip_address:
                return ip_address.group(0)
            else:
                print("未能获取设备 IP 地址，请确认设备已连接。")
                return None
        except FileNotFoundError:
            print("未找到 ADB，确保 ADB 已安装并正确配置在 PATH 中。")
            return None

    def wifi(ip_address):
        """
        通过 Wi-Fi 连接 Android 设备
        ip_address:Android设备的ip地址,可以从getip函数获取.
        """
        try:
            """进入无限调试模式"""
            subprocess.run(["adb", "tcpip", "5555"], check=True)
            # 通过 IP 地址连接设备
            subprocess.run(["adb", "connect", ip_address + ":5555"], check=True)
            print(f"成功连接到设备：{ip_address}")
        except subprocess.CalledProcessError as e:
            print(f"连接失败: {e}")

    def commands(command):
        """
        执行给定的命令
        command:命令
        """
        try:
            # 使用 ADB 执行命令
            result = subprocess.run(command, capture_output=True, text=True)
            return result.stdout
        except Exception as e:
            print(f"命令执行失败: {e}")
            return None

    def root():
        """尝试切换到 Root 用户"""
        command = ["adb", "shell", "su"]
        output = execute_command(command)

        if "permission denied" in output.lower():
            print("没有权限切换到 Root 用户，确保设备已 Root 并安装了适当的权限管理。")

        else:
            print("已成功切换到 Root 用户。")

def admin():
    """判断有没有管理员权限"""
    try:
        return ctypes.windll.shell32.IsUserAnAdmin()
    except:
        return False

def uac():
    """弹出请求管理员权限界面"""
    ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1)

class Setting(adb):
    desktop = desktop()
    user = username()
    time_cur = timecur()
    admin = admin()
    
ADB = adb
android = adb
DESKTOP = desktop()
USERNAME = username()
folder_path = os.path.expanduser("~")

def cwd():
    """get? 获取当前工作目录"""
    if os.name == 'nt':  # Windows
        kernel32 = ctypes.WinDLL('kernel32')
        buffer = ctypes.create_unicode_buffer(260)
        kernel32.GetCurrentDirectoryW(260, buffer)
        return buffer.value
        
    else:  # Unix/Linux
        libc = ctypes.CDLL(ctypes.util.find_library('c'))
        buffer = ctypes.create_string_buffer(4096)
        libc.getcwd(buffer, 4096)
        return buffer.value.decode('utf-8')


def pytodll(file):
    """将py文件编译成dll文件(实验性,可能无法生成可用的dll文件)"""
    python_file = file
    if python_file:
        with open("converted.pyx", "w") as f:
            with open(python_file, "r") as py_file:
                f.write(py_file.read())

        with open("setup.py", "w") as f:
            f.write("""
    from setuptools import setup
    from Cython.Build import cythonize

    setup(
        ext_modules=cythonize("converted.pyx"),
    )
    """)
        # 运行 setup.py 以编译 .pyx 文件为 DLL
        result = subprocess.run(["python", "setup.py", "build_ext", "--inplace"], capture_output=True, text=True)
        if result.returncode == 0:
            print("DLL 文件已生成。")
        else:
            print("生成 DLL 失败:", result.stderr)

    else:
        print("未选择文件。")

if __name__ == '__main__':
    print('当前时间:',timecur())
    default('hyypns','larry3d')
    default('modole','larry3d')
    print('hyypns modole')
    input()