use crate::utils::{db_put_simple, open_database, tmpdir};
use leveldb::database::Slice;
use leveldb::database::batch::{Batch, Writebatch, WritebatchIterator};
use leveldb::database::kv::KV;
use leveldb::options::{ReadOptions, WriteOptions};

#[test]
fn test_writebatch() {
    let tmp = tmpdir("writebatch");
    let database = &mut open_database(tmp.path(), true);

    // Write initial data using utility function
    db_put_simple(database, b"1", b"1");

    let batch = &mut Writebatch::new();
    batch.put(Slice::from("1".as_bytes()), Slice::from("1".as_bytes()));
    batch.put(Slice::from("2".as_bytes()), Slice::from("2".as_bytes()));
    batch.delete(Slice::from("1".as_bytes()));

    let wopts = WriteOptions::new();
    let ack = database.write(wopts, batch);
    assert!(ack.is_ok());

    // Test that key 2 exists
    let read_opts = ReadOptions::new();
    let res = database.get(read_opts, Slice::from("2".as_bytes()));
    assert!(res.is_ok());
    assert_eq!(res.unwrap().unwrap().as_bytes(), b"2");

    // Test that key 1 was deleted
    let read_opts2 = ReadOptions::new();
    let res2 = database.get(read_opts2, Slice::from("1".as_bytes()));
    assert!(res2.is_ok());
    assert_eq!(res2.unwrap(), None);
}

struct Iter {
    put: i32,
    deleted: i32,
}

impl WritebatchIterator for Iter {
    fn put(&mut self, _key: Slice, _value: Slice) {
        self.put += 1;
    }

    fn deleted(&mut self, _key: Slice) {
        self.deleted += 1;
    }
}

#[test]
fn test_writebatchiter() {
    let tmp = tmpdir("writebatch");
    let database = &mut open_database(tmp.path(), true);

    let batch = &mut Writebatch::new();
    batch.put(Slice::from("1".as_bytes()), Slice::from("1".as_bytes()));
    batch.put(Slice::from("2".as_bytes()), Slice::from("2".as_bytes()));
    batch.delete(Slice::from("1".as_bytes()));

    let wopts = WriteOptions::new();
    let ack = database.write(wopts, batch);
    assert!(ack.is_ok());

    let iter = Box::new(Iter { put: 0, deleted: 0 });
    let iter2 = batch.iterate(iter);
    assert_eq!(iter2.put, 2);
    assert_eq!(iter2.deleted, 1);
}
