use super::{QuotaPoolBuffer, VACANT};
use crate::Quota;

#[test]
fn with_capacity_reserves_dense_storage() {
    let buffer = QuotaPoolBuffer::with_capacity(4);

    assert!(buffer.quotas.capacity() >= 4);
    assert!(buffer.last_access_times_ns.capacity() >= 4);
    assert!(buffer.elapsed_since_refills_ns.capacity() >= 4);
    assert!(buffer.generations.capacity() >= 4);
    assert!(buffer.free_list.capacity() >= 4);
    assert!(buffer.slot_to_dense.capacity() >= 4);
    assert!(buffer.dense_to_slot.capacity() >= 4);
}

#[test]
fn accessors_update_dense_slot_state() {
    let mut buffer = QuotaPoolBuffer::new();
    let id = buffer.push(Quota::with_initial_tokens(1));

    *buffer.last_access_time_ns_mut(id).unwrap() = 7;
    *buffer.elapsed_since_refill_ns_mut(id).unwrap() = 11;

    assert_eq!(buffer.last_access_time_ns(id), Some(&7));
    assert_eq!(buffer.elapsed_since_refill_ns(id), Some(&11));

    assert!(buffer.get_mut(id).unwrap().consume(1).is_ok());
    assert!(buffer.raw_quota(id).unwrap().consume(1).is_err());

    let old = buffer.replace(id, Quota::with_initial_tokens(2)).unwrap();

    assert!(old.consume(1).is_err());
    assert!(buffer.raw_quota(id).unwrap().consume(2).is_ok());
}

#[test]
fn remove_keeps_dense_storage_packed_and_preserves_moved_id() {
    let mut buffer = QuotaPoolBuffer::new();

    let _a = buffer.push(Quota::with_initial_tokens(1));
    let b = buffer.push(Quota::with_initial_tokens(2));
    let c = buffer.push(Quota::with_initial_tokens(3));

    assert!(buffer.remove(b));

    assert_eq!(buffer.quotas.len(), 2);
    assert_eq!(buffer.last_access_times_ns.len(), 2);
    assert_eq!(buffer.elapsed_since_refills_ns.len(), 2);
    assert_eq!(buffer.dense_to_slot.len(), 2);
    assert_eq!(buffer.slot_to_dense[b.index], VACANT);
    assert_eq!(buffer.slot_to_dense[c.index], 1);

    assert!(buffer.raw_quota(b).is_none());
    assert!(buffer.raw_quota(c).is_some());
}

#[test]
fn removed_slot_is_reused_with_next_generation() {
    let mut buffer = QuotaPoolBuffer::new();

    let old = buffer.push(Quota::with_initial_tokens(1));
    assert!(buffer.remove(old));

    let new = buffer.push(Quota::with_initial_tokens(1));

    assert_eq!(new.index, old.index);
    assert_ne!(new.generation, old.generation);
    assert!(buffer.raw_quota(old).is_none());
    assert!(buffer.raw_quota(new).is_some());
}

#[test]
fn remove_rejects_stale_id() {
    let mut buffer = QuotaPoolBuffer::new();

    let old = buffer.push(Quota::with_initial_tokens(1));
    assert!(buffer.remove(old));

    assert!(!buffer.remove(old));
}
