// lua_playdate.c - Cell integration for Playdate Lua API
// Wraps pd_api_lua.h functions for JavaScript access
// Note: This provides interop with Playdate's Lua runtime if needed

#include "cell.h"
#include "common.h"
#include <string.h>

// --- Lua API Functions ---

JSC_CCALL(lua_stop,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    pd_lua->stop();
    return JS_NULL;
)

JSC_CCALL(lua_start,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    pd_lua->start();
    return JS_NULL;
)

JSC_CCALL(lua_getArgCount,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    return JS_NewInt32(js, pd_lua->getArgCount());
)

JSC_CCALL(lua_getArgType,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    int pos = (int)js2number(js, argv[0]);
    const char *outClass = NULL;
    enum LuaType type = pd_lua->getArgType(pos, &outClass);
    JSValue obj = JS_NewObject(js);
    JS_SetPropertyStr(js, obj, "type", JS_NewInt32(js, type));
    JS_SetPropertyStr(js, obj, "class", outClass ? JS_NewString(js, outClass) : JS_NULL);
    return obj;
)

JSC_CCALL(lua_argIsNil,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    return JS_NewBool(js, pd_lua->argIsNil((int)js2number(js, argv[0])));
)

JSC_CCALL(lua_getArgBool,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    return JS_NewBool(js, pd_lua->getArgBool((int)js2number(js, argv[0])));
)

JSC_CCALL(lua_getArgInt,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    return JS_NewInt32(js, pd_lua->getArgInt((int)js2number(js, argv[0])));
)

JSC_CCALL(lua_getArgFloat,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    return JS_NewFloat64(js, pd_lua->getArgFloat((int)js2number(js, argv[0])));
)

JSC_CCALL(lua_getArgString,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    const char *str = pd_lua->getArgString((int)js2number(js, argv[0]));
    return str ? JS_NewString(js, str) : JS_NULL;
)

JSC_CCALL(lua_getArgBytes,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    size_t len;
    const char *bytes = pd_lua->getArgBytes((int)js2number(js, argv[0]), &len);
    if (!bytes) return JS_NULL;
    return js_new_blob_stoned_copy(js, bytes, len);
)

JSC_CCALL(lua_pushNil,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    pd_lua->pushNil();
    return JS_NULL;
)

JSC_CCALL(lua_pushBool,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    pd_lua->pushBool(JS_ToBool(js, argv[0]));
    return JS_NULL;
)

JSC_CCALL(lua_pushInt,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    pd_lua->pushInt((int)js2number(js, argv[0]));
    return JS_NULL;
)

JSC_CCALL(lua_pushFloat,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    pd_lua->pushFloat((float)js2number(js, argv[0]));
    return JS_NULL;
)

JSC_SCALL(lua_pushString,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    pd_lua->pushString(str);
)

JSC_CCALL(lua_pushBytes,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    size_t len;
    const char *data = js_get_blob_data(js, &len, argv[0]);
    if (data == (void*)-1) return JS_EXCEPTION;
    pd_lua->pushBytes(data, len);
    return JS_NULL;
)

JSC_SCALL(lua_callFunction,
    if (!pd_lua) return JS_RaiseDisrupt(js, "lua not initialized");
    int nargs = argc > 1 ? (int)js2number(js, argv[1]) : 0;
    const char *outerr = NULL;
    int result = pd_lua->callFunction(str, nargs, &outerr);
    if (result == 0 && outerr) {
        ret = JS_RaiseDisrupt(js, "Lua error: %s", outerr);
    } else {
        ret = JS_NewBool(js, result);
    }
)

static const JSCFunctionListEntry js_lua_funcs[] = {
    MIST_FUNC_DEF(lua, stop, 0),
    MIST_FUNC_DEF(lua, start, 0),
    MIST_FUNC_DEF(lua, getArgCount, 0),
    MIST_FUNC_DEF(lua, getArgType, 1),
    MIST_FUNC_DEF(lua, argIsNil, 1),
    MIST_FUNC_DEF(lua, getArgBool, 1),
    MIST_FUNC_DEF(lua, getArgInt, 1),
    MIST_FUNC_DEF(lua, getArgFloat, 1),
    MIST_FUNC_DEF(lua, getArgString, 1),
    MIST_FUNC_DEF(lua, getArgBytes, 1),
    MIST_FUNC_DEF(lua, pushNil, 0),
    MIST_FUNC_DEF(lua, pushBool, 1),
    MIST_FUNC_DEF(lua, pushInt, 1),
    MIST_FUNC_DEF(lua, pushFloat, 1),
    MIST_FUNC_DEF(lua, pushString, 1),
    MIST_FUNC_DEF(lua, pushBytes, 1),
    MIST_FUNC_DEF(lua, callFunction, 2),
};

JSValue js_lua_use(JSContext *js) {
    JSValue mod = JS_NewObject(js);
    JS_SetPropertyFunctionList(js, mod, js_lua_funcs, countof(js_lua_funcs));
    // Export type constants
    JS_SetPropertyStr(js, mod, "TYPE_NIL", JS_NewInt32(js, kTypeNil));
    JS_SetPropertyStr(js, mod, "TYPE_BOOL", JS_NewInt32(js, kTypeBool));
    JS_SetPropertyStr(js, mod, "TYPE_INT", JS_NewInt32(js, kTypeInt));
    JS_SetPropertyStr(js, mod, "TYPE_FLOAT", JS_NewInt32(js, kTypeFloat));
    JS_SetPropertyStr(js, mod, "TYPE_STRING", JS_NewInt32(js, kTypeString));
    JS_SetPropertyStr(js, mod, "TYPE_TABLE", JS_NewInt32(js, kTypeTable));
    JS_SetPropertyStr(js, mod, "TYPE_FUNCTION", JS_NewInt32(js, kTypeFunction));
    JS_SetPropertyStr(js, mod, "TYPE_THREAD", JS_NewInt32(js, kTypeThread));
    JS_SetPropertyStr(js, mod, "TYPE_OBJECT", JS_NewInt32(js, kTypeObject));
    return mod;
}
