#pragma once
#include <Windows.h>
#include <string>

class Registry {
public:
    // 定义注册表值的类型枚举
    enum class RegistryValueKind {
        None = REG_NONE,           // 无类型
        String = REG_SZ,           // 字符串类型
        ExpandString = REG_EXPAND_SZ,   // 可扩展字符串类型
        Binary = REG_BINARY,       // 二进制类型
        DWord = REG_DWORD,         // 双字类型
        QWord = REG_QWORD,         // 四字类型
        MultiString = REG_MULTI_SZ // 多字符串类型
    };

    /**
      * @brief 设置注册表值
      *
      * @param hKey 注册表主键
      * @param subKey 子键路径
      * @param valueName 值名称
      * @param data 指向要写入的数据的指针
      * @param dataSize 要写入的数据的大小(字节数)
      * @param kind 值的类型
      * @param use64View 是否使用 64 位注册表视图(默认为 false)
      * @return true 设置成功
      * @return false 设置失败
      */
    static bool SetValue(HKEY hKey, const std::string& subKey, const std::string& valueName, const void* data, DWORD dataSize, RegistryValueKind kind, bool use64View = false) {
        if (subKey.empty() || valueName.empty()) {
            return false;
        }

        const DWORD flags = use64View ? KEY_WOW64_64KEY : 0;

        HKEY hKey_;
        LONG result = RegCreateKeyEx(hKey, subKey.c_str(), 0, nullptr, REG_OPTION_NON_VOLATILE, KEY_WRITE | flags, nullptr, &hKey_, nullptr);
        if (result != ERROR_SUCCESS) {
            return false;
        }

        result = RegSetValueEx(hKey_, valueName.c_str(), 0, static_cast<DWORD>(kind), static_cast<const BYTE*>(data), dataSize);
        if (result != ERROR_SUCCESS) {
            RegCloseKey(hKey_);
            return false;
        }

        RegCloseKey(hKey_);
        return true;
    }

    /**
     * @brief 获取注册表值
     *
     * @param hKey 注册表主键
     * @param subKey 子键路径
     * @param valueName 值名称
     * @param data 指向存储获取到的数据的缓冲区的指针
     * @param dataSize 输入为要读取的数据缓冲区的大小,输出为实际读取的数据大小(字节数)
     * @param kind 输出参数,用于返回值的类型
     * @param use64View 是否使用 64 位注册表视图(默认为 false)
     * @return true 获取成功
     * @return false 获取失败
     */
    static bool GetValue(HKEY hKey, const std::string& subKey, const std::string& valueName, void* data, DWORD& dataSize, RegistryValueKind& kind, bool use64View = false) {
        if (subKey.empty() || valueName.empty()) {
            return false;
        }

        const DWORD flags = use64View ? KEY_WOW64_64KEY : 0;

        HKEY hKey_;
        LONG result = RegOpenKeyEx(hKey, subKey.c_str(), 0, KEY_READ | flags, &hKey_);
        if (result != ERROR_SUCCESS) {
            return false;
        }

        result = RegQueryValueEx(hKey_, valueName.c_str(), nullptr, reinterpret_cast<LPDWORD>(&kind), static_cast<LPBYTE>(data), &dataSize);
        if (result != ERROR_SUCCESS) {
            RegCloseKey(hKey_);
            return false;
        }

        RegCloseKey(hKey_);
        return true;
    }

    /**
     * @brief 删除注册表项
     *
     * @param hKey 注册表主键
     * @param subKey 子键路径
     * @return true 删除成功
     * @return false 删除失败
     */
    static bool DeleteKey(HKEY hKey, const std::string& subKey) {
        if (subKey.empty()) {
            return false;
        }

        const LONG result = RegDeleteKey(hKey, subKey.c_str());
        if (result != ERROR_SUCCESS) {
            return false;
        }
        return true;
    }

    /**
     * @brief 删除注册表值
     *
     * @param hKey 注册表主键
     * @param subKey 子键路径
     * @param valueName 值名称
     * @param use64View 是否使用 64 位注册表视图(默认为 false)
     * @return true 删除成功
     * @return false 删除失败
     */
    static bool DeleteValue(HKEY hKey, const std::string& subKey, const std::string& valueName, bool use64View = false) {
        if (subKey.empty() || valueName.empty()) {
            return false;
        }

        const DWORD flags = use64View ? KEY_WOW64_64KEY : 0;

        HKEY hKey_;
        LONG result = RegOpenKeyEx(hKey, subKey.c_str(), 0, KEY_WRITE | flags, &hKey_);
        if (result != ERROR_SUCCESS) {
            return false;
        }

        result = RegDeleteValue(hKey_, valueName.c_str());
        if (result != ERROR_SUCCESS) {
            return false;
        }

        RegCloseKey(hKey_);
        return true;
    }
};