#include "ui_button_outbox.h"
#include <cassert>
#include <thread>

int main() {
    UiButtonOutbox queue;UiButtonOutbox::Event event{};
    // Sender can be stalled: producer fills its bounded storage without waiting.
    for(unsigned i=0;i<queue.capacity;++i)assert(queue.push(i%2?'B':'A',1,100+i));
    assert(!queue.push('A',1,108));
    for(unsigned i=0;i<queue.capacity;++i) {
        assert(queue.pop_current(event,1,true,200));
        assert(event.button==(i%2?'B':'A') && event.timestamp_ms==100+i);
    }
    assert(!queue.pop_current(event,1,true,200));
    // Disconnect/reconnect and age expiry cannot replay old telemetry.
    assert(queue.push('A',1,300));assert(queue.push('B',2,300));
    assert(queue.pop_current(event,2,true,301) && event.button=='B');
    assert(queue.push('A',2,400));assert(!queue.pop_current(event,2,false,401));
    assert(queue.push('B',2,500));assert(!queue.pop_current(event,2,true,2501));
    assert(queue.push('A',2,3000));assert(!queue.pop_current(event,2,true,2999));
    assert(queue.push('B',2,4000));assert(queue.pop_current(event,2,true,6000));
    // Cross-core publication, wraparound and FIFO while producer/consumer race.
    std::thread producer([&] {
        for(unsigned i=0;i<100000;++i)while(!queue.push(i%2?'B':'A',3,1000))std::this_thread::yield();
    });
    for(unsigned i=0;i<100000;++i) {
        while(!queue.pop_current(event,3,true,1000))std::this_thread::yield();
        assert(event.timestamp_ms==1000 && event.button==(i%2?'B':'A'));
    }
    producer.join();
}
