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

use kabel::{
	ServiceCollection, ServiceProvider,
	scope::{GlobalScopeProvider, ScopeDefault, ScopeProvider, ThreadLocalScope},
};

struct ScopedA(usize);
struct ScopedB(usize);

#[test]
fn test_global_refresh_scope() {
	let mut sc = ServiceCollection::new();
	let a_counter = Arc::new(AtomicUsize::new(0));
	let a_factory_counter = a_counter.clone();
	sc.add_scoped::<ScopedA, _>(move || ScopedA(a_factory_counter.fetch_add(1, Ordering::SeqCst)))
		.unwrap();

	let sp = ServiceProvider::new(sc);
	GlobalScopeProvider::initialize(sp.create_scope());

	let a1 = sp.dir::<ScopedA>().unwrap();
	assert_eq!(a1.0, 0);

	let b_factory_counter = Arc::new(AtomicUsize::new(0));
	sp.mutate(move |sc| {
		sc.add_scoped::<ScopedB, _>(move || {
			ScopedB(b_factory_counter.fetch_add(1, Ordering::SeqCst))
		})
		.unwrap();
	});

	GlobalScopeProvider::refresh_scope_with(&sp).unwrap();

	let b1 = sp.dir::<ScopedB>().unwrap();
	let a2 = sp.dir::<ScopedA>().unwrap();
	assert_eq!(b1.0, 0);
	assert_eq!(a2.0, 0);
}

#[test]
fn test_thread_local_refresh_scope() {
	let mut sc = ServiceCollection::new();
	let a_counter = Arc::new(AtomicUsize::new(0));
	let a_factory_counter = a_counter.clone();
	sc.add_scoped::<ScopedA, _>(move || ScopedA(a_factory_counter.fetch_add(1, Ordering::SeqCst)))
		.unwrap();

	let sp = ServiceProvider::new(sc);
	ThreadLocalScope::initialize(sp.create_scope());

	let provider: Arc<dyn ScopeProvider> = Arc::new(ThreadLocalScope);
	let a1 = sp.disr::<ScopedA>(provider.clone()).unwrap();
	assert_eq!(a1.0, 0);

	let b_factory_counter = Arc::new(AtomicUsize::new(0));
	sp.mutate(move |sc| {
		sc.add_scoped::<ScopedB, _>(move || {
			ScopedB(b_factory_counter.fetch_add(1, Ordering::SeqCst))
		})
		.unwrap();
	});

	ThreadLocalScope::refresh_scope_with(&sp).unwrap();

	let b1 = sp.disr::<ScopedB>(provider.clone()).unwrap();
	let a2 = sp.disr::<ScopedA>(provider).unwrap();
	assert_eq!(b1.0, 0);
	assert_eq!(a2.0, 0);
}

#[cfg(feature = "tokio")]
#[test]
fn test_task_refresh_scope() {
	use kabel::scope::tasks::TaskScopeProvider;

	let mut sc = ServiceCollection::new();
	let a_counter = Arc::new(AtomicUsize::new(0));
	let a_factory_counter = a_counter.clone();
	sc.add_scoped::<ScopedA, _>(move || ScopedA(a_factory_counter.fetch_add(1, Ordering::SeqCst)))
		.unwrap();

	let sp = ServiceProvider::new(sc);
	let scope = (*sp.create_scope()).clone();

	TaskScopeProvider::initialize_sync(scope, || {
		let provider: Arc<dyn ScopeProvider> = Arc::new(TaskScopeProvider);
		let a1 = sp.disr::<ScopedA>(provider.clone()).unwrap();
		assert_eq!(a1.0, 0);

		let b_factory_counter = Arc::new(AtomicUsize::new(0));
		sp.mutate(move |sc| {
			sc.add_scoped::<ScopedB, _>(move || {
				ScopedB(b_factory_counter.fetch_add(1, Ordering::SeqCst))
			})
			.unwrap();
		});

		TaskScopeProvider::refresh_scope_with(&sp).unwrap();

		let b1 = sp.disr::<ScopedB>(provider.clone()).unwrap();
		let a2 = sp.disr::<ScopedA>(provider).unwrap();
		assert_eq!(b1.0, 0);
		assert_eq!(a2.0, 0);
	});
}