#[cfg(feature = "var-collections")]
use armdb::VarTree;
use armdb::{Config, ConstTree};
use tempfile::tempdir;

#[test]
fn test_const_recovery() {
    let dir = tempdir().unwrap();

    // Write 100 entries, then close
    {
        let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test()).unwrap();

        for i in 0u64..100 {
            let key = i.to_be_bytes();
            let value = (i * 10).to_be_bytes();
            tree.put(&key, &value).unwrap();
        }

        tree.close().unwrap();
    }

    // Reopen and verify all 100 entries
    {
        let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test()).unwrap();

        assert_eq!(tree.len(), 100);

        for i in 0u64..100 {
            let key = i.to_be_bytes();
            let expected = (i * 10).to_be_bytes();
            let actual = tree.get(&key).unwrap_or_else(|| {
                panic!("key {i} not found after recovery");
            });
            assert_eq!(actual, expected, "value mismatch for key {i}");
        }
    }
}

#[cfg(feature = "var-collections")]
#[test]
fn test_var_recovery() {
    let dir = tempdir().unwrap();

    // Write 100 entries, then close
    {
        let tree = VarTree::<[u8; 8]>::open(dir.path(), Config::test()).unwrap();

        for i in 0u64..100 {
            let key = i.to_be_bytes();
            let value = format!("value_{i}").into_bytes();
            tree.put(&key, &value).unwrap();
        }

        tree.close().unwrap();
    }

    // Reopen and verify all 100 entries
    {
        let tree = VarTree::<[u8; 8]>::open(dir.path(), Config::test()).unwrap();

        assert_eq!(tree.len(), 100);

        for i in 0u64..100 {
            let key = i.to_be_bytes();
            let expected = format!("value_{i}").into_bytes();
            let actual = tree.get(&key).unwrap_or_else(|| {
                panic!("key {i} not found after recovery");
            });
            assert_eq!(
                actual.as_bytes(),
                expected.as_slice(),
                "value mismatch for key {i}"
            );
        }
    }
}

#[test]
fn test_recovery_with_deletes() {
    let dir = tempdir().unwrap();

    // Write 100 entries, delete the first 50, then close
    {
        let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test()).unwrap();

        for i in 0u64..100 {
            let key = i.to_be_bytes();
            let value = (i * 10).to_be_bytes();
            tree.put(&key, &value).unwrap();
        }

        for i in 0u64..50 {
            let key = i.to_be_bytes();
            let deleted = tree.delete(&key).unwrap();
            assert!(deleted.is_some(), "expected key {i} to exist for deletion");
        }

        tree.close().unwrap();
    }

    // Reopen and verify: first 50 absent, last 50 present
    {
        let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test()).unwrap();

        assert_eq!(tree.len(), 50);

        for i in 0u64..50 {
            let key = i.to_be_bytes();
            assert!(
                tree.get(&key).is_none(),
                "key {i} should have been deleted but was found"
            );
        }

        for i in 50u64..100 {
            let key = i.to_be_bytes();
            let expected = (i * 10).to_be_bytes();
            let actual = tree.get(&key).unwrap_or_else(|| {
                panic!("key {i} not found after recovery");
            });
            assert_eq!(actual, expected, "value mismatch for key {i}");
        }
    }
}

#[test]
fn test_recovery_with_overwrites() {
    let dir = tempdir().unwrap();

    // Write 100 entries, overwrite the first 50 with new values, then close
    {
        let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test()).unwrap();

        for i in 0u64..100 {
            let key = i.to_be_bytes();
            let value = (i * 10).to_be_bytes();
            tree.put(&key, &value).unwrap();
        }

        for i in 0u64..50 {
            let key = i.to_be_bytes();
            let new_value = (i * 100 + 1).to_be_bytes();
            tree.put(&key, &new_value).unwrap();
        }

        tree.close().unwrap();
    }

    // Reopen and verify latest values
    {
        let tree = ConstTree::<[u8; 8], 8>::open(dir.path(), Config::test()).unwrap();

        assert_eq!(tree.len(), 100);

        // First 50: should have the overwritten values
        for i in 0u64..50 {
            let key = i.to_be_bytes();
            let expected = (i * 100 + 1).to_be_bytes();
            let actual = tree.get(&key).unwrap_or_else(|| {
                panic!("key {i} not found after recovery");
            });
            assert_eq!(actual, expected, "overwritten value mismatch for key {i}");
        }

        // Last 50: should have the original values
        for i in 50u64..100 {
            let key = i.to_be_bytes();
            let expected = (i * 10).to_be_bytes();
            let actual = tree.get(&key).unwrap_or_else(|| {
                panic!("key {i} not found after recovery");
            });
            assert_eq!(actual, expected, "original value mismatch for key {i}");
        }
    }
}
