use retainer::Cache;
use smol::Timer;

use std::sync::Arc;
use std::time::{Duration, Instant};

fn main() {
    smol::block_on(async {
        // construct our cache
        let cache = Arc::new(Cache::new());
        let clone = cache.clone();

        // spawn the monitor
        let handle = smol::spawn(async move {
            // don't forget to monitor your cache to evict entries
            clone.monitor(25, Duration::from_secs(1), 0.25).await
        });

        // insert using an `Instant` type to specify expiration
        cache.insert("one", 1usize, Instant::now()).await;

        // insert using a `Duration` type to wait before expiration
        cache.insert("two", 2, Duration::from_secs(2)).await;

        // insert using a number of milliseconds
        cache.insert("three", 3, 3500).await;

        // insert using a random number of milliseconds
        cache.insert("four", 4, 3500..5000).await;

        // insert without expiration (i.e. manual removal)
        cache.insert_untracked("five", 5).await;

        // wait until the monitor has run once
        Timer::after(Duration::from_millis(3250)).await;

        // the first two keys should have been removed
        assert!(cache.get(&"one").await.is_none());
        assert!(cache.get(&"two").await.is_none());

        // the rest should be there still for now
        assert!(cache.get(&"three").await.is_some());
        assert!(cache.get(&"four").await.is_some());
        assert!(cache.get(&"five").await.is_some());

        // wait until the monitor has run again
        Timer::after(Duration::from_millis(3250)).await;

        // the other two keys should have been removed
        assert!(cache.get(&"three").await.is_none());
        assert!(cache.get(&"four").await.is_none());

        // the key with no expiration should still exist
        assert!(cache.get(&"five").await.is_some());

        // but we should be able to manually remove it
        assert!(cache.remove(&"five").await.is_some());
        assert!(cache.get(&"five").await.is_none());

        // and now our cache should be empty
        assert!(cache.is_empty().await);

        // cancel the monitor
        handle.cancel().await;
    });
}
