#pragma once
#include "squirrel.h"
#include "sqstdaux.h"
#include "sqstdblob.h"
#include "sqstdio.h"
#include "sqstdmath.h"
#include "sqstdstring.h"
#include "sqstdsystem.h"
#include "CConnectPool.h"
#include "l_socket.h"
#include <iostream>
#include <functional>
#include <list>
#include <ffi.h>

#define CONTAINS_STRING(str, substr) (str == substr)

template <typename R, typename A, typename... ARG>
R CallGameT(A call_addr, const ARG... arguments)
{
    if (!call_addr)
    {
        return R();
    }
    const auto control = reinterpret_cast<R (*)(ARG...)>(call_addr);
    try
    {
        return control(arguments...);
    }
    catch (...)
    {
    }
    return R();
}
template <typename R>
R CallGameRT(void *call_addr, va_list arguments, std::vector<std::string> Type)
{
    if (!call_addr)
    {
        return R();
    }
    try
    {
        // 使用汇编语言将va_list中的值一个一个push进去
        R result;
        va_list args;
        va_copy(args, arguments);

        asm volatile(
            "pushl %0"
            :
            : "g"(va_arg(args, int))
            : "memory");

        va_end(args);

        asm volatile(
            "call *%1"
            : "=a"(result)
            : "r"(call_addr)
            : "memory");

        return result;
    }
    catch (...)
    {
    }
    return R();
}

static char szGamePath[256];
static int getargs(char ***argv)
{
    size_t buflen = 1024, readlen = 0, maxlen = buflen;
    int fd = open("/proc/self/cmdline", O_RDONLY);
    if (fd == -1)
        return 0;
    char *buf = (char *)malloc(buflen);
    while (1)
    {
        ssize_t n = read(fd, buf + readlen, buflen - readlen);
        if (n == -1)
        {
            free(buf);
            close(fd);
            return 0;
        }
        readlen += n;
        if (!n || readlen < buflen)
            break;
        maxlen += buflen;
        buf = (char *)realloc(buf, maxlen);
    }
    close(fd);
    int argc = 0;
    char *cp = buf;
    do
    {
        while (*cp != '\0')
            cp++;
        argc++;
    } while (++cp < buf + readlen);
    *argv = (char **)malloc(argc * sizeof(char *));
    argc = 0;
    cp = buf;
    do
    {
        (*argv)[argc] = (char *)malloc(strlen(cp) + 1);
        strcpy((*argv)[argc], cp);
        argc++;
        while (*cp != '\0')
            cp++;
    } while (++cp < buf + readlen);
    free(buf);
    return argc;
}
static int getConfigPath(char *pPath, size_t nSize)
{
    if (readlink("/proc/self/exe", pPath, nSize) <= 0)
        return -1;
    char **argv = NULL;
    int argc = getargs(&argv);
    if (!argv || argc < 2)
    {
        if (argv)
        {
            for (int i = 0; i < argc; i++)
            {
                if (argv[i])
                    free(argv[i]);
            }
            free(argv);
        }
        return -1;
    }
    *strrchr(pPath, '/') = '\0';
    sprintf(pPath, "%s/cfg/%s.cfg", pPath, argv[1]);
    for (int i = 0; i < argc; i++)
    {
        if (argv[i])
            free(argv[i]);
    }
    free(argv);
    return 0;
}
static SQInteger Game_GetConfig(HSQUIRRELVM v)
{
    sq_pushstring(v, szGamePath, -1);
    return 1;
}

// 指针转int
static SQInteger L_Ptr2Int(HSQUIRRELVM v)
{
    SQUserPointer P;
    sq_getuserpointer(v, 2, &P);
    sq_pushinteger(v, (int)P);
    return 1;
}
// int转指针
static SQInteger L_Int2Ptr(HSQUIRRELVM v)
{
    SQInteger Address;
    sq_getinteger(v, 2, &Address);
    sq_pushuserpointer(v, (void *)Address);
    return 1;
}

// 写内存
static SQInteger L_WriteAddress(HSQUIRRELVM v)
{
    // 内存地址 int型
    SQUserPointer Address;
    // 内存偏移 int型
    SQInteger Offset;
    // 获取参数个数
    int ParameterNum = sq_gettop(v);
    // 2个参数时
    if (ParameterNum == 4)
    {
        // 获取地址
        sq_getuserpointer(v, 2, &Address);
        // 获取偏移
        sq_getinteger(v, 3, &Offset);
        // 获取修改的值
        SQInteger WriteValue;
        sq_getinteger(v, 4, &WriteValue);

        *(int *)((void *)Address + Offset) = WriteValue;
        sq_pushbool(v, true);
        return 1;
    }
    if (ParameterNum == 5)
    {
    }
    else
    {
        sq_pushbool(v, false);
        return 1;
    }
    return 0;
}
// 读内存
static SQInteger L_ReadAddress(HSQUIRRELVM v)
{
    // 内存地址 int型
    SQUserPointer Address;
    // 获取地址
    sq_getuserpointer(v, 2, &Address);
    sq_pushinteger(v, *(int *)Address);
    return 1;
}
// 读内存字符串
static SQInteger L_ReadAddressString(HSQUIRRELVM v)
{
    // 内存地址 int型
    SQUserPointer Address;
    // 获取地址
    sq_getuserpointer(v, 2, &Address);
    if (sq_gettop(v) == 3)
    {
        SQInteger Length;
        sq_getinteger(v, 3, &Length);
        sq_pushstring(v, (char *)(Address), Length);
    }
    else
    {
        sq_pushstring(v, (char *)(Address), -1);
    }
    return 1;
}

// 读取字节数组
static SQInteger L_ReadByteArr(HSQUIRRELVM v)
{
    SQUserPointer P;
    sq_getuserpointer(v, 2, &P);
    SQInteger Count;
    sq_getinteger(v, 3, &Count);

    char *Address = (char *)P;
    sq_newarray(v, 0);
    for (size_t i = 0; i < Count; i++)
    {
        sq_pushinteger(v, (int)(Address[i]));
        sq_arrayappend(v, -2);
    }
    return 1;
}
// 指针转Blob
static SQInteger L_Point2Blob(HSQUIRRELVM v)
{
    SQUserPointer P;
    sq_getuserpointer(v, 2, &P);
    SQInteger Count;
    sq_getinteger(v, 3, &Count);

    char *Address = (char *)P;
    SQUserPointer Blobobj = sqstd_createblob(v, Count);
    memcpy(Blobobj, P, Count);

    return 1;
}
// 写字节数组
static SQInteger L_WriteByteArr(HSQUIRRELVM v)
{
    SQUserPointer P;
    sq_getuserpointer(v, 2, &P);
    char *Address = (char *)P;

    size_t Idx = 0;
    sq_pushnull(v); // null iterator
    while (SQ_SUCCEEDED(sq_next(v, 3)))
    {
        SQInteger Buf;
        sq_getinteger(v, -1, &Buf);
        Address[Idx] = Buf;
        // 这里-1是值，-2是键
        sq_pop(v, 2); // 在下一次迭代之前弹出键和值
        Idx++;
    }
    sq_pop(v, 1);

    return 0;
}
// 写Blob到指定地址
static SQInteger L_WriteBlobToAddress(HSQUIRRELVM v)
{
    SQUserPointer P;
    sq_getuserpointer(v, 2, &P);
    SQUserPointer Blobobj;
    // sq_getuserpointer(v, 3, &P);
    sqstd_getblob(v, 3, &Blobobj);
    int Size = sqstd_getblobsize(v, 3);

    memcpy(P, Blobobj, Size);
    return 0;
}
// 通过ID从Pvf中查询名称
static SQInteger L_GetNameByIdFromPvf(HSQUIRRELVM v)
{
    SQInteger Idx;
    sq_getinteger(v, 2, &Idx);

    void *Ret = CallGameT<void *>(0x835FA32, CallGameT<void *>(0x80CC19B), (unsigned int)Idx);
    if (Ret)
    {
        const char *Name = CallGameT<const char *>(0x811ed82, Ret);
        sq_pushstring(v, Name, -1);
    }
    else
    {
        sq_pushnull(v);
    }
    return 1;
}
// 通过ID从Pvf中查询Data
static SQInteger L_GetDataByIdFromPvf(HSQUIRRELVM v)
{
    SQInteger Idx;
    sq_getinteger(v, 2, &Idx);

    void *Ret = CallGameT<void *>(0x835FA32, CallGameT<void *>(0x80CC19B), (unsigned int)Idx);
    if (Ret)
    {
        sq_pushuserpointer(v, Ret);
    }
    else
    {
        sq_pushnull(v);
    }
    return 1;
}

// 创建数据库连接池
static SQInteger L_CreatCConnectPool(HSQUIRRELVM v)
{
    SQInteger MinConnectCount, MaxConnectCount, Port;
    const SQChar *Host;
    const SQChar *Account;
    const SQChar *Passwd;

    sq_getinteger(v, 2, &MinConnectCount);
    sq_getinteger(v, 3, &MaxConnectCount);
    sq_getstring(v, 4, &Host);
    sq_getinteger(v, 5, &Port);
    sq_getstring(v, 6, &Account);
    sq_getstring(v, 7, &Passwd);

    // 初始化数据库
    CConnectPool::CreatePool(MinConnectCount, MaxConnectCount, Host, Port, Account, Passwd);
    return 0;
}
// 阻塞线程的数据库操作 无返回值
static SQInteger L_MysqlExecNoRet(HSQUIRRELVM v)
{
    const SQChar *Sql;
    sq_getstring(v, 2, &Sql);

    MYSQL *MysqlObject = CConnectPool::GetConnect();
    mysql_query(MysqlObject, Sql);
    CConnectPool::PutConnect(MysqlObject);
    return 0;
}

struct CreateSocketInfo
{
    std::string Ip;
    std::string Port;
};

static void *SocketThread_function(void *arg)
{
    CreateSocketInfo *Info = (CreateSocketInfo *)arg;
    l_socket::getInstance().Init(Info->Ip, Info->Port);
    delete Info;
    // 在这里编写线程的具体操作

    pthread_exit(NULL);
}

// 创建Socket连接
static SQInteger L_CreatSocketConnect(HSQUIRRELVM v)
{
    const SQChar *Host;
    const SQChar *Port;
    sq_getstring(v, 2, &Host);
    sq_getstring(v, 3, &Port);
    CreateSocketInfo *Info = new CreateSocketInfo();
    Info->Ip = Host;
    Info->Port = Port;

    pthread_t SocketThread;
    // 创建线程1
    if (pthread_create(&SocketThread, NULL, SocketThread_function, Info) != 0)
    {
        std::cerr << "Error creating thread 1" << std::endl;
    }
    return 0;
}

static SQInteger register_Game_func(HSQUIRRELVM v, SQFUNCTION f, const char *fname)
{
    sq_pushroottable(v);
    sq_pushstring(v, fname, -1);
    sq_newclosure(v, f, 0); // create a new function
    sq_newslot(v, -3, SQFalse);
    sq_pop(v, 1); // pops the root table
}

static void Aprintfunc(const SQChar *s, ...)
{
    fflush(stdout);
    va_list vl;
    va_start(vl, s);
    scvprintf(stdout, s, vl);
    va_end(vl);
    printf("\n");
    fflush(stdout);
}

// CallFunc
static SQInteger L_CallFunc(HSQUIRRELVM v)
{
    // 得到参数个数
    SQInteger Count = sq_gettop(v);
    // 得到函数地址
    SQUserPointer FuncAddress;
    sq_getuserpointer(v, 2, &FuncAddress);
    // 得到返回值类型
    const SQChar *RetType;
    sq_getstring(v, 3, &RetType);

    std::vector<std::string> ParameterType;
    // 遍历参数类型数组
    sq_pushnull(v); // null iterator
    while (SQ_SUCCEEDED(sq_next(v, 4)))
    {
        const SQChar *path;
        sq_getstring(v, -1, &path);
        ParameterType.push_back(path);
        sq_pop(v, 2);
    }
    sq_pop(v, 1);

    // 头部信息个数
    int HeaderCount = 4;

    // 计算valist内存
    int AdrSize = 0;
    for (std::string Type : ParameterType)
    {
        if (CONTAINS_STRING(Type, "int"))
            AdrSize += sizeof(int);
        else if (CONTAINS_STRING(Type, "bool"))
            AdrSize += sizeof(bool);
        else if (CONTAINS_STRING(Type, "string"))
            AdrSize += sizeof(char *);
        else if (CONTAINS_STRING(Type, "float"))
            AdrSize += sizeof(float);
        else if (CONTAINS_STRING(Type, "pointer"))
            AdrSize += sizeof(void *);
        else if (CONTAINS_STRING(Type, "short"))
            AdrSize += sizeof(short);
        else if (CONTAINS_STRING(Type, "char"))
            AdrSize += sizeof(char);
    }

    char *m = (char *)malloc(AdrSize);
    void *bm = m;
    // 定义函数签名
    ffi_cif cif;
    ffi_type **args = (ffi_type **)malloc(ParameterType.size() * sizeof(ffi_type *)); // 动态分配参数类型数组
    void **values = (void **)malloc(ParameterType.size() * sizeof(void *));           // 动态分配参数值数组
    ffi_arg result;

    int CFlag = 0;
    for (int i = (HeaderCount + 1); i < (Count + 1); i++)
    {
        if (CONTAINS_STRING(ParameterType[0], "int"))
        {
            sq_getinteger(v, i, (SQInteger *)m);
            args[CFlag] = &ffi_type_sint;
            values[CFlag] = m;
            m += sizeof(int);
        }
        else if (CONTAINS_STRING(ParameterType[0], "float"))
        {
            sq_getfloat(v, i, (SQFloat *)m);
            args[CFlag] = &ffi_type_float;
            values[CFlag] = m;
            m += sizeof(float);
        }
        else if (CONTAINS_STRING(ParameterType[0], "bool"))
        {
            sq_getbool(v, i, (SQBool *)m);
            args[CFlag] = &ffi_type_sint8;
            values[CFlag] = m;
            m += sizeof(bool);
        }
        else if (CONTAINS_STRING(ParameterType[0], "string"))
        {

            sq_getstring(v, i, (const SQChar **)m);
            args[CFlag] = &ffi_type_pointer;
            values[CFlag] = m;
            m += sizeof(void *);
        }
        else if (CONTAINS_STRING(ParameterType[0], "pointer"))
        {
            sq_getuserpointer(v, i, (SQUserPointer *)m);
            args[CFlag] = &ffi_type_pointer;
            values[CFlag] = m;
            m += sizeof(void *);
        }
        else if (CONTAINS_STRING(ParameterType[0], "short"))
        {
            sq_getinteger(v, i, (SQInteger *)m);
            args[CFlag] = &ffi_type_sint16;
            values[CFlag] = m;
            m += sizeof(short);
        }
        else if (CONTAINS_STRING(ParameterType[0], "char"))
        {
            sq_getinteger(v, i, (SQInteger *)m);
            args[CFlag] = &ffi_type_schar;
            values[CFlag] = m;
            m += sizeof(char);
        }

        ParameterType.erase(ParameterType.begin());
        CFlag++;
    }

    ffi_type *RetTypeFlag = &ffi_type_void;

    std::string RetTypeString = RetType;
    if (CONTAINS_STRING(RetTypeString, "int"))
        RetTypeFlag = &ffi_type_sint;
    else if (CONTAINS_STRING(RetTypeString, "float"))
        RetTypeFlag = &ffi_type_float;
    else if (CONTAINS_STRING(RetTypeString, "bool"))
        RetTypeFlag = &ffi_type_sint8;
    else if (CONTAINS_STRING(RetTypeString, "string"))
        RetTypeFlag = &ffi_type_pointer;
    else if (CONTAINS_STRING(RetTypeString, "pointer"))
        RetTypeFlag = &ffi_type_pointer;
    else if (CONTAINS_STRING(RetTypeString, "short"))
        RetTypeFlag = &ffi_type_sint16;
    else if (CONTAINS_STRING(RetTypeString, "char"))
        RetTypeFlag = &ffi_type_schar;

    if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, CFlag, RetTypeFlag, args) == FFI_OK)
    {
        // 动态调用函数
        ffi_call(&cif, FFI_FN(FuncAddress), &result, values);
    }

    free(args);
    free(values);
    free(bm);

    if (CONTAINS_STRING(RetTypeString, "int"))
        sq_pushinteger(v, (int)result);
    else if (CONTAINS_STRING(RetTypeString, "float"))
        sq_pushfloat(v, (float)result);
    else if (CONTAINS_STRING(RetTypeString, "bool"))
        sq_pushbool(v, (bool)result);
    else if (CONTAINS_STRING(RetTypeString, "string"))
        sq_pushstring(v, (char *)result, -1);
    else if (CONTAINS_STRING(RetTypeString, "pointer"))
        sq_pushuserpointer(v, (void *)result);
    else if (CONTAINS_STRING(RetTypeString, "short"))
        sq_pushinteger(v, (int)result);
    else if (CONTAINS_STRING(RetTypeString, "char"))
        sq_pushinteger(v, (int)result);
    else
        return 0;
    return 1;
}
static SQInteger L_S_Ptr(HSQUIRRELVM v)
{
    const SQChar *str;
    sq_getstring(v, 2, &str);
    unsigned long long addr = std::stoull(str, 0, 16);
    void *ptr = reinterpret_cast<void *>(addr);
    sq_pushuserpointer(v, ptr);
    return 1;
}

static void RegisterGame(HSQUIRRELVM v)
{
    getConfigPath(szGamePath, sizeof(szGamePath));

    // int 和指针相互转换
    register_World_func(v, L_Ptr2Int, _SC("Sq_Ptr2Int"));
    register_World_func(v, L_Int2Ptr, _SC("Sq_Int2Ptr"));
    register_World_func(v, L_S_Ptr, _SC("S_Ptr"));

    // 获取频道配置
    register_World_func(v, Game_GetConfig, _SC("Sq_Game_GetConfig"));
    // 写地址int
    register_World_func(v, L_WriteAddress, _SC("Sq_WriteAddress"));
    // 读地址int
    register_World_func(v, L_ReadAddress, _SC("Sq_ReadAddress"));
    // 读地址字符串
    register_World_func(v, L_ReadAddressString, _SC("Sq_ReadAddressString"));
    // 读取Byte
    register_World_func(v, L_ReadByteArr, _SC("Sq_ReadByteArr"));
    // 写入Byte
    register_World_func(v, L_WriteByteArr, _SC("Sq_WriteByteArr"));
    // 通过指针转Blob
    register_World_func(v, L_Point2Blob, _SC("Sq_Point2Blob"));
    // 写Blob到指定地址
    register_World_func(v, L_WriteBlobToAddress, _SC("Sq_WriteBlobToAddress"));
    // 通过ID从Pvf中查询名称
    register_World_func(v, L_GetNameByIdFromPvf, _SC("Sq_GetNameByIdFromPvf"));
    // 通过ID从Pvf中查询Data
    register_World_func(v, L_GetDataByIdFromPvf, _SC("Sq_GetDataByIdFromPvf"));
    // 创建数据库连接池
    register_World_func(v, L_CreatCConnectPool, _SC("Sq_CreatCConnectPool"));
    // 阻塞线程的数据库操作 无返回值
    register_World_func(v, L_MysqlExecNoRet, _SC("Sq_MysqlExecNoRet"));
    // 创建Socket连接
    register_World_func(v, L_CreatSocketConnect, _SC("Sq_CreatSocketConnect"));

    register_World_func(v, L_CallFunc, _SC("Sq_CallFunc"));
}