#include "lumacs/lua_api.hpp"
#include "lumacs/command_system.hpp"
#include "lumacs/minibuffer_mode.hpp" // Added for MinibufferMode enum binding
#include "lumacs/completion_system.hpp" // Added for CompletionSystem access
#include "lumacs/plugin_manager.hpp" // Added for PluginManager access
#include "lumacs/buffer_manager.hpp" // Added for BufferManager::BufferInfo
#include "lumacs/logger.hpp"
#include "../src/defaults.hpp" // Include embedded defaults
#include <spdlog/spdlog.h>
#include <iostream> // Kept for now if needed by sol2 internals or other parts, but trying to remove direct usage
#include <fstream>
#include <filesystem> // For std::filesystem::path

namespace lumacs {

// Helper class to adapt a lambda/function to ICompletionSource
class LambdaCompletionSource : public ICompletionSource {
public:
    explicit LambdaCompletionSource(sol::function provider) : provider_(std::move(provider)) {}

    std::vector<CompletionCandidate> get_candidates(const std::string& input) override {
        sol::protected_function_result lua_result = provider_(input); // Get the raw Lua result
        std::vector<CompletionCandidate> candidates;

        if (lua_result.valid()) {
            sol::type result_type = lua_result.get_type();
            if (result_type == sol::type::table) {
                sol::table result_table = lua_result; // Convert to sol::table
                for (auto& pair : result_table) {
                    if (pair.second.get_type() == sol::type::table) {
                        sol::table candidate_table = pair.second;
                        std::string text = "";
                        int score = 50;
                        std::string desc = "";
                        
                        if (candidate_table["text"].valid()) {
                            text = candidate_table["text"];
                        }
                        if (candidate_table["score"].valid()) {
                            score = candidate_table["score"];
                        }
                        if (candidate_table["description"].valid()) {
                            desc = candidate_table["description"].get<std::string>(); // Get the string
                        }
                        
                        candidates.emplace_back(text, score, "", desc); // Fix: Explicitly pass empty string for display_text
                    }
                }
            }
        }
        return candidates;
    }

private:
    sol::function provider_;
};

LuaApi::LuaApi() {
    lua_.open_libraries(
        sol::lib::base,
        sol::lib::package,
        sol::lib::string,
        sol::lib::math,
        sol::lib::table,
        sol::lib::io,
        sol::lib::os,
        sol::lib::debug // Open debug library early for MobDebug
    );
}

void LuaApi::set_core(EditorCore& core) {
    core_ = &core;
    setup_api();
}

bool LuaApi::load_file(const std::filesystem::path& path) {
    try {
        spdlog::debug("Loading Lua file: {}", path.string());
        lua_.script_file(path.string());
        spdlog::debug("Lua file loaded successfully");
        spdlog::info("Loaded Lua file: {}", path.string());
        return true;
    } catch (const sol::error& e) {
        spdlog::error("Lua error loading {}: {}", path.string(), e.what());
        return false;
    } catch (const std::exception& e) {
        spdlog::error("Exception loading {}: {}", path.string(), e.what());
        return false;
    }
}

bool LuaApi::execute(std::string_view code) {
    try {
        lua_.script(code);
        return true;
    } catch (const sol::error& e) {
        spdlog::error("Lua error: {}", e.what());
        return false;
    }
}

bool LuaApi::load_init_file() {
    // 1. ALWAYS load the embedded defaults first
    spdlog::info("Loading embedded defaults...");
    try {
        lua_.script(LUA_DEFAULTS);
    } catch (const sol::error& e) {
        spdlog::critical("FAILED TO LOAD EMBEDDED DEFAULTS: {}", e.what());
        // Continue anyway
    }

    // Get home directory
    const char* home = getenv("HOME");
    std::string home_dir = home ? home : ".";

    // Try multiple locations in order
    std::vector<std::filesystem::path> search_paths = {
        std::filesystem::current_path() / "init.lua",
        std::filesystem::path(home_dir) / ".config" / "lumacs" / "init.lua",
        
        std::filesystem::path(home_dir) / ".lumacs" / "init.lua",
    };

    for (const auto& path : search_paths) {
        if (std::filesystem::exists(path)) {
            spdlog::info("Found init file: {}", path.string());
            return load_file(path);
        }
    }

    spdlog::warn("No init.lua found (searched: ./init.lua, ~/.config/lumacs/init.lua, ~/.lumacs/init.lua). Using defaults only.");
    return true; // Return true because defaults were loaded
}

void LuaApi::bind_key(std::string key, sol::function callback, std::string description) {
    spdlog::debug("Registering key binding: {}", key);
    
    // Create a unique command name for the Lua function
    // This is a simple way; a more robust system might handle conflicts or namespaces
    std::string command_name = "lua_cmd_" + key; // Use key itself as part of name

    // Register a C++ CommandFunction that wraps the Lua callback
    core_->command_system().register_command(command_name, 
        [callback, this](CommandContext& context) -> CommandResult { // Added 'this' to capture
            try {
                // Pass args from context to Lua function
                sol::table args_table = get_lua_state().create_table(); // Use get_lua_state()
                const auto& args = context.get_args(); // Use getter
                for (size_t i = 0; i < args.size(); ++i) {
                    args_table[i + 1] = args[i];
                }
                auto result = callback(args_table);
                if (result.valid()) {
                    if (result.get_type() == sol::type::table) {
                        sol::table res_table = result;
                        CommandStatus status = CommandStatus::Success;
                        std::string message = "";
                        
                        if (res_table["success"].valid()) {
                            status = res_table["success"].get<bool>() ? CommandStatus::Success : CommandStatus::Failure;
                        }
                        if (res_table["message"].valid()) {
                            message = res_table["message"];
                        }
                        return CommandResult{status, message};
                    } else if (result.get_type() == sol::type::string) {
                        std::string message = result.get<std::string>();
                        return CommandResult{CommandStatus::Success, message};
                    } else {
                        return CommandResult{CommandStatus::Success, ""};
                    }
                } else {
                    return CommandResult{CommandStatus::Success, ""};
                }
            } catch (const sol::error& e) {
                return CommandResult{CommandStatus::Failure, "Lua error in key binding callback: " + std::string(e.what())};
            }
        },
        description, // Use original description
        false,       // Not interactive directly via spec, Lua callback handles interactivity
        ""           // No interactive spec for this wrapper command
    );

    // Now bind the key to the newly registered C++ command's name
    core_->keybinding_manager().bind(KeySequence(key), command_name, description);
}

KeyProcessingResult LuaApi::process_key(const std::string& key) { // Corrected return type
    return core_->keybinding_manager().process_key(key);
}

// Legacy methods for backward compatibility
bool LuaApi::has_key_binding(const std::string& key) const {
    return legacy_key_bindings_.find(key) != legacy_key_bindings_.end() ||
           core_->keybinding_manager().has_exact_binding(KeySequence(key));
}

bool LuaApi::execute_key_binding(const std::string& key) {
    auto it = legacy_key_bindings_.find(key);
    if (it == legacy_key_bindings_.end()) {
        return false;
    }

    try {
        it->second();
        return true;
    } catch (const sol::error& e) {
        spdlog::error("Lua error executing key binding '{}': {}", key, e.what());
        return false;
    }
}

// Manual C functions implementations
int LuaApi::get_active_buffer_line_count_lua() {
    if (!core_ || !core_->active_window() || !core_->active_window()->buffer_ptr()) {
        spdlog::warn("get_active_buffer_line_count_lua: Core, active window or buffer is null!");
        return 0;
    }
    return static_cast<int>(core_->buffer().line_count());
}

void LuaApi::lua_editor_move_right() {
    if (!core_) {
        spdlog::warn("lua_editor_move_right: Core is null!");
        return;
    }
    core_->move_right();
}

void LuaApi::lua_editor_new_buffer(const std::string& name) {
    if (!core_) {
        spdlog::warn("lua_editor_new_buffer: Core is null!");
        return;
    }
    core_->new_buffer(name);
}

sol::optional<std::string> LuaApi::lua_editor_get_buffer_by_name(const std::string& name) {
    if (!core_) {
        spdlog::warn("lua_editor_get_buffer_by_name: Core is null!");
        return sol::nullopt;
    }
    if (auto buffer = core_->get_buffer_by_name(name)) {
        return buffer->name(); // Return name as a string to avoid complex Buffer usertype issues
    }
    return sol::nullopt;
}

void LuaApi::lua_editor_set_message(const std::string& message) {
    if (!core_) {
        spdlog::warn("lua_editor_set_message: Core is null!");
        return;
    }
    core_->set_message(message);
}

void LuaApi::lua_config_set_string(const std::string& key, const std::string& value) {
    if (!core_) {
        spdlog::warn("lua_config_set_string: Core is null!");
        return;
    }
    core_->config().set(key, value);
}

std::string LuaApi::lua_config_get_string(const std::string& key, const std::string& default_val) {
    if (!core_) {
        spdlog::warn("lua_config_get_string: Core is null!");
        return default_val;
    }
    return core_->config().get<std::string>(key, default_val);
}

void LuaApi::lua_config_set_bool(const std::string& key, bool value) {
    if (!core_) {
        spdlog::warn("lua_config_set_bool: Core is null!");
        return;
    }
    core_->config().set(key, value);
}

bool LuaApi::lua_config_get_bool(const std::string& key, bool default_val) {
    if (!core_) {
        spdlog::warn("lua_config_get_bool: Core is null!");
        return default_val;
    }
    return core_->config().get<bool>(key, default_val);
}

void LuaApi::lua_config_set_int(const std::string& key, int value) {
    if (!core_) {
        spdlog::warn("lua_config_set_int: Core is null!");
        return;
    }
    core_->config().set(key, value);
}

int LuaApi::lua_config_get_int(const std::string& key, int default_val) {
    if (!core_) {
        spdlog::warn("lua_config_get_int: Core is null!");
        return default_val;
    }
    return core_->config().get<int>(key, default_val);
}

void LuaApi::setup_api() {
    register_types();
    register_functions();

    // Set version info and add constructor functions to lumacs namespace
    auto lumacs_table = lua_.create_table();
    lumacs_table["version"] = "0.1.0";
    lumacs_table["name"] = "Lumacs";

    // Add constructor functions
    lumacs_table["Position"] = [](size_t line, size_t column) {
        return Position{line, column};
    };
    lumacs_table["Range"] = [](Position start, Position end) {
        return Range{start, end};
    };
    lumacs_table["TextAttribute"] = [](TextAttribute::ColorType color, int style) {
        return TextAttribute{color, style};
    };
    lumacs_table["StyledRange"] = [](Range range, TextAttribute attr) {
        return StyledRange{range, attr};
    };

    // Add enums to lumacs namespace for convenience
    lumacs_table["ColorType"] = lua_["ColorType"];
    lumacs_table["Style"] = lua_["Style"];
    lumacs_table["BufferEvent"] = lua_["BufferEvent"];
    lumacs_table["ThemeElement"] = lua_["ThemeElement"];
    lumacs_table["FontWeight"] = lua_["FontWeight"];
    lumacs_table["FontSlant"] = lua_["FontSlant"];
    lumacs_table["FaceAttributes"] = lua_["FaceAttributes"];
    lumacs_table["MinibufferMode"] = lua_["MinibufferMode"]; // Expose MinibufferMode to Lua
    
    lua_["lumacs"] = lumacs_table;

    // Initialize MobDebug if enabled
    if (core_->config().get<bool>("debug_lua", false)) { // Corrected Config access
        spdlog::debug("Lua debugging enabled.");
        std::string debug_host = core_->config().get<std::string>("debug_host", "127.0.0.1"); // Corrected Config access
        int debug_port = core_->config().get<int>("debug_port", 8171); // Corrected Config access

        try {
            // MobDebug requires socket library, which is already opened in constructor.
            // Explicitly require 'mobdebug' module
            sol::optional<sol::table> mobdebug = lua_["require"]("mobdebug");
            if (mobdebug) {
                spdlog::debug("MobDebug module loaded.");
                sol::function mobdebug_start = mobdebug.value()["start"];
                if (mobdebug_start.valid()) {
                    mobdebug_start(debug_host, debug_port);
                    spdlog::info("MobDebug started on {}:{}", debug_host, debug_port);
                } else {
                    spdlog::error("MobDebug.start function not found.");
                }
            } else {
                spdlog::error("Failed to load MobDebug module. Is LuaRocks installed and configured?");
            }
        } catch (const sol::error& e) {
            spdlog::error("Lua error during MobDebug initialization: {}", e.what());
        }
    }
}

void LuaApi::register_types() {
    // Position type
    lua_.new_usertype<Position>("Position",
        sol::constructors<Position(), Position(size_t, size_t)>(),
        "line", &Position::line,
        "column", &Position::column
    );

    // Range type
    lua_.new_usertype<Range>("Range",
        sol::constructors<Range(), Range(Position, Position)>(),
        "start", &Range::start,
        "end", &Range::end
    );

    // Font weight
    lua_.new_enum<FontWeight>("FontWeight",
        {
            {"Normal", FontWeight::Normal},
            {"Bold", FontWeight::Bold},
            {"Light", FontWeight::Light}
        }
    );

    // Font slant
    lua_.new_enum<FontSlant>("FontSlant",
        {
            {"Normal", FontSlant::Normal},
            {"Italic", FontSlant::Italic},
            {"Oblique", FontSlant::Oblique}
        }
    );

    // FaceAttributes type
    lua_.new_usertype<FaceAttributes>("FaceAttributes",
        sol::constructors<FaceAttributes()>(),
        "family", &FaceAttributes::family,
        "height", &FaceAttributes::height,
        "weight", &FaceAttributes::weight,
        "slant", &FaceAttributes::slant,
        "foreground", &FaceAttributes::foreground,
        "background", &FaceAttributes::background,
        "underline", &FaceAttributes::underline,
        "inverse", &FaceAttributes::inverse,
        "inherit", &FaceAttributes::inherit
    );

    // TextAttribute type
    lua_.new_usertype<TextAttribute>("TextAttribute",
        sol::constructors<TextAttribute(), TextAttribute(std::string), TextAttribute(TextAttribute::ColorType, int)>(),
        "face_name", &TextAttribute::face_name
    );

    // TextAttribute::ColorType enum
    lua_.new_enum<TextAttribute::ColorType>("ColorType",
        {
            {"Default", TextAttribute::ColorType::Default},
            {"Keyword", TextAttribute::ColorType::Keyword},
            {"String", TextAttribute::ColorType::String},
            {"Comment", TextAttribute::ColorType::Comment},
            {"Function", TextAttribute::ColorType::Function},
            {"Type", TextAttribute::ColorType::Type},
            {"Number", TextAttribute::ColorType::Number},
            {"Operator", TextAttribute::ColorType::Operator},
            {"Variable", TextAttribute::ColorType::Variable},
            {"Constant", TextAttribute::ColorType::Constant},
            {"Error", TextAttribute::ColorType::Error}
        }
    );

    // TextAttribute::Style enum
    lua_.new_enum<TextAttribute::Style>("Style",
        {
            {"Normal", TextAttribute::Style::Normal},
            {"Bold", TextAttribute::Style::Bold},
            {"Italic", TextAttribute::Style::Italic},
            {"Underline", TextAttribute::Style::Underline}
        }
    );

    // BufferEvent enum
    lua_.new_enum<BufferEvent>("BufferEvent",
        {
            {"Created", BufferEvent::Created},
            {"Loaded", BufferEvent::Loaded},
            {"Closed", BufferEvent::Closed},
            {"BeforeChange", BufferEvent::BeforeChange},
            {"AfterChange", BufferEvent::AfterChange},
            {"LineChanged", BufferEvent::LineChanged},
            {"BeforeSave", BufferEvent::BeforeSave},
            {"AfterSave", BufferEvent::AfterSave},
            {"LanguageChanged", BufferEvent::LanguageChanged}
        }
    );

    // BufferEventData type
    lua_.new_usertype<BufferEventData>("BufferEventData",
        sol::no_constructor,
        "event", &BufferEventData::event,
        "line", &BufferEventData::line,
        "language", &BufferEventData::language
    );

    // StyledRange type
    lua_.new_usertype<StyledRange>("StyledRange",
        sol::constructors<StyledRange(), StyledRange(Range, TextAttribute)>(),
        "range", &StyledRange::range,
        "attr", &StyledRange::attr
    );

    // BufferInfo type
    lua_.new_usertype<BufferManager::BufferInfo>("BufferInfo", // Corrected
        sol::no_constructor,
        "name", &BufferManager::BufferInfo::name, // Corrected
        "size", &BufferManager::BufferInfo::size, // Corrected
        "modified", &BufferManager::BufferInfo::modified, // Corrected
        "mode", &BufferManager::BufferInfo::mode, // Corrected
        "filepath", sol::property([](const BufferManager::BufferInfo& info) -> sol::optional<std::string> { // Corrected
            if (info.filepath.has_value()) {
                return info.filepath->string();
            }
            return sol::nullopt;
        })
    );





    // Color type
    lua_.new_usertype<Color>("Color",
        sol::constructors<Color(), Color(int, int, int)>(),
        "r", &Color::r,
        "g", &Color::g,
        "b", &Color::b
    );

    // ThemeElement enum
    lua_.new_enum<ThemeElement>("ThemeElement",
        {
            {"Normal", ThemeElement::Normal},
            {"Keyword", ThemeElement::Keyword},
            {"String", ThemeElement::String},
            {"Comment", ThemeElement::Comment},
            {"Function", ThemeElement::Function},
            {"Type", ThemeElement::Type},
            {"Number", ThemeElement::Number},
            {"Constant", ThemeElement::Constant},
            {"Error", ThemeElement::Error},
            {"StatusLine", ThemeElement::StatusLine},
            {"StatusLineInactive", ThemeElement::StatusLineInactive},
            {"MessageLine", ThemeElement::MessageLine},
            {"LineNumber", ThemeElement::LineNumber},
            {"Cursor", ThemeElement::Cursor},
            {"Selection", ThemeElement::Selection},
            {"SearchMatch", ThemeElement::SearchMatch},
            {"SearchFail", ThemeElement::SearchFail}, // Corrected
            {"WindowBorder", ThemeElement::WindowBorder},
            {"WindowBorderActive", ThemeElement::WindowBorderActive},
            {"Background", ThemeElement::Background}
        }
    );

    // Theme type
    lua_.new_usertype<Theme>("Theme",
        sol::no_constructor,
        "set_color", [](Theme& theme, ThemeElement element, Color fg, sol::optional<Color> bg) {
            Color bg_color = bg.value_or(Color(-1, -1, -1));
            theme.set_color(element, fg, bg_color);
        },
        "set_face", &Theme::set_face,
        "get_fg_color", &Theme::get_fg_color,
        "get_bg_color", &Theme::get_bg_color,
        "name", &Theme::name
    );

    // ThemeManager type
    lua_.new_usertype<ThemeManager>("ThemeManager",
        sol::no_constructor,
        "set_active_theme", &ThemeManager::set_active_theme,
        "theme_names", &ThemeManager::theme_names,
        "active_theme", &ThemeManager::active_theme
    );

    // Config type
    lua_.new_usertype<Config>("Config",
        sol::no_constructor,
        "set", [](Config& config, const std::string& key, sol::object value) {
            if (value.is<bool>()) {
                config.set(key, value.as<bool>());
            } else if (value.is<int>()) {
                config.set(key, value.as<int>());
            } else if (value.is<std::string>()) {
                config.set(key, value.as<std::string>());
            }
        },
        "get_bool", [](const Config& config, const std::string& key, sol::optional<bool> default_val) {
            return config.get<bool>(key, default_val.value_or(false));
        },
        "get_int", [](const Config& config, const std::string& key, sol::optional<int> default_val) {
            return config.get<int>(key, default_val.value_or(0));
        },
        "get_string", [](const Config& config, const std::string& key, sol::optional<std::string> default_val) {
            return config.get<std::string>(key, default_val.value_or(""));
        },
        "has", &Config::has,
        "keys", &Config::keys
    );

    // MinibufferMode enum
    lua_.new_enum<MinibufferMode>("MinibufferMode", {
        {"None", MinibufferMode::None},
        {"Command", MinibufferMode::Command},
        {"FilePath", MinibufferMode::FilePath},
        {"BufferName", MinibufferMode::BufferName},
        {"ThemeName", MinibufferMode::ThemeName},
        {"ISearch", MinibufferMode::ISearch},
        {"ystring", MinibufferMode::ystring},
        {"y_or_n_p", MinibufferMode::y_or_n_p}
    });

    // Buffer type
    lua_.new_usertype<Buffer>("Buffer",
        sol::no_constructor,
        "name", &Buffer::name,
        "set_name", &Buffer::set_name,
        "filepath", [](const Buffer& b) -> sol::optional<std::string> {
            auto path = b.file_path();
            if (!path.has_value()) return sol::nullopt;
            return path->string();
        },
        "line_count", &Buffer::line_count,
        "is_modified", &Buffer::is_modified,
        "line", [](Buffer& b, size_t idx) {
            if (idx >= b.line_count()) return std::string("");
            return b.line(idx);
        },
        "content", &Buffer::content,
        "insert", &Buffer::insert,
        "insert_newline", &Buffer::insert_newline,
        "erase", &Buffer::erase,
        "erase_char", &Buffer::erase_char,
        "clear", &Buffer::clear,
        "save", &Buffer::save,
        
        // Mark & Region
        "set_mark", &Buffer::set_mark,
        "deactivate_mark", &Buffer::deactivate_mark,
        "has_mark", [](const Buffer& b) { return b.mark().has_value(); },
        "mark", sol::property([](const Buffer& b) -> sol::optional<Position> {
            auto m = b.mark();
            if (m.has_value()) return *m;
            return sol::nullopt;
        }),
        "get_region", [](Buffer& b, Position p) -> sol::optional<Range> {
            auto r = b.get_region(p);
            if (r.has_value()) return *r;
            return sol::nullopt;
        },
        "get_text_in_range", &Buffer::get_text_in_range,
        "get_all_text", &Buffer::content, // Alias
        "replace", [](Buffer& b, Range r, const std::string& text) {
            b.erase(r);
            b.insert(r.start, text);
        },

        // Styling
        "set_style", &Buffer::set_style,
        "clear_styles", &Buffer::clear_styles,
        "get_line_styles", &Buffer::get_line_styles,

        // Events
        "on_buffer_event", [](Buffer& b, sol::function callback) {
            b.on_buffer_event([callback](const BufferEventData& data) {
                try {
                    callback(data);
                } catch (const sol::error& e) {
                    spdlog::error("Lua error in buffer event listener: {}", e.what());
                }
            });
        },
        
        // Search
        "find", [](Buffer& b, const std::string& query, sol::optional<Position> start_pos) -> sol::optional<Range> {
            auto r = b.find(query, start_pos.value_or(Position{0,0}));
            if (r.has_value()) return *r;
            return sol::nullopt;
        }
    );

    // EditorCore type
    lua_.new_usertype<EditorCore>("EditorCore",
        sol::no_constructor,

        "cursor", sol::property(&EditorCore::cursor, &EditorCore::set_cursor), // Added cursor property
        "set_cursor", &EditorCore::set_cursor, // Explicit setter method
        
        // Movement
        "move_up", &EditorCore::move_up,
        "move_down", &EditorCore::move_down,
        "move_left", &EditorCore::move_left,
        "move_right", &EditorCore::move_right,
        "move_to_line_start", &EditorCore::move_to_line_start,
        "move_to_line_end", &EditorCore::move_to_line_end,
        "move_forward_word", &EditorCore::move_forward_word,
        "move_backward_word", &EditorCore::move_backward_word,

        "page_up", &EditorCore::page_up,
        "page_down", &EditorCore::page_down,
        "goto_beginning", &EditorCore::goto_beginning,
        "goto_end", &EditorCore::goto_end,
        "goto_line", &EditorCore::goto_line,
        "load_file", &EditorCore::load_file,

        "split_horizontally", &EditorCore::split_horizontally,
        "split_vertically", &EditorCore::split_vertically,
        "close_window", &EditorCore::close_active_window,
        "next_window", &EditorCore::next_window, // Corrected
        "set_active_window", &EditorCore::set_active_window,
        "undo", &EditorCore::undo,
        "redo", &EditorCore::redo,
        "command_mode", &EditorCore::enter_command_mode,
        "buffer_switch_mode", &EditorCore::enter_buffer_switch_mode,
        "kill_buffer_mode", &EditorCore::enter_kill_buffer_mode,
        "find_file_mode", &EditorCore::enter_find_file_mode,
        "isearch_mode", &EditorCore::enter_isearch_mode,
        "isearch_backward_mode", &EditorCore::enter_isearch_backward_mode,
        "quit", &EditorCore::request_quit,
        // Kill ring
        "kill_line", &EditorCore::kill_line,
        "kill_region", &EditorCore::kill_region,
        "kill_word", &EditorCore::kill_word,
        "backward_kill_word", &EditorCore::backward_kill_word,
        "copy_region_as_kill", &EditorCore::copy_region_as_kill,
        "yank", &EditorCore::yank,
        "yank_pop", &EditorCore::yank_pop,
        // Registers
        "copy_to_register", &EditorCore::copy_to_register,
        "insert_register", &EditorCore::insert_register,
        "copy_region_to_register", &EditorCore::copy_region_to_register,
        "yank_from_register", &EditorCore::yank_from_register,
        // Keyboard macros
        "start_kbd_macro", &EditorCore::start_kbd_macro,
        "end_kbd_macro_or_call", &EditorCore::end_kbd_macro_or_call,
        "record_key_sequence", &EditorCore::record_key_sequence,
        "is_recording_macro", &EditorCore::is_recording_macro,
        // Rectangles
        "kill_rectangle", &EditorCore::kill_rectangle,
        "yank_rectangle", &EditorCore::yank_rectangle,
        "string_rectangle", &EditorCore::string_rectangle,
        // Buffer management
        "get_buffer_names", &EditorCore::get_buffer_names,

        "buffer", sol::property([](EditorCore& e) -> Buffer* {
            try {
                return &e.buffer();
            } catch (const std::exception& ex) {
                spdlog::error("Exception in editor.buffer: {}", ex.what());
                return nullptr;
            }
        }),

        "switch_buffer_in_window", &EditorCore::switch_buffer_in_window,
        "close_buffer", &EditorCore::close_buffer,
        "get_all_buffer_info", &EditorCore::get_all_buffer_info,
        // Theme management
        "theme_manager", sol::property([](EditorCore& e) -> ThemeManager& { return e.theme_manager(); }),
        "config", sol::property([](EditorCore& e) -> Config& { return e.config(); }), // Added config property
        "set_theme", [](EditorCore& e, const std::string& theme_name) { e.theme_manager().set_active_theme(theme_name); }, // Corrected
        "active_theme", sol::property([](EditorCore& e) -> const Theme& { return *e.theme_manager().active_theme(); }), // Corrected
        "message", &EditorCore::set_message, // Added message alias for set_message

        
        // Key binding (method on EditorCore)
        "bind_key", [this](EditorCore& core, std::string key, sol::object callback_or_cmd, sol::optional<std::string> description) {
            if (callback_or_cmd.is<std::string>()) {
                // Bind directly to an existing command name
                std::string cmd_name = callback_or_cmd.as<std::string>();
                core.keybinding_manager().bind(KeySequence(key), cmd_name, description.value_or(""));
            } 
            else if (callback_or_cmd.is<sol::function>()) {
                // Create a unique command name for the Lua function
                std::string command_name = "lua_cmd_" + key; // Use key itself as part of name
                sol::function callback = callback_or_cmd.as<sol::function>();

                // Register a C++ CommandFunction that wraps the Lua callback
                core.command_system().register_command(command_name, 
                    [callback, this](CommandContext& context) -> CommandResult { // Added 'this' to capture
                        try {
                            // Pass args from context to Lua function
                            sol::table args_table = get_lua_state().create_table(); // Use get_lua_state()
                            const auto& args = context.get_args(); // Use getter
                            for (size_t i = 0; i < args.size(); ++i) {
                                args_table[i + 1] = args[i];
                            }
                            auto result = callback(args_table);
                            if (result.valid()) {
                                if (result.get_type() == sol::type::table) {
                                    sol::table res_table = result;
                                    CommandStatus status = CommandStatus::Success;
                                    std::string message = "";
                                    
                                    if (res_table["success"].valid()) {
                                        status = res_table["success"].get<bool>() ? CommandStatus::Success : CommandStatus::Failure;
                                    }
                                    if (res_table["message"].valid()) {
                                        message = res_table["message"];
                                    }
                                    return CommandResult{status, message};
                                } else if (result.get_type() == sol::type::string) {
                                    std::string message = result.get<std::string>();
                                    return CommandResult{CommandStatus::Success, message};
                                } else {
                                    return CommandResult{CommandStatus::Success, ""};
                                }
                            } else {
                                return CommandResult{CommandStatus::Success, ""};
                            }
                        } catch (const sol::error& e) {
                            return CommandResult{CommandStatus::Failure, "Lua error in key binding callback: " + std::string(e.what())};
                        }
                    },
                    description.value_or(""), // Use original description
                    false,       // Not interactive directly via spec, Lua callback handles interactivity
                    ""           // No interactive spec for this wrapper command
                );

                // Now bind the key to the newly registered C++ command's name
                core.keybinding_manager().bind(KeySequence(key), command_name, description.value_or(""));
            }
            else {
                spdlog::error("bind_key: Invalid argument type for callback. Expected string or function.");
            }
        },

        // Register command (method on EditorCore)
        "register_command", [this](EditorCore& core, std::string name, std::string description, sol::function func, sol::optional<sol::table> aliases_table, sol::optional<bool> interactive, sol::optional<std::string> interactive_spec) {
            std::vector<std::string> aliases;
            if (aliases_table) {
                for (auto& pair : aliases_table.value()) {
                    aliases.push_back(pair.second.as<std::string>());
                }
            }
            
            CommandFunction command_func = [this, func](CommandContext& context) -> CommandResult {
                try {
                    // Pass args from context to Lua function
                    sol::table args_table = get_lua_state().create_table(); // Use get_lua_state()
                    const auto& args = context.get_args(); // Use getter
                    for (size_t i = 0; i < args.size(); ++i) {
                        args_table[i + 1] = args[i];
                    }
                    auto result = func(args_table);
                    if (result.valid()) {
                        if (result.get_type() == sol::type::table) {
                            sol::table res_table = result;
                            CommandStatus status = CommandStatus::Success;
                            std::string message = "";
                            
                            if (res_table["success"].valid()) {
                                status = res_table["success"].get<bool>() ? CommandStatus::Success : CommandStatus::Failure;
                            }
                            if (res_table["message"].valid()) {
                                message = res_table["message"];
                            }
                            return CommandResult{status, message};
                        } else if (result.get_type() == sol::type::string) {
                            std::string message = result.get<std::string>();
                            return CommandResult{CommandStatus::Success, message};
                        } else {
                            return CommandResult{CommandStatus::Success, ""};
                        }
                    } else {
                        return CommandResult{CommandStatus::Success, ""};
                    }
                } catch (const sol::error& e) {
                    return CommandResult{CommandStatus::Failure, "Lua error: " + std::string(e.what())};
                }
            };
            
            core.command_system().register_command(name, command_func, description, interactive.value_or(true), interactive_spec.value_or(""), aliases);
        },



        // Define face (method on EditorCore)
        "define_face", [](EditorCore& core, std::string name, const FaceAttributes& attrs) {
            if (auto theme = core.theme_manager().active_theme()) {
                theme->set_face(name, attrs);
            }
        },

        // Command system (method on EditorCore)
        "execute_command", [](EditorCore& core, std::string command_name, sol::optional<sol::table> args_table) {
            std::vector<std::string> args;
            if (args_table) {
                for (auto& pair : args_table.value()) {
                    args.push_back(pair.second.as<std::string>());
                }
            }
            auto result = core.command_system().execute(command_name, args);
            return std::make_tuple((bool)(result.status == CommandStatus::Success), result.message);
        }
    );
}

void LuaApi::register_functions() {
    // Global editor instance
    lua_["editor"] = std::ref(*core_);

    // Print function that goes to stderr (since stdout is used by TUI)
    lua_["print"] = [](sol::variadic_args args) {
        std::string message;
        for (auto arg : args) {
            message += lua_tostring(arg.lua_state(), arg.stack_index());
            message += "\t";
        }
        spdlog::info("[Lua] {}", message);
    };

    // Command system functions
    lua_["execute_command_line"] = [this](std::string command_string) {
        auto result = core_->minibuffer_manager().parse_and_execute_command_string(command_string);
        return std::make_tuple((bool)(result.status == CommandStatus::Success), result.message);
    };

    lua_["get_command_names"] = [this]() {
        return core_->command_system().get_command_names();
    };

    // New binding for executing interactive commands from Lua
    lua_["execute_interactive_command"] = [this](std::string command_name) {
        auto result = core_->command_system().execute_interactive(command_name);
        return std::make_tuple((bool)(result.status == CommandStatus::Success), result.message);
    };

    // New binding for getting interactive spec
    lua_["get_command_interactive_spec"] = [this](std::string command_name) {
        return core_->command_system().get_command_interactive_spec(command_name);
    };

    // New manual bindings for core interactions
    lua_["lumacs_get_active_buffer_line_count"] = [this]() {
        return this->get_active_buffer_line_count_lua();
    };
    lua_["lumacs_editor_move_right"] = [this]() {
        this->lua_editor_move_right();
    };
    lua_["lumacs_editor_new_buffer"] = [this](const std::string& name) {
        this->lua_editor_new_buffer(name);
    };
    lua_["lumacs_editor_get_buffer_by_name"] = [this](const std::string& name) {
        return this->lua_editor_get_buffer_by_name(name);
    };
    lua_["lumacs_editor_set_message"] = [this](const std::string& message) {
        this->lua_editor_set_message(message);
    };
    lua_["lumacs_config_set_string"] = [this](const std::string& key, const std::string& value) {
        this->lua_config_set_string(key, value);
    };
    lua_["lumacs_config_get_string"] = [this](const std::string& key, const std::string& default_val) {
        return this->lua_config_get_string(key, default_val);
    };
    lua_["lumacs_config_set_bool"] = [this](const std::string& key, bool value) {
        this->lua_config_set_bool(key, value);
    };
    lua_["lumacs_config_get_bool"] = [this](const std::string& key, bool default_val) {
        return this->lua_config_get_bool(key, default_val);
    };
    lua_["lumacs_config_set_int"] = [this](const std::string& key, int value) {
        this->lua_config_set_int(key, value);
    };
    lua_["lumacs_config_get_int"] = [this](const std::string& key, int default_val) {
        return this->lua_config_get_int(key, default_val);
    };

    // Completion functions
    lua_["get_completion_candidates"] = [this](int mode_int, std::string input) {
        MinibufferMode mode = static_cast<MinibufferMode>(mode_int);
        auto candidates = (*core_).completion_system().get_candidates_for_mode(mode, input);
        sol::table result = lua_.create_table();
        for (size_t i = 0; i < candidates.size(); ++i) {
            sol::table candidate = lua_.create_table();
            candidate["text"] = candidates[i].text;
            candidate["score"] = candidates[i].score;
            candidate["description"] = candidates[i].description;
            result[i + 1] = candidate;
        }
        return result;
    };

    lua_["register_completion_provider"] = [this](int mode_int, sol::function provider_func) {
        MinibufferMode mode = static_cast<MinibufferMode>(mode_int);
        // Pass the sol::function directly to the LambdaCompletionSource constructor
        (*core_).completion_system().register_source(mode, std::make_unique<LambdaCompletionSource>(provider_func));
    };

    // Plugin Manager functions
    lua_["plugin_manager"] = std::ref(core_->plugin_manager()); // Expose PluginManager to Lua

    // PluginManager types
    lua_.new_usertype<PluginManager>("PluginManager",
        sol::no_constructor,
        "discover_plugins", &PluginManager::discover_plugins,
        "load_plugin", &PluginManager::load_plugin,
        "unload_plugin", &PluginManager::unload_plugin,
        "get_discovered_plugins", sol::overload(
            [] (PluginManager& pm) { return pm.get_discovered_plugins(); },
            [] (PluginManager& pm, sol::this_state s) {
                // Convert to Lua table
                sol::state_view lua(s);
                sol::table t = lua.create_table();
                auto names = pm.get_discovered_plugins();
                for(size_t i = 0; i < names.size(); ++i) {
                    t[i+1] = names[i];
                }
                return t;
            }
        ),
        "get_loaded_plugins", sol::overload(
            [] (PluginManager& pm) { return pm.get_loaded_plugins(); },
            [] (PluginManager& pm, sol::this_state s) {
                // Convert to Lua table
                sol::state_view lua(s);
                sol::table t = lua.create_table();
                auto names = pm.get_loaded_plugins();
                for(size_t i = 0; i < names.size(); ++i) {
                    t[i+1] = names[i];
                }
                return t;
            }
        )
    );
}

} // namespace lumacs