// ============================================================================
// LUA BINDINGS - IMPLEMENTATION
// ============================================================================
// Exposes C++ rendering and input APIs to Lua scripts

#include "lua_bindings.h"
#include "lua_game.h"
#include "../display/low_level_render.h"
#include "../display/low_level_gui.h"
#include "../lib/input_manager.h"
#include <stdio.h>

// Registry key for LuaGame pointer
static const char* LUAGAME_REGISTRY_KEY = "LUAGAME_PTR";

// Helper: Get LuaGame instance from registry
static LuaGame* get_game(lua_State* L) {
    lua_pushstring(L, LUAGAME_REGISTRY_KEY);
    lua_gettable(L, LUA_REGISTRYINDEX);
    LuaGame* game = (LuaGame*)lua_touserdata(L, -1);
    lua_pop(L, 1);
    return game;
}

// ============================================================================
// RENDERER BINDINGS
// ============================================================================

// renderer.clear(white)
static int lua_renderer_clear(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    bool white = lua_toboolean(L, 1);
    game->renderer->clear_buffer();
    
    return 0;
}

// renderer.pixel(x, y, on)
static int lua_renderer_pixel(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    int x = luaL_checkinteger(L, 1);
    int y = luaL_checkinteger(L, 2);
    bool on = lua_toboolean(L, 3);
    
    game->renderer->set_pixel(x, y, on);
    
    return 0;
}

// renderer.rect(x, y, w, h, on, filled)
static int lua_renderer_rect(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    int x = luaL_checkinteger(L, 1);
    int y = luaL_checkinteger(L, 2);
    int w = luaL_checkinteger(L, 3);
    int h = luaL_checkinteger(L, 4);
    bool on = lua_toboolean(L, 5);
    bool filled = lua_isnone(L, 6) ? false : lua_toboolean(L, 6);
    
    if (filled) {
        game->renderer->draw_filled_rectangle(x, y, w, h, on, 1);
    } else {
        game->renderer->draw_rectangle(x, y, w, h, on, 1);
    }
    
    return 0;
}

// renderer.circle(x, y, radius, on, filled)
static int lua_renderer_circle(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    int x = luaL_checkinteger(L, 1);
    int y = luaL_checkinteger(L, 2);
    int radius = luaL_checkinteger(L, 3);
    bool on = lua_toboolean(L, 4);
    bool filled = lua_isnone(L, 5) ? false : lua_toboolean(L, 5);
    
    if (filled) {
        game->renderer->draw_filled_circle(x, y, radius, on);
    } else {
        game->renderer->draw_circle(x, y, radius, on);
    }
    
    return 0;
}

// renderer.line(x0, y0, x1, y1, on, width)
static int lua_renderer_line(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    int x0 = luaL_checkinteger(L, 1);
    int y0 = luaL_checkinteger(L, 2);
    int x1 = luaL_checkinteger(L, 3);
    int y1 = luaL_checkinteger(L, 4);
    bool on = lua_toboolean(L, 5);
    int width = lua_isnone(L, 6) ? 1 : luaL_checkinteger(L, 6);
    
    game->renderer->draw_line(x0, y0, x1, y1, on, width);
    
    return 0;
}

// renderer.text(x, y, text, on)
static int lua_renderer_text(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    int x = luaL_checkinteger(L, 1);
    int y = luaL_checkinteger(L, 2);
    const char* text = luaL_checkstring(L, 3);
    bool on = lua_toboolean(L, 4);
    
    game->renderer->set_text_color(on);
    game->renderer->draw_string(x, y, text, true);
    
    return 0;
}

// renderer.text_scaled(x, y, text, on, scale)
static int lua_renderer_text_scaled(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    int x = luaL_checkinteger(L, 1);
    int y = luaL_checkinteger(L, 2);
    const char* text = luaL_checkstring(L, 3);
    bool on = lua_toboolean(L, 4);
    int scale = lua_isnone(L, 5) ? 1 : luaL_checkinteger(L, 5);
    
    game->renderer->set_text_color(on);
    game->renderer->draw_string_scaled(x, y, text, scale, 1);
    
    return 0;
}

// renderer.triangle(x0, y0, x1, y1, x2, y2, on, filled)
static int lua_renderer_triangle(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    int x0 = luaL_checkinteger(L, 1);
    int y0 = luaL_checkinteger(L, 2);
    int x1 = luaL_checkinteger(L, 3);
    int y1 = luaL_checkinteger(L, 4);
    int x2 = luaL_checkinteger(L, 5);
    int y2 = luaL_checkinteger(L, 6);
    bool on = lua_toboolean(L, 7);
    bool filled = lua_isnone(L, 8) ? false : lua_toboolean(L, 8);
    
    if (filled) {
        game->renderer->draw_filled_triangle(x0, y0, x1, y1, x2, y2, on);
    } else {
        game->renderer->draw_triangle(x0, y0, x1, y1, x2, y2, on);
    }
    
    return 0;
}

// ============================================================================
// GAME STATE BINDINGS
// ============================================================================

// Global table to store persistent state variables
// game.vars[key] = value

// game.width() - get display width
static int lua_game_width(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    lua_pushinteger(L, game->width);
    return 1;
}

// game.height() - get display height
static int lua_game_height(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    lua_pushinteger(L, game->height);
    return 1;
}

// game.exit() - request exit to launcher
static int lua_game_exit(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    // Set exit flag (will be checked in wants_to_exit())
    lua_pushstring(L, "__exit_requested");
    lua_pushboolean(L, true);
    lua_settable(L, LUA_REGISTRYINDEX);
    
    return 0;
}

// game.set_frame_updates(enabled) - enable/disable continuous frame tick events
static int lua_game_set_frame_updates(lua_State* L) {
    LuaGame* game = get_game(L);
    if (!game) return 0;
    
    bool enabled = lua_toboolean(L, 1);
    
    // Set frame updates flag (will be checked in wants_frame_updates())
    lua_pushstring(L, "__wants_frame_updates");
    lua_pushboolean(L, enabled);
    lua_settable(L, LUA_REGISTRYINDEX);
    
    return 0;
}

// ============================================================================
// INPUT TYPE CONSTANTS
// ============================================================================

// Set up input type constants as global table
static void register_input_constants(lua_State* L) {
    lua_newtable(L);
    
    lua_pushstring(L, "NONE");
    lua_pushinteger(L, 0);
    lua_settable(L, -3);
    
    lua_pushstring(L, "TOUCH_DOWN");
    lua_pushinteger(L, 1);
    lua_settable(L, -3);
    
    lua_pushstring(L, "TOUCH_MOVE");
    lua_pushinteger(L, 2);
    lua_settable(L, -3);
    
    lua_pushstring(L, "TOUCH_UP");
    lua_pushinteger(L, 3);
    lua_settable(L, -3);
    
    lua_pushstring(L, "BUTTON_0");
    lua_pushinteger(L, 4);
    lua_settable(L, -3);
    
    lua_pushstring(L, "BUTTON_1");
    lua_pushinteger(L, 5);
    lua_settable(L, -3);
    
    lua_pushstring(L, "GESTURE");
    lua_pushinteger(L, 6);
    lua_settable(L, -3);

    lua_pushstring(L, "FRAME_TICK");
    lua_pushinteger(L, 7);
    lua_settable(L, -3);
    
    lua_setglobal(L, "INPUT");
}

// ============================================================================
// MAIN REGISTRATION FUNCTION
// ============================================================================

void lua_bindings_register(lua_State* L, LuaGame* game) {
    // Store game pointer in registry
    lua_pushstring(L, LUAGAME_REGISTRY_KEY);
    lua_pushlightuserdata(L, game);
    lua_settable(L, LUA_REGISTRYINDEX);
    
    // Create renderer table
    lua_newtable(L);
    
    lua_pushstring(L, "clear");
    lua_pushcfunction(L, lua_renderer_clear);
    lua_settable(L, -3);
    
    lua_pushstring(L, "pixel");
    lua_pushcfunction(L, lua_renderer_pixel);
    lua_settable(L, -3);
    
    lua_pushstring(L, "rect");
    lua_pushcfunction(L, lua_renderer_rect);
    lua_settable(L, -3);
    
    lua_pushstring(L, "circle");
    lua_pushcfunction(L, lua_renderer_circle);
    lua_settable(L, -3);
    
    lua_pushstring(L, "line");
    lua_pushcfunction(L, lua_renderer_line);
    lua_settable(L, -3);
    
    lua_pushstring(L, "text");
    lua_pushcfunction(L, lua_renderer_text);
    lua_settable(L, -3);
    
    lua_pushstring(L, "text_scaled");
    lua_pushcfunction(L, lua_renderer_text_scaled);
    lua_settable(L, -3);
    
    lua_pushstring(L, "triangle");
    lua_pushcfunction(L, lua_renderer_triangle);
    lua_settable(L, -3);
    
    lua_setglobal(L, "renderer");
    
    // Create game table
    lua_newtable(L);
    
    lua_pushstring(L, "width");
    lua_pushcfunction(L, lua_game_width);
    lua_settable(L, -3);
    
    lua_pushstring(L, "height");
    lua_pushcfunction(L, lua_game_height);
    lua_settable(L, -3);
    
    lua_pushstring(L, "exit");
    lua_pushcfunction(L, lua_game_exit);
    lua_settable(L, -3);
    
    lua_pushstring(L, "set_frame_updates");
    lua_pushcfunction(L, lua_game_set_frame_updates);
    lua_settable(L, -3);
    
    // Create empty vars table for persistent state
    lua_pushstring(L, "vars");
    lua_newtable(L);
    lua_settable(L, -3);
    
    lua_setglobal(L, "game");
    
    // Register input type constants
    register_input_constants(L);
    
    printf("Lua bindings registered\n");
}
