//! Error fan-out. Not covered by the source suite.

mod common;

use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

use debounce_promise::Debounce;

use common::sleep;

#[tokio::test]
async fn rejection_fans_out_to_every_caller_in_the_window() {
    // A1: the function errors. Every shared caller in the window gets the same
    // error, and the wrapper is reusable in the next window.
    let attempts = Arc::new(AtomicUsize::new(0));
    let a = Arc::clone(&attempts);
    let debounced = Debounce::latest(move |n: i32| {
        let a = Arc::clone(&a);
        async move {
            let attempt = a.fetch_add(1, Ordering::SeqCst);
            if attempt == 0 {
                Err::<i32, String>(format!("boom {n}"))
            } else {
                Ok(n)
            }
        }
    })
    .wait_ms(10)
    .build();

    let first = debounced.call(1);
    let second = debounced.call(2);
    let third = debounced.call(3);

    sleep(20).await;

    assert_eq!(first.await, Err("boom 3".to_string()));
    assert_eq!(second.await, Err("boom 3".to_string()));
    assert_eq!(third.await, Err("boom 3".to_string()));

    // Next window resolves with the live wrapper.
    let again = debounced.call(7);
    sleep(20).await;
    assert_eq!(again.await, Ok(7));
}

#[tokio::test]
async fn leading_rejection_is_independent_of_the_trailing_call() {
    // A2: the leading call errors. A later in-window trailing call still resolves
    // on its own.
    let attempts = Arc::new(AtomicUsize::new(0));
    let a = Arc::clone(&attempts);
    let debounced = Debounce::latest(move |n: i32| {
        let a = Arc::clone(&a);
        async move {
            let attempt = a.fetch_add(1, Ordering::SeqCst);
            if attempt == 0 {
                Err::<i32, String>("leading boom".to_string())
            } else {
                Ok(n)
            }
        }
    })
    .wait_ms(50)
    .leading(true)
    .build();

    let leading = debounced.call(1);
    let trailing = debounced.call(2);

    assert_eq!(leading.await, Err("leading boom".to_string()));
    sleep(80).await;
    assert_eq!(trailing.await, Ok(2));
}
