#include <gtest/gtest.h>

#include <thread>
#include <vector>

#include <mission_adapters/event.h>

namespace
{
using namespace mission_adapters;

Event makeEvent(EventType type)
{
    Event event;
    event.type = type;
    return event;
}

// ─────────────────────────────────────────────────────────────────────────────
// A5 — thứ tự xử lý phải bằng thứ tự phát sinh.
//
// Bản trước sắp theo priority toàn phần: CANCEL (1) luôn đứng trước SUBMIT (5). Phát order rồi huỷ
// ngay thì huỷ được xử lý trước, order vào hàng đợi sau, và robot chạy đúng cái người dùng vừa huỷ.
// ─────────────────────────────────────────────────────────────────────────────

TEST(EventBusTest, SubmitThenCancelKeepsCausalOrder)
{
    EventBus bus;

    bus.push(makeEvent(EventType::SUBMIT_REQUEST));
    bus.push(makeEvent(EventType::CANCEL));

    Event event;
    ASSERT_TRUE(bus.pop(event));
    EXPECT_EQ(event.type, EventType::SUBMIT_REQUEST);

    ASSERT_TRUE(bus.pop(event));
    EXPECT_EQ(event.type, EventType::CANCEL) << "the cancel was processed before the order it "
                                                "cancels";
}

TEST(EventBusTest, PreservesFifoOrderAcrossEventTypes)
{
    EventBus bus;

    const std::vector<EventType> pushed = {
        EventType::PAUSE,
        EventType::SUBMIT_REQUEST,
        EventType::RESUME,
        EventType::NAV_DONE,
        EventType::CANCEL,
    };

    for (const auto type : pushed)
        bus.push(makeEvent(type));

    for (size_t i = 0; i < pushed.size(); ++i)
    {
        Event event;
        ASSERT_TRUE(bus.pop(event)) << "event number " << i;
        EXPECT_EQ(event.type, pushed[i]) << "wrong order at position " << i;
        EXPECT_EQ(event.sequence, i);
    }
}

// ─────────────────────────────────────────────────────────────────────────────
// Emergency đi ngoài hàng đợi: độ trễ phản ứng không được phụ thuộc độ dài hàng đợi.
// ─────────────────────────────────────────────────────────────────────────────

TEST(EventBusTest, EmergencyOvertakesQueue)
{
    EventBus bus;

    for (int i = 0; i < 50; ++i)
        bus.push(makeEvent(EventType::SUBMIT_REQUEST));

    EXPECT_FALSE(bus.emergencyPending());
    bus.pushEmergency(makeEvent(EventType::EMERGENCY));

    // Thấy được ngay, không phải rút hết 50 sự kiện kia ra trước.
    EXPECT_TRUE(bus.emergencyPending());
    EXPECT_EQ(bus.size(), 51u) << "an EMERGENCY event must still sit in the queue to keep the log "
                                  "sequence";

    EXPECT_TRUE(bus.takeEmergency());
    EXPECT_FALSE(bus.takeEmergency()) << "the emergency flag was consumed twice";
}

TEST(EventBusTest, EmergencyEventStillArrivesInOrder)
{
    EventBus bus;

    bus.push(makeEvent(EventType::PAUSE));
    bus.pushEmergency(makeEvent(EventType::EMERGENCY));

    Event event;
    ASSERT_TRUE(bus.pop(event));
    EXPECT_EQ(event.type, EventType::PAUSE);

    ASSERT_TRUE(bus.pop(event));
    EXPECT_EQ(event.type, EventType::EMERGENCY);
}

TEST(EventBusTest, StopUnblocksPop)
{
    EventBus bus;
    Event event;

    std::thread stopper([&bus] { bus.stop(); });
    EXPECT_FALSE(bus.pop(event));
    stopper.join();
}

TEST(EventBusTest, ResetDropsPendingEventsAndEmergencyFlag)
{
    EventBus bus;

    bus.push(makeEvent(EventType::PAUSE));
    bus.pushEmergency(makeEvent(EventType::EMERGENCY));

    bus.reset();

    EXPECT_TRUE(bus.empty());
    EXPECT_FALSE(bus.emergencyPending());
}

}  // namespace

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