//! Leading edge: immediate first call plus a trailing run.

mod common;

use std::convert::Infallible;

use debounce_promise::Debounce;

use common::{sleep, Counter};

#[tokio::test]
async fn leading_uses_the_value_from_the_first_call() {
    // README leading timeline: debounced() -> P(1), P(2), P(2), P(2).
    // The first caller gets its own leading result, the rest share the trailing
    // result with the last argument.
    let debounced =
        Debounce::latest(|value: &'static str| async move { Ok::<_, Infallible>(value) })
            .wait_ms(100)
            .leading(true)
            .build();

    let calls = ["foo", "bar", "baz", "qux"].map(|v| debounced.call(v));
    let mut results = Vec::new();
    for c in calls {
        results.push(c.await);
    }

    assert_eq!(results, vec![Ok("foo"), Ok("qux"), Ok("qux"), Ok("qux")]);
}

#[tokio::test]
async fn leading_single_call_does_not_fire_again() {
    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_ms(100)
    .leading(true)
    .build();

    let _ = debounced.call(0).await;
    sleep(200).await;
    assert_eq!(calls.get(), 1);
}

#[tokio::test]
async fn leading_burst_fires_once_more_at_the_trailing_edge() {
    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_ms(100)
    .leading(true)
    .build();

    let futures = [1, 2, 3, 4].map(|n| debounced.call(n));
    for f in futures {
        let _ = f.await;
    }
    sleep(200).await;
    assert_eq!(calls.get(), 2);
}
