use inc_id::IdGenerator;
use inc_id::IdGenError;

#[test]
fn get_unique_ids() {
    let mut id_gen = IdGenerator::<u16>::new();
    let id1 = id_gen.get_id().unwrap();
    let id2 = id_gen.get_id().unwrap();
    assert_ne!(id1, id2);
}

#[test]
fn reuse_ids() {
    let mut id_gen = IdGenerator::<u64>::new();
    let id1 = id_gen.get_id().unwrap();
    let id2 = id_gen.get_id().unwrap();

    id_gen.return_id(id1).unwrap();
    assert_eq!(id_gen.returned_len(), 1);

    let id3 = id_gen.get_id().unwrap();
    let id4 = id_gen.get_id().unwrap();

    assert_eq!(id1, id3);
    assert_ne!(id2, id3);
    assert_ne!(id3, id4);
    assert_ne!(id2, id4);
}

#[test]
fn returned_len() {
    let mut id_gen = IdGenerator::<u64>::new();

    assert_eq!(id_gen.returned_len(), 0);

    let id1 = id_gen.get_id().unwrap();
    let id2 = id_gen.get_id().unwrap();
    
    assert_eq!(id_gen.returned_len(), 0);

    id_gen.return_id(id1).unwrap();
    assert_eq!(id_gen.returned_len(), 1);

    id_gen.return_id(id2).unwrap();
    assert_eq!(id_gen.returned_len(), 2);
}

#[test]
fn dup_return() {
    let mut id_gen = IdGenerator::<u8>::new();
    let id1 = id_gen.get_id().unwrap();

    // Shouldn't get any errors from this one
    assert!(
        id_gen.return_id(id1).is_ok(),
        "Returning an ID should be OK"
    );

    // We should get one after repeating it though
    let res = id_gen.return_id(id1);
    assert!(
        res.is_err(),
        "Returning an ID more than once should cause an Error"
    );

    let err = res.unwrap_err();

    assert!(
        matches!(err, IdGenError::DuplicateIdReturn(_)),
        "The error should be a DuplicateIdReturn variant"
    );

    // It should reference the ID we just returned
    assert_eq!(
        err.get_id(),
        &id1
    );
}

#[test]
fn invalid_return() {
    let mut id_gen = IdGenerator::<u32>::new();
    id_gen.get_id().unwrap();

    let res = id_gen.return_id(2);
    assert!(
        res.is_err(),
        "Returning an invalid ID should cause an Error"
    );

    let err = res.unwrap_err();

    assert!(
        matches!(err, IdGenError::InvalidId(_)),
        "The error should be an InvalidId variant"
    )
}

#[test]
fn invalid_return_unused() {
    let mut id_gen = IdGenerator::<u32>::new();
    let res = id_gen.return_id(2);
    assert!(
        res.is_err(),
        "Returning an invalid ID should cause an Error"
    );

    let err = res.unwrap_err();

    assert!(
        matches!(err, IdGenError::InvalidId(_)),
        "The error should be an InvalidId variant"
    )
}

#[test]
fn exhausted() {
    let mut id_gen = IdGenerator::<u8>::new();

    // generate all available values
    for _ in 0..256 {
        id_gen.get_id().unwrap();
    }

    // generate 1 more
    let res = id_gen.get_id();
    assert!(res.is_err());

    let err = res.unwrap_err();

    assert!(
        matches!(err, IdGenError::IdsExhausted(_)),
        "The error should be an exhausted variant"
    );

    assert_eq!(err.get_id(), &u8::MAX);
}
