#pragma once
#include <iostream>
#include <iconv.h>
#include <vector>
#include <dirent.h>
#include <string.h>
#include "squirrel.h"
#include <nlohmann/json.hpp>
using json = nlohmann::json;

class Tool
{
private:
    /* data */
public:
    Tool(/* args */);
    ~Tool();

    // 将小端序列 转为int
    static int ByteLittleToInt(unsigned char *Count);
public:
    // 错误输出
    static void Error(std::string E);
    // 警告输出
    static void Warring(std::string W);
    // 常规输出
    static void Logger(std::string L);
    //分割字符串
    static void Split(const std::string &src, std::vector<std::string> &dest, const std::string &separator);

    // 获取当前时间戳
    static long long get_cur_time();

    static int UTF8ToGB2312(char *szSrc, size_t iSrcLen, char *szDst, size_t iDstLen);
    static int GB2312ToUTF8(char *szSrc, size_t iSrcLen, char *szDst, size_t iDstLen);

    // 输出字节数组
    static void printUint8Array(uint8_t *array, size_t length)
    {
        for (size_t i = 0; i < length; ++i)
        {
            std::cout << static_cast<int>(array[i]);
            if (i != length - 1)
            {
                std::cout << ", "; // 添加逗号分隔符
            }
        }
        std::cout << std::endl;
    }

    // 批量替换字符串中文本
    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 std::vector<std::string> GetListFiles(const std::string &path, const std::string &exten = "*")
    {
        std::vector<std::string> list;
        list.clear();

        DIR *dp = NULL;
        struct dirent *dirp = NULL;
        if ((dp = opendir(path.c_str())) == NULL)
        {
            return list;
        }

        while ((dirp = readdir(dp)) != NULL)
        {
            if (dirp->d_type == DT_REG)
            {
                if (exten.compare("*") == 0)
                    list.emplace_back(static_cast<std::string>(dirp->d_name));
                else if (std::string(dirp->d_name).find(exten) != std::string::npos)
                    list.emplace_back(static_cast<std::string>(dirp->d_name));
            }
        }

        closedir(dp);

        return list;
    }

    // 遍历指定文件夹下的所有文件夹，不包括指定文件夹下的文件
    static std::vector<std::string> GetListFolders(const std::string &path, const std::string &exten = "*")
    {
        std::vector<std::string> list;
        list.clear();

        DIR *dp = NULL;
        struct dirent *dirp = NULL;
        if ((dp = opendir(path.c_str())) == NULL)
        {
            return list;
        }

        while ((dirp = readdir(dp)) != NULL)
        {
            if (dirp->d_type == DT_DIR && strcmp(dirp->d_name, ".") != 0 && strcmp(dirp->d_name, "..") != 0)
            {
                if (exten.compare("*") == 0)
                    list.emplace_back(static_cast<std::string>(dirp->d_name));
                else if (std::string(dirp->d_name).find(exten) != std::string::npos)
                    list.emplace_back(static_cast<std::string>(dirp->d_name));
            }
        }

        closedir(dp);

        return list;
    }

    // 遍历指定文件夹下的所有文件，包括指定文件夹内的文件夹
    static std::vector<std::string> GetListFilesR(const std::string &path, const std::string &exten = "*")
    {
        std::vector<std::string> list = Tool::GetListFiles(path, exten);

        std::vector<std::string> dirs = Tool::GetListFolders(path, exten);

        // 遍历目录
        for (auto it = dirs.cbegin(); it != dirs.cend(); ++it)
        {
            // 递归调用扫完
            std::vector<std::string> dirsvecBuf = Tool::GetListFilesR(path + "/" + *it);
            if (dirsvecBuf.size() > 0)
            {
                for (auto dirsvecBufF = dirsvecBuf.cbegin(); dirsvecBufF != dirsvecBuf.cend(); ++dirsvecBufF)
                {
                    list.emplace_back(*it + "/" + *dirsvecBufF);
                }
            }
        }

        return list;
    }

    // 序列化Array为字符串
    static std::string EncodeARRAY(HSQUIRRELVM v, std::string Jso)
    {
        Jso += "[";
        sq_pushnull(v);
        while (SQ_SUCCEEDED(sq_next(v, -2)))
        {
            SQObjectType Type = sq_gettype(v, -1);
            switch (Type)
            {
            case OT_INTEGER:
            {
                SQInteger value;
                sq_getinteger(v, -1, &value);
                Jso += std::to_string(value);
                Jso += ",";
            }
            break;
            case OT_FLOAT:
            {
                SQFloat value;
                sq_getfloat(v, -1, &value);
                Jso += std::to_string(value);
                Jso += ",";
            }
            break;
            case OT_BOOL:
            {
                SQBool value;
                sq_getbool(v, -1, &value);
                Jso += std::to_string(value);
                Jso += ",";
            }
            break;
            case OT_STRING:
            {
                const SQChar *value;
                sq_getstring(v, -1, &value);
                std::string vstr = value;
                Jso += "\"";
                Jso += vstr;
                Jso += "\"";
                Jso += ",";
            }
            break;
            case OT_TABLE:
            {
                SQInteger Top = sq_gettop(v);
                SQObject obj;
                sq_getstackobj(v, -1, &obj);
                sq_pushobject(v, obj);
                Jso = EncodeTABLE(v, Jso);
                sq_settop(v, Top);
                Jso += ",";
            }
            break;
            case OT_ARRAY:
            {
                SQInteger Top = sq_gettop(v);
                SQObject obj;
                sq_getstackobj(v, -1, &obj);
                sq_pushobject(v, obj);
                Jso = EncodeARRAY(v, Jso);
                sq_settop(v, Top);
                Jso += ",";
            }
            break;
            default:
                break;
            }

            // 这里-1是值，-2是键
            sq_pop(v, 2); // 在下一次迭代之前弹出键和值
        }
        sq_pop(v, 1); // 在下一次迭代之前弹出键和值
        Jso = Jso.substr(0, Jso.length() - 1);
        Jso += "]";
        return Jso;
    }

    // 序列化Table为字符串
    static std::string EncodeTABLE(HSQUIRRELVM v, std::string Jso)
    {
        Jso += "{";
        sq_pushnull(v); // null iterator
        while (SQ_SUCCEEDED(sq_next(v, -2)))
        {
            const SQChar *Key;
            sq_getstring(v, -2, &Key);

            std::string str = Key;

            Jso += "\"";
            Jso += str;
            Jso += "\"";
            Jso += ":";

            SQObjectType Type = sq_gettype(v, -1);
            switch (Type)
            {
            case OT_INTEGER:
            {
                SQInteger value;
                sq_getinteger(v, -1, &value);
                Jso += std::to_string(value);
                Jso += ",";
            }
            break;
            case OT_FLOAT:
            {
                SQFloat value;
                sq_getfloat(v, -1, &value);
                Jso += std::to_string(value);
                Jso += ",";
            }
            break;
            case OT_BOOL:
            {
                SQBool value;
                sq_getbool(v, -1, &value);
                Jso += std::to_string(value);
                Jso += ",";
            }
            break;
            case OT_STRING:
            {
                const SQChar *value;
                sq_getstring(v, -1, &value);

                std::string vstr = value;
                Jso += "\"";
                Jso += vstr;
                Jso += "\"";
                Jso += ",";
            }
            break;
            case OT_TABLE:
            {
                SQInteger Top = sq_gettop(v);
                SQObject obj;
                sq_getstackobj(v, -1, &obj);
                sq_pushobject(v, obj);
                Jso = Tool::EncodeTABLE(v, Jso);
                sq_settop(v, Top);
                Jso += ",";
            }
            break;
            case OT_ARRAY:
            {
                SQInteger Top = sq_gettop(v);
                SQObject obj;
                sq_getstackobj(v, -1, &obj);
                sq_pushobject(v, obj);
                Jso = Tool::EncodeARRAY(v, Jso);
                sq_settop(v, Top);
                Jso += ",";
            }
            break;
            default:
                break;
            }

            // 这里-1是值，-2是键
            sq_pop(v, 2); // 在下一次迭代之前弹出键和值
        }
        sq_pop(v, 1); // 在下一次迭代之前弹出键和值
        Jso = Jso.substr(0, Jso.length() - 1);
        Jso += "}";
        return Jso;
    }
};

static void push_squirrel_value(HSQUIRRELVM vm, const json &j)
{
    switch (j.type())
    {
    case json::value_t::object:
    {
        sq_newtable(vm);
        for (auto &item : j.items())
        {
            const std::string &key = item.key();
            auto &value = item.value(); // 根据实际类型可能需要改为 const auto&

            sq_pushstring(vm, key.c_str(), -1);
            push_squirrel_value(vm, value);
            sq_createslot(vm, -3);
        }
        break;
    }
    case json::value_t::array:
    {
        sq_newarray(vm, 0);
        for (const auto &item : j)
        {
            push_squirrel_value(vm, item);
            sq_arrayappend(vm, -2);
        }
        break;
    }
    case json::value_t::string:
        sq_pushstring(vm, j.get<std::string>().c_str(), -1);
        break;
    case json::value_t::boolean:
        sq_pushbool(vm, j.get<bool>() ? SQTrue : SQFalse);
        break;
    case json::value_t::number_integer:
        sq_pushinteger(vm, j.get<SQInteger>());
        break;
    case json::value_t::number_unsigned:
    {
        auto val = j.get<uint64_t>();
        if (val > static_cast<uint64_t>(std::numeric_limits<SQInteger>::max()))
        {
            sq_pushfloat(vm, static_cast<SQFloat>(val));
        }
        else
        {
            sq_pushinteger(vm, static_cast<SQInteger>(val));
        }
        break;
    }
    case json::value_t::number_float:
        sq_pushfloat(vm, j.get<SQFloat>());
        break;
    case json::value_t::null:
        sq_pushnull(vm);
        break;
    default:
        sq_pushnull(vm);
        break;
    }
}
