#include <gtest/gtest.h>
#include "../../src/libs/CircularBuffer.h"

// Test fixture for CircularBuffer
class CircularBufferTest : public ::testing::Test {
protected:
    void SetUp() override {
        // Initialization code that runs before each test
        buffer = new CircularBuffer<int>(3); // Create a circular buffer of integers with capacity 5
    }

    void TearDown() override {
        // Clean-up code that runs after each test
        delete buffer;
    }

    // Member variables accessible in test cases
    CircularBuffer<int>* buffer;
};

// Test CircularBuffer push and pop operations
TEST_F(CircularBufferTest, PushAndPop) {
    // Push some integers into the circular buffer
    EXPECT_EQ(buffer->pushBack(10), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(buffer->pushBack(20), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(buffer->pushBack(30), CircularBufferErrorCode::SUCCESS);

    // Pop integers from the circular buffer and check values
    int item;
    EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(item, 10);
    EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(item, 20);
    EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(item, 30);
}

// Test CircularBuffer with different types
TEST_F(CircularBufferTest, DifferentTypes) {
    // Create a circular buffer of characters with capacity 3
    CircularBuffer<char> charBuffer(3);

    // Push some characters into the circular buffer
    EXPECT_EQ(charBuffer.pushBack('a'), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(charBuffer.pushBack('b'), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(charBuffer.pushBack('c'), CircularBufferErrorCode::SUCCESS);

    // Pop characters from the circular buffer and check values
    char c;
    EXPECT_EQ(charBuffer.popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'a');
    EXPECT_EQ(charBuffer.popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'b');
    EXPECT_EQ(charBuffer.popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'c');
}

// Test CircularBuffer with full and empty conditions
TEST_F(CircularBufferTest, FullAndEmpty) {
    // Fill up the buffer
    buffer->pushBack(10);
    buffer->pushBack(20);
    buffer->pushBack(30);

    // Try pushing into a full buffer
    EXPECT_EQ(buffer->pushBack(40), CircularBufferErrorCode::BUFFER_FULL);

    // Pop all elements from the buffer
    int item;
    EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::SUCCESS);

    // Try popping from an empty buffer
    EXPECT_EQ(buffer->popFront(item), CircularBufferErrorCode::BUFFER_EMPTY);
}

// Test CircularBuffer with nested CircularBuffer
TEST_F(CircularBufferTest, CircularBufferWithNestedCircularBuffer) {
    CircularBuffer<CircularBuffer<char>*> charBuffer(2);

    CircularBuffer<char> charSubBuffer1(3);
    CircularBuffer<char> charSubBuffer2(3);

    EXPECT_EQ(charSubBuffer1.pushBack('a'), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(charSubBuffer1.pushBack('b'), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(charSubBuffer1.pushBack('c'), CircularBufferErrorCode::SUCCESS);

    EXPECT_EQ(charSubBuffer2.pushBack('d'), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(charSubBuffer2.pushBack('e'), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(charSubBuffer2.pushBack('f'), CircularBufferErrorCode::SUCCESS);

    EXPECT_EQ(charBuffer.pushBack(&charSubBuffer1), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(charBuffer.pushBack(&charSubBuffer2), CircularBufferErrorCode::SUCCESS);

    CircularBuffer<char>* poppedCharSubBuffer;
    EXPECT_EQ(charBuffer.popFront(poppedCharSubBuffer), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(poppedCharSubBuffer, &charSubBuffer1);

    char c;
    EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'a');
    EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'b');
    EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'c');

    EXPECT_EQ(charBuffer.popFront(poppedCharSubBuffer), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(poppedCharSubBuffer, &charSubBuffer2);

    EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'd');
    EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'e');
    EXPECT_EQ(poppedCharSubBuffer->popFront(c), CircularBufferErrorCode::SUCCESS);
    EXPECT_EQ(c, 'f');
}