#include "gtest/gtest.h"
#include "lumacs/editor_core.hpp"
#include "lumacs/lua_api.hpp"
#include "lumacs/keybinding.hpp"
#include "lumacs/command_system.hpp"
#include "lumacs/window.hpp"
#include <memory>

using namespace lumacs;

class DefaultsLoadingTest : public ::testing::Test {
protected:
    void SetUp() override {
        core = std::make_unique<EditorCore>();
        
        // Load the REAL defaults (this is what main.cpp does)
        core->lua_api()->load_init_file();
        
        // Ensure buffer is ready and attached to window
        core->new_buffer("*scratch*");
        
        // Ensure we have an active window (Core constructor makes one, new_buffer assigns buffer to it)
        if (!core->active_window()) {
             // This shouldn't happen given EditorCore ctor logic, but safe check
        }
        
        core->set_cursor({0,0});
    }

    void TearDown() override {
        core.reset();
    }

    std::unique_ptr<EditorCore> core;
};

TEST_F(DefaultsLoadingTest, SelfInsertFromDefaults) {
    std::string input_key = "h";
    
    // 1. Process key (should be unbound in defaults)
    // Wait, 'h' is unbound. fallback triggers self-insert-command.
    // KeyBindingManager returns Unbound.
    auto result = core->keybinding_manager().process_key(input_key);
    EXPECT_EQ(result.type, KeyResult::Unbound);
    
    // 2. Simulate GtkEditor fallback logic
    if (result.type == KeyResult::Unbound) {
        if (input_key.length() == 1) {
            // This executes the LUA version of self-insert-command defined in defaults.hpp
            auto cmd_result = core->command_system().execute("self-insert-command", {input_key});
            
            EXPECT_EQ(cmd_result.status, CommandStatus::Success) << "Message: " << cmd_result.message;
        }
    }
    
    // 3. Verify state
    EXPECT_EQ(core->buffer().content(), "h");
}

TEST_F(DefaultsLoadingTest, NextLineCommand) {
    // Setup: 2 lines
    core->buffer().insert({0,0}, "Line 1\nLine 2");
    core->set_cursor({0,0});
    
    // Press C-n
    // "C-n" -> "next-line" -> editor:move_down()
    auto result = core->keybinding_manager().process_key("C-n");
    
    EXPECT_EQ(result.type, KeyResult::Executed);
    
    // Check cursor position. Should be line 1.
    EXPECT_EQ(core->cursor().line, 1);
}

TEST_F(DefaultsLoadingTest, ReturnKeyNewline) {
    core->buffer().insert({0,0}, "Line1");
    core->set_cursor({0,5}); // End of line
    
    // Press Return
    // "Return" -> "insert-newline"
    auto result = core->keybinding_manager().process_key("Return");
    EXPECT_EQ(result.type, KeyResult::Executed);
    
    // Check content
    EXPECT_EQ(core->buffer().content(), "Line1\n");
    // Check cursor (should be line 1, col 0)
    EXPECT_EQ(core->cursor().line, 1);
    EXPECT_EQ(core->cursor().column, 0);
}