//! Verifies the iceoryx2 API surface this crate depends on.
//! If this test fails to compile, the iceoryx2 version pinned in the
//! workspace manifest has shifted shapes and the rest of the plan needs
//! to be adapted.

use core::time::Duration;
use iceoryx2::prelude::*;

static SEQ: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);

fn unique(prefix: &str) -> String {
    let n = SEQ.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
    format!("{prefix}.{}.{n}", std::process::id())
}

#[derive(Debug, Default, Clone, Copy, ZeroCopySend)]
#[repr(C)]
struct Tick(u64);

#[test]
fn pubsub_event_waitset_round_trip() {
    let node = NodeBuilder::new()
        .create::<ipc::Service>()
        .expect("create node");

    // Publish-subscribe service.
    let pubsub_name = unique("taktora.smoke.tick");
    let event_name = format!("{pubsub_name}.__taktora_event");

    let pubsub = node
        .service_builder(&pubsub_name.as_str().try_into().unwrap())
        .publish_subscribe::<Tick>()
        .open_or_create()
        .expect("create pubsub service");

    let publisher = pubsub.publisher_builder().create().expect("publisher");
    let subscriber = pubsub.subscriber_builder().create().expect("subscriber");

    // Paired event service used to wake the WaitSet on send.
    let event = node
        .service_builder(&event_name.as_str().try_into().unwrap())
        .event()
        .open_or_create()
        .expect("create event service");

    let notifier = event.notifier_builder().create().expect("notifier");
    let listener = event.listener_builder().create().expect("listener");

    // WaitSet attaches the listener.
    let waitset = WaitSetBuilder::new()
        .create::<ipc::Service>()
        .expect("waitset");
    let _guard = waitset
        .attach_notification(&listener)
        .expect("attach listener");

    // Publisher sends, notifier wakes the waitset.
    publisher.send_copy(Tick(7)).expect("send");
    notifier.notify().expect("notify");

    // Drive the waitset for a bounded time.
    let mut got_event = false;
    let _interval = waitset
        .attach_interval(Duration::from_millis(50))
        .expect("attach interval");

    waitset
        .wait_and_process(|_| {
            // Drain the listener unconditionally — the interval attachment may
            // fire before the listener notification is delivered, so we must
            // not assume the first wakeup originates from the listener.
            while let Ok(Some(_)) = listener.try_wait_one() {
                got_event = true;
            }
            // Keep looping until we have confirmed at least one listener event.
            if got_event {
                CallbackProgression::Stop
            } else {
                CallbackProgression::Continue
            }
        })
        .expect("wait_and_process");

    assert!(got_event, "waitset did not wake on listener notify");

    // Subscriber sees the published payload.
    let sample = subscriber
        .receive()
        .expect("receive")
        .expect("sample present");
    assert_eq!(sample.payload().0, 7);
}
