#pragma once
#include "DNFTOOL.hpp"

#include "zlib.h"
#include <ctime>
#include <sstream>
#include <chrono>
#include "json.hpp"

using json = nlohmann::json;



// 定义互斥锁和需要重载的文件列表
static std::mutex reloadListMutex;
static std::vector<std::string> reloadFileList;
struct AutoReloadSt
{
    std::string Path;
};
std::string calculateMD5(const std::string& filePath)
{
    std::ifstream file(filePath, std::ios::binary | std::ios::ate);
    if (!file)
    {
        return "";
    }
    std::streampos size = file.tellg();
    file.seekg(0, std::ios::beg);

    unsigned char buffer[16];
    MD5_CTX md5Context;
    MD5_Init(&md5Context);

    while (file.read(reinterpret_cast<char*>(buffer), sizeof(buffer)))
    {
        MD5_Update(&md5Context, buffer, file.gcount());
    }

    MD5_Final(buffer, &md5Context);

    file.close();
    return LenheartBase::CBASE64::encode((char*)buffer);
}
void processDirectory(const std::string& directoryPath, std::unordered_map<std::string, std::string>& fileMD5Map) {
    std::string searchPath = directoryPath + "\\*";
    WIN32_FIND_DATAA findData;
    HANDLE hFind = FindFirstFileA(searchPath.c_str(), &findData);

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
                if (std::string(findData.cFileName) != "." && std::string(findData.cFileName) != "..") {
                    std::string subDirPath = directoryPath + "\\" + findData.cFileName;
                    processDirectory(subDirPath, fileMD5Map);
                }
            }
            else {
                std::string filePath = directoryPath + "\\" + findData.cFileName;
                if (filePath.find(".nut") == std::string::npos)continue;
                std::string currentMD5 = calculateMD5(filePath);

                if (fileMD5Map.find(filePath) != fileMD5Map.end()) {
                    if (fileMD5Map[filePath] != currentMD5) {
                        fileMD5Map[filePath] = currentMD5;
                        // 加锁将需要重载的文件添加到列表中
                        std::lock_guard<std::mutex> lock(reloadListMutex);
                        reloadFileList.push_back(filePath);
                    }
                }
                else {
                    fileMD5Map[filePath] = currentMD5;
                }
            }
        } while (FindNextFileA(hFind, &findData) != 0);
        FindClose(hFind);
    }
    else {
        std::cerr << "无法打开目录：" << directoryPath << std::endl;
    }
}
static DWORD WINAPI AutoReloadThread(LPVOID lpParam)
{
    AutoReloadSt* Info = static_cast<AutoReloadSt*>(lpParam);
    std::string ReloadPath = Info->Path;
    delete Info;

    std::unordered_map<std::string, std::string> fileMD5Map;
    while (true)
    {
        processDirectory(ReloadPath, fileMD5Map);
        Sleep(10);
    }
    return 0;
}
static SQInteger AutoReload(HSQUIRRELVM v) {
    const SQChar* value;
    Sq_getstring((HSQUIRRELVM)v, 2, &value);
    char* vOutPutText = DNFTOOL::SquirrelU2W(value);
    std::string ReloadPath = vOutPutText;
    delete[]vOutPutText;
    //构造路径结构体传递
    AutoReloadSt* Info = new AutoReloadSt();
    Info->Path = ReloadPath;

    DWORD threadID;
    HANDLE Thand = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AutoReloadThread, Info, 0, &threadID);
    return 0;
}
static SQInteger ReloadLogic(HSQUIRRELVM v) {
    // 加锁获取需要重载的文件列表
    std::lock_guard<std::mutex> lock(reloadListMutex);
    for (const auto& file : reloadFileList) {
        std::string line = file;

        std::string ContentString = "";
        std::fstream F;
        F.open((line).c_str(), std::ios::in);
        if (F.is_open()) {
            std::stringstream ContentStringStream;
            ContentStringStream << F.rdbuf();
            ContentString = (ContentStringStream.str());
            F.close();
        }

        std::wstring filename = DNFTOOL::charTowchar_t((char*)line.c_str(), line.length());
        std::wstring str = DNFTOOL::charTowchar_t((char*)ContentString.c_str(), ContentString.length());
        if (sq_mycompilebuffer(v, str.c_str(), str.length(), filename.c_str(), true) >= 0) {
            Sq_pushroottable(v);
            Sq_call(v, 1, SQTrue, SQTrue);
            Sq_pop(v, 1);
        }
    }
    // 清空列表
    reloadFileList.clear();
    return 0;
}

static void RegisterNutApi_System(wchar_t* funcName, SQFUNCTION funcAddr)
{
    HSQUIRRELVM v = *(HSQUIRRELVM*)0x1AF3544;
    Sq_pushroottable(v);
    Sq_pushstring(v, funcName, -1);
    RealSqNewClosure(v, funcAddr, 0);
    SQNewSlot(v, -3, SQFalse);
    SQPopTop(v);
}

void R_Register_System() {
    RegisterNutApi_System(L"Sq_AutoReload", AutoReload);//开启热重载
    RegisterNutApi_System(L"Sq_ReloadLogic", ReloadLogic);//热重载逻辑(保持主线程加载)
}