use std::time::Duration;

use dope_runtime::DefaultBackend;
use dope_runtime::executor::{LocalExecutor, Throughput};
use dope_runtime::runtime::Runtime;

#[test]
fn concurrent_spawn_burst_completes() {
    const TASKS: usize = 10_000;

    let mut rt =
        Runtime::<LocalExecutor<DefaultBackend, Throughput>>::new_local().expect("runtime");
    let ctx = rt.ctx();
    let got = rt.run_until(async {
        let mut handles = Vec::with_capacity(TASKS);
        for i in 0..TASKS {
            handles.push(ctx.spawn(async move { i ^ (i << 1) }));
        }

        let mut acc = 0usize;
        for handle in handles {
            acc ^= handle.await;
        }
        acc
    });

    let mut expected = 0usize;
    for i in 0..TASKS {
        expected ^= i ^ (i << 1);
    }

    assert_eq!(got, expected);
}

#[test]
fn concurrent_spawn_with_timers_completes() {
    const TASKS: usize = 2_000;

    let mut rt =
        Runtime::<LocalExecutor<DefaultBackend, Throughput>>::new_local().expect("runtime");
    let ctx = rt.ctx();
    let got = rt.run_until(async {
        let mut handles = Vec::with_capacity(TASKS);
        for i in 0..TASKS {
            let timer_ctx = ctx;
            handles.push(ctx.spawn(async move {
                dope_runtime::time::sleep_with(timer_ctx, Duration::from_millis(1))
                    .await
                    .expect("sleep");
                i
            }));
        }

        let mut total = 0usize;
        for handle in handles {
            total += handle.await;
        }
        total
    });

    let expected = (0..TASKS).sum::<usize>();
    assert_eq!(got, expected);
}
