#include <gtest/gtest.h>
#include <glog/logging.h>
#include <atomic>
#include <chrono>
#include <thread>
#include <vector>
#include "thread_safe_queue.h"

namespace mooncake {

class ThreadSafeQueueTest : public ::testing::Test {
   protected:
    void SetUp() override {
        google::InitGoogleLogging("ThreadSafeQueueTest");
        FLAGS_logtostderr = 1;
    }

    void TearDown() override { google::ShutdownGoogleLogging(); }
};

TEST_F(ThreadSafeQueueTest, BasicPushPop) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_TRUE(queue.push(1));
    EXPECT_EQ(queue.size_approx(), 1);
    EXPECT_FALSE(queue.empty());

    auto item = queue.pop();
    EXPECT_TRUE(item.has_value());
    EXPECT_EQ(item.value(), 1);
    EXPECT_EQ(queue.size_approx(), 0);
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, MultipleOperations) {
    const int num_items = 1000;
    ThreadSafeQueue<int> queue(2000);

    for (int i = 0; i < num_items; ++i) {
        EXPECT_TRUE(queue.push(i));
    }
    EXPECT_EQ(queue.size_approx(), num_items);

    for (int i = 0; i < num_items; ++i) {
        auto item = queue.pop();
        EXPECT_TRUE(item.has_value());
        EXPECT_EQ(item.value(), i);
    }

    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, BlockingPush) {
    ThreadSafeQueue<int> queue(3);
    std::atomic<bool> thread_started{false};
    std::atomic<bool> push_succeeded{false};

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));
    EXPECT_TRUE(queue.push(3));
    EXPECT_EQ(queue.size_approx(), 3);

    std::thread producer([&]() {
        thread_started = true;
        push_succeeded = queue.push(4);
    });

    while (!thread_started) {
        std::this_thread::yield();
    }

    auto item = queue.pop();
    EXPECT_TRUE(item.has_value());

    producer.join();

    EXPECT_TRUE(push_succeeded);
    EXPECT_EQ(queue.size_approx(), 3);
}

TEST_F(ThreadSafeQueueTest, BlockingPop) {
    ThreadSafeQueue<int> queue(10);
    std::atomic<bool> thread_started{false};
    std::optional<int> popped_item = std::nullopt;

    std::thread consumer([&]() {
        thread_started = true;
        popped_item = queue.pop();
    });

    while (!thread_started) {
        std::this_thread::yield();
    }

    EXPECT_TRUE(queue.push(42));

    consumer.join();

    EXPECT_TRUE(popped_item.has_value());
    EXPECT_EQ(popped_item.value(), 42);
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, PushWithTimeout) {
    ThreadSafeQueue<int> queue(2);

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));

    auto start = std::chrono::steady_clock::now();
    bool result = queue.push(3, std::chrono::milliseconds(10));
    auto end = std::chrono::steady_clock::now();

    EXPECT_FALSE(result);
    auto duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_GE(duration.count(), 10);

    queue.pop();
    start = std::chrono::steady_clock::now();
    result = queue.push(3, std::chrono::milliseconds(100));
    end = std::chrono::steady_clock::now();

    EXPECT_TRUE(result);
    duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_LT(duration.count(), 100);
}

TEST_F(ThreadSafeQueueTest, PopWithTimeout) {
    ThreadSafeQueue<int> queue(10);

    auto start = std::chrono::steady_clock::now();
    auto item = queue.pop(std::chrono::milliseconds(10));
    auto end = std::chrono::steady_clock::now();

    EXPECT_FALSE(item.has_value());
    auto duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_GE(duration.count(), 10);

    queue.push(42);
    start = std::chrono::steady_clock::now();
    item = queue.pop(std::chrono::milliseconds(100));
    end = std::chrono::steady_clock::now();

    EXPECT_TRUE(item.has_value());
    EXPECT_EQ(item.value(), 42);
    duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_LT(duration.count(), 100);
}

TEST_F(ThreadSafeQueueTest, ProducerConsumer) {
    const int num_producers = 2;
    const int num_consumers = 2;
    const int items_per_producer = 20;
    const int total_items = num_producers * items_per_producer;

    ThreadSafeQueue<int> queue(20);
    std::atomic<int> items_processed{0};
    std::vector<int> received_items;
    std::mutex items_mutex;
    std::atomic<bool> all_produced{false};

    std::mutex cv_mutex;
    std::condition_variable cv;

    auto start_time = std::chrono::steady_clock::now();
    const auto timeout = std::chrono::milliseconds(10);

    std::vector<std::thread> consumers;
    for (int i = 0; i < num_consumers; ++i) {
        consumers.emplace_back([&, i]() {
            while (true) {
                auto now = std::chrono::steady_clock::now();
                if (now - start_time > timeout && all_produced.load()) {
                    break;
                }

                auto item = queue.pop(std::chrono::milliseconds(1));
                if (item.has_value()) {
                    {
                        std::lock_guard<std::mutex> lock(items_mutex);
                        received_items.push_back(item.value());
                    }
                    items_processed++;
                    if (items_processed.load() == total_items) {
                        cv.notify_one();
                        break;
                    }
                } else if (all_produced.load() && queue.empty()) {
                    break;
                }
            }
        });
    }

    std::vector<std::thread> producers;
    for (int i = 0; i < num_producers; ++i) {
        producers.emplace_back([&, producer_id = i]() {
            for (int j = 0; j < items_per_producer; ++j) {
                int item = producer_id * 1000 + j;
                if (!queue.push(item, std::chrono::milliseconds(1))) {
                    LOG(WARNING) << "Push timeout for item " << item;
                    if (!queue.push(item, std::chrono::milliseconds(1))) {
                        LOG(ERROR)
                            << "Push failed after retry for item " << item;
                        break;
                    }
                }
            }
        });
    }

    for (auto& producer : producers) {
        producer.join();
    }
    all_produced = true;

    {
        std::unique_lock<std::mutex> lock(cv_mutex);
        cv.wait_for(lock, std::chrono::milliseconds(5),
                    [&]() { return items_processed.load() == total_items; });
    }

    queue.shutdown();

    for (auto& consumer : consumers) {
        if (consumer.joinable()) {
            consumer.join();
        }
    }

    EXPECT_EQ(items_processed.load(), total_items);
    EXPECT_EQ(received_items.size(), total_items);
}

TEST_F(ThreadSafeQueueTest, Shutdown) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_FALSE(queue.is_shutdown());

    queue.shutdown();
    EXPECT_TRUE(queue.is_shutdown());

    EXPECT_FALSE(queue.push(1));

    auto item = queue.pop();
    EXPECT_FALSE(item.has_value());

    EXPECT_FALSE(queue.push(1, std::chrono::milliseconds(10)));

    item = queue.pop(std::chrono::milliseconds(10));
    EXPECT_FALSE(item.has_value());
}

TEST_F(ThreadSafeQueueTest, ShutdownWakesBlockedThreads) {
    ThreadSafeQueue<int> queue(2);
    std::atomic<int> successful_ops{0};
    std::vector<std::thread> threads;

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));

    threads.emplace_back([&]() {
        if (queue.push(3)) {
            successful_ops++;
        }
    });
    std::this_thread::sleep_for(std::chrono::milliseconds(1));

    queue.shutdown();

    for (auto& thread : threads) {
        thread.join();
    }

    EXPECT_EQ(successful_ops.load(), 0);
    EXPECT_TRUE(queue.is_shutdown());
}

TEST_F(ThreadSafeQueueTest, StressTest) {
    const int num_operations = 10000;
    const int max_size = 50;

    ThreadSafeQueue<int> queue(max_size);
    std::atomic<int> push_count{0};
    std::atomic<int> pop_count{0};

    std::thread producer([&]() {
        for (int i = 0; i < num_operations; ++i) {
            if (queue.push(i, std::chrono::milliseconds(1))) {
                push_count++;
            }
        }
    });

    std::thread consumer([&]() {
        for (int i = 0; i < num_operations; ++i) {
            auto item = queue.pop(std::chrono::milliseconds(1));
            if (item.has_value()) {
                pop_count++;
            }
        }
    });

    producer.join();
    consumer.join();

    while (pop_count.load() < push_count.load()) {
        auto item = queue.pop(std::chrono::milliseconds(1));
        if (item.has_value()) {
            pop_count++;
        } else {
            break;
        }
    }

    EXPECT_EQ(push_count.load(), pop_count.load());
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, MoveSemantics) {
    struct MovableData {
        int value;
        explicit MovableData(int v) : value(v) {}
        MovableData(MovableData&& other) noexcept : value(other.value) {
            other.value = -1;
        }
        MovableData& operator=(MovableData&& other) noexcept {
            if (this != &other) {
                value = other.value;
                other.value = -1;
            }
            return *this;
        }

        MovableData(const MovableData&) = delete;
        MovableData& operator=(const MovableData&) = delete;
    };

    ThreadSafeQueue<MovableData> queue(10);

    MovableData data1(42);
    EXPECT_TRUE(queue.push(std::move(data1)));
    EXPECT_EQ(data1.value, -1);  // MovableData's move operations set the
                                 // moved-from object's value to -1
    auto item = queue.pop();
    EXPECT_TRUE(item.has_value());
    EXPECT_EQ(item.value().value, 42);
}

TEST_F(ThreadSafeQueueTest, QueueFullBehavior) {
    ThreadSafeQueue<int> queue(2);

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));
    EXPECT_EQ(queue.size_approx(), 2);

    auto start = std::chrono::steady_clock::now();
    bool result = queue.push(3, std::chrono::milliseconds(10));
    auto end = std::chrono::steady_clock::now();

    EXPECT_FALSE(result);
    auto duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_GE(duration.count(), 10);

    std::vector<std::thread> threads;
    std::atomic<int> successful_pushes{0};
    std::atomic<int> failed_pushes{0};
    for (int i = 0; i < 5; ++i) {
        threads.emplace_back([&, id = i]() {
            if (queue.push(100 + id, std::chrono::milliseconds(5))) {
                successful_pushes++;
            } else {
                failed_pushes++;
            }
        });
    }

    for (auto& thread : threads) {
        thread.join();
    }

    EXPECT_EQ(successful_pushes, 0);
    EXPECT_EQ(failed_pushes, 5);
}

/**********************************************************************************************
 */
TEST_F(ThreadSafeQueueTest, PopBatch_EmptyQueue) {
    ThreadSafeQueue<int> queue(10);

    auto start = std::chrono::steady_clock::now();
    auto batch_opt = queue.pop_batch(5, std::chrono::milliseconds(10));
    auto end = std::chrono::steady_clock::now();

    EXPECT_FALSE(batch_opt.has_value());
    auto duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_GE(duration.count(), 10);
}

TEST_F(ThreadSafeQueueTest, PopBatch_SingleItem) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_TRUE(queue.push(42));

    auto batch_opt = queue.pop_batch(5, std::chrono::milliseconds(100));

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 1);
    EXPECT_EQ(batch[0], 42);
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, PopBatch_MultipleItems) {
    const int num_items = 10;
    ThreadSafeQueue<int> queue(20);

    for (int i = 0; i < num_items; ++i) {
        EXPECT_TRUE(queue.push(i));
    }

    auto batch_opt = queue.pop_batch(5, std::chrono::milliseconds(100));

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 5);
    for (int i = 0; i < 5; ++i) {
        EXPECT_EQ(batch[i], i);
    }

    EXPECT_EQ(queue.size_approx(), 5);
}

TEST_F(ThreadSafeQueueTest, PopBatch_LessThanMaxBatch) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));

    auto batch_opt = queue.pop_batch(5, std::chrono::milliseconds(100));

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 2);
    EXPECT_EQ(batch[0], 1);
    EXPECT_EQ(batch[1], 2);
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, PopBatch_ExactBatchSize) {
    const int batch_size = 5;
    ThreadSafeQueue<int> queue(20);

    for (int i = 0; i < batch_size; ++i) {
        EXPECT_TRUE(queue.push(i));
    }

    auto batch_opt =
        queue.pop_batch(batch_size, std::chrono::milliseconds(100));

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), batch_size);
    for (int i = 0; i < batch_size; ++i) {
        EXPECT_EQ(batch[i], i);
    }
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, PopBatch_ShutdownDuringWait) {
    ThreadSafeQueue<int> queue(10);
    std::atomic<bool> thread_started{false};
    std::optional<std::vector<int>> result_batch_opt;

    std::thread consumer([&]() {
        thread_started = true;
        result_batch_opt = queue.pop_batch(5, std::chrono::milliseconds(1000));
    });

    while (!thread_started) {
        std::this_thread::yield();
    }

    std::this_thread::sleep_for(std::chrono::milliseconds(10));

    queue.shutdown();

    consumer.join();

    EXPECT_FALSE(result_batch_opt.has_value());
    EXPECT_TRUE(queue.is_shutdown());
}

TEST_F(ThreadSafeQueueTest, PopBatch_ConcurrentProducers) {
    const int num_producers = 3;
    const int items_per_producer = 10;
    const int total_items = num_producers * items_per_producer;

    ThreadSafeQueue<int> queue(total_items);
    std::vector<std::thread> producers;
    std::atomic<int> items_pushed{0};

    for (int i = 0; i < num_producers; ++i) {
        producers.emplace_back([&, producer_id = i]() {
            for (int j = 0; j < items_per_producer; ++j) {
                int item = producer_id * 100 + j;
                if (queue.push(item)) {
                    items_pushed++;
                }
            }
        });
    }

    for (auto& producer : producers) {
        producer.join();
    }

    EXPECT_EQ(items_pushed.load(), total_items);
    EXPECT_EQ(queue.size_approx(), total_items);

    int batches_received = 0;
    int total_received = 0;
    std::vector<int> all_received;

    while (total_received < total_items) {
        auto batch_opt = queue.pop_batch(7, std::chrono::milliseconds(100));
        if (batch_opt.has_value()) {
            batches_received++;
            auto& batch = batch_opt.value();
            total_received += batch.size();
            all_received.insert(all_received.end(), batch.begin(), batch.end());
        }
    }

    EXPECT_EQ(total_received, total_items);
    EXPECT_GE(batches_received, 1);
    EXPECT_LE(batches_received, (total_items + 6) / 7);

    std::sort(all_received.begin(), all_received.end());
    std::vector<int> expected;
    for (int i = 0; i < num_producers; ++i) {
        for (int j = 0; j < items_per_producer; ++j) {
            expected.push_back(i * 100 + j);
        }
    }
    std::sort(expected.begin(), expected.end());

    EXPECT_EQ(all_received, expected);
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, TryPopBatch_EmptyQueue) {
    ThreadSafeQueue<int> queue(10);

    auto batch_opt = queue.try_pop_batch(5);

    EXPECT_FALSE(batch_opt.has_value());
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, TryPopBatch_SingleItem) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_TRUE(queue.push(42));

    auto batch_opt = queue.try_pop_batch(5);

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 1);
    EXPECT_EQ(batch[0], 42);
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, TryPopBatch_LessThanMaxBatch) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));
    EXPECT_TRUE(queue.push(3));

    auto batch_opt = queue.try_pop_batch(5);

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 3);
    EXPECT_EQ(batch[0], 1);
    EXPECT_EQ(batch[1], 2);
    EXPECT_EQ(batch[2], 3);
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, TryPopBatch_ExactBatchSize) {
    const int batch_size = 4;
    ThreadSafeQueue<int> queue(10);

    for (int i = 0; i < batch_size; ++i) {
        EXPECT_TRUE(queue.push(i));
    }

    auto batch_opt = queue.try_pop_batch(batch_size);

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), batch_size);
    for (int i = 0; i < batch_size; ++i) {
        EXPECT_EQ(batch[i], i);
    }
    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, TryPopBatch_MoreThanMaxBatch) {
    ThreadSafeQueue<int> queue(10);

    for (int i = 0; i < 8; ++i) {
        EXPECT_TRUE(queue.push(i));
    }

    auto batch_opt = queue.try_pop_batch(5);

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 5);
    for (int i = 0; i < 5; ++i) {
        EXPECT_EQ(batch[i], i);
    }

    EXPECT_EQ(queue.size_approx(), 3);

    auto batch2_opt = queue.try_pop_batch(5);
    EXPECT_TRUE(batch2_opt.has_value());
    auto batch2 = batch2_opt.value();
    EXPECT_EQ(batch2.size(), 3);
    for (int i = 0; i < 3; ++i) {
        EXPECT_EQ(batch2[i], i + 5);
    }

    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, TryPopBatch_ShutdownQueue) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));

    queue.shutdown();

    auto batch_opt = queue.try_pop_batch(5);

    EXPECT_TRUE(batch_opt.has_value());

    EXPECT_TRUE(queue.is_shutdown());

    auto batch2_opt = queue.try_pop_batch(5);
    EXPECT_FALSE(batch2_opt.has_value());
}

TEST_F(ThreadSafeQueueTest, MixedOperations) {
    ThreadSafeQueue<int> queue(20);

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));

    auto item = queue.pop();
    EXPECT_TRUE(item.has_value());
    EXPECT_EQ(item.value(), 1);

    auto batch_opt = queue.try_pop_batch(3);
    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 1);
    EXPECT_EQ(batch[0], 2);

    for (int i = 0; i < 10; ++i) {
        EXPECT_TRUE(queue.push(100 + i));
    }

    auto batch2_opt = queue.pop_batch(5, std::chrono::milliseconds(100));
    EXPECT_TRUE(batch2_opt.has_value());
    auto batch2 = batch2_opt.value();
    EXPECT_EQ(batch2.size(), 5);
    for (int i = 0; i < 5; ++i) {
        EXPECT_EQ(batch2[i], 100 + i);
    }

    auto batch3_opt = queue.try_pop_batch(10);
    EXPECT_TRUE(batch3_opt.has_value());
    auto batch3 = batch3_opt.value();
    EXPECT_EQ(batch3.size(), 5);
    for (int i = 0; i < 5; ++i) {
        EXPECT_EQ(batch3[i], 105 + i);
    }

    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, PopBatch_TimeoutBehavior) {
    ThreadSafeQueue<int> queue(10);

    auto start = std::chrono::steady_clock::now();
    auto batch_opt = queue.pop_batch(3, std::chrono::milliseconds(50));
    auto end = std::chrono::steady_clock::now();

    EXPECT_FALSE(batch_opt.has_value());
    auto duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_GE(duration.count(), 50);

    std::thread producer([&]() {
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        queue.push(1);
    });

    start = std::chrono::steady_clock::now();
    batch_opt = queue.pop_batch(3, std::chrono::milliseconds(100));
    end = std::chrono::steady_clock::now();

    producer.join();

    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 1);
    EXPECT_EQ(batch[0], 1);
    duration =
        std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
    EXPECT_GE(duration.count(), 20);
    EXPECT_LT(duration.count(), 100);
}

TEST_F(ThreadSafeQueueTest, TryPopBatch_ConcurrentAccess) {
    const int num_threads = 4;
    const int items_per_thread = 25000;
    const int total_items = num_threads * items_per_thread;

    ThreadSafeQueue<int> queue(total_items);
    std::vector<std::thread> producers;
    std::vector<std::thread> consumers;
    std::atomic<int> total_popped{0};
    std::mutex result_mutex;
    std::vector<int> all_popped;

    for (int i = 0; i < num_threads; ++i) {
        producers.emplace_back([&, thread_id = i]() {
            for (int j = 0; j < items_per_thread; ++j) {
                int value = thread_id * 1000 + j;
                queue.push(value);
            }
        });
    }

    for (int i = 0; i < num_threads; ++i) {
        consumers.emplace_back([&]() {
            while (total_popped.load() < total_items) {
                auto batch_opt = queue.try_pop_batch(10);
                if (batch_opt.has_value()) {
                    auto batch = batch_opt.value();
                    total_popped += batch.size();
                    {
                        std::lock_guard<std::mutex> lock(result_mutex);
                        all_popped.insert(all_popped.end(), batch.begin(),
                                          batch.end());
                    }
                } else {
                    if (queue.empty() && total_popped.load() < total_items) {
                        std::this_thread::sleep_for(
                            std::chrono::milliseconds(1));
                    }
                }
            }
        });
    }

    for (auto& producer : producers) {
        producer.join();
    }
    for (auto& consumer : consumers) {
        consumer.join();
    }

    EXPECT_EQ(total_popped.load(), total_items);
    EXPECT_EQ(all_popped.size(), total_items);
    EXPECT_TRUE(queue.empty());

    std::sort(all_popped.begin(), all_popped.end());
    std::vector<int> expected;
    for (int i = 0; i < num_threads; ++i) {
        for (int j = 0; j < items_per_thread; ++j) {
            expected.push_back(i * 1000 + j);
        }
    }
    std::sort(expected.begin(), expected.end());

    EXPECT_EQ(all_popped, expected);
}

TEST_F(ThreadSafeQueueTest, BatchOperationsWithCustomType) {
    struct TestData {
        int id;
        std::string name;

        TestData(int i, std::string n) : id(i), name(std::move(n)) {}
        TestData(TestData&&) = default;
        TestData& operator=(TestData&&) = default;

        TestData(const TestData&) = delete;
        TestData& operator=(const TestData&) = delete;
    };

    ThreadSafeQueue<TestData> queue(10);

    EXPECT_TRUE(queue.push(TestData(1, "Alice")));
    EXPECT_TRUE(queue.push(TestData(2, "Bob")));
    EXPECT_TRUE(queue.push(TestData(3, "Charlie")));

    auto batch_opt = queue.pop_batch(2, std::chrono::milliseconds(100));
    EXPECT_TRUE(batch_opt.has_value());
    auto& batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 2);
    EXPECT_EQ(batch[0].id, 1);
    EXPECT_EQ(batch[0].name, "Alice");
    EXPECT_EQ(batch[1].id, 2);
    EXPECT_EQ(batch[1].name, "Bob");

    EXPECT_EQ(queue.size_approx(), 1);

    auto batch2_opt = queue.try_pop_batch(5);
    EXPECT_TRUE(batch2_opt.has_value());
    auto& batch2 = batch2_opt.value();
    EXPECT_EQ(batch2.size(), 1);
    EXPECT_EQ(batch2[0].id, 3);
    EXPECT_EQ(batch2[0].name, "Charlie");

    EXPECT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, PopBatch_QueueFullBehavior) {
    const int capacity = 5;
    ThreadSafeQueue<int> queue(capacity);

    for (int i = 0; i < capacity; ++i) {
        EXPECT_TRUE(queue.push(i));
    }

    EXPECT_EQ(queue.size_approx(), capacity);

    auto batch_opt = queue.pop_batch(3, std::chrono::milliseconds(100));
    EXPECT_TRUE(batch_opt.has_value());
    auto batch = batch_opt.value();
    EXPECT_EQ(batch.size(), 3);

    EXPECT_EQ(queue.size_approx(), 2);

    EXPECT_TRUE(queue.push(100));
    EXPECT_TRUE(queue.push(101));

    EXPECT_EQ(queue.size_approx(), 4);

    auto batch2_opt = queue.try_pop_batch(10);
    EXPECT_TRUE(batch2_opt.has_value());
    auto batch2 = batch2_opt.value();
    EXPECT_EQ(batch2.size(), 4);
}

TEST_F(ThreadSafeQueueTest, BatchSizeZero) {
    ThreadSafeQueue<int> queue(10);

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));

    auto batch_opt = queue.pop_batch(0, std::chrono::milliseconds(10));
    EXPECT_FALSE(batch_opt.has_value());

    auto batch2_opt = queue.try_pop_batch(0);
    EXPECT_FALSE(batch2_opt.has_value());

    EXPECT_EQ(queue.size_approx(), 2);
}

TEST_F(ThreadSafeQueueTest, BatchOperationsPerformance) {
    const int num_items = 100000;
    const int batch_size = 100;

    ThreadSafeQueue<int> queue(num_items);

    auto start_fill = std::chrono::steady_clock::now();
    for (int i = 0; i < num_items; ++i) {
        queue.push(i);
    }
    auto end_fill = std::chrono::steady_clock::now();

    auto fill_time = std::chrono::duration_cast<std::chrono::milliseconds>(
        end_fill - start_fill);
    LOG(INFO) << "Filled " << num_items << " items in " << fill_time.count()
              << "ms";

    int total_popped = 0;
    std::vector<std::vector<int>> all_batches;
    auto start_pop = std::chrono::steady_clock::now();

    while (total_popped < num_items) {
        auto batch_opt =
            queue.pop_batch(batch_size, std::chrono::milliseconds(1000));
        if (batch_opt.has_value()) {
            auto batch = batch_opt.value();
            total_popped += batch.size();
            all_batches.push_back(batch);
        }
    }

    auto end_pop = std::chrono::steady_clock::now();
    auto pop_time = std::chrono::duration_cast<std::chrono::milliseconds>(
        end_pop - start_pop);

    LOG(INFO) << "Popped " << num_items << " items in " << all_batches.size()
              << " batches, time: " << pop_time.count() << "ms";

    EXPECT_EQ(total_popped, num_items);
    EXPECT_TRUE(queue.empty());

    int expected_value = 0;
    for (const auto& batch : all_batches) {
        for (int value : batch) {
            EXPECT_EQ(value, expected_value++);
        }
    }
}

TEST_F(ThreadSafeQueueTest, PeekBatch_BasicFunctionality) {
    ThreadSafeQueue<int> queue(10);

    {
        auto result = queue.peek_batch(5);
        EXPECT_FALSE(result.has_value());
    }

    EXPECT_TRUE(queue.push(1));
    EXPECT_TRUE(queue.push(2));
    EXPECT_TRUE(queue.push(3));

    {
        auto result = queue.peek_batch(3);
        EXPECT_TRUE(result.has_value());
        ASSERT_EQ(result->size(), 3);
        EXPECT_EQ((*result)[0], 1);
        EXPECT_EQ((*result)[1], 2);
        EXPECT_EQ((*result)[2], 3);
    }

    {
        auto result = queue.peek_batch(5);
        EXPECT_TRUE(result.has_value());
        EXPECT_EQ(result->size(), 3);
    }

    {
        auto result = queue.peek_batch(2);
        EXPECT_TRUE(result.has_value());
        EXPECT_EQ(result->size(), 2);
        EXPECT_EQ((*result)[0], 1);
        EXPECT_EQ((*result)[1], 2);
    }

    EXPECT_EQ(queue.size_approx(), 3);
    auto item = queue.pop();
    EXPECT_TRUE(item.has_value());
    EXPECT_EQ(*item, 1);
}

TEST_F(ThreadSafeQueueTest, PeekBatch_EdgeCases) {
    ThreadSafeQueue<int> queue(10);

    {
        auto result = queue.peek_batch(0);
        EXPECT_FALSE(result.has_value());
    }

    queue.push(1);
    {
        auto result = queue.peek_batch(0);
        EXPECT_FALSE(result.has_value());
    }

    queue.pop();
    {
        auto result = queue.peek_batch(5);
        EXPECT_FALSE(result.has_value());
    }
}

TEST_F(ThreadSafeQueueTest, PeekBatch_ConcurrentSafety) {
    ThreadSafeQueue<int> queue(10);

    for (int i = 0; i < 5; ++i) {
        queue.push(i);
    }

    std::vector<std::thread> threads;
    std::atomic<int> correct_count{0};
    constexpr int kNumThreads = 4;
    constexpr int kIterations = 1000;

    for (int t = 0; t < kNumThreads; ++t) {
        threads.emplace_back([&queue, &correct_count]() {
            for (int i = 0; i < kIterations; ++i) {
                auto result = queue.peek_batch(3);
                if (result && result->size() >= 1 && (*result)[0] == 0) {
                    correct_count.fetch_add(1, std::memory_order_relaxed);
                }
                std::this_thread::yield();
            }
        });
    }

    for (auto& t : threads) {
        t.join();
    }

    EXPECT_GT(correct_count.load(), 0);
    EXPECT_EQ(queue.size_approx(), 5);
}

TEST_F(ThreadSafeQueueTest, PeekAt_BasicFunctionality) {
    ThreadSafeQueue<int> queue(10);

    {
        std::vector<size_t> positions = {0, 1, 2};
        auto result = queue.peek_at(positions);

        EXPECT_EQ(result.size(), 3);
        for (const auto& opt : result) {
            EXPECT_FALSE(opt.has_value());
        }
    }

    for (int i = 0; i < 5; ++i) {
        queue.push(i * 10);
    }

    {
        std::vector<size_t> positions = {0, 2, 4};
        auto result = queue.peek_at(positions);

        ASSERT_EQ(result.size(), 3);
        EXPECT_TRUE(result[0].has_value());
        EXPECT_EQ(*result[0], 0);
        EXPECT_TRUE(result[1].has_value());
        EXPECT_EQ(*result[1], 20);
        EXPECT_TRUE(result[2].has_value());
        EXPECT_EQ(*result[2], 40);
    }

    {
        std::vector<size_t> positions = {0, 5, 2, 10};
        auto result = queue.peek_at(positions);

        ASSERT_EQ(result.size(), 4);
        EXPECT_TRUE(result[0].has_value());
        EXPECT_EQ(*result[0], 0);
        EXPECT_FALSE(result[1].has_value());
        EXPECT_TRUE(result[2].has_value());
        EXPECT_EQ(*result[2], 20);
        EXPECT_FALSE(result[3].has_value());
    }

    {
        std::vector<size_t> positions = {5, 6, 7};
        auto result = queue.peek_at(positions);

        ASSERT_EQ(result.size(), 3);
        for (const auto& opt : result) {
            EXPECT_FALSE(opt.has_value());
        }
    }

    EXPECT_EQ(queue.size_approx(), 5);
    auto item = queue.pop();
    EXPECT_TRUE(item.has_value());
    EXPECT_EQ(*item, 0);
}

TEST_F(ThreadSafeQueueTest, PeekAt_EdgeCases) {
    ThreadSafeQueue<int> queue(10);

    {
        std::vector<size_t> positions;
        auto result = queue.peek_at(positions);
        EXPECT_TRUE(result.empty());
    }

    queue.push(100);

    {
        std::vector<size_t> positions = {0};
        auto result = queue.peek_at(positions);
        ASSERT_EQ(result.size(), 1);
        EXPECT_TRUE(result[0].has_value());
        EXPECT_EQ(*result[0], 100);
    }

    {
        std::vector<size_t> positions = {0, 0, 0};
        auto result = queue.peek_at(positions);
        ASSERT_EQ(result.size(), 3);
        for (const auto& opt : result) {
            EXPECT_TRUE(opt.has_value());
            EXPECT_EQ(*opt, 100);
        }
    }

    {
        std::vector<size_t> positions = {0, 1000, 2000};
        auto result = queue.peek_at(positions);
        ASSERT_EQ(result.size(), 3);
        EXPECT_TRUE(result[0].has_value());
        EXPECT_EQ(*result[0], 100);
        EXPECT_FALSE(result[1].has_value());
        EXPECT_FALSE(result[2].has_value());
    }
}

TEST_F(ThreadSafeQueueTest, PeekAt_ConcurrentSafety) {
    ThreadSafeQueue<int> queue(10);

    for (int i = 0; i < 5; ++i) {
        queue.push(i * 100);
    }

    std::vector<std::thread> threads;
    std::atomic<int> correct_count{0};
    constexpr int kNumThreads = 4;
    constexpr int kIterations = 1000;

    for (int t = 0; t < kNumThreads; ++t) {
        threads.emplace_back([&queue, &correct_count]() {
            std::vector<size_t> positions = {0, 2, 4};
            for (int i = 0; i < kIterations; ++i) {
                auto result = queue.peek_at(positions);
                if (result.size() == 3 && result[0].has_value() &&
                    *result[0] == 0 && result[1].has_value() &&
                    *result[1] == 200 && result[2].has_value() &&
                    *result[2] == 400) {
                    correct_count.fetch_add(1, std::memory_order_relaxed);
                }
                std::this_thread::yield();
            }
        });
    }

    for (auto& t : threads) {
        t.join();
    }

    EXPECT_GT(correct_count.load(), 0);
    EXPECT_EQ(queue.size_approx(), 5);
}

TEST_F(ThreadSafeQueueTest, PeekBatchAndPopConsistency) {
    ThreadSafeQueue<int> queue(10);

    for (int i = 0; i < 5; ++i) {
        queue.push(i);
    }

    auto peek_result = queue.peek_batch(3);
    EXPECT_TRUE(peek_result.has_value());
    EXPECT_EQ(peek_result->size(), 3);

    ASSERT_EQ(peek_result->size(), 3);
    EXPECT_EQ((*peek_result)[0], 0);
    EXPECT_EQ((*peek_result)[1], 1);
    EXPECT_EQ((*peek_result)[2], 2);

    for (int i = 0; i < 3; ++i) {
        auto item = queue.pop();
        EXPECT_TRUE(item.has_value());
        EXPECT_EQ(*item, i);
    }

    EXPECT_EQ(queue.size_approx(), 2);

    auto peek_result2 = queue.peek_batch(3);
    EXPECT_TRUE(peek_result2.has_value());
    EXPECT_EQ(peek_result2->size(), 2);

    ASSERT_EQ(peek_result2->size(), 2);
    EXPECT_EQ((*peek_result2)[0], 3);
    EXPECT_EQ((*peek_result2)[1], 4);
}

TEST_F(ThreadSafeQueueTest, PeekAtAndPopConsistency) {
    ThreadSafeQueue<int> queue(10);

    for (int i = 0; i < 5; ++i) {
        queue.push(i * 10);
    }

    std::vector<size_t> positions = {0, 2, 4};
    auto peek_result = queue.peek_at(positions);

    ASSERT_EQ(peek_result.size(), 3);
    EXPECT_TRUE(peek_result[0].has_value());
    EXPECT_EQ(*peek_result[0], 0);
    EXPECT_TRUE(peek_result[1].has_value());
    EXPECT_EQ(*peek_result[1], 20);
    EXPECT_TRUE(peek_result[2].has_value());
    EXPECT_EQ(*peek_result[2], 40);

    auto item = queue.pop();
    EXPECT_TRUE(item.has_value());
    EXPECT_EQ(*item, 0);

    auto peek_result2 = queue.peek_at({0, 1, 2});
    ASSERT_EQ(peek_result2.size(), 3);
    EXPECT_TRUE(peek_result2[0].has_value());
    EXPECT_EQ(*peek_result2[0], 10);
    EXPECT_TRUE(peek_result2[1].has_value());
    EXPECT_EQ(*peek_result2[1], 20);
    EXPECT_TRUE(peek_result2[2].has_value());
    EXPECT_EQ(*peek_result2[2], 30);
}

TEST_F(ThreadSafeQueueTest, HighContentionMPSC_PerformanceAndAccuracy) {
    const int NUM_PRODUCERS = 8;
    const int NUM_EVENTS_PER_PRODUCER = 10000;
    const int QUEUE_CAPACITY = 100000;
    const int CONSUMER_BATCH_SIZE = 10;
    const int TOTAL_EVENTS = NUM_PRODUCERS * NUM_EVENTS_PER_PRODUCER;

    const int64_t BLOCKING_THRESHOLD_NS = 100000;

    ThreadSafeQueue<int> queue(QUEUE_CAPACITY);

    struct TestStats {
        std::atomic<int64_t> total_produced{0};
        std::atomic<int64_t> producer_block_count{0};
        std::atomic<int64_t> producer_failures{0};
        std::atomic<int64_t> producer_total_push_time_ns{0};

        std::atomic<int64_t> total_consumed{0};
        std::atomic<int64_t> consumer_batches_processed{0};
        std::atomic<int64_t> consumer_total_time_ns{0};

        std::atomic<int64_t> max_observed_size{0};
        std::atomic<int64_t> min_observed_size{0};

        std::atomic<int64_t> events_out_of_range{0};
    };

    TestStats stats;
    stats.min_observed_size.store(INT64_MAX);

    std::atomic<bool> producers_done{false};

    auto start_time = std::chrono::steady_clock::now();

    std::thread consumer([&]() {
        LOG(INFO) << "Consumer thread started";

        int consecutive_empty_cycles = 0;
        const int MAX_EMPTY_CYCLES = 10;
        auto consumer_start = std::chrono::steady_clock::now();

        while (consecutive_empty_cycles < MAX_EMPTY_CYCLES) {
            auto batch_start = std::chrono::steady_clock::now();
            auto batch_opt = queue.pop_batch(CONSUMER_BATCH_SIZE,
                                             std::chrono::milliseconds(10));
            auto batch_end = std::chrono::steady_clock::now();

            if (batch_opt.has_value()) {
                consecutive_empty_cycles = 0;
                auto& batch = batch_opt.value();
                int batch_size = static_cast<int>(batch.size());

                stats.total_consumed += batch_size;
                stats.consumer_batches_processed++;

                auto batch_time_ns =
                    std::chrono::duration_cast<std::chrono::nanoseconds>(
                        batch_end - batch_start)
                        .count();
                stats.consumer_total_time_ns += batch_time_ns;

                for (int value : batch) {
                    if (value < 0 || value >= TOTAL_EVENTS) {
                        stats.events_out_of_range++;
                        LOG(ERROR) << "Event out of range: " << value;
                    }
                }

                int64_t current_size = queue.size_approx();
                int64_t max_observed = stats.max_observed_size.load();
                int64_t min_observed = stats.min_observed_size.load();

                while (current_size > max_observed &&
                       !stats.max_observed_size.compare_exchange_weak(
                           max_observed, current_size)) {
                }

                if (current_size < min_observed) {
                    stats.min_observed_size.store(current_size);
                }
            } else {
                consecutive_empty_cycles++;
                if (producers_done.load() && queue.empty()) {
                    break;
                }
            }
        }

        auto consumer_end = std::chrono::steady_clock::now();
        auto consumer_duration_ms =
            std::chrono::duration_cast<std::chrono::milliseconds>(
                consumer_end - consumer_start)
                .count();

        LOG(INFO) << "Consumer thread completed: "
                  << stats.total_consumed.load() << " events, "
                  << stats.consumer_batches_processed.load()
                  << " batches, duration " << consumer_duration_ms << "ms";
    });

    std::vector<std::thread> producers;
    producers.reserve(NUM_PRODUCERS);

    for (int producer_id = 0; producer_id < NUM_PRODUCERS; ++producer_id) {
        producers.emplace_back([&, producer_id]() {
            LOG(INFO) << "Producer " << producer_id << " started";

            int64_t local_events_produced = 0;
            int64_t local_block_count = 0;
            int64_t local_failures = 0;
            int64_t local_total_push_time_ns = 0;

            auto producer_start = std::chrono::steady_clock::now();

            for (int event_id = 0; event_id < NUM_EVENTS_PER_PRODUCER;
                 ++event_id) {
                int value = producer_id * NUM_EVENTS_PER_PRODUCER + event_id;

                auto push_start = std::chrono::steady_clock::now();
                bool pushed = queue.push(value);
                auto push_end = std::chrono::steady_clock::now();

                int64_t push_duration_ns =
                    std::chrono::duration_cast<std::chrono::nanoseconds>(
                        push_end - push_start)
                        .count();

                local_total_push_time_ns += push_duration_ns;

                if (pushed) {
                    local_events_produced++;
                    stats.total_produced++;

                    if (push_duration_ns > BLOCKING_THRESHOLD_NS) {
                        local_block_count++;
                    }

                    if (event_id % 2000 == 0) {
                        int64_t current_size = queue.size_approx();
                        int64_t max_observed = stats.max_observed_size.load();
                        int64_t min_observed = stats.min_observed_size.load();

                        while (current_size > max_observed &&
                               !stats.max_observed_size.compare_exchange_weak(
                                   max_observed, current_size)) {
                        }

                        if (current_size < min_observed) {
                            stats.min_observed_size.store(current_size);
                        }
                    }
                } else {
                    LOG(WARNING) << "Producer " << producer_id
                                 << " push failed, retrying...";
                    pushed = queue.push(value, std::chrono::milliseconds(1));

                    if (pushed) {
                        local_events_produced++;
                        stats.total_produced++;
                        local_failures++;
                    } else {
                        local_failures++;
                        LOG(ERROR) << "Producer " << producer_id
                                   << " failed to push event " << event_id;
                    }
                }

                if (event_id % 1000 == 0) {
                    std::this_thread::yield();
                }
            }

            stats.producer_block_count += local_block_count;
            stats.producer_failures += local_failures;
            stats.producer_total_push_time_ns += local_total_push_time_ns;

            auto producer_end = std::chrono::steady_clock::now();
            auto producer_duration_ms =
                std::chrono::duration_cast<std::chrono::milliseconds>(
                    producer_end - producer_start)
                    .count();

            LOG(INFO) << "Producer " << producer_id
                      << " completed: " << local_events_produced << " events, "
                      << local_block_count << " blocks, " << local_failures
                      << " failures, "
                      << "duration " << producer_duration_ms << "ms";
        });
    }

    auto producer_join_start = std::chrono::steady_clock::now();
    for (auto& producer : producers) {
        producer.join();
    }
    auto producer_join_end = std::chrono::steady_clock::now();

    producers_done = true;
    LOG(INFO) << "All producers completed, waiting for consumer...";

    consumer.join();

    auto end_time = std::chrono::steady_clock::now();
    auto total_duration_ms =
        std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
                                                              start_time)
            .count();
    auto producer_only_duration_ms =
        std::chrono::duration_cast<std::chrono::milliseconds>(
            producer_join_end - start_time)
            .count();

    double total_duration_seconds = total_duration_ms / 1000.0;
    double producer_duration_seconds = producer_only_duration_ms / 1000.0;

    double events_per_second_total = TOTAL_EVENTS / total_duration_seconds;
    double events_per_second_producer =
        TOTAL_EVENTS / producer_duration_seconds;

    int64_t actual_produced = stats.total_produced.load();
    int64_t actual_consumed = stats.total_consumed.load();

    double avg_push_time_ns = stats.producer_total_push_time_ns /
                              static_cast<double>(actual_produced);
    double avg_batch_time_ns =
        stats.consumer_total_time_ns /
        static_cast<double>(stats.consumer_batches_processed);
    double avg_batch_size =
        actual_consumed / static_cast<double>(stats.consumer_batches_processed);

    double blocking_percentage =
        stats.producer_block_count * 100.0 / actual_produced;
    double failure_percentage = stats.producer_failures * 100.0 /
                                (actual_produced + stats.producer_failures);

    int64_t max_size = stats.max_observed_size.load();
    int64_t min_size = stats.min_observed_size.load();

    LOG(INFO) << "========================================";
    LOG(INFO) << "MPSC High Contention Test Results";
    LOG(INFO) << "========================================";

    LOG(INFO) << "Data Integrity:";
    LOG(INFO) << "  Planned events: " << TOTAL_EVENTS;
    LOG(INFO) << "  Actual produced: " << actual_produced;
    LOG(INFO) << "  Actual consumed: " << actual_consumed;
    LOG(INFO) << "  Queue remaining size: " << queue.size_approx();
    LOG(INFO) << "  Queue empty: " << (queue.empty() ? "yes" : "no");
    LOG(INFO) << "  Events out of range: " << stats.events_out_of_range.load();

    EXPECT_EQ(actual_produced, TOTAL_EVENTS) << "Mismatch in produced events";
    EXPECT_EQ(actual_consumed, TOTAL_EVENTS) << "Mismatch in consumed events";
    EXPECT_TRUE(queue.empty()) << "Queue not empty after test";
    EXPECT_EQ(stats.events_out_of_range.load(), 0)
        << "Events out of range found";

    LOG(INFO) << "Performance Metrics:";
    LOG(INFO) << "  Total duration: " << total_duration_ms << "ms";
    LOG(INFO) << "  Producer duration: " << producer_only_duration_ms << "ms";
    LOG(INFO) << "  Total throughput: " << events_per_second_total
              << " events/sec";
    LOG(INFO) << "  Producer throughput: " << events_per_second_producer
              << " events/sec";
    LOG(INFO) << "  Average push time: " << avg_push_time_ns << " ns";
    LOG(INFO) << "  Average batch processing time: " << avg_batch_time_ns
              << " ns";
    LOG(INFO) << "  Average batch size: " << avg_batch_size << " events/batch";
    LOG(INFO) << "  Blocking push ratio: " << blocking_percentage << "%";
    LOG(INFO) << "  Push failure ratio: " << failure_percentage << "%";

    EXPECT_GT(events_per_second_total, 10000) << "Throughput too low";
    EXPECT_LT(avg_push_time_ns, 20000) << "Average push time too high";
    EXPECT_LT(failure_percentage, 0.1) << "Push failure rate too high";

    LOG(INFO) << "Queue Behavior:";
    LOG(INFO) << "  Max observed queue size: " << max_size;
    LOG(INFO) << "  Min observed queue size: " << min_size;
    LOG(INFO) << "  Queue size range: " << (max_size - min_size);
    LOG(INFO) << "  Total consumer batches: "
              << stats.consumer_batches_processed.load();

    EXPECT_LE(max_size, QUEUE_CAPACITY + NUM_PRODUCERS * 2)
        << "Queue size exceeds reasonable range";
    EXPECT_GE(min_size, 0) << "Queue size should not be negative";

    LOG(INFO) << "Blocking Behavior:";
    LOG(INFO) << "  Blocking push count: " << stats.producer_block_count.load();
    LOG(INFO) << "  Blocking push ratio: " << blocking_percentage << "%";

    if (blocking_percentage > 5.0) {
        LOG(WARNING) << "High blocking ratio, consider adjusting queue "
                        "capacity or number of producers";
    }

    LOG(INFO) << "Resource Usage Summary:";
    LOG(INFO) << "  Estimated memory usage: " << (max_size * sizeof(int))
              << " bytes";
    LOG(INFO) << "  Producer threads: " << NUM_PRODUCERS;
    LOG(INFO) << "  Consumer threads: 1";
    LOG(INFO) << "  Peak queue capacity usage: "
              << (max_size * 100.0 / QUEUE_CAPACITY) << "%";

    EXPECT_LE(blocking_percentage, 20.0) << "Blocking ratio too high";

    if (avg_batch_size < 10) {
        LOG(WARNING) << "Batch size too small(" << avg_batch_size
                     << "< 10), consumer efficiency low";
    }

    LOG(INFO) << "========================================";
    LOG(INFO) << "========================================";
}

TEST_F(ThreadSafeQueueTest, PerformanceBaseline) {
    ThreadSafeQueue<int> queue(100000);
    auto start = std::chrono::steady_clock::now();
    for (int i = 0; i < 1000; ++i) {
        queue.push(i);
    }
    auto end = std::chrono::steady_clock::now();
    auto avg_ns =
        std::chrono::duration_cast<std::chrono::nanoseconds>(end - start)
            .count() /
        1000.0;

    LOG(INFO) << "Baseline push time: " << avg_ns << " ns";
}

}  // namespace mooncake

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}