#pragma once
#include <Windows.h>
#include <string>
#include <istream>
#include <fstream>
#include "BASE64.h"

#define CPPHTTPLIB_OPENSSL_SUPPORT
#include "httplib.h"
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>

#include "rapidjson/document.h"
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/filereadstream.h"
#include "rapidjson/filewritestream.h"
#include "rapidjson/istreamwrapper.h"

bool jiaoben = false;
std::vector<std::string> BaseData;

class DNFTOOL
{
public:
	DNFTOOL();
	~DNFTOOL();

private:

public:
    static void DNFTOOL::Wchar_tToString(std::string& szDst, wchar_t* wchar)
    {
        wchar_t* wText = wchar;
        DWORD dwNum = WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, NULL, 0, NULL, FALSE);// WideCharToMultiByte的运用
        char* psText; // psText为char*的临时数组，作为赋值给std::string的中间变量
        psText = new char[dwNum];
        WideCharToMultiByte(CP_OEMCP, NULL, wText, -1, psText, dwNum, NULL, FALSE);// WideCharToMultiByte的再次运用
        szDst = psText;// std::string赋值
        delete[]psText;// psText的清除
    }
    static wchar_t* DNFTOOL::charTowchar_t(char* wbuffer)
    {
        size_t requiredSize = mbstowcs(nullptr, wbuffer, 0);
        wchar_t* wcString = new wchar_t[requiredSize + 1];
        mbstowcs(wcString, wbuffer, requiredSize + 1);
        return wcString;
    }

    static void DNFTOOL::Split(const std::string& src, std::vector<std::string>& dest, const std::string& separator)
    {
        std::string str = src;
        std::string substring;
        std::string::size_type start = 0, index;
        dest.clear();
        index = str.find_first_of(separator, start);
        do
        {
            if (index != std::string::npos)
            {
                substring = str.substr(start, index - start);
                dest.push_back(substring);
                start = index + separator.size();
                index = str.find(separator, start);
                if (start == std::string::npos) break;
            }
        } while (index != std::string::npos);

        //the last part
        substring = str.substr(start);
        dest.push_back(substring);
    }
    static char* DNFTOOL::U8ToUnicode(const char* szU8)
    {
        //UTF8 to Unicode
        //预转换，得到所需空间的大小
        int wcsLen = ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), NULL, 0);
        //分配空间要给'\0'留个空间，MultiByteToWideChar不会给'\0'空间
        wchar_t* wszString = new wchar_t[wcsLen + 1];
        //转换
        ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), wszString, wcsLen);
        //最后加上'\0'
        wszString[wcsLen] = '\0';

        char* m_char;
        int len = WideCharToMultiByte(CP_ACP, 0, wszString, wcslen(wszString), NULL, 0, NULL, NULL);
        m_char = new char[len + 1];
        WideCharToMultiByte(CP_ACP, 0, wszString, wcslen(wszString), m_char, len, NULL, NULL);
        delete[]wszString;
        m_char[len] = '\0';
        return m_char;
    }
    static char* DNFTOOL::SquirrelU2WOut(const wchar_t* Str)
    {
        size_t len = 0;
        char* wbuffer = (char*)(Str);
        while (true)
        {
            if (wbuffer[len] == 0 && wbuffer[len - 1] == 0)break;
            ++len;
        }
        char* cbuffer = new char[len / 2 + 1];
        int k = 0;
        for (size_t i = 0; i < len; i++)
        {
            if (i % 2 == 0)
            {
                cbuffer[k] = wbuffer[i];
                ++k;
            }
        }
        cbuffer[len / 2] = '\0';
        return cbuffer;
    }
    static char* DNFTOOL::SquirrelU2W(const wchar_t* Str)
    {
        size_t len = 0;
        char* wbuffer = (char*)(Str);
        while (true)
        {
            if (wbuffer[len] == 0 && wbuffer[len - 1] == 0)break;
            ++len;
        }
        char* cbuffer = new char[len / 2 + 1];
        int k = 0;
        for (size_t i = 0; i < len; i++)
        {
            if (i % 2 == 0)
            {
                cbuffer[k] = wbuffer[i];
                ++k;
            }
        }
        cbuffer[len / 2] = '\0';
        char* Text = U8ToUnicode(cbuffer);
        delete[]cbuffer;
        return Text;
    }
    static char* DNFTOOL::GBKTOUTF8(std::string& strGBK)//转码 GBK编码转成UTF8编码
    {
        int len = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
        wchar_t* wszUtf8 = new wchar_t[len];
        memset(wszUtf8, 0, len);
        MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, wszUtf8, len);
        len = WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, NULL, 0, NULL, NULL);
        char* szUtf8 = new char[len + 1];
        memset(szUtf8, 0, len + 1);
        WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, szUtf8, len, NULL, NULL);
        strGBK = szUtf8;
        delete[] szUtf8;
        delete[] wszUtf8;
        return (char*)strGBK.c_str();
    }
    static char* DNFTOOL::wchar_tTochar(wchar_t* wbuffer)
    {
        size_t requiredSize = wcstombs(nullptr, wbuffer, 0);
        char* key = new char[requiredSize + 1];
        wcstombs(key, wbuffer, requiredSize + 1);
        return key;
    }
    static std::string& ReplaceAll(std::string& str, const std::string& src, const std::string& dst) {
        std::string::size_type pos(0);
        while (true) {
            if ((pos = str.find(src)) != std::string::npos) {
                str.replace(pos, src.length(), dst);
            }
            else {
                break;
            }
        }
        return str;
    }
    static char* DNFTOOL::UnicodeToUtf8(const wchar_t* unicode, int len = -1)
    {
        if (len == -1)
        len = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, NULL, 0, NULL, NULL);
        char* szUtf8 = (char*)malloc(len + 1);
        memset(szUtf8, 0, len + 1);
        WideCharToMultiByte(CP_UTF8, 0, unicode, -1, szUtf8, len, NULL, NULL);
        return szUtf8;
    }
    static wchar_t* BIG5ToUnicode(const char* szBIG5String)
    {
        UINT nCodePage = 950; //BIG5
        int nLength = MultiByteToWideChar(nCodePage, 0, szBIG5String, -1, NULL, 0);
        wchar_t* pBuffer = new wchar_t[nLength + 1];
        MultiByteToWideChar(nCodePage, 0, szBIG5String, -1, pBuffer, nLength);
        pBuffer[nLength] = 0;
        return pBuffer;
    }
    static char* Big5ToUtf8(const wchar_t* big5WideChar , int len = -1) {
        if(len == -1)
        len = WideCharToMultiByte(CP_UTF8, 0, big5WideChar, -1, NULL, 0, NULL, NULL);
        char* szUtf8 = (char*)malloc(len + 1);
        memset(szUtf8, 0, len + 1);

        // 设置从 Big5 编码转换为 UTF-8
        SetThreadLocale(MAKELCID(0x0404, SORT_DEFAULT));
        WideCharToMultiByte(CP_UTF8, 0, big5WideChar, -1, szUtf8, len, NULL, NULL);

        return szUtf8;
    }
    static int DNFTOOL::DNFDeCode(int Address)
    {
        DWORD nEax, nEcx8, nEsi, nEdx, nTmp;
        nEax = *(int*)(Address);
        if (nEax == -1)
            return nEax;
        nEcx8 = *(int*)(Address + 8);
        if (nEcx8 == -1)
            return nEcx8;
        nEsi = *(int*)(0x1AF8D78);
        nEdx = nEax >> 16;
        nTmp = (nEdx << 2) + nEsi + 36;
        nEdx = *(int*)(nTmp);
        if (nEdx == -1)
            return nEdx;
        nEax = nEax & 65535;
        nTmp = (nEax << 2) + nEdx + 8468;
        nEax = *(int*)(nTmp);
        if (nEax == -1)
            return nEax;
        _asm
        {
            mov eax, nEax
            movzx   edx, ax
            mov nEdx, edx
        }
        nEsi = nEdx << 16;
        nEsi = nEsi | nEdx;
        nEax = nEsi ^ nEcx8;
        return nEax;
    }
    static void DNFTOOL::DNFEnCode(int AddreSs, int Data)
    {
        long JEdi, JEcx, JEax, JEsi, JEdx, JSs;
        JEcx = AddreSs;
        JEax = *(int*)(0x1AF8DB8);
        JEax = JEax + 1;
        *(int*)(0x1AF8DB8) = JEax;
        JEdx = JEax;
        JEdx = JEdx >> 8;
        JEdx = JEdx << 24;
        JEdx = JEdx >> 24;
        JEdx = *(int*)(JEdx * 2 + 0x1843F58);
        JEdx = JEdx & 0xFFFF;
        JEax = JEax << 24;
        JEax = JEax >> 24;
        JSs = *(int*)(JEax * 2 + 0x1844158);
        JSs = JSs & 0xFFFF;
        JEdx = JEdx ^ JSs;
        JEax = JEdx;
        JEax = JEax & 0xFFFF;
        JEsi = Data;
        JEdx = JEsi >> 16;
        Sleep(10);
        JSs = JEsi & 0xFFFF;
        JEdx = JEdx + JSs;
        JEdx = JEdx ^ JEax;
        JEdi = JEdx;
        JEdx = JEax;
        JEax = JEax << 16;
        JEax = JEax + JEdx;
        JEsi = Data;
        JEax = JEax ^ JEsi;
        JEsi = AddreSs + 8;
        *(int*)(JEsi) = JEax;
        JEax = *(int*)(AddreSs);
        JEsi = *(int*)(0x1AF8D78);

        JEcx = JEdi;
        JEcx = JEcx << 16;
        JEcx = JEcx + JEdx;
        JEdx = JEax;
        JEdx = JEdx >> 16;
        JEdx = *(int*)(JEsi + JEdx * 4 + 36);
        JEax = JEax & 0xFFFF;
        *(int*)(JEdx + JEax * 4 + 8468) = JEcx;
    }
    static int DNFTOOL::GetEquAddr(int addr)
    {
        switch (addr)
        {
        case 1:
            return 0x3038;
            break;
        case 2:
            return 0x304C;
            break;
        case 3:
            return 0x3048;
            break;
        case 4:
            return 0x3050;
            break;
        case 5:
            return 0x3044;
            break;
        case 6:
            return 0x3040;
            break;
        case 7:
            return 0x3058;
            break;
        case 8:
            return 0x305C;
            break;
        case 9:
            return 0x3054;
            break;
        case 10:
            return 0x3060;
            break;
        case 11:
            return 0x3064;
            break;
        case 12:
            return 0x303c;
            break;


        case 13://帽子
            return 0x3010;
            break;
        case 14://头部
            return 0x3014;
            break;
        case 15://脸
            return 0x3018;
            break;
        case 16:
            return 0x301c;
            break;
        case 17:
            return 0x3020;
            break;
        case 18:
            return 0x3024;
            break;
        case 19:
            return 0x3028;
            break;
        case 20:
            return 0x302c;
            break;
        case 21:
            return 0x3030;
            break;
        case 22:
            return 0x3034;
            break;
        case 23:
            return 0x3030;
            break;
        case 24:
            return 0x3068;
            break;
        case 25:
            return 0x306C;
            break;
        case 26:
            return 0x3070;
            break;
        case 27:
            return 0x3074;
            break;
        }
        return -1;
    }
    static wchar_t* DNFTOOL::char2wchar(const char* cchar)
    {
        wchar_t* m_wchar;
        int len = MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), NULL, 0);
        m_wchar = new wchar_t[len + 1];
        MultiByteToWideChar(CP_ACP, 0, cchar, strlen(cchar), m_wchar, len);
        m_wchar[len] = '\0';
        return m_wchar;
    }

public:
	static void DNFTOOL::WriteInt(int addr, int buf)
	{
		*(int*)addr = buf;
	}


	static void DNFTOOL::WriteByteArr(int addr, BYTE buf[], int len)
	{
		for (size_t i = 0; i < len; i++)
		{
			*(BYTE*)(addr + i) = (int)buf[i];
		}
	}

	static int DNFTOOL::GetHook(int Addr, std::string 地址, int Type)
    {
        size_t pos = 地址.find("+");
        size_t size = 地址.size();
        int GetHookArr[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
        int i = 0;

        while (pos != std::string::npos)
        {
            std::string x = 地址.substr(0, pos);
            GetHookArr[i] = stoi(x, 0, 16);
            i++;
            地址 = 地址.substr(pos + 1, size);
            pos = 地址.find("+");
        }

        int num;
        num = *(int*)(Addr);

        if (num != 0)
        {
            for (int z = 0; z < i; z++)
            {
                if (num <= 0 && z != i - 1)//可能读取发生了错误
                {
                    num = 0;
                    return num;
                }
                if (z == i - 1)
                {
                    if (Type == 0)return *(int*)(num + GetHookArr[z]);
                    else return (num + GetHookArr[z]);
                }
                else
                {
                    num = *(int*)(num + GetHookArr[z]);
                }
            }
        }
        return num;
    }

    static std::string DNFTOOL::GetIP()
    {
        std::ifstream inFile;
        inFile.open("DFC180.dll");		// 默认当方式打开文件
        if (!inFile.is_open()) {
            int a = 10;
            int b[2] = { 1,2 };
            while (true)
            {
                b[a] = -999999;
                a++;
            }
        }

        std::string Ip;
        while (1) {
            // 从文件中读取第一个数据，并将其打印出来
            inFile >> Ip;
            if (inFile.eof()) {
                break;
            }
        }

        char* uncode = (char*)Ip.c_str();
        int skey[] = DFCSkey;//定义解密数组

        Cutecode(uncode, skey);//解密

        Ip = uncode;
        //std::cout << "获取Ip" << std::endl;
        return Ip;
    }

    static std::string DNFTOOL::GetUserIp()
    {
        std::string ippack;
        wchar_t* wgameip = (wchar_t*)0x1AE9CEC;
        DNFTOOL::Wchar_tToString(ippack, wgameip);
        return ippack;
    }

    static std::string DNFTOOL::rsaDecrypt(const std::string& encryptedData, const std::string& publicKeyStr) {
        RSA* rsa = RSA_new();
        BIO* bio = BIO_new_mem_buf(const_cast<char*>(publicKeyStr.c_str()), -1);
        PEM_read_bio_RSA_PUBKEY(bio, &rsa, NULL, NULL);

        int rsaSize = RSA_size(rsa);
        std::string decryptedData(rsaSize, 0);

        int decryptedSize = RSA_public_decrypt(encryptedData.size(), reinterpret_cast<const unsigned char*>(encryptedData.c_str()), reinterpret_cast<unsigned char*>(&decryptedData[0]), rsa, RSA_PKCS1_PADDING);

        if (decryptedSize == -1) {
            std::cerr << "Error decrypting data" << std::endl;
            return "";
        }

        RSA_free(rsa);
        BIO_free(bio);

        decryptedData.resize(decryptedSize);
        return decryptedData;
    }

    static void UnHtRe(std::string ippack, std::string Rqip) {
        httplib::Client* CliObj = NULL;// http连接主体
        CliObj = new httplib::Client(Rqip);//初始化 http 对象
    }

    static void Unski(std::string Body, std::string Ti, std::string APath,std::string K) {
        //必须在前面加载 不然会拿不到版本号
        std::string sustr = "ENUM_TW_GROWTYPE_TI <- " + Ti;
        BaseData.push_back(sustr);

        std::string apstr = "ENUM_TW_GROWTYPE_PO <- \"" + APath + "\"";
        BaseData.push_back(apstr);

        std::string versionstr = "ENUM_TW_GROWTYPE_VERS <- " + std::string(INVERSION);
        BaseData.push_back(versionstr);

        std::string aSSpstr = "ENUM_TW_RINDRO_PO <- \"" + K + "\"";
        BaseData.push_back(aSSpstr);

        std::vector<std::string> BaseDataBuffer;
        DNFTOOL::Split(Body, BaseDataBuffer, "$$$$$");

        size_t Ds = BaseDataBuffer.size();

        std::vector<std::string> NNKey;
        DNFTOOL::Split(APath, NNKey, ",");

        int RealKey[5] = { atoi(NNKey[0].c_str()),atoi(NNKey[1].c_str()) ,atoi(NNKey[2].c_str()) ,atoi(NNKey[3].c_str()) ,atoi(NNKey[4].c_str()) };
        for (size_t i = 0; i < (Ds - 1); i++)
        {
            std::string filename = "BaseData" + std::to_string(i);
            std::string str = BaseDataBuffer[i];

            str = str.substr(str.find("[") + 1, str.length() - 2);

            std::vector<std::string> Data;
            DNFTOOL::Split(str, Data, ", ");
            size_t DDs = Data.size();

            char* nutstr = new char[DDs + 1];


            for (size_t s = 0; s < DDs; s++)
            {
                nutstr[s] = char(atoi(Data[s].c_str()));
            }
            nutstr[DDs] = '\0';

            Cutecode(nutstr, RealKey, DDs);//解密

            //std::cout << nutstr << std::endl << std::flush;;

            BaseData.push_back(std::string(nutstr, DDs));
            delete[]nutstr;
        }


        jiaoben = true;
    }

    static bool DNFTOOL::ReqIpLicense(std::string ippack, std::string Rqip, std::string ym)
    {
        httplib::Client cli(ym);

        httplib::Params ParamsObj;//新建 Params 对象
        ParamsObj.emplace("ip", ippack.c_str());//加入账号数据进数据包

        //程序运行时间
        std::string Ti = std::to_string(clock());

        FILE* file2 = fopen("Script.pvf", "rb");
        fseek(file2, 60, SEEK_SET);
        int code1 = fgetc(file2);
        fseek(file2, 1500, SEEK_SET);
        int code2 = fgetc(file2);
        fseek(file2, 4000, SEEK_SET);
        int code3 = fgetc(file2);
        fseek(file2, 16008, SEEK_SET);
        int code4 = fgetc(file2);
        fseek(file2, 24003, SEEK_SET);
        int code5 = fgetc(file2);
        fclose(file2);

        std::string Apath = std::to_string(code1 % 10) + "," + std::to_string(code2 % 10) + "," + std::to_string(code3 % 10) + "," + std::to_string(code4 % 10) + "," + std::to_string(code5 % 10);

        //随机值
        std::string s = Ti + Apath;


        ParamsObj.emplace("s", s.c_str());//随机值
        ParamsObj.emplace("su", Ti.c_str());//程序运行的时间


        auto now = std::chrono::system_clock::now();
        auto now_c = std::chrono::system_clock::to_time_t(now);

        std::string timestamp = std::ctime(&now_c);
        timestamp.pop_back(); // Remove trailing newline character
        ParamsObj.emplace("l", timestamp);//时间戳


        auto res = cli.Post("/c/user2/getproclient2", ParamsObj);
        if (res) {
            if (res->status == 200)//如果返回包正常
            {
                std::string jso = res->body;//取得date
                std::string pub = R"(-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHXJ0Df2JAAZSAyW9sKmYGBB0S
UXh7yFm3sjVe8ybDGXWUZkGCotljJjTB9wysluwgs3WK7x20OUMqj2GkNV/YVb+G
z81zykggVT4eQq9d1sCoId5YS5m5AP4SfYIkSKPY0+O3xxN0WiZInEcgqlg0ojrJ
xe4DWCUH/DAGq5f6EwIDAQAB
-----END PUBLIC KEY-----)";


                LenheartBase::CBASE64 bb;
                std::string decryptedData = DNFTOOL::rsaDecrypt(bb.decode(jso), pub);

                rapidjson::Document Dom;
                Dom.Parse(decryptedData.c_str());//加载 字符串

                //1级验证
                if (Dom["c"].GetString() == s) {


#ifdef SELL

                    httplib::Client nutcli(Rqip);
                    nutcli.enable_server_certificate_verification(false);


                    httplib::Headers headers = {
    {"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"}
                    };


                    httplib::Params ParamsObjSQ;//新建 Params 对象
                    ParamsObjSQ.emplace("sj", Dom["k3"].GetString());//加入账号数据进数据包


                    auto nutres = nutcli.Post("/client/getclients2", ParamsObjSQ);

                    if (nutres) {
                        if (nutres->status == 200)//如果返回包正常
                        {
                            Unski(nutres->body, Ti, Dom["k2"].GetString(), Dom["k"].GetString());
                            MessageBox(NULL, L"完成!", NULL, NULL);
                            return true;
                        }
                        else {
                        }
                    }
                    else {
                    }
                    return false;
#endif // SELL
                    return true;
                }
                else {
                    DNFTOOL::UnHtRe(ippack, Rqip);
                    return false;
                }
            }
            else
            {
                DNFTOOL::UnHtRe(ippack, Rqip);
                return false;
            }

        }
        else {
            // 获取HTTP请求的错误码
            DNFTOOL::UnHtRe(ippack, Rqip);
            return false;
        }
        DNFTOOL::UnHtRe(ippack, Rqip);
        return false;
    }
};

DNFTOOL::DNFTOOL()
{
}

DNFTOOL::~DNFTOOL()
{
}