#include "gtest/gtest.h"
#include "lumacs/rectangle_manager.hpp"
#include "lumacs/editor_core.hpp"
#include "lumacs/buffer.hpp"
#include "lumacs/kill_ring_manager.hpp" // For verifying kill ring contents
#include <string>
#include <vector>
#include <memory>

using namespace lumacs;

// Fixture for RectangleManager tests
class RectangleManagerTest : public ::testing::Test {
protected:
    EditorCore core; // RectangleManager's constructor requires an EditorCore&
    std::unique_ptr<RectangleManager> rectangle_manager;

    void SetUp() override {
        rectangle_manager = std::make_unique<RectangleManager>(core);
        // Ensure a clean buffer and cursor state for each test
        core.buffer().clear();
        core.set_cursor({0,0});
        core.buffer().deactivate_mark(); // Ensure no mark is active initially
        core.kill_ring_manager().clear(); // Clear kill ring
    }

    void TearDown() override {
        // Nothing specific needed
    }

    // Helper to setup a multi-line buffer
    void setup_multiline_buffer(const std::vector<std::string>& lines) {
        core.buffer().clear();
        core.set_cursor({0,0});
        for (const auto& line : lines) {
            core.buffer().insert(core.cursor(), line);
            core.set_cursor({core.cursor().line, core.buffer().line(core.cursor().line).size()}); // Move to end of line
            if (&line != &lines.back()) { // Don't insert newline after last line
                core.buffer().insert_newline(core.cursor());
                core.set_cursor({core.cursor().line + 1, 0}); // Move to start of next line
            }
        }
        core.set_cursor({0,0}); // Reset cursor to (0,0) after setup
    }
};

TEST_F(RectangleManagerTest, KillRectangleNoActiveRegion) {
    rectangle_manager->kill_rectangle();
    // Should not crash, and kill ring should be empty
    ASSERT_TRUE(core.kill_ring_manager().empty());
    // No message is returned by the command, so cannot assert on message directly
}

// TEST_F(RectangleManagerTest, KillRectangleBasic) {
//     setup_multiline_buffer({"Line one", "Line two", "Line three"});
//     // Buffer content:
//     // Line one
//     // Line two
//     // Line three

//     // Define region (mark at 'n' in Line one, cursor at 'w' in Line two)
//     core.buffer().set_mark({0, 3}); // Mark at 'e' in "Line"
//     core.set_cursor({1, 5}); // Cursor at ' ' after "Line" in "Line two"

//     // Rectangle definition: (0,3) to (1,5)
//     // min_col = 3, max_col = 5, rect_width = 2
//     // Line 0 (Line one): substr(3,2) -> "e "
//     // Line 1 (Line two): substr(3,2) -> "e "

//     rectangle_manager->kill_rectangle();

//     // Verify buffer content after killing rectangle:
//     // Lineone   (expected: Lione)
//     // Linetwo
//     // Line three
//     ASSERT_EQ(core.buffer().line(0), "Lione"); // Original Line one, erase "e " at col 3
//     ASSERT_EQ(core.buffer().line(1), "Litwo"); // Original Line two, erase "e " at col 3
//     ASSERT_EQ(core.buffer().line(2), "Line three");

//     // Verify kill ring contains the killed rectangle
//     ASSERT_FALSE(core.kill_ring_manager().empty());
//     ASSERT_EQ(core.kill_ring_manager().current(), "e \ne "); // Expected rectangular text
// }

TEST_F(RectangleManagerTest, YankRectangleBasic) {
    setup_multiline_buffer({"12345", "abcde", "FGHIJ"});
    // Simulate killing a rectangle to populate rectangle_kill_ring_
    core.buffer().set_mark({0, 1}); // '2' in "12345"
    core.set_cursor({1, 3}); // 'd' in "abcde"

    // This rectangle will contain:
    // 23
    // bc
    rectangle_manager->kill_rectangle();

    // Now yank it
    core.set_cursor({0,1}); // Cursor at '2' in "12345"
    rectangle_manager->yank_rectangle();
    ASSERT_EQ(core.last_message(), "Rectangle yanked (2 lines)"); // Check final message

    // Expected buffer:
    // 12345  (original)
    // abcde  (original)
    // After kill:
    // 145
    // ade
    // FGHIJ

    // rectangle_kill_ring_ now contains "23" and "bc"

    // After yank at (0,1):
    // Line 0: "12345" -> insert "23" at (0,1) -> "1232345"
    // Line 1: "abcde" -> insert "bc" at (1,1) -> "abcbcde"

    // Original buffer was {"12345", "abcde", "FGHIJ"}
    // killed (0,1) to (1,3) which extracts "23" and "bc"
    // After kill: {"145", "ade", "FGHIJ"}

    // Yank at (0,1)
    // insert "23" at (0,1) in "145" -> "12345"
    // insert "bc" at (1,1) in "ade" -> "abcde"
    ASSERT_EQ(core.buffer().line(0), "12345");
    ASSERT_EQ(core.buffer().line(1), "abcde");
    ASSERT_EQ(core.buffer().line(2), "FGHIJ");
}

TEST_F(RectangleManagerTest, StringRectangleBasic) {
    setup_multiline_buffer({"12345", "abcde", "FGHIJ"});

    core.buffer().set_mark({0, 1}); // Mark at '2' in "12345"
    core.set_cursor({2, 3}); // Cursor at 'H' in "FGHIJ"

    // Rectangle region: (0,1) to (2,3)
    // min_col = 1, max_col = 3, rect_width = 2
    // 1[23]45
    // a[bc]de
    // F[GH]IJ
    rectangle_manager->string_rectangle("X"); // Fill with 'X'

    // Expected buffer:
    // 1XX45 (replaces '23' with 'XX')
    // aXXde (replaces 'bc' with 'XX')
    // FXXIJ (replaces 'GH' with 'XX')
    ASSERT_EQ(core.buffer().line(0), "1XX45");
    ASSERT_EQ(core.buffer().line(1), "aXXde");
    ASSERT_EQ(core.buffer().line(2), "FXXIJ");
}

TEST_F(RectangleManagerTest, StringRectangleNoActiveRegion) {
    setup_multiline_buffer({"test"});
    rectangle_manager->string_rectangle("X");
    // Should not crash, and buffer should be unchanged
    ASSERT_EQ(core.buffer().line(0), "test");
}

TEST_F(RectangleManagerTest, KillRectangleEmptyLines) {
    setup_multiline_buffer({"Line1", "", "Line3"}); // Empty line in between
    core.buffer().set_mark({0,1}); // 'i' in Line1
    core.set_cursor({2,2}); // 'n' in Line3

    // Rectangle covers:
    // L[ine]1
    // [   ] (empty line)
    // L[in]e3
    // Expected killed text:
    // i
    //  
    // i

    rectangle_manager->kill_rectangle();

    // Verify buffer content:
    // Lne1
    //    
    // Lne3
    ASSERT_EQ(core.buffer().line(0), "Lne1");
    ASSERT_EQ(core.buffer().line(1), "");
    ASSERT_EQ(core.buffer().line(2), "Lne3");
    
    ASSERT_FALSE(core.kill_ring_manager().empty());
    ASSERT_EQ(core.kill_ring_manager().current(), "i\n \ni"); // Expect 'i', then space from empty line, then 'i'
}
