#include "pch.h"

#include "tunnel.h"
#include "usrerr.h"
#include "globalcfg.h"
#include "httplib.h"
#include "misc.h"
#include "network.h"
#include "protocol.h"
#include "user.h"

#include <shlwapi.h>
#include <strsafe.h>

static HANDLE                 g_HeartTimerQueue = nullptr;
static LPTUNNEL_HEART_ROUTINE g_lpHeartCb       = nullptr;

int RemoteHeartControl(bool isStart, LPTUNNEL_HEART_ROUTINE lpHeartCbAddress) {
    if (isStart && lpHeartCbAddress == nullptr) {
        SPDLOG_ERROR(TEXT("Input lpHeartCbAddress params nullptr"));
        return -ERR_INPUT_PARAMS;
    }

    g_lpHeartCb = lpHeartCbAddress;

    if (isStart) {
        if (!g_HeartTimerQueue) {
            HANDLE hTimer     = nullptr;
            // Create the timer queue.
            g_HeartTimerQueue = CreateTimerQueue();
            if (nullptr == g_HeartTimerQueue) {
                SPDLOG_ERROR(TEXT("CreateTimerQueue failed ({0})"), GetLastError());
                return -ERR_CREATE_TIMER;
            }

            // Set a timer to call the timer routine in 10 seconds.
            if (!CreateTimerQueueTimer(
                    &hTimer,
                    g_HeartTimerQueue,
                    [](PVOID lpParam, BOOLEAN TimerOrWaitFired) {
                        int                              ret;
                        ProtocolRequest<ReqHeartParams>  req;
                        ProtocolResponse<RspHeartParams> rsp;

                        ret = ProtolPostMessage(SET_CLIENTHEART_PATH, &req, &rsp, false);
                        if (g_lpHeartCb && ret) {
                            g_lpHeartCb(rsp.msgContent.message.c_str(), rsp.timeStamp);
                        }
                    },
                    nullptr,
                    0,
                    HEART_PERIOD_MS,
                    WT_EXECUTEDEFAULT)) {
                SPDLOG_ERROR(TEXT("CreateTimerQueueTimer failed ({0})"), GetLastError());
                return -ERR_CREATE_TIMER;
            }
        }
    } else {
        if (g_HeartTimerQueue) {
            if (!DeleteTimerQueue(g_HeartTimerQueue)) {
                SPDLOG_ERROR(TEXT("DeleteTimerQueue failed ({0})"), GetLastError());
                g_HeartTimerQueue = nullptr;
                return -ERR_DELETE_TIMER;
            }

            g_HeartTimerQueue = nullptr;
        }
    }

    return ERR_SUCCESS;
}

int RemoteWireGuardControl(bool isStart) {
    int                                   ret;
    ProtocolRequest<ReqStartTunnelParams> req;
    ProtocolResponse<ResponseStatus>      rsp;

    req.msgContent.isStart = isStart;

    ret = ProtolPostMessage(SET_CLIENTSTART_TUNNEL, &req, &rsp, false);

    if (ret != ERR_SUCCESS) {
        return ret;
    }

    if (rsp.msgContent.errCode != ERR_SUCCESS) {
        SPDLOG_ERROR(TEXT("Service Response error({0}): {1}"), rsp.msgContent.errCode, rsp.msgContent.errMessage);
        return rsp.msgContent.errCode;
    }

    return ERR_SUCCESS;
}

int LocalWireGuardControl(bool isStart, bool setPrivateMode) {
    int  ret;
    bool chkStatus = false;
    int  ifInetlnetIndex, ifWireGuardIndex;

    // 获取 Intelnet 网络网卡 Index
    if ((ret = GetInternetIfIndex(&ifInetlnetIndex)) != ERR_SUCCESS) {
        SPDLOG_ERROR(TEXT("Call GetInternetIfIndex error: {0}"), ret);
        return ret;
    }

    // 判断先前是否启动过服务
    if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &chkStatus)) != ERR_SUCCESS) {
        SPDLOG_ERROR(TEXT("Call IsWireGuardServerInstalled error: {0}"), ret);
        return ret;
    }

    // 先停止以前启动的隧道服务
    if (chkStatus) {
        if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
            // 返回停止服务失败
            SPDLOG_ERROR(TEXT("Call WireGuardUnInstallServerService error: {0}"), ret);
            return ret;
        }
    }

    // 检查 Internet 网络共享状态
    if ((ret = GetNetIntelnetConnectionSharing(ifInetlnetIndex, &chkStatus)) != ERR_SUCCESS) {
        SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
        return ret;
    }

    // 关闭 Intelnet 网络连接共享
    if (chkStatus) {
        if ((ret = SetNetIntelnetConnectionSharing(ifInetlnetIndex, false, false)) != ERR_SUCCESS) {
            SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
            return ret;
        }
    }

    if (isStart) {
        // 启动服务
        ret = WireGuardInstallDefaultServerService(true);
        if (ret != ERR_SUCCESS) {
            // 返回启动服务失败
            SPDLOG_ERROR(TEXT("Call WireGuardInstallDefaultServerService error: {0}"), ret);
            return ret;
        }

        if (GetCurrentNetShareMode() == ICS_SHARE_MODE) {
            // 获取 WireGuard 隧道网络网卡 Index
            if ((ret = GetInterfaceIfIndexByName(GetGlobalCfgInfo()->userCfg.userName, &ifWireGuardIndex)) !=
                ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call GetInterfaceIfIndexByName error: {0}"), ret);
                return ret;
            }

            // 启动 WireGard 网络 ICS 服务为私有网络
            if ((ret = SetNetIntelnetConnectionSharing(ifWireGuardIndex, true, true)) != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
                return ret;
            }

            // 启动 Intelnet 网络 ICS 服务为公共网络
            if ((ret = SetNetIntelnetConnectionSharing(ifInetlnetIndex, true, false)) != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
                return ret;
            }

            // 校验 ICS 共享状态
            // 检查 WireGuard 网络共享状态
            if ((ret = GetNetIntelnetConnectionSharing(ifWireGuardIndex, &chkStatus)) != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
                return ret;
            }

            if (!chkStatus) {
                SPDLOG_ERROR(TEXT("WireGuard network ICS error"));
                return -ERR_NET_WIREGUARD_ICS;
            }

            // 检查 WireGuard 网络共享状态
            if ((ret = GetNetIntelnetConnectionSharing(ifInetlnetIndex, &chkStatus)) != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
                return ret;
            }

            if (!chkStatus) {
                SPDLOG_ERROR(TEXT("Internet network ICS error"));
                return -ERR_NET_WIREGUARD_ICS;
            }

            SPDLOG_INFO(TEXT("Net Share Service Work now on ICS mode: {0}"), GetGlobalCfgInfo()->userCfg.userName);
        } else if (GetCurrentNetShareMode() == NAT_SHARE_MODE) {
            IP_INFO ipInfo;
            TCHAR   ipNat[MAX_IP_LEN];
            GetIpV4InfoFromCIDR(GetGlobalCfgInfo()->userCfg.cliConfig.cliAddress, &ipInfo);
            StringCbPrintf(ipNat, MAX_IP_LEN, TEXT("%s/%d"), ipInfo.hostmax, ipInfo.prefix);

            // 检查 WireGuard 网络共享状态
            if ((ret = SetNATRule(GetGlobalCfgInfo()->userCfg.userName, ipNat)) != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
                return ret;
            }

            SPDLOG_INFO(TEXT("Net Share Service Work now on NAT mode: {0}_nat --> {1}"),
                        GetGlobalCfgInfo()->userCfg.userName,
                        ipNat);
        } else {
            SPDLOG_ERROR(TEXT("Not support Net Share Type: {0}"), static_cast<int>(GetCurrentNetShareMode()));
            return -ERR_UN_SUPPORT;
        }
    } else {
        if (GetCurrentNetShareMode() == NAT_SHARE_MODE) {
            // 检查 WireGuard 网络共享状态
            if ((ret = RemoveNATRule(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call RemoveNATRule error: {0}"), ret);
                return ret;
            }
        }
        SPDLOG_INFO(TEXT("Net Share Service Stoped: {0}"), GetGlobalCfgInfo()->userCfg.userName);
    }

    return ERR_SUCCESS;
}

int RemoteCtrlSvrCfgUserTunnel(int vmId, const TCHAR *pCliNetwork) {
    const PUSER_CONFIG        pUser    = &GetGlobalCfgInfo()->userCfg;
    const PUSER_CLIENT_CONFIG pUserCfg = &pUser->cliConfig;

    for (int i = 0; i < pUserCfg->tolVM; i++) {
        if (pUserCfg->pVMConfig[i].vmId == vmId) {
            IP_INFO                                  ipInfo = {};
            int                                      ret;
            ProtocolRequest<ReqUserSetCliCfgParams>  req;
            ProtocolResponse<RspUserSetCliCfgParams> rsp;

            req.msgContent.cliPublicKey = pUserCfg->cliPublicKey;
            req.msgContent.cliNetwork   = pCliNetwork;
            GetIpV4InfoFromCIDR(pUserCfg->cliAddress, &ipInfo);
            req.msgContent.cliTunnelAddr = ipInfo.ip;

            GetGlobalCfgInfo()->curConnVmId = vmId;            
            SPDLOG_DEBUG(TEXT("Current VMID: {0}"), vmId);

            // 连接到服务端控制服务
            InitControlServer(pUserCfg->pVMConfig[i].scgGateWay);

            // 发送本地配置参数到控制服务
            ret = ProtolPostMessage(SET_CLIENTCFG_PATH, &req, &rsp, false);

            if (ret != ERR_SUCCESS) {
                return ret;
            }

            if (rsp.msgContent.errCode != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Service Response error({0}): {1}"),
                             rsp.msgContent.errCode,
                             rsp.msgContent.errMessage);
                return rsp.msgContent.errCode;
            }

            // 返回成功配置本地参数
            ret = SetTunnelConfigure(pUserCfg->cliPrivateKey,
                                     pUserCfg->pVMConfig[i].svrPublicKey,
                                     pUserCfg->pVMConfig[i].vmNetwork,
                                     pUserCfg->cliAddress,
                                     rsp.msgContent.svrNetwork.c_str(),
                                     pUserCfg->pVMConfig[i].scgTunnelGw);

            if (ret != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("SetTunnelConfigure Error: {0}"), ret);
                return ret;
            }

            return ERR_SUCCESS;
        }
    }

    return -ERR_ITEM_UNEXISTS;
}

int SetTunnelConfigure(const TCHAR *pCliPrivateKey,
                       const TCHAR *pSvrPublicKey,
                       const TCHAR *pSvrNetwork,
                       const TCHAR *pCliNetwork,
                       const TCHAR *pSvrTunnelAddr,
                       const TCHAR *pSvrEndPoint) {
    int             ret;
    bool            isSvrStart = false;
    int             ifInetlnetIndex;
    IP_INFO         tunnelInfo = {};
    IP_INFO         svrInfo    = {};
    WGCLIENT_CONFIG cliCfg     = {};

#pragma region

    if (pCliPrivateKey == nullptr || lstrlen(pCliPrivateKey) == 0) {
        SPDLOG_ERROR(TEXT("Input pCliPrivateKey error: {0}"), pCliPrivateKey);
        return -ERR_INPUT_PARAMS;
    }

    if (pSvrPublicKey == nullptr || lstrlen(pSvrPublicKey) == 0) {
        SPDLOG_ERROR(TEXT("Input pSvrPublicKey error: {0}"), pSvrPublicKey);
        return -ERR_INPUT_PARAMS;
    }

    if (pSvrNetwork == nullptr || lstrlen(pSvrNetwork) == 0) {
        SPDLOG_ERROR(TEXT("Input pSvrNetwork error: {0}"), pSvrNetwork);
        return -ERR_INPUT_PARAMS;
    }

    if (pCliNetwork == nullptr || lstrlen(pCliNetwork) == 0) {
        SPDLOG_ERROR(TEXT("Input pCliNetwork error: {0}"), pCliNetwork);
        return -ERR_INPUT_PARAMS;
    }

    if (pSvrTunnelAddr == nullptr || lstrlen(pSvrTunnelAddr) == 0) {
        SPDLOG_ERROR(TEXT("Input pSvrTunnelAddr error: {0}"), pSvrTunnelAddr);
        return -ERR_INPUT_PARAMS;
    }

    if (pSvrEndPoint == nullptr || lstrlen(pSvrEndPoint) == 0) {
        SPDLOG_ERROR(TEXT("Input pSvrEndPoint error: {0}"), pSvrEndPoint);
        return -ERR_INPUT_PARAMS;
    }

#pragma endregion 参数检查

    // 判断先前是否启动过服务
    if ((ret = IsWireGuardServerRunning(GetGlobalCfgInfo()->userCfg.userName, &isSvrStart)) != ERR_SUCCESS) {
        SPDLOG_ERROR(TEXT("IsWireGuardServerInstalled error: {0}"), ret);
        return ret;
    }

    // 停止先前隧道网络
    if (isSvrStart) {
        SPDLOG_DEBUG(TEXT("WireGuardUnInstallServerService: {0}"), GetGlobalCfgInfo()->userCfg.userName);
        if ((ret = WireGuardUnInstallServerService(GetGlobalCfgInfo()->userCfg.userName)) != ERR_SUCCESS) {
            // 返回停止服务失败
            SPDLOG_ERROR(TEXT("WireGuardUnInstallServerService error: {0}"), ret);
            return ret;
        }
    }

    // 获取 Intelnet 网络网卡 Index
    if ((ret = GetInternetIfIndex(&ifInetlnetIndex)) != ERR_SUCCESS) {
        SPDLOG_ERROR(TEXT("Call GetInternetIfIndex error: {0}"), ret);
        return ret;
    }

    if (GetCurrentNetShareMode() == ICS_SHARE_MODE) {
        // 检查 Internet 网络共享状态
        if ((ret = GetNetIntelnetConnectionSharing(ifInetlnetIndex, &isSvrStart)) != ERR_SUCCESS) {
            SPDLOG_ERROR(TEXT("Call GetNetIntelnetConnectionSharing error: {0}"), ret);
            return ret;
        }

        // 关闭 Intelnet 网络连接共享
        if (isSvrStart) {
            if ((ret = SetNetIntelnetConnectionSharing(ifInetlnetIndex, false, false)) != ERR_SUCCESS) {
                SPDLOG_ERROR(TEXT("Call SetNetIntelnetConnectionSharing error: {0}"), ret);
                return ret;
            }
        }
    }

    ret = GetIpV4InfoFromCIDR(pSvrTunnelAddr, &tunnelInfo);

    if (ret != ERR_SUCCESS) {
        return ret;
    }

    ret = GetIpV4InfoFromCIDR(pSvrNetwork, &svrInfo);

    if (ret != ERR_SUCCESS) {
        return ret;
    }

    memset(&cliCfg, 0, sizeof(WGCLIENT_CONFIG));

    StringCbCopy(cliCfg.Name, 64, GetGlobalCfgInfo()->userCfg.userName);
    StringCbCopy(cliCfg.PrivateKey, 64, pCliPrivateKey);
    StringCbCopy(cliCfg.Address, 32, pCliNetwork);
    StringCbCopy(cliCfg.SvrPubKey, 64, pSvrPublicKey);
    if (UsedSCGProxy()) {
        StringCbPrintf(cliCfg.ServerURL, 256, TEXT("127.0.0.1:%d"), GetGlobalCfgInfo()->scgProxy.proxyPort);
    } else {
        StringCbCopy(cliCfg.ServerURL, 256, pSvrEndPoint);
    }

    StringCbPrintf(cliCfg.AllowNet,
                   256,
                   TEXT("%s/%d,%s/%d"),
                   tunnelInfo.network,
                   tunnelInfo.prefix,
                   svrInfo.network,
                   svrInfo.prefix);

    ret = WireGuardCreateClientConfig(&cliCfg);

    if (ret != ERR_SUCCESS) {
        return ret;
    }

    return ERR_SUCCESS;
}

int GetUserServerConfigure(const TCHAR *pUserName, const TCHAR *pToken, PUSER_SERVER_CONFIG *pSvrCfg) {
    int                 ret;
    PUSER_CONFIG        pUser    = &GetGlobalCfgInfo()->userCfg;
    PUSER_SERVER_CONFIG pUserCfg = &pUser->svrConfig;

    ProtocolRequest<ReqGetUserCfgParams>   req;
    ProtocolResponse<RspUserSevrCfgParams> rsp;

    if (pSvrCfg == nullptr) {
        SPDLOG_ERROR(TEXT("Input pSvrCfg params error"));
        return -ERR_INPUT_PARAMS;
    }

    if (pToken == nullptr || lstrlen(pToken) == 0) {
        SPDLOG_ERROR(TEXT("Input pToken params error: {0}"), pToken);
        return -ERR_INPUT_PARAMS;
    }

    if (pUserName && lstrlen(pUserName) > 0) {
        memset(pUser->userName, 0, MAX_PATH);
        StringCbCopy(pUser->userName, MAX_PATH, pUserName);
    } else {
        StringCbCopy(pUser->userName, MAX_PATH, TEXT("tunnel_svr"));
    }

    StringCbCopy(pUser->userToken, MAX_PATH, pToken);

    req.msgContent.token = pToken;
    req.msgContent.user  = pUser->userName;

    ret = ProtolPostMessage(GET_SERVERCFG_PATH, &req, &rsp, true);

    if (ret != ERR_SUCCESS) {
        return ret;
    }

    pUserCfg->svrListenPort = rsp.msgContent.svrListenPort;
    StringCbCopy(pUserCfg->svrPrivateKey, 64, rsp.msgContent.svrPrivateKey.c_str());
    StringCbCopy(pUserCfg->svrAddress, MAX_IP_LEN, rsp.msgContent.svrAddress.c_str());

    *pSvrCfg = pUserCfg;
    return ERR_SUCCESS;
}

int GetUserClientConfigure(const TCHAR *pUserName, const TCHAR *pToken, PUSER_CLIENT_CONFIG *pCliCfg) {
    PUSER_CONFIG        pUser    = &GetGlobalCfgInfo()->userCfg;
    PUSER_CLIENT_CONFIG pUserCfg = &pUser->cliConfig;
    TCHAR               userPath[MAX_PATH];
    int                 ret;

    ProtocolRequest<ReqGetUserCfgParams>    req;
    ProtocolResponse<RspUsrCliConfigParams> rsp;

    if (pUserName == nullptr || lstrlen(pUserName) == 0) {
        SPDLOG_ERROR(TEXT("Input pUserName params error: {0}"), pUserName);
        return -ERR_INPUT_PARAMS;
    }

    if (pToken == nullptr || lstrlen(pToken) == 0) {
        SPDLOG_ERROR(TEXT("Input pToken params error: {0}"), pToken);
        return -ERR_INPUT_PARAMS;
    }

    if (pCliCfg == nullptr) {
        SPDLOG_ERROR(TEXT("Input pCliCfg params error"));
        return -ERR_INPUT_PARAMS;
    }

    StringCbPrintf(userPath, MAX_PATH, "%s\\%s", GetGlobalCfgInfo()->configDirectory, pUserName);
    // 如果配置目录不存在则自动创建
    if (!PathFileExists(userPath)) {
        if (!CreateDirectory(userPath, nullptr)) {
            SPDLOG_ERROR(TEXT("Create user {1} directory '{0}' error."), userPath, pUserName);
            return -ERR_CREATE_FILE;
        }
    }

    memset(pUser->userName, 0, MAX_PATH);
    if (pUserName && lstrlen(pUserName) > 0) {
        StringCbCopy(pUser->userName, MAX_PATH, pUserName);
    }
    StringCbCopy(pUser->userToken, MAX_PATH, pToken);

    req.msgContent.token = pToken;
    req.msgContent.user  = pUserName;

    ret = ProtolPostMessage(GET_CLIENTCFG_PATH, &req, &rsp, true);

    if (ret != ERR_SUCCESS) {
        return ret;
    }
        
    StringCbCopy(pUserCfg->cliPrivateKey, 64, rsp.msgContent.cliPrivateKey.c_str());
    StringCbCopy(pUserCfg->cliPublicKey, 64, rsp.msgContent.cliPublicKey.c_str());
    StringCbCopy(pUserCfg->cliAddress, MAX_IP_LEN, rsp.msgContent.cliAddress.c_str());

    if (!rsp.msgContent.vmConfig.empty()) {
        PVM_CFG      pVm;
        unsigned int memSize = sizeof(VM_CFG) * static_cast<UINT>(rsp.msgContent.vmConfig.size());
        pUserCfg->pVMConfig  = static_cast<PVM_CFG>(CoTaskMemAlloc(memSize));
        if (pUserCfg->pVMConfig == nullptr) {
            SPDLOG_ERROR(TEXT("Error allocating memory {0} bytes"), memSize);
            return -ERR_MALLOC_MEMORY;
        }

        memset(pUserCfg->pVMConfig, 0, memSize);

        pUserCfg->tolVM = static_cast<int>(rsp.msgContent.vmConfig.size());
        pVm             = pUserCfg->pVMConfig;

        for (auto vm : rsp.msgContent.vmConfig) {
            TCHAR tmpAddr[MAX_PATH];
            pVm->vmId = vm.vmId;
            StringCbCopy(pVm->vmName, MAX_PATH, vm.vmName.c_str());
            StringCbCopy(pVm->svrPublicKey, 64, vm.svrPublicKey.c_str());
            StringCbCopy(pVm->vmNetwork, MAX_IP_LEN, vm.vmNetwork.c_str());
            //StringCbCopy(pVm->scgGateWay, MAX_PATH, vm.scgGateway.c_str());
            StringCbPrintf(pVm->scgGateWay, MAX_PATH, TEXT("http://%s"), vm.scgGateway.c_str());
            StringCbCopy(tmpAddr, MAX_PATH, vm.scgGateway.c_str());
            httplib::Client cli(pVm->scgGateWay);
            StringCbPrintf(pVm->scgTunnelGw, MAX_PATH, TEXT("%s:%d"), cli.host().c_str(), cli.port() - 1);
            pVm++;
        }
    }

    *pCliCfg = pUserCfg;
    return ERR_SUCCESS;
}

int GetUserConfigFiles(const TCHAR *pUserName, PUSER_CFGFILE *pCfgFile, int *pItems) {
    PUSER_CFGFILE pCfg;
    FILE_LIST     fileList         = {nullptr, 0};
    TCHAR         fnPath[MAX_PATH] = {};
    TCHAR         cfgVal[MAX_PATH];
    bool          isSelected = false;

    if (pUserName == nullptr || lstrlen(pUserName) == 0) {
        SPDLOG_ERROR(TEXT("Input pUserName params error: {0}"), pUserName);
        return -ERR_INPUT_PARAMS;
    }

    if (pCfgFile == nullptr) {
        SPDLOG_ERROR(TEXT("Input pCfgFile params error"));
        return -ERR_INPUT_PARAMS;
    }

    if (pItems == nullptr) {
        SPDLOG_ERROR(TEXT("Input pItems params error"));
        return -ERR_INPUT_PARAMS;
    }

    GetPrivateProfileString(CFG_WIREGUARD_SECTION,
                            CFG_WGCFG_PATH,
                            TEXT(""),
                            cfgVal,
                            MAX_PATH,
                            GetGlobalCfgInfo()->cfgPath);

    if (PathFileExists(cfgVal)) {
        isSelected = true;
    }

    StringCbPrintf(fnPath, MAX_PATH, "%s\\%s\\*.conf", GetGlobalCfgInfo()->configDirectory, pUserName);

    int ret = FindFile(fnPath, &fileList, false);

    if (ret != ERR_SUCCESS) {
        SPDLOG_ERROR(TEXT("Find WireGuard user {1} configure file  error: {0}"), ret, pUserName);
        return ret;
    }

    pCfg = static_cast<PUSER_CFGFILE>(CoTaskMemAlloc(sizeof(USER_CFGFILE) * fileList.nItems));

    if (pCfg == nullptr) {
        SPDLOG_ERROR(TEXT("Error allocating memory {0} bytes"), sizeof(USER_CFGFILE) * fileList.nItems);
        return -ERR_SUCCESS;
    }

    memset(pCfg, 0, sizeof(USER_CFGFILE) * fileList.nItems);

    *pCfgFile = pCfg;
    *pItems   = static_cast<int>(fileList.nItems);

    for (unsigned int i = 0; fileList.pFilePath && i < fileList.nItems; i++) {
        StringCbCopy(pCfg->CfgPath, MAX_PATH, fileList.pFilePath[i].path);
        if (isSelected && StrCmp(pCfg->CfgPath, cfgVal) == 0) {
            pCfg->isCurrent = true;
        } else {
            pCfg->isCurrent = false;
        }
        pCfg++;
    }

    if (fileList.pFilePath) {
        HeapFree(GetProcessHeap(), 0, fileList.pFilePath);
    }

    return ERR_SUCCESS;
}