/// \file test_spsc_ring.cpp — Unit test cho SpscRing (Phase 0).
/// Dùng assert thuần để không phụ thuộc framework; khi wire vcpkg sẽ chuyển Catch2.

#include "core/spsc_ring.hpp"

#include <print>
#include <thread>
#include <vector>

#define CHECK(cond)                                                            \
    do {                                                                       \
        if (!(cond)) {                                                         \
            std::println("FAIL: {} ({}:{})", #cond, __FILE__, __LINE__);       \
            std::exit(1);                                                      \
        }                                                                      \
    } while (0)

namespace {

void test_fifo_order_single_thread() {
    ares::SpscRing<int, 8> ring;
    for (int i = 0; i < 8; ++i) {
        CHECK(ring.push(i));
    }
    CHECK(!ring.push(99)); // full
    int v = -1;
    for (int i = 0; i < 8; ++i) {
        CHECK(ring.pop(v));
        CHECK(v == i);
    }
    CHECK(!ring.pop(v)); // empty
    CHECK(ring.size_approx() == 0);
}

void test_reuse_after_drain() {
    ares::SpscRing<int, 4> ring;
    for (int i = 0; i < 4; ++i) { CHECK(ring.push(i)); }
    int v = 0;
    for (int i = 0; i < 4; ++i) { CHECK(ring.pop(v)); }
    for (int i = 10; i < 14; ++i) { CHECK(ring.push(i)); }
    for (int i = 10; i < 14; ++i) { CHECK(ring.pop(v)); CHECK(v == i); }
}

void test_spsc_stress_100k() {
    constexpr int kCount = 100'000;
    ares::SpscRing<int, 1024> ring;
    std::vector<int> received;
    received.reserve(kCount);

    std::jthread producer([&] {
        for (int i = 0; i < kCount; ++i) {
            while (!ring.push(i)) {
                std::this_thread::yield();
            }
        }
    });
    for (int got = 0; got < kCount;) {
        int v = -1;
        if (ring.pop(v)) {
            received.push_back(v);
            ++got;
        } else {
            std::this_thread::yield();
        }
    }
    CHECK(received.size() == static_cast<std::size_t>(kCount));
    for (int i = 0; i < kCount; ++i) {
        CHECK(received[static_cast<std::size_t>(i)] == i); // đúng thứ tự FIFO
    }
}

} // namespace

int main() {
    test_fifo_order_single_thread();
    test_reuse_after_drain();
    test_spsc_stress_100k();
    std::println("All SPSC ring tests passed ✔");
    return 0;
}
