#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "clua.h"

int LuaPcall(lua_State* L, char* exp)
{

    // 加载并编译Lua代码
    if (luaL_loadstring(L, exp) != 0) {
        fprintf(stderr, "Error compiling Lua code: %s\n", lua_tostring(L, -1));
        lua_close(L);
        return 1;
    }

    // 执行Lua代码
    if (lua_pcall(L, 0, 0, 0) != 0) {
        fprintf(stderr, "Error running Lua code: %s\n", lua_tostring(L, -1));
        lua_close(L);
        return 1;
    }
    return 0;
}

int LuaMatch(const char* input, const char* pattern, char *result, int len)
{
    int ret = 0;
    // 创建Lua状态
    lua_State* Ltmp = luaL_newstate();
    luaL_openlibs(Ltmp);  // 打开标准库，以便使用string.match

    // 将string.match函数压入堆栈
    lua_getglobal(Ltmp, "string");
    lua_getfield(Ltmp, -1, "match");

    // 压入要匹配的字符串和模式
    lua_pushstring(Ltmp, input);
    lua_pushstring(Ltmp, pattern);

    // 调用string.match函数
    if (lua_pcall(Ltmp, 2, 1, 0) != 0) {
        fprintf(stderr, "Error running Lua code: %s\n", lua_tostring(Ltmp, -1));
        lua_close(Ltmp);
        return -1;
    }

    // 从返回值中获取结果
    const char* matched = lua_tostring(Ltmp, -1);
    if(matched != NULL)
    {
        strncpy(result, matched, len);
        ret = 0;
    }
    else
    {
        ret = 1;
    }
    // 关闭Lua状态
    lua_close(Ltmp);
    
    return ret;
}

int LuaGsub(const char* originalStr, const char* pattern,const char *replace, char *result, int len)
{
    lua_State* L = luaL_newstate();  // 创建Lua状态

    luaL_openlibs(L);  // 打开Lua标准库

    // 调用Lua中的gsub函数执行替换
    lua_getglobal(L, "string");
    lua_getfield(L, -1, "gsub");  // 获取string库中的gsub函数

    // 加载字符串到栈中
    lua_pushstring(L, originalStr);
    lua_pushstring(L, pattern);
    lua_pushstring(L, replace);

    // 调用gsub函数进行替换，参数个数为3
    if (lua_pcall(L, 3, 1, 0) != 0) {
        fprintf(stderr, "Error running Lua code: %s\n", lua_tostring(L, -1));
        lua_close(L);
        return 1;
    }

    // 获取替换后的字符串
    const char* replacedStr = lua_tostring(L, -1);
    strncpy(result, replacedStr,len);

    lua_close(L);  // 关闭Lua状态

    return 0;
}

int LuaFormat(const char* format, char* pattern[], int patternNum, char* result, int len)
{
    lua_State* L = luaL_newstate();  // 创建Lua状态

    luaL_openlibs(L);  // 打开Lua标准库

    // 调用Lua中的gsub函数执行替换
    lua_getglobal(L, "string");
    lua_getfield(L, -1, "format");  // 获取string库中的format函数

    // 加载字符串到栈中
    lua_pushstring(L, format);
    for(int i=0; i< patternNum; i++)
    {
        lua_pushstring(L, pattern[i]);
    }

    // 调用gsub函数进行替换，参数个数为3
    if (lua_pcall(L, (patternNum+1), 1, 0) != 0) {
        fprintf(stderr, "Error running Lua code: %s\n", lua_tostring(L, -1));
        lua_close(L);
        return 1;
    }

    // 获取替换后的字符串
    const char* replacedStr = lua_tostring(L, -1);
    strncpy(result, replacedStr, len);

    lua_close(L);  // 关闭Lua状态

    return 0;
}

// 格式化解析函数
int bunpack(const char* data, const char* format ,void *value) 
{
    // 根据指定的格式 format 解析数据并返回对应的值
    // 进行格式化解析
    if (strncmp(format, "L", 1) == 0) {
        // 处理长整型数据
        sscanf(data, "%ld", (long*)value);
        return 0;
    }
    else if (strncmp(format, "I", 1) == 0) {
        // 处理整型数据
        sscanf(data, "%d", (int *)value);
        return 0;
    }
    else if (strncmp(format, "S", 1) == 0) {
        // 处理U16
        sscanf(data, "%hu", (uint16_t *)value);
        return 0;
    }
    else {
        return -1;
    }
}


// 函数用于将十六进制字符串转换为十进制数值
int strToHex(const char* hex) {
    return (int)strtol(hex, NULL, 16);
}

// 函数用于将十六进制字符串转换为十进制数值
int numToString(int num,char *result, int len)
{
    char str[20];
    sprintf(str, "%d", num);
    strncpy(result,str,len);

    return 0;
}

// conversionHex函数将数字转换为指定长度的16进制字符串
char* conversionHex(int num, int width) {
    // 注意：调用者负责释放返回的字符串
    char* hexStr = (char*)malloc(width + 1);
    sprintf(hexStr, "%0*X", width, num);
    return hexStr;
}

char* calculateExpression(char* expression) {
    int num1, num2;
    char op;
    float result = 0.0;
    // 尝试解析形式为 "(num1 op num2)" 的表达式
    if (sscanf(expression, "%d %c %d", &num1, &op, &num2) == 3) 
    {
        // 根据运算符执行计算
        switch (op) {
        case '+': result = num1 + num2; break;
        case '-': result = num1 - num2; break;
        case '*': result = num1 * num2; break;
        case '/':
            if (num2 != 0) {
                result = (float)num1 / num2;
            }
            else {
                return NULL; // 防止除数为0
            }
            break;
        default: return NULL; // 如果运算符不可识别，返回NULL
        }

        char* resultStr = (char*)malloc(64); // 分配足够的空间
        if (!resultStr) return NULL; // 内存分配失败
        snprintf(resultStr, 64, "%.2f", result); // 格式化计算结果到字符串
        return resultStr;
    }
    //部分配置中可能是一个数值，没有带运算符
    else if(sscanf(expression, "%d", &num1) == 1)
    {
        char* resultStr = (char*)malloc(64); // 分配足够的空间
        snprintf(resultStr, 64, "%.2f", (float)num1); // 格式化计算结果到字符串
        return resultStr;
    }
    return NULL; // 如果表达式不匹配或有其他错误，返回NULL
}

char* simpleMathExpression(char* expression) {
    // 简单处理，不执行计算
    char* result = strdup(expression); // 直接复制表达式作为字符串返回
    return result;
}

// 处理不定数量参数的函数
void processFormatString(char* formatStr) {
    char format[100]; // 存储格式化字符串
    char* results[10];
    int count = 0;
    char dstResult[1024] = {0};
    // 提取format字符串格式
    char* startPos = strstr(formatStr, "format('");
    if (startPos) {
        char* endPos = strchr(startPos + 8, '\'');  // 查找格式字符串闭合的单引号
        if (endPos) {
            strncpy(format, startPos + 8, endPos - (startPos + 8));  // 提取格式字符串
            format[endPos - (startPos + 8)] = '\0';  // 确保格式字符串以null终止
        }
    }

    int num, width;
    char* position = formatStr;
    while ((position = strstr(position, "conversionHex(")) != NULL) {
        if (sscanf(position, "conversionHex(%d,%d)", &num, &width) == 2) {
            results[count++] = conversionHex(num, width);
            position += strlen("conversionHex()");
        }
    }

    position = formatStr;
    char seps[] = ",()"; // 分隔符：点、左括号、右括号
#ifdef WIN32
    char* context = NULL; // strtok_s需要的额外指针，用于在后续调用中维持状态
    char* token = strtok_s(position, seps, &context); // 初始化标记
#else
    char* rest = position;  // strtok_r的额外指针，用于保持上下文
    char* token = strtok_r(position, seps, &rest); // 初始化标记
#endif

     while (token != NULL) {

        char* expression = token;
        char* exprResult = calculateExpression(expression);
        if (exprResult) {
            results[count++] = exprResult;
        }
#ifdef WIN32
        token = strtok_s(NULL, seps, &context);
#else
        // 为下一个迭代获得新token
        token = strtok_r(NULL, seps, &rest);
#endif
    }
    LuaFormat(format, results, count, dstResult,1024);
}

// 原lua expr2function 函数的 C 语言实现
int expr2function(int term_addr, const char* extrainfo_str, const char* format, size_t len, char * result) 
{
    char rawdata[1024] = {0},dstdata[1024] = {0};
    char seg_in[128] = {0};

    strncpy(rawdata, extrainfo_str,1024);
    // 处理表达式中的 & 地址符号
    while(0 == LuaMatch(rawdata, "&%w+", seg_in, 128))
    {
        if (seg_in != NULL) 
        {
            char seg_out[20];
            
            // uint16_t regAddr = strToHex(seg_in);
            //TODO:获取提供内存的值
            LuaGsub(rawdata, seg_in,seg_out, dstdata,1024);
            strncpy(rawdata, dstdata,1024);
        }
    }

    processFormatString(rawdata);

    return 0;
}

/**
 * @brief       根据lua节点路径获取值
 * @param[in]   void *obj            lua对象
 * @param[in]   const char* path     lua节点路径
 * @example     path:"event_config.BCU_point_table[1].regs[1].extrainfo[4][2]"
 * @param[out]  LuaValue* result     结果
 * @return      int
 * @retval      0:正常  !0:错误
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-02           JHC        创建初始版本          \n
*/
int clua_getvalue(void *obj, const char* path, LuaValue* result) 
{
    if(obj == NULL || path == NULL || result == NULL)
    {
        return -1;
    }

    lua_State *L = (lua_State *)obj;
    char seps[] = ".[]"; // 分隔符：点、左括号、右括号

#ifdef WIN32
    char* path_copy = _strdup(path); // 创建path的副本
#else
    char* path_copy = strdup(path); // 创建path的副本
#endif

    lua_getglobal(L, "_G"); // 从全局环境开始
#ifdef WIN32
    char* context = NULL; // strtok_s需要的额外指针，用于在后续调用中维持状态
    char* token = strtok_s(path_copy, seps, &context); // 初始化标记
#else
    char* rest = path_copy;  // strtok_r的额外指针，用于保持上下文
    char* token = strtok_r(path_copy, seps, &rest); // 初始化标记
#endif
    while (token != NULL) {
        char* endptr;
        long index = strtol(token, &endptr, 10); // 尝试将token转换为数字

        if (*endptr == '\0') { // token全是数字，说明是索引
            lua_pushnumber(L, index);
            lua_gettable(L, -2);
        }
        else { // 否则，作为键名处理
            lua_getfield(L, -1, token);
        }

        if (lua_isnil(L, -1)) { // 如果找不到对应值
            //printf("%s未找到\n", token);
            return -1;
        }

#ifdef WIN32
        token = strtok_s(NULL, seps, &context);
#else
        // 为下一个迭代获得新token
        token = strtok_r(NULL, seps, &rest);
#endif
    }

    result->type = LUA_VALUE_NONE;
    if (lua_isnumber(L, -1)) {
        result->int64Val = lua_tointeger(L, -1);
        result->type = LUA_VALUE_NUMBER;
    }
    else if (lua_isstring(L, -1)) {
        strncpy(result->stringVal, lua_tostring(L, -1), MAX_LUA_STRING_SIZE - 1);
        result->type = LUA_VALUE_STRING;
    }

    return 0;
}

/**
 * @brief       根据lua文件创建对应的对象
 * @param[in]   const char * luafile lua文件路径
 * @return      void *
 * @retval      obj对象
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-02           JHC        创建初始版本          \n
*/
void * clua_createluaobj(const char * luafile)
{
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    if (luaL_loadfile(L, luafile) || lua_pcall(L, 0, LUA_MULTRET, 0)) {
        fprintf(stderr, "Cannot run Lua file: %s\n", lua_tostring(L, -1));
        lua_close(L);
        return NULL;
    }

    return (void *)L;
}

/**
 * @brief       lua对象销毁
 * @param[in]   void *luaobj
 * @return      void
 * @retval      none
 * @par         修改日志:
 * Date                Author     Description           \n
 * 2024-02-02           JHC        创建初始版本          \n
*/
void clua_destoryluaobj(void *luaobj)
{
    lua_close((lua_State *)luaobj);
}