//! Generic iterator tests for all vec types.
//!
//! These tests run against any type implementing `StoredVec`, ensuring
//! consistent iterator behavior across BytesVec, ZeroCopyVec, PcoVec, LZ4Vec, and ZstdVec.

use rawdb::Database;
use tempfile::TempDir;
use vecdb::{Result, StoredVec, Version};

// ============================================================================
// Test Setup Helpers
// ============================================================================

fn setup_db() -> Result<(Database, TempDir)> {
    let temp = TempDir::new()?;
    let db = Database::open(temp.path())?;
    Ok((db, temp))
}

// ============================================================================
// Generic Clean Iterator Tests
// ============================================================================

mod clean_iter {
    use super::*;

    fn run_basic<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected.len(), 100);
        assert_eq!(collected[0], 0);
        assert_eq!(collected[99], 99);
        Ok(())
    }

    fn run_nth<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        // Test point reads at specific indices
        assert_eq!(vec.collect_first().unwrap(), 0);
        assert_eq!(vec.collect_one(10).unwrap(), 10);
        assert_eq!(vec.collect_one(11).unwrap(), 11);
        Ok(())
    }

    fn run_skip<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected = vec.collect_range(50, 100);
        assert_eq!(collected.len(), 50);
        assert_eq!(collected[0], 50);
        Ok(())
    }

    fn run_take<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected = vec.collect_range(0, 25);
        assert_eq!(collected.len(), 25);
        assert_eq!(collected[24], 24);
        Ok(())
    }

    fn run_set_position<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected = vec.collect_range(50, 52);
        assert_eq!(collected[0], 50);
        assert_eq!(collected[1], 51);
        Ok(())
    }

    fn run_set_end<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected = vec.collect_range(0, 50);
        assert_eq!(collected.len(), 50);
        Ok(())
    }

    fn run_last<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        assert_eq!(vec.collect_last().unwrap(), 99);
        Ok(())
    }

    fn run_last_empty<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let vec = V::forced_import(&db, "test", Version::ONE)?;

        assert_eq!(vec.len(), 0);
        assert!(vec.collect().is_empty());
        Ok(())
    }

    fn run_exact_size<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        assert_eq!(vec.len(), 100);
        assert_eq!(vec.collect_range(0, 100).len(), 100);
        assert_eq!(vec.collect_range(1, 100).len(), 99);
        Ok(())
    }

    fn run_buffer_crossing<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..10000 {
            vec.push(i);
        }
        vec.write()?;

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected.len(), 10000);

        for (i, &val) in collected.iter().enumerate() {
            assert_eq!(val, i as i32);
        }
        Ok(())
    }

    fn run_multiple_skip_take<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..1000 {
            vec.push(i);
        }
        vec.write()?;

        // skip(100).take(200).skip(50).take(100) => collect_range(150, 250)
        let collected = vec.collect_range(150, 250);

        assert_eq!(collected.len(), 100);
        assert_eq!(collected[0], 150);
        assert_eq!(collected[99], 249);
        Ok(())
    }

    fn run_set_position_multiple<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..1000 {
            vec.push(i);
        }
        vec.write()?;

        // Random access reads at various positions
        assert_eq!(vec.collect_one(100).unwrap(), 100);
        assert_eq!(vec.collect_one(500).unwrap(), 500);
        assert_eq!(vec.collect_one(50).unwrap(), 50);
        Ok(())
    }

    fn run_nth_beyond_end<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..10 {
            vec.push(i);
        }
        vec.write()?;

        // Reading beyond end returns empty
        let collected = vec.collect_range(10, 10);
        assert!(collected.is_empty());
        Ok(())
    }

    fn run_skip_all<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected = vec.collect_range(100, 100);
        assert!(collected.is_empty());
        Ok(())
    }

    fn run_take_zero<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected = vec.collect_range(0, 0);
        assert_eq!(collected.len(), 0);
        Ok(())
    }

    fn run_size_hint_consistency<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        // Test that collect_range returns correct sizes for progressive ranges
        for i in 0..100 {
            let remaining = vec.collect_range(i, 100);
            assert_eq!(remaining.len(), 100 - i);
        }
        Ok(())
    }

    // ============================================================================
    // Test instantiation for each vec type
    // ============================================================================

    mod bytes {
        use super::*;
        use vecdb::BytesVec;
        type V = BytesVec<usize, i32>;

        #[test]
        fn basic() -> Result<()> {
            run_basic::<V>()
        }
        #[test]
        fn nth() -> Result<()> {
            run_nth::<V>()
        }
        #[test]
        fn skip() -> Result<()> {
            run_skip::<V>()
        }
        #[test]
        fn take() -> Result<()> {
            run_take::<V>()
        }
        #[test]
        fn set_position() -> Result<()> {
            run_set_position::<V>()
        }
        #[test]
        fn set_end() -> Result<()> {
            run_set_end::<V>()
        }
        #[test]
        fn last() -> Result<()> {
            run_last::<V>()
        }
        #[test]
        fn last_empty() -> Result<()> {
            run_last_empty::<V>()
        }
        #[test]
        fn exact_size() -> Result<()> {
            run_exact_size::<V>()
        }
        #[test]
        fn buffer_crossing() -> Result<()> {
            run_buffer_crossing::<V>()
        }
        #[test]
        fn multiple_skip_take() -> Result<()> {
            run_multiple_skip_take::<V>()
        }
        #[test]
        fn set_position_multiple() -> Result<()> {
            run_set_position_multiple::<V>()
        }
        #[test]
        fn nth_beyond_end() -> Result<()> {
            run_nth_beyond_end::<V>()
        }
        #[test]
        fn skip_all() -> Result<()> {
            run_skip_all::<V>()
        }
        #[test]
        fn take_zero() -> Result<()> {
            run_take_zero::<V>()
        }
        #[test]
        fn size_hint_consistency() -> Result<()> {
            run_size_hint_consistency::<V>()
        }
    }

    #[cfg(feature = "zerocopy")]
    mod zerocopy {
        use super::*;
        use vecdb::ZeroCopyVec;
        type V = ZeroCopyVec<usize, i32>;

        #[test]
        fn basic() -> Result<()> {
            run_basic::<V>()
        }
        #[test]
        fn nth() -> Result<()> {
            run_nth::<V>()
        }
        #[test]
        fn skip() -> Result<()> {
            run_skip::<V>()
        }
        #[test]
        fn take() -> Result<()> {
            run_take::<V>()
        }
        #[test]
        fn set_position() -> Result<()> {
            run_set_position::<V>()
        }
        #[test]
        fn set_end() -> Result<()> {
            run_set_end::<V>()
        }
        #[test]
        fn last() -> Result<()> {
            run_last::<V>()
        }
        #[test]
        fn last_empty() -> Result<()> {
            run_last_empty::<V>()
        }
        #[test]
        fn exact_size() -> Result<()> {
            run_exact_size::<V>()
        }
        #[test]
        fn buffer_crossing() -> Result<()> {
            run_buffer_crossing::<V>()
        }
        #[test]
        fn multiple_skip_take() -> Result<()> {
            run_multiple_skip_take::<V>()
        }
        #[test]
        fn set_position_multiple() -> Result<()> {
            run_set_position_multiple::<V>()
        }
        #[test]
        fn nth_beyond_end() -> Result<()> {
            run_nth_beyond_end::<V>()
        }
        #[test]
        fn skip_all() -> Result<()> {
            run_skip_all::<V>()
        }
        #[test]
        fn take_zero() -> Result<()> {
            run_take_zero::<V>()
        }
        #[test]
        fn size_hint_consistency() -> Result<()> {
            run_size_hint_consistency::<V>()
        }
    }

    #[cfg(feature = "pco")]
    mod pco {
        use super::*;
        use vecdb::PcoVec;
        type V = PcoVec<usize, i32>;

        #[test]
        fn basic() -> Result<()> {
            run_basic::<V>()
        }
        #[test]
        fn nth() -> Result<()> {
            run_nth::<V>()
        }
        #[test]
        fn skip() -> Result<()> {
            run_skip::<V>()
        }
        #[test]
        fn take() -> Result<()> {
            run_take::<V>()
        }
        #[test]
        fn set_position() -> Result<()> {
            run_set_position::<V>()
        }
        #[test]
        fn set_end() -> Result<()> {
            run_set_end::<V>()
        }
        #[test]
        fn last() -> Result<()> {
            run_last::<V>()
        }
        #[test]
        fn last_empty() -> Result<()> {
            run_last_empty::<V>()
        }
        #[test]
        fn exact_size() -> Result<()> {
            run_exact_size::<V>()
        }
        #[test]
        fn buffer_crossing() -> Result<()> {
            run_buffer_crossing::<V>()
        }
        #[test]
        fn multiple_skip_take() -> Result<()> {
            run_multiple_skip_take::<V>()
        }
        #[test]
        fn set_position_multiple() -> Result<()> {
            run_set_position_multiple::<V>()
        }
        #[test]
        fn nth_beyond_end() -> Result<()> {
            run_nth_beyond_end::<V>()
        }
        #[test]
        fn skip_all() -> Result<()> {
            run_skip_all::<V>()
        }
        #[test]
        fn take_zero() -> Result<()> {
            run_take_zero::<V>()
        }
        #[test]
        fn size_hint_consistency() -> Result<()> {
            run_size_hint_consistency::<V>()
        }
    }

    #[cfg(feature = "lz4")]
    mod lz4 {
        use super::*;
        use vecdb::LZ4Vec;
        type V = LZ4Vec<usize, i32>;

        #[test]
        fn basic() -> Result<()> {
            run_basic::<V>()
        }
        #[test]
        fn nth() -> Result<()> {
            run_nth::<V>()
        }
        #[test]
        fn skip() -> Result<()> {
            run_skip::<V>()
        }
        #[test]
        fn take() -> Result<()> {
            run_take::<V>()
        }
        #[test]
        fn set_position() -> Result<()> {
            run_set_position::<V>()
        }
        #[test]
        fn set_end() -> Result<()> {
            run_set_end::<V>()
        }
        #[test]
        fn last() -> Result<()> {
            run_last::<V>()
        }
        #[test]
        fn last_empty() -> Result<()> {
            run_last_empty::<V>()
        }
        #[test]
        fn exact_size() -> Result<()> {
            run_exact_size::<V>()
        }
        #[test]
        fn buffer_crossing() -> Result<()> {
            run_buffer_crossing::<V>()
        }
        #[test]
        fn multiple_skip_take() -> Result<()> {
            run_multiple_skip_take::<V>()
        }
        #[test]
        fn set_position_multiple() -> Result<()> {
            run_set_position_multiple::<V>()
        }
        #[test]
        fn nth_beyond_end() -> Result<()> {
            run_nth_beyond_end::<V>()
        }
        #[test]
        fn skip_all() -> Result<()> {
            run_skip_all::<V>()
        }
        #[test]
        fn take_zero() -> Result<()> {
            run_take_zero::<V>()
        }
        #[test]
        fn size_hint_consistency() -> Result<()> {
            run_size_hint_consistency::<V>()
        }
    }

    #[cfg(feature = "zstd")]
    mod zstd {
        use super::*;
        use vecdb::ZstdVec;
        type V = ZstdVec<usize, i32>;

        #[test]
        fn basic() -> Result<()> {
            run_basic::<V>()
        }
        #[test]
        fn nth() -> Result<()> {
            run_nth::<V>()
        }
        #[test]
        fn skip() -> Result<()> {
            run_skip::<V>()
        }
        #[test]
        fn take() -> Result<()> {
            run_take::<V>()
        }
        #[test]
        fn set_position() -> Result<()> {
            run_set_position::<V>()
        }
        #[test]
        fn set_end() -> Result<()> {
            run_set_end::<V>()
        }
        #[test]
        fn last() -> Result<()> {
            run_last::<V>()
        }
        #[test]
        fn last_empty() -> Result<()> {
            run_last_empty::<V>()
        }
        #[test]
        fn exact_size() -> Result<()> {
            run_exact_size::<V>()
        }
        #[test]
        fn buffer_crossing() -> Result<()> {
            run_buffer_crossing::<V>()
        }
        #[test]
        fn multiple_skip_take() -> Result<()> {
            run_multiple_skip_take::<V>()
        }
        #[test]
        fn set_position_multiple() -> Result<()> {
            run_set_position_multiple::<V>()
        }
        #[test]
        fn nth_beyond_end() -> Result<()> {
            run_nth_beyond_end::<V>()
        }
        #[test]
        fn skip_all() -> Result<()> {
            run_skip_all::<V>()
        }
        #[test]
        fn take_zero() -> Result<()> {
            run_take_zero::<V>()
        }
        #[test]
        fn size_hint_consistency() -> Result<()> {
            run_size_hint_consistency::<V>()
        }
    }

    // ============================================================================
    // EagerVec Tests (wrapping different underlying vec types)
    // ============================================================================

    #[cfg(feature = "zerocopy")]
    mod eager_zerocopy {
        use super::*;
        use vecdb::{EagerVec, ZeroCopyVec};
        type V = EagerVec<ZeroCopyVec<usize, i32>>;

        #[test]
        fn basic() -> Result<()> {
            run_basic::<V>()
        }
        #[test]
        fn nth() -> Result<()> {
            run_nth::<V>()
        }
        #[test]
        fn skip() -> Result<()> {
            run_skip::<V>()
        }
        #[test]
        fn take() -> Result<()> {
            run_take::<V>()
        }
        #[test]
        fn set_position() -> Result<()> {
            run_set_position::<V>()
        }
        #[test]
        fn set_end() -> Result<()> {
            run_set_end::<V>()
        }
        #[test]
        fn last() -> Result<()> {
            run_last::<V>()
        }
        #[test]
        fn last_empty() -> Result<()> {
            run_last_empty::<V>()
        }
        #[test]
        fn exact_size() -> Result<()> {
            run_exact_size::<V>()
        }
        #[test]
        fn buffer_crossing() -> Result<()> {
            run_buffer_crossing::<V>()
        }
        #[test]
        fn multiple_skip_take() -> Result<()> {
            run_multiple_skip_take::<V>()
        }
        #[test]
        fn set_position_multiple() -> Result<()> {
            run_set_position_multiple::<V>()
        }
        #[test]
        fn nth_beyond_end() -> Result<()> {
            run_nth_beyond_end::<V>()
        }
        #[test]
        fn skip_all() -> Result<()> {
            run_skip_all::<V>()
        }
        #[test]
        fn take_zero() -> Result<()> {
            run_take_zero::<V>()
        }
        #[test]
        fn size_hint_consistency() -> Result<()> {
            run_size_hint_consistency::<V>()
        }
    }

    #[cfg(feature = "pco")]
    mod eager_pco {
        use super::*;
        use vecdb::{EagerVec, PcoVec};
        type V = EagerVec<PcoVec<usize, i32>>;

        #[test]
        fn basic() -> Result<()> {
            run_basic::<V>()
        }
        #[test]
        fn nth() -> Result<()> {
            run_nth::<V>()
        }
        #[test]
        fn skip() -> Result<()> {
            run_skip::<V>()
        }
        #[test]
        fn take() -> Result<()> {
            run_take::<V>()
        }
        #[test]
        fn set_position() -> Result<()> {
            run_set_position::<V>()
        }
        #[test]
        fn set_end() -> Result<()> {
            run_set_end::<V>()
        }
        #[test]
        fn last() -> Result<()> {
            run_last::<V>()
        }
        #[test]
        fn last_empty() -> Result<()> {
            run_last_empty::<V>()
        }
        #[test]
        fn exact_size() -> Result<()> {
            run_exact_size::<V>()
        }
        #[test]
        fn buffer_crossing() -> Result<()> {
            run_buffer_crossing::<V>()
        }
        #[test]
        fn multiple_skip_take() -> Result<()> {
            run_multiple_skip_take::<V>()
        }
        #[test]
        fn set_position_multiple() -> Result<()> {
            run_set_position_multiple::<V>()
        }
        #[test]
        fn nth_beyond_end() -> Result<()> {
            run_nth_beyond_end::<V>()
        }
        #[test]
        fn skip_all() -> Result<()> {
            run_skip_all::<V>()
        }
        #[test]
        fn take_zero() -> Result<()> {
            run_take_zero::<V>()
        }
        #[test]
        fn size_hint_consistency() -> Result<()> {
            run_size_hint_consistency::<V>()
        }
    }
}

// ============================================================================
// Generic Dirty Iterator Tests (stored + pushed data)
// ============================================================================

mod dirty_iter {
    use super::*;

    fn run_only_stored<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected.len(), 100);
        assert_eq!(collected[0], 0);
        assert_eq!(collected[99], 99);
        Ok(())
    }

    fn run_only_pushed<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        // Don't flush

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected.len(), 50);
        assert_eq!(collected[0], 0);
        assert_eq!(collected[49], 49);
        Ok(())
    }

    fn run_stored_and_pushed<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        vec.write()?;

        for i in 50..100 {
            vec.push(i);
        }

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected.len(), 100);

        for (i, &val) in collected.iter().enumerate() {
            assert_eq!(val, i as i32);
        }
        Ok(())
    }

    fn run_skip_across_boundary<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        vec.write()?;

        for i in 50..100 {
            vec.push(i);
        }

        let collected = vec.collect_range(40, 100);
        assert_eq!(collected.len(), 60);
        assert_eq!(collected[0], 40);
        assert_eq!(collected[59], 99);
        Ok(())
    }

    fn run_take_across_boundary<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        vec.write()?;

        for i in 50..100 {
            vec.push(i);
        }

        let collected = vec.collect_range(40, 60);
        assert_eq!(collected.len(), 20);
        assert_eq!(collected[0], 40);
        assert_eq!(collected[19], 59);
        Ok(())
    }

    fn run_nth_across_boundary<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        vec.write()?;

        for i in 50..100 {
            vec.push(i);
        }

        // Test reading across stored/pushed boundary
        let vals = vec.collect_range(45, 52);
        assert_eq!(vals[0], 45); // In stored
        assert_eq!(vals[1], 46); // In stored
        assert_eq!(vals[4], 49); // In stored
        assert_eq!(vals[5], 50); // In pushed
        assert_eq!(vals[6], 51); // In pushed
        Ok(())
    }

    fn run_set_position_to_pushed<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        vec.write()?;

        for i in 50..100 {
            vec.push(i);
        }

        let vals = vec.collect_range(75, 77);
        assert_eq!(vals[0], 75);
        assert_eq!(vals[1], 76);
        Ok(())
    }

    fn run_last_in_pushed<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        vec.write()?;

        for i in 50..100 {
            vec.push(i);
        }

        assert_eq!(vec.collect_last().unwrap(), 99);
        Ok(())
    }

    fn run_last_in_stored<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..100 {
            vec.push(i);
        }
        vec.write()?;

        assert_eq!(vec.collect_last().unwrap(), 99);
        Ok(())
    }

    fn run_exact_size_with_pushed<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..50 {
            vec.push(i);
        }
        vec.write()?;

        for i in 50..75 {
            vec.push(i);
        }

        assert_eq!(vec.len(), 75);
        assert_eq!(vec.collect_range(0, 75).len(), 75);
        assert_eq!(vec.collect_range(1, 75).len(), 74);
        assert_eq!(vec.collect_range(51, 75).len(), 24); // Cross boundary
        Ok(())
    }

    fn run_large_dataset_boundary<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        // Large stored portion
        for i in 0..10000 {
            vec.push(i);
        }
        vec.write()?;

        // Small pushed portion
        for i in 10000..10100 {
            vec.push(i);
        }

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected.len(), 10100);

        for (i, &val) in collected.iter().enumerate() {
            assert_eq!(val, i as i32);
        }
        Ok(())
    }

    fn run_skip_take_complex<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..8000 {
            vec.push(i);
        }
        vec.write()?;

        for i in 8000..12000 {
            vec.push(i);
        }

        // skip(7000).take(3000).skip(500).take(1000) => collect_range(7500, 8500)
        let collected = vec.collect_range(7500, 8500);

        assert_eq!(collected.len(), 1000);
        assert_eq!(collected[0], 7500);
        assert_eq!(collected[999], 8499);
        Ok(())
    }

    // ============================================================================
    // Test instantiation for each vec type
    // ============================================================================

    mod bytes {
        use super::*;
        use vecdb::BytesVec;
        type V = BytesVec<usize, i32>;

        #[test]
        fn only_stored() -> Result<()> {
            run_only_stored::<V>()
        }
        #[test]
        fn only_pushed() -> Result<()> {
            run_only_pushed::<V>()
        }
        #[test]
        fn stored_and_pushed() -> Result<()> {
            run_stored_and_pushed::<V>()
        }
        #[test]
        fn skip_across_boundary() -> Result<()> {
            run_skip_across_boundary::<V>()
        }
        #[test]
        fn take_across_boundary() -> Result<()> {
            run_take_across_boundary::<V>()
        }
        #[test]
        fn nth_across_boundary() -> Result<()> {
            run_nth_across_boundary::<V>()
        }
        #[test]
        fn set_position_to_pushed() -> Result<()> {
            run_set_position_to_pushed::<V>()
        }
        #[test]
        fn last_in_pushed() -> Result<()> {
            run_last_in_pushed::<V>()
        }
        #[test]
        fn last_in_stored() -> Result<()> {
            run_last_in_stored::<V>()
        }
        #[test]
        fn exact_size_with_pushed() -> Result<()> {
            run_exact_size_with_pushed::<V>()
        }
        #[test]
        fn large_dataset_boundary() -> Result<()> {
            run_large_dataset_boundary::<V>()
        }
        #[test]
        fn skip_take_complex() -> Result<()> {
            run_skip_take_complex::<V>()
        }
    }

    #[cfg(feature = "zerocopy")]
    mod zerocopy {
        use super::*;
        use vecdb::ZeroCopyVec;
        type V = ZeroCopyVec<usize, i32>;

        #[test]
        fn only_stored() -> Result<()> {
            run_only_stored::<V>()
        }
        #[test]
        fn only_pushed() -> Result<()> {
            run_only_pushed::<V>()
        }
        #[test]
        fn stored_and_pushed() -> Result<()> {
            run_stored_and_pushed::<V>()
        }
        #[test]
        fn skip_across_boundary() -> Result<()> {
            run_skip_across_boundary::<V>()
        }
        #[test]
        fn take_across_boundary() -> Result<()> {
            run_take_across_boundary::<V>()
        }
        #[test]
        fn nth_across_boundary() -> Result<()> {
            run_nth_across_boundary::<V>()
        }
        #[test]
        fn set_position_to_pushed() -> Result<()> {
            run_set_position_to_pushed::<V>()
        }
        #[test]
        fn last_in_pushed() -> Result<()> {
            run_last_in_pushed::<V>()
        }
        #[test]
        fn last_in_stored() -> Result<()> {
            run_last_in_stored::<V>()
        }
        #[test]
        fn exact_size_with_pushed() -> Result<()> {
            run_exact_size_with_pushed::<V>()
        }
        #[test]
        fn large_dataset_boundary() -> Result<()> {
            run_large_dataset_boundary::<V>()
        }
        #[test]
        fn skip_take_complex() -> Result<()> {
            run_skip_take_complex::<V>()
        }
    }

    #[cfg(feature = "pco")]
    mod pco {
        use super::*;
        use vecdb::PcoVec;
        type V = PcoVec<usize, i32>;

        #[test]
        fn only_stored() -> Result<()> {
            run_only_stored::<V>()
        }
        #[test]
        fn only_pushed() -> Result<()> {
            run_only_pushed::<V>()
        }
        #[test]
        fn stored_and_pushed() -> Result<()> {
            run_stored_and_pushed::<V>()
        }
        #[test]
        fn skip_across_boundary() -> Result<()> {
            run_skip_across_boundary::<V>()
        }
        #[test]
        fn take_across_boundary() -> Result<()> {
            run_take_across_boundary::<V>()
        }
        #[test]
        fn nth_across_boundary() -> Result<()> {
            run_nth_across_boundary::<V>()
        }
        #[test]
        fn set_position_to_pushed() -> Result<()> {
            run_set_position_to_pushed::<V>()
        }
        #[test]
        fn last_in_pushed() -> Result<()> {
            run_last_in_pushed::<V>()
        }
        #[test]
        fn last_in_stored() -> Result<()> {
            run_last_in_stored::<V>()
        }
        #[test]
        fn exact_size_with_pushed() -> Result<()> {
            run_exact_size_with_pushed::<V>()
        }
        #[test]
        fn large_dataset_boundary() -> Result<()> {
            run_large_dataset_boundary::<V>()
        }
        #[test]
        fn skip_take_complex() -> Result<()> {
            run_skip_take_complex::<V>()
        }
    }

    #[cfg(feature = "lz4")]
    mod lz4 {
        use super::*;
        use vecdb::LZ4Vec;
        type V = LZ4Vec<usize, i32>;

        #[test]
        fn only_stored() -> Result<()> {
            run_only_stored::<V>()
        }
        #[test]
        fn only_pushed() -> Result<()> {
            run_only_pushed::<V>()
        }
        #[test]
        fn stored_and_pushed() -> Result<()> {
            run_stored_and_pushed::<V>()
        }
        #[test]
        fn skip_across_boundary() -> Result<()> {
            run_skip_across_boundary::<V>()
        }
        #[test]
        fn take_across_boundary() -> Result<()> {
            run_take_across_boundary::<V>()
        }
        #[test]
        fn nth_across_boundary() -> Result<()> {
            run_nth_across_boundary::<V>()
        }
        #[test]
        fn set_position_to_pushed() -> Result<()> {
            run_set_position_to_pushed::<V>()
        }
        #[test]
        fn last_in_pushed() -> Result<()> {
            run_last_in_pushed::<V>()
        }
        #[test]
        fn last_in_stored() -> Result<()> {
            run_last_in_stored::<V>()
        }
        #[test]
        fn exact_size_with_pushed() -> Result<()> {
            run_exact_size_with_pushed::<V>()
        }
        #[test]
        fn large_dataset_boundary() -> Result<()> {
            run_large_dataset_boundary::<V>()
        }
        #[test]
        fn skip_take_complex() -> Result<()> {
            run_skip_take_complex::<V>()
        }
    }

    #[cfg(feature = "zstd")]
    mod zstd {
        use super::*;
        use vecdb::ZstdVec;
        type V = ZstdVec<usize, i32>;

        #[test]
        fn only_stored() -> Result<()> {
            run_only_stored::<V>()
        }
        #[test]
        fn only_pushed() -> Result<()> {
            run_only_pushed::<V>()
        }
        #[test]
        fn stored_and_pushed() -> Result<()> {
            run_stored_and_pushed::<V>()
        }
        #[test]
        fn skip_across_boundary() -> Result<()> {
            run_skip_across_boundary::<V>()
        }
        #[test]
        fn take_across_boundary() -> Result<()> {
            run_take_across_boundary::<V>()
        }
        #[test]
        fn nth_across_boundary() -> Result<()> {
            run_nth_across_boundary::<V>()
        }
        #[test]
        fn set_position_to_pushed() -> Result<()> {
            run_set_position_to_pushed::<V>()
        }
        #[test]
        fn last_in_pushed() -> Result<()> {
            run_last_in_pushed::<V>()
        }
        #[test]
        fn last_in_stored() -> Result<()> {
            run_last_in_stored::<V>()
        }
        #[test]
        fn exact_size_with_pushed() -> Result<()> {
            run_exact_size_with_pushed::<V>()
        }
        #[test]
        fn large_dataset_boundary() -> Result<()> {
            run_large_dataset_boundary::<V>()
        }
        #[test]
        fn skip_take_complex() -> Result<()> {
            run_skip_take_complex::<V>()
        }
    }

    // ============================================================================
    // EagerVec Tests (wrapping different underlying vec types)
    // ============================================================================

    #[cfg(feature = "zerocopy")]
    mod eager_zerocopy {
        use super::*;
        use vecdb::{EagerVec, ZeroCopyVec};
        type V = EagerVec<ZeroCopyVec<usize, i32>>;

        #[test]
        fn only_stored() -> Result<()> {
            run_only_stored::<V>()
        }
        #[test]
        fn only_pushed() -> Result<()> {
            run_only_pushed::<V>()
        }
        #[test]
        fn stored_and_pushed() -> Result<()> {
            run_stored_and_pushed::<V>()
        }
        #[test]
        fn skip_across_boundary() -> Result<()> {
            run_skip_across_boundary::<V>()
        }
        #[test]
        fn take_across_boundary() -> Result<()> {
            run_take_across_boundary::<V>()
        }
        #[test]
        fn nth_across_boundary() -> Result<()> {
            run_nth_across_boundary::<V>()
        }
        #[test]
        fn set_position_to_pushed() -> Result<()> {
            run_set_position_to_pushed::<V>()
        }
        #[test]
        fn last_in_pushed() -> Result<()> {
            run_last_in_pushed::<V>()
        }
        #[test]
        fn last_in_stored() -> Result<()> {
            run_last_in_stored::<V>()
        }
        #[test]
        fn exact_size_with_pushed() -> Result<()> {
            run_exact_size_with_pushed::<V>()
        }
        #[test]
        fn large_dataset_boundary() -> Result<()> {
            run_large_dataset_boundary::<V>()
        }
        #[test]
        fn skip_take_complex() -> Result<()> {
            run_skip_take_complex::<V>()
        }
    }

    #[cfg(feature = "pco")]
    mod eager_pco {
        use super::*;
        use vecdb::{EagerVec, PcoVec};
        type V = EagerVec<PcoVec<usize, i32>>;

        #[test]
        fn only_stored() -> Result<()> {
            run_only_stored::<V>()
        }
        #[test]
        fn only_pushed() -> Result<()> {
            run_only_pushed::<V>()
        }
        #[test]
        fn stored_and_pushed() -> Result<()> {
            run_stored_and_pushed::<V>()
        }
        #[test]
        fn skip_across_boundary() -> Result<()> {
            run_skip_across_boundary::<V>()
        }
        #[test]
        fn take_across_boundary() -> Result<()> {
            run_take_across_boundary::<V>()
        }
        #[test]
        fn nth_across_boundary() -> Result<()> {
            run_nth_across_boundary::<V>()
        }
        #[test]
        fn set_position_to_pushed() -> Result<()> {
            run_set_position_to_pushed::<V>()
        }
        #[test]
        fn last_in_pushed() -> Result<()> {
            run_last_in_pushed::<V>()
        }
        #[test]
        fn last_in_stored() -> Result<()> {
            run_last_in_stored::<V>()
        }
        #[test]
        fn exact_size_with_pushed() -> Result<()> {
            run_exact_size_with_pushed::<V>()
        }
        #[test]
        fn large_dataset_boundary() -> Result<()> {
            run_large_dataset_boundary::<V>()
        }
        #[test]
        fn skip_take_complex() -> Result<()> {
            run_skip_take_complex::<V>()
        }
    }
}

// ============================================================================
// Raw-specific Tests (holes and updates - only BytesVec and ZeroCopyVec)
// ============================================================================

mod raw_features {
    use super::*;
    use std::ops::DerefMut;
    use vecdb::{BytesVec, ReadWriteRawVec};

    // Generic test functions for raw vecs

    fn run_iter_skips_holes<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32> + DerefMut,
        V::Target: RawVecOps,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..10 {
            vec.push(i);
        }
        vec.write()?;

        // Delete some values (create holes)
        vec.deref_mut().delete_at(3);
        vec.deref_mut().delete_at(5);
        vec.deref_mut().delete_at(7);

        let collected: Vec<i32> = vec.collect();
        // Should skip holes: 0,1,2,4,6,8,9
        assert_eq!(collected, vec![0, 1, 2, 4, 6, 8, 9]);
        Ok(())
    }

    fn run_iter_with_updates<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32> + DerefMut,
        V::Target: RawVecOps,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..10 {
            vec.push(i);
        }
        vec.write()?;

        // Update some values
        vec.deref_mut().update_at(2, 200)?;
        vec.deref_mut().update_at(5, 500)?;
        vec.deref_mut().update_at(8, 800)?;

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected, vec![0, 1, 200, 3, 4, 500, 6, 7, 800, 9]);
        Ok(())
    }

    fn run_iter_with_holes_and_updates<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32> + DerefMut,
        V::Target: RawVecOps,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..10 {
            vec.push(i);
        }
        vec.write()?;

        // Create holes and updates
        vec.deref_mut().delete_at(1);
        vec.deref_mut().delete_at(3);
        vec.deref_mut().update_at(2, 200)?;
        vec.deref_mut().update_at(5, 500)?;

        let collected: Vec<i32> = vec.collect();
        // Should be: 0, (skip 1), 200, (skip 3), 4, 500, 6, 7, 8, 9
        assert_eq!(collected, vec![0, 200, 4, 500, 6, 7, 8, 9]);
        Ok(())
    }

    fn run_iter_holes_and_pushed<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32> + DerefMut,
        V::Target: RawVecOps,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..5 {
            vec.push(i);
        }
        vec.write()?;

        // Create holes in stored data
        vec.deref_mut().delete_at(1);
        vec.deref_mut().delete_at(3);

        // Push more data
        for i in 5..10 {
            vec.push(i);
        }

        let collected: Vec<i32> = vec.collect();
        // Should be: 0, (skip 1), 2, (skip 3), 4, 5, 6, 7, 8, 9
        assert_eq!(collected, vec![0, 2, 4, 5, 6, 7, 8, 9]);
        Ok(())
    }

    fn run_iter_updates_and_pushed<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32> + DerefMut,
        V::Target: RawVecOps,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..5 {
            vec.push(i);
        }
        vec.write()?;

        // Update some stored values
        vec.deref_mut().update_at(1, 100)?;
        vec.deref_mut().update_at(3, 300)?;

        // Push more data
        for i in 5..10 {
            vec.push(i);
        }

        let collected: Vec<i32> = vec.collect();
        assert_eq!(collected, vec![0, 100, 2, 300, 4, 5, 6, 7, 8, 9]);
        Ok(())
    }

    fn run_iter_skip_over_holes<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32> + DerefMut,
        V::Target: RawVecOps,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..20 {
            vec.push(i);
        }
        vec.write()?;

        // Create holes at indices 5, 6, 7
        vec.deref_mut().delete_at(5);
        vec.deref_mut().delete_at(6);
        vec.deref_mut().delete_at(7);

        // Skip past the holes — collect skips holes automatically
        let collected: Vec<i32> = vec.collect();
        // Should be: 0, 1, 2, 3, 4, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19
        // (holes at 5,6,7 are skipped)
        assert_eq!(collected[5..10], [8, 9, 10, 11, 12]);
        Ok(())
    }

    fn run_fill_holes<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = i32> + DerefMut,
        V::Target: RawVecOps,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = V::forced_import(&db, "test", Version::ONE)?;

        for i in 0..10 {
            vec.push(i);
        }
        vec.write()?;

        // Create holes
        vec.deref_mut().delete_at(2);
        vec.deref_mut().delete_at(5);

        // Fill first hole
        let idx = vec.deref_mut().fill_first_hole_or_push(999)?;
        assert_eq!(idx, 2);

        let collected: Vec<i32> = vec.collect();
        // 0,1,999,3,4,(skip 5),6,7,8,9
        assert_eq!(collected, vec![0, 1, 999, 3, 4, 6, 7, 8, 9]);
        Ok(())
    }

    // Helper trait for raw vec operations
    pub trait RawVecOps {
        fn delete_at(&mut self, index: usize);
        fn update_at(&mut self, index: usize, value: i32) -> Result<()>;
        fn fill_first_hole_or_push(&mut self, value: i32) -> Result<usize>;
    }

    impl<I, T, S> RawVecOps for ReadWriteRawVec<I, T, S>
    where
        I: vecdb::VecIndex,
        T: vecdb::VecValue + From<i32> + Into<i32>,
        S: vecdb::RawStrategy<T>,
    {
        fn delete_at(&mut self, index: usize) {
            vecdb::ReadWriteRawVec::delete_at(self, index)
        }
        fn update_at(&mut self, index: usize, value: i32) -> Result<()> {
            vecdb::ReadWriteRawVec::update_at(self, index, T::from(value))
        }
        fn fill_first_hole_or_push(&mut self, value: i32) -> Result<usize> {
            vecdb::ReadWriteRawVec::fill_first_hole_or_push(self, T::from(value))
                .map(|i| i.to_usize())
        }
    }

    // ============================================================================
    // BytesVec Tests
    // ============================================================================

    mod bytes {
        use super::*;
        type V = BytesVec<usize, i32>;

        #[test]
        fn iter_skips_holes() -> Result<()> {
            run_iter_skips_holes::<V>()
        }
        #[test]
        fn iter_with_updates() -> Result<()> {
            run_iter_with_updates::<V>()
        }
        #[test]
        fn iter_with_holes_and_updates() -> Result<()> {
            run_iter_with_holes_and_updates::<V>()
        }
        #[test]
        fn iter_holes_and_pushed() -> Result<()> {
            run_iter_holes_and_pushed::<V>()
        }
        #[test]
        fn iter_updates_and_pushed() -> Result<()> {
            run_iter_updates_and_pushed::<V>()
        }
        #[test]
        fn iter_skip_over_holes() -> Result<()> {
            run_iter_skip_over_holes::<V>()
        }
        #[test]
        fn fill_holes() -> Result<()> {
            run_fill_holes::<V>()
        }
    }

    // ============================================================================
    // ZeroCopyVec Tests
    // ============================================================================

    #[cfg(feature = "zerocopy")]
    mod zerocopy {
        use super::*;
        use vecdb::ZeroCopyVec;
        type V = ZeroCopyVec<usize, i32>;

        #[test]
        fn iter_skips_holes() -> Result<()> {
            run_iter_skips_holes::<V>()
        }
        #[test]
        fn iter_with_updates() -> Result<()> {
            run_iter_with_updates::<V>()
        }
        #[test]
        fn iter_with_holes_and_updates() -> Result<()> {
            run_iter_with_holes_and_updates::<V>()
        }
        #[test]
        fn iter_holes_and_pushed() -> Result<()> {
            run_iter_holes_and_pushed::<V>()
        }
        #[test]
        fn iter_updates_and_pushed() -> Result<()> {
            run_iter_updates_and_pushed::<V>()
        }
        #[test]
        fn iter_skip_over_holes() -> Result<()> {
            run_iter_skip_over_holes::<V>()
        }
        #[test]
        fn fill_holes() -> Result<()> {
            run_fill_holes::<V>()
        }
    }
}
