#include <cstdio>
#include <netcon.h>
#include <atlstr.h>

static int WideCharToTChar2(const WCHAR *pWStr, TCHAR *pOutStr, int maxOutLen) {
    if (sizeof(TCHAR) == sizeof(WCHAR)) {
        if (wcslen(pWStr) * sizeof(WCHAR) >= maxOutLen) {
            return -1;
        }
        memcpy(pOutStr, pWStr, wcslen(pWStr));
    } else {
        int len = WideCharToMultiByte(CP_ACP, 0, pWStr, static_cast<int>(wcslen(pWStr)), nullptr, 0, nullptr, nullptr);

        if (len >= maxOutLen) {
            return -1;
        }

        WideCharToMultiByte(CP_ACP, 0, pWStr, static_cast<int>(wcslen(pWStr)), pOutStr, len, nullptr, nullptr);
        pOutStr[len] = 0;

        return 0;
    }
}

HRESULT shareNet2(INetSharingManager *pNSM) {    // this is done in 2 parts:
    // 1:  enum connections until we get one that we can convert into an INetSharingConfiguration
    // 2:  then, enum portmappings, and delete if we find a match.

    // PART 1: find a valid connection
    INetConnection *pNC = nullptr;    // fill this out for part 2 below

    INetSharingEveryConnectionCollection *pNSECC = nullptr;
    HRESULT                               hr     = pNSM->get_EnumEveryConnection(&pNSECC);
    if (!pNSECC) {
        printf("failed to get EveryConnectionCollection!\r\n");
    } else {
        // enumerate connections
        IEnumVARIANT *pEV  = nullptr;
        IUnknown     *pUnk = nullptr;
        hr                 = pNSECC->get__NewEnum(&pUnk);
        if (pUnk) {
            hr = pUnk->QueryInterface(__uuidof(IEnumVARIANT), (void **)&pEV);
            pUnk->Release();
        }
        if (pEV) {
            VARIANT v;
            VariantInit(&v);
            BOOL bFoundIt = FALSE;
            while (S_OK == pEV->Next(1, &v, nullptr)) {
                if (V_VT(&v) == VT_UNKNOWN) {
                    V_UNKNOWN(&v)->QueryInterface(__uuidof(INetConnection), (void **)&pNC);
                    if (pNC) {
                        INetConnectionProps *pNCP = nullptr;
                        pNSM->get_NetConnectionProps(pNC, &pNCP);
                        if (!pNCP) {
                            printf("failed to get NetConnectionProps!\r\n");
                        } else {
                            // check properties for firewalled or shared connection
                            DWORD dwCharacteristics = 0;
                            pNCP->get_Characteristics(&dwCharacteristics);
                            if (dwCharacteristics & (NCCF_SHARED | NCCF_FIREWALLED)) {
                                NETCON_MEDIATYPE MediaType = NCM_NONE;
                                pNCP->get_MediaType(&MediaType);
                                if ((MediaType != NCM_SHAREDACCESSHOST_LAN) &&
                                    (MediaType != NCM_SHAREDACCESSHOST_RAS)) {
                                    // got a shared/firewalled connection
                                    bFoundIt = TRUE;
                                }
                            }

                            BSTR  sName = {};
                            TCHAR ifName[MAX_PATH];

                            pNCP->get_Name(&sName);

                            WideCharToTChar2(sName, ifName, MAX_PATH);
                            SysFreeString(sName);

                            printf("Get NC Name %s\r\n", ifName);
                            if(strcmp(ifName, "admin") == 0) {
                                bFoundIt = TRUE;
                            }
                            pNCP->Release();
                        }
                        if (bFoundIt == FALSE) {
                            pNC->Release();
                            pNC = nullptr;
                        }
                    }
                }
                VariantClear(&v);
                if (bFoundIt == TRUE) {
                    break;
                }
            }
            pEV->Release();
        }
        pNSECC->Release();
    }
    if (pNC == nullptr) {
        printf("failed to find a valid connection!\r\n");
        return E_FAIL;
    }
    INetSharingConfiguration *pNSC = nullptr;
    hr                             = pNSM->get_INetSharingConfigurationForINetConnection(pNC, &pNSC);

    if (!pNSC) {
        printf("can't make INetSharingConfiguration object!\r\n");
        return hr;
    }

    NETCON_PROPERTIES *pNP = nullptr;
    pNC->GetProperties(&pNP);

    hr = pNSM->get_INetSharingConfigurationForINetConnection(pNC, &pNSC);
    printf("**************find nic srcName : %s\r\n", static_cast<const char *>(CW2A(pNP->pszwName)));
    //hr = pNSC->DisableSharing();
    Sleep(500);
    //getchar();
    hr = pNSC->EnableSharing(ICSSHARINGTYPE_PUBLIC);

    pNC->Release();    // don't need this anymore
    pNSC->Release();
    return hr;
}

HRESULT shareNet(INetSharingManager *pNSM, const char *srcName, const char *dstName) {
    INetConnection                       *pNC    = nullptr;
    INetSharingConfiguration             *pNSC   = nullptr;
    IEnumVARIANT                         *pEV    = nullptr;
    IUnknown                             *pUnk   = nullptr;
    INetSharingEveryConnectionCollection *pNSECC = nullptr;

    HRESULT hr = pNSM->get_EnumEveryConnection(&pNSECC);
    VARIANT v;
    VariantInit(&v);

    if (!pNSECC) {
        printf(TEXT("failed to get EveryConnectionCollection!\r\n"));
        return 0;
    }

    hr = pNSECC->get__NewEnum(&pUnk);
    if (pUnk) {
        hr = pUnk->QueryInterface(__uuidof(IEnumVARIANT), (void **)&pEV);
        pUnk->Release();
    }

    printf(TEXT("----------------------------------------------------------\n"));
    int i = 0;
    while (S_OK == pEV->Next(1, &v, nullptr)) {
        if (V_VT(&v) == VT_UNKNOWN) {
            V_UNKNOWN(&v)->QueryInterface(__uuidof(INetConnection), (void **)&pNC);
            if (pNC) {
                WCHAR              guid[256];
                NETCON_PROPERTIES *pNP = nullptr;
                pNC->GetProperties(&pNP);
                //setlocale(LC_ALL, "chs");
                StringFromGUID2(pNP->guidId, guid, 256);
                printf("+++++++++++ %d\n", i++);
                printf(TEXT("guid--%s\n"), static_cast<const char *>(CW2A(guid)));
                printf(TEXT("pszwName--%s\n"), static_cast<const char *>(CW2A(pNP->pszwName)));
                printf(TEXT("pszwDeviceName--%s\n"), static_cast<const char *>(CW2A(pNP->pszwDeviceName)));
                printf(TEXT("Status--%d\n"), pNP->Status);
                printf(TEXT("\n"));

                //continue;
                if (pNP->Status != NCS_CONNECTED) {
                    continue;
                }
                TCHAR *tmpName = CW2A(pNP->pszwName);
                // printf("###### |%s| : |%s|\r\n", tmpName, "");

                if (i == 2) {
                    hr = pNSM->get_INetSharingConfigurationForINetConnection(pNC, &pNSC);
                    printf("**************find nic srcName : %s\r\n", static_cast<const char *>(CW2A(pNP->pszwName)));
                    //hr = pNSC->DisableSharing();
                    Sleep(500);
                    //getchar();
                    hr = pNSC->EnableSharing(ICSSHARINGTYPE_PUBLIC);
                    pNSC->Release();
                }

#if 1

                if (i == 5) {
                    hr = pNSM->get_INetSharingConfigurationForINetConnection(pNC, &pNSC);
                    printf("**************find nic dstName : %s\r\n", static_cast<const char *>(CW2A(pNP->pszwName)));
                    //hr = pNSC->DisableSharing();
                    Sleep(500);
                    hr = pNSC->EnableSharing(ICSSHARINGTYPE_PRIVATE);
                    pNSC->Release();
                }
#endif
            }
        }
    }
    return hr;
}

int NetShare() {
    CoInitialize(nullptr);
    CoInitializeSecurity(nullptr,
                         -1,
                         nullptr,
                         nullptr,
                         RPC_C_AUTHN_LEVEL_PKT,
                         RPC_C_IMP_LEVEL_IMPERSONATE,
                         nullptr,
                         EOAC_NONE,
                         nullptr);

    INetSharingManager *pNSM = NULL;
    HRESULT             hr   = ::CoCreateInstance(__uuidof(NetSharingManager),
                                    NULL,
                                    CLSCTX_ALL,
                                    __uuidof(INetSharingManager),
                                    (void **)&pNSM);

    if (!pNSM) {
        printf(TEXT("failed to create NetSharingManager object\r\n"));
    } else {
        //shareNet(pNSM, "WLAN", "мн╠Ф═Э 4");
        shareNet2(pNSM);
        //StartHostednetwork();
    }
    return 0;
}