/*
 * dr_lua.c
 *
 * Author : Charles KWON
 *
 * This module provides a simple and reusable interface layer
 * between C firmware code and embedded Lua scripts.
 * It is designed to make calling Lua functions from C firmware
 * straightforward and safe.
 *
 * Example:
 *   Lua function: add3(x) = x + 3
 *   C function   : dr_lua_add3(int num1)
 */

#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"

/* -------------------------------------------------
 * External output function (UART / RTT, etc.)
 * This function must be implemented by the project.
 * ------------------------------------------------- */
extern void board_print(const char *s);

/* -------------------------------------------------
 * Global Lua state
 * ------------------------------------------------- */
static lua_State *g_L = NULL;

/* -------------------------------------------------
 * Initialize Lua VM
 * ------------------------------------------------- */
void dr_lua_init(void)
{
    g_L = luaL_newstate();

    /* Load base library only */
    luaL_requiref(g_L, "_G", luaopen_base, 1);
    lua_pop(g_L, 1);
}

/* -------------------------------------------------
 * Load Lua script
 * Defines:
 *   function add3(x)
 *       return x + 3
 *   end
 * ------------------------------------------------- */
void dr_lua_load_script(void)
{
    const char *lua_code =
        "function add3(x)\n"
        "    return x + 3\n"
        "end";

    if (luaL_dostring(g_L, lua_code) != LUA_OK) {
        const char *err = lua_tostring(g_L, -1);
        board_print(err);
        lua_pop(g_L, 1);
    }
}

/* -------------------------------------------------
 * Core interface function
 * Calls Lua function add3 from C firmware
 *
 * @param num1  Input integer value
 * @return      Result of (num1 + 3)
 *              -1 if Lua function is not found
 *              -2 if Lua call fails
 * ------------------------------------------------- */
int dr_lua_add3(int num1)
{
    int result = 0;

    /* 1. Get Lua function: add3 */
    lua_getglobal(g_L, "add3");

    if (!lua_isfunction(g_L, -1)) {
        lua_pop(g_L, 1);
        return -1;   /* Function not found */
    }

    /* 2. Push argument */
    lua_pushinteger(g_L, num1);

    /* 3. Call Lua function (1 argument, 1 return value) */
    if (lua_pcall(g_L, 1, 1, 0) != LUA_OK) {
        const char *err = lua_tostring(g_L, -1);
        board_print(err);
        lua_pop(g_L, 1);
        return -2;   /* Call failed */
    }

    /* 4. Read return value */
    if (lua_isinteger(g_L, -1)) {
        result = (int)lua_tointeger(g_L, -1);
    }

    /* 5. Clean up Lua stack */
    lua_pop(g_L, 1);

    return result;   /* num1 + 3 */
}
