//! Wait read from a closure on every call.

mod common;

use std::convert::Infallible;
use std::time::Duration;

use debounce_promise::Debounce;

use common::{sleep, Counter};

#[tokio::test]
async fn supports_passing_function_as_wait_parameter() {
    let calls = Counter::new();
    let wait_calls = Counter::new();

    let c = calls.clone();
    let w = wait_calls.clone();
    let debounced = Debounce::latest(move |_: i32| {
        let c = c.clone();
        async move { Ok::<_, Infallible>(c.bump()) }
    })
    .wait_fn(move || {
        w.bump();
        Duration::from_millis(100)
    })
    .build();

    debounced.call(1);
    debounced.call(2);
    debounced.call(3);

    sleep(90).await;
    assert_eq!(calls.get(), 0);

    sleep(20).await;
    // The wait closure runs once per call, never cached. Three calls run it
    // exactly three times. The looser != 0 check would pass even if it ran once.
    assert_eq!(wait_calls.get(), 3);
    assert_eq!(calls.get(), 1);
}

#[tokio::test]
async fn dynamic_wait_value_sets_the_window_length() {
    // The closure runs and returns 50ms. Prove the window honors that value, not
    // some default. A real timer is used so the spawned flush task gets polled.
    // Before 50ms the flush has not fired. After 50ms it has.
    let calls = Counter::new();
    let c = calls.clone();
    let debounced = Debounce::latest(move |_: i32| {
        let c = c.clone();
        async move { Ok::<_, Infallible>(c.bump()) }
    })
    .wait_fn(|| Duration::from_millis(50))
    .build();

    debounced.call(1);

    sleep(30).await;
    assert_eq!(calls.get(), 0); // before 50ms: not fired

    sleep(40).await;
    assert_eq!(calls.get(), 1); // after 50ms total: fired
}
