#include "gtest/gtest.h"
#include "lumacs/editor_core.hpp"
#include "lumacs/buffer_manager.hpp"
#include "lumacs/window_manager.hpp"
#include "lumacs/kill_ring_manager.hpp"

using namespace lumacs;

class IntegrationTest : public ::testing::Test {
protected:
    std::unique_ptr<EditorCore> core;

    void SetUp() override {
        core = std::make_unique<EditorCore>();
        core->buffer().clear(); // Start with clean scratch buffer
        core->set_cursor({0,0});
    }

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

TEST_F(IntegrationTest, BufferWindowIndependenceAndKillRing) {
    // 1. Setup initial buffer "buffer1"
    core->new_buffer("buffer1");
    core->buffer().insert({0,0}, "Hello");
    ASSERT_EQ(core->buffer().content(), "Hello");

    // 2. Split window. Both should show "buffer1"
    core->split_horizontally();
    // Now we have 2 windows. The new one is active.
    auto w2 = core->active_window();
    // Switch focus to w1 (previous) just to check
    core->next_window();
    auto w1 = core->active_window();
    ASSERT_NE(w1, w2);
    ASSERT_EQ(w1->buffer().name(), "buffer1");
    ASSERT_EQ(w2->buffer().name(), "buffer1");

    // 3. Create "buffer2" and switch active window (w1) to it
    // Note: new_buffer switches the active window to the new buffer
    core->new_buffer("buffer2");
    ASSERT_EQ(core->active_window()->buffer().name(), "buffer2");
    // Check that w2 still shows buffer1
    ASSERT_EQ(w2->buffer().name(), "buffer1");

    // 4. Insert text in buffer2
    core->buffer().insert({0,0}, "World");
    ASSERT_EQ(core->buffer().content(), "World");
    
    // Verify buffer1 is unchanged
    ASSERT_EQ(w2->buffer().content(), "Hello");

    // 5. Kill Ring Interaction
    // Switch to w2 (buffer1)
    core->set_active_window(w2);
    ASSERT_EQ(core->buffer().name(), "buffer1");
    
    // Kill "Hello"
    core->set_cursor({0,0});
    core->kill_line(); 
    ASSERT_EQ(core->buffer().content(), ""); // Empty now (newline might remain depending on kill_line logic)
    // Actually kill_line kills the text. If it was "Hello", and no newline, it kills "Hello".
    
    // Switch to w1 (buffer2)
    core->set_active_window(w1);
    ASSERT_EQ(core->buffer().name(), "buffer2");
    
    // Go to end
    core->goto_end();
    // Yank "Hello"
    core->yank();
    
    ASSERT_EQ(core->buffer().content(), "WorldHello");
}

TEST_F(IntegrationTest, CursorIndependenceSameBuffer) {
    core->new_buffer("shared_buf");
    core->buffer().insert({0,0}, "Line1\nLine2\nLine3");
    
    core->split_vertically();
    auto w2 = core->active_window();
    core->next_window();
    auto w1 = core->active_window();
    
    // Both view shared_buf
    ASSERT_EQ(w1->buffer().name(), "shared_buf");
    ASSERT_EQ(w2->buffer().name(), "shared_buf");
    
    // Move cursor in w1 to Line 3
    core->set_active_window(w1);
    core->goto_line(2); // 0-indexed -> Line 3
    ASSERT_EQ(core->cursor().line, 2);
    
    // Check w2 cursor - should still be at 0,0
    ASSERT_EQ(w2->cursor().line, 0);
    
    // Move w2 cursor to Line 2
    core->set_active_window(w2);
    core->goto_line(1);
    ASSERT_EQ(core->cursor().line, 1);
    
    // Check w1 cursor again
    ASSERT_EQ(w1->cursor().line, 2);
}
