//! Generic rollback tests for all vec types.
//!
//! This module contains two sets of rollback tests:
//! 1. Generic rollback tests - work with ALL vec types (BytesVec, ZeroCopyVec, PcoVec, LZ4Vec, ZstdVec, EagerVec)
//!    These use only push/truncate operations available on all vecs.
//! 2. Raw-only rollback tests - work with raw vecs (BytesVec, ZeroCopyVec) only
//!    These test update/hole operations specific to raw vecs.

use rawdb::Database;
use std::ops::DerefMut;
use tempfile::TempDir;
use vecdb::{
    AnyStoredVec, ImportOptions, ImportableVec, ReadableVec, Result, Stamp, StoredVec, VecReader,
    Version, WritableVec,
};

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

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

// ============================================================================
// PART 1: Generic Rollback Tests (ALL vec types)
// ============================================================================
// These tests use only push/truncate operations and work with any StoredVec.

mod generic_rollback {
    use super::*;

    fn import_with_changes<V>(db: &Database, name: &str, changes: u16) -> Result<V>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let mut options: ImportOptions = (db, name, Version::TWO).into();
        options = options.with_saved_stamped_changes(changes);
        V::forced_import_with(options)
    }

    fn run_basic_rollback<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.stamp(), Stamp::new(1));

        // Stamp 2: [0, 1, 2, 3, 4, 5, 6]
        vec.push(5);
        vec.push(6);
        vec.stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5, 6]);
        assert_eq!(vec.stamp(), Stamp::new(2));

        // Rollback to stamp 1
        vec.rollback()?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_with_truncation<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: [0, 1, 2, 3, 4, 5, 6, 7]
        vec.push(5);
        vec.push(6);
        vec.push(7);
        vec.stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5, 6, 7]);

        // Rollback - should restore to [0, 1, 2, 3, 4]
        vec.rollback()?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_multiple_sequential_rollbacks<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: [0, 1, 2, 3, 4, 5]
        vec.push(5);
        vec.stamped_write_with_changes(Stamp::new(2))?;

        // Stamp 3: [0, 1, 2, 3, 4, 5, 6]
        vec.push(6);
        vec.stamped_write_with_changes(Stamp::new(3))?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5, 6]);

        // Rollback to stamp 2
        vec.rollback()?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5]);
        assert_eq!(vec.stamp(), Stamp::new(2));

        // Rollback to stamp 1
        vec.rollback()?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_then_save_new_state<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: [0, 1, 2, 3, 4, 5]
        vec.push(5);
        vec.stamped_write_with_changes(Stamp::new(2))?;

        // Rollback to stamp 1
        vec.rollback()?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4]);

        // Save new stamp 2: [0, 1, 2, 3, 4, 99]
        vec.push(99);
        vec.stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 99]);
        assert_eq!(vec.stamp(), Stamp::new(2));

        Ok(())
    }

    fn run_rollback_to_empty<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Stamp 1: []
        vec.stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.collect(), Vec::<u32>::new());

        // Stamp 2: [0, 1, 2]
        vec.push(0);
        vec.push(1);
        vec.push(2);
        vec.stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.collect(), vec![0, 1, 2]);

        // Rollback to empty
        vec.rollback()?;
        assert_eq!(vec.collect(), Vec::<u32>::new());

        Ok(())
    }

    fn run_rollback_before<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Build stamps 1-5
        for i in 0..5 {
            vec.push(i);
        }
        vec.stamped_write_with_changes(Stamp::new(1))?;

        vec.push(5);
        vec.stamped_write_with_changes(Stamp::new(2))?;

        vec.push(6);
        vec.stamped_write_with_changes(Stamp::new(3))?;

        vec.push(7);
        vec.stamped_write_with_changes(Stamp::new(4))?;

        vec.push(8);
        vec.stamped_write_with_changes(Stamp::new(5))?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]);

        // Rollback before stamp 4 (should go to stamp 3)
        let _ = vec.rollback_before(Stamp::new(4))?;
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5, 6]);
        assert_eq!(vec.stamp(), Stamp::new(3));

        Ok(())
    }

    fn run_deep_rollback_chain<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Build chain of stamps with pushes only
        vec.stamped_write_with_changes(Stamp::new(1))?; // []

        vec.push(0);
        vec.stamped_write_with_changes(Stamp::new(2))?; // [0]

        vec.push(1);
        vec.stamped_write_with_changes(Stamp::new(3))?; // [0, 1]

        vec.push(2);
        vec.stamped_write_with_changes(Stamp::new(4))?; // [0, 1, 2]

        vec.push(3);
        vec.push(4);
        vec.stamped_write_with_changes(Stamp::new(5))?; // [0, 1, 2, 3, 4]
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4]);

        // Rollback through chain
        vec.rollback()?; // -> 4
        assert_eq!(vec.collect(), vec![0, 1, 2]);

        vec.rollback()?; // -> 3
        assert_eq!(vec.collect(), vec![0, 1]);

        vec.rollback()?; // -> 2
        assert_eq!(vec.collect(), vec![0]);

        vec.rollback()?; // -> 1
        assert_eq!(vec.collect(), Vec::<u32>::new());

        Ok(())
    }

    fn run_rollback_persistence<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;

        // Create and populate
        {
            let mut vec = import_with_changes::<V>(&db, "test", 10)?;

            for i in 0..5 {
                vec.push(i);
            }
            vec.stamped_write_with_changes(Stamp::new(1))?;

            vec.push(5);
            vec.push(6);
            vec.stamped_write_with_changes(Stamp::new(2))?;

            // Rollback and flush
            vec.rollback()?;
            vec.stamped_write_with_changes(Stamp::new(1))?;
        }

        // Reopen and verify
        {
            let vec = import_with_changes::<V>(&db, "test", 10)?;
            assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4]);
            assert_eq!(vec.stamp(), Stamp::new(1));
        }

        Ok(())
    }

    fn run_reset<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let mut vec = import_with_changes::<V>(&db, "test", 10)?;

        // Add initial data and flush
        for i in 0..10 {
            vec.push(i);
        }
        vec.stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.len(), 10);
        assert_eq!(vec.stored_len(), 10);
        assert_eq!(vec.pushed_len(), 0);
        assert_eq!(vec.collect(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);

        // Add more data without flushing
        vec.push(10);
        vec.push(11);
        assert_eq!(vec.len(), 12);
        assert_eq!(vec.stored_len(), 10);
        assert_eq!(vec.pushed_len(), 2);

        // Reset should clear everything
        vec.reset()?;
        assert_eq!(vec.len(), 0);
        assert_eq!(vec.stored_len(), 0);
        assert_eq!(vec.pushed_len(), 0);
        assert_eq!(vec.collect(), Vec::<u32>::new());

        // Should be able to add new data after reset
        vec.push(100);
        vec.push(101);
        vec.push(102);
        assert_eq!(vec.len(), 3);
        assert_eq!(vec.stored_len(), 0);
        assert_eq!(vec.pushed_len(), 3);
        assert_eq!(vec.collect(), vec![100, 101, 102]);

        // Flush the new data
        vec.stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.len(), 3);
        assert_eq!(vec.stored_len(), 3);
        assert_eq!(vec.pushed_len(), 0);
        assert_eq!(vec.collect(), vec![100, 101, 102]);

        Ok(())
    }

    // Test modules for each vec type
    mod bytes {
        use super::*;
        use vecdb::BytesVec;
        type V = BytesVec<usize, u32>;

        #[test]
        fn basic_rollback() -> Result<()> {
            run_basic_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_persistence() -> Result<()> {
            run_rollback_persistence::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
    }

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

        #[test]
        fn basic_rollback() -> Result<()> {
            run_basic_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_persistence() -> Result<()> {
            run_rollback_persistence::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
    }

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

        #[test]
        fn basic_rollback() -> Result<()> {
            run_basic_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_persistence() -> Result<()> {
            run_rollback_persistence::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
    }

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

        #[test]
        fn basic_rollback() -> Result<()> {
            run_basic_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_persistence() -> Result<()> {
            run_rollback_persistence::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
    }

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

        #[test]
        fn basic_rollback() -> Result<()> {
            run_basic_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_persistence() -> Result<()> {
            run_rollback_persistence::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
    }

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

        #[test]
        fn basic_rollback() -> Result<()> {
            run_basic_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_persistence() -> Result<()> {
            run_rollback_persistence::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
    }

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

        #[test]
        fn basic_rollback() -> Result<()> {
            run_basic_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_persistence() -> Result<()> {
            run_rollback_persistence::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
    }
}

// ============================================================================
// PART 2: Raw-Only Rollback Tests (BytesVec and ZeroCopyVec)
// ============================================================================
// These tests use update/hole operations specific to raw vecs.

mod raw_rollback {
    use super::*;

    // ============================================================================
    // Trait for raw vec rollback operations
    // ============================================================================

    /// Trait for raw vecs that support rollback operations.
    pub trait RollbackVec: StoredVec<I = usize, T = u32> + DerefMut
    where
        Self::Target: RollbackOps,
    {
        fn import_with_changes<'a>(
            db: &'a Database,
            name: &'a str,
            changes: u16,
        ) -> Result<(Self, ImportOptions<'a>)>;
    }

    /// Operations required for rollback testing.
    pub trait RollbackOps {
        type Reader;

        fn update(&mut self, index: usize, value: u32) -> Result<()>;
        fn take(&mut self, index: usize) -> Option<u32>;
        fn stamped_write_with_changes(&mut self, stamp: Stamp) -> Result<()>;
        fn rollback(&mut self) -> Result<()>;
        fn rollback_before(&mut self, stamp: Stamp) -> Result<Stamp>;
        fn stamp(&self) -> Stamp;
        fn stored_len(&self) -> usize;
        fn collect(&self) -> Vec<u32>;
        fn collect_holed(&self) -> Vec<Option<u32>>;
        fn get_with_reader(&self, index: usize, reader: &Self::Reader) -> Option<u32>;
        fn reader(&self) -> Self::Reader;
    }

    // ============================================================================
    // Implementations for ZeroCopyVec
    // ============================================================================

    #[cfg(feature = "zerocopy")]
    use vecdb::{ReadWriteRawVec, ZeroCopyStrategy, ZeroCopyVec};

    #[cfg(feature = "zerocopy")]
    impl RollbackVec for ZeroCopyVec<usize, u32> {
        fn import_with_changes<'a>(
            db: &'a Database,
            name: &'a str,
            changes: u16,
        ) -> Result<(Self, ImportOptions<'a>)> {
            let mut options: ImportOptions = (db, name, Version::TWO).into();
            options = options.with_saved_stamped_changes(changes);
            let vec = Self::forced_import_with(options)?;
            Ok((vec, options))
        }
    }

    #[cfg(feature = "zerocopy")]
    impl RollbackOps for ReadWriteRawVec<usize, u32, ZeroCopyStrategy<u32>> {
        type Reader = VecReader<usize, u32, ZeroCopyStrategy<u32>>;

        fn update(&mut self, index: usize, value: u32) -> Result<()> {
            ReadWriteRawVec::update(self, index, value)
        }

        fn take(&mut self, index: usize) -> Option<u32> {
            let reader = self.reader();
            let result = ReadWriteRawVec::take(self, index, &reader);
            drop(reader);
            result
        }

        fn stamped_write_with_changes(&mut self, stamp: Stamp) -> Result<()> {
            WritableVec::stamped_write_with_changes(self, stamp)
        }

        fn rollback(&mut self) -> Result<()> {
            WritableVec::rollback(self)
        }

        fn rollback_before(&mut self, stamp: Stamp) -> Result<Stamp> {
            WritableVec::rollback_before(self, stamp)
        }

        fn stamp(&self) -> Stamp {
            AnyStoredVec::stamp(self)
        }

        fn stored_len(&self) -> usize {
            AnyStoredVec::stored_len(self)
        }

        fn collect(&self) -> Vec<u32> {
            ReadableVec::collect(self)
        }

        fn collect_holed(&self) -> Vec<Option<u32>> {
            ReadWriteRawVec::collect_holed(self)
        }

        fn get_with_reader(&self, index: usize, reader: &Self::Reader) -> Option<u32> {
            ReadWriteRawVec::get_with_reader(self, index, reader)
        }

        fn reader(&self) -> Self::Reader {
            ReadWriteRawVec::reader(self)
        }
    }

    // ============================================================================
    // Implementations for BytesVec
    // ============================================================================

    #[cfg(not(feature = "zerocopy"))]
    use vecdb::ReadWriteRawVec;
    use vecdb::{BytesStrategy, BytesVec};

    impl RollbackVec for BytesVec<usize, u32> {
        fn import_with_changes<'a>(
            db: &'a Database,
            name: &'a str,
            changes: u16,
        ) -> Result<(Self, ImportOptions<'a>)> {
            let mut options: ImportOptions = (db, name, Version::TWO).into();
            options = options.with_saved_stamped_changes(changes);
            let vec = Self::forced_import_with(options)?;
            Ok((vec, options))
        }
    }

    impl RollbackOps for ReadWriteRawVec<usize, u32, BytesStrategy<u32>> {
        type Reader = VecReader<usize, u32, BytesStrategy<u32>>;

        fn update(&mut self, index: usize, value: u32) -> Result<()> {
            ReadWriteRawVec::update(self, index, value)
        }

        fn take(&mut self, index: usize) -> Option<u32> {
            let reader = self.reader();
            let result = ReadWriteRawVec::take(self, index, &reader);
            drop(reader);
            result
        }

        fn stamped_write_with_changes(&mut self, stamp: Stamp) -> Result<()> {
            WritableVec::stamped_write_with_changes(self, stamp)
        }

        fn rollback(&mut self) -> Result<()> {
            WritableVec::rollback(self)
        }

        fn rollback_before(&mut self, stamp: Stamp) -> Result<Stamp> {
            WritableVec::rollback_before(self, stamp)
        }

        fn stamp(&self) -> Stamp {
            AnyStoredVec::stamp(self)
        }

        fn stored_len(&self) -> usize {
            AnyStoredVec::stored_len(self)
        }

        fn collect(&self) -> Vec<u32> {
            ReadableVec::collect(self)
        }

        fn collect_holed(&self) -> Vec<Option<u32>> {
            ReadWriteRawVec::collect_holed(self)
        }

        fn get_with_reader(&self, index: usize, reader: &Self::Reader) -> Option<u32> {
            ReadWriteRawVec::get_with_reader(self, index, reader)
        }

        fn reader(&self) -> Self::Reader {
            ReadWriteRawVec::reader(self)
        }
    }

    // ============================================================================
    // Generic Rollback Test Functions
    // ============================================================================

    fn run_basic_single_rollback<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Initial state: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        // Modify to [0, 1, 99, 3, 4]
        vec.deref_mut().update(2, 99)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 99, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(2));

        // Rollback to stamp 1
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_with_truncation<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Initial state: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);

        // Add more: [0, 1, 2, 3, 4, 5, 6, 7]
        vec.push(5);
        vec.push(6);
        vec.push(7);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4, 5, 6, 7]);

        // Rollback - should restore to [0, 1, 2, 3, 4]
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_multiple_sequential_rollbacks<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: [0, 1, 2, 3, 4, 5]
        vec.push(5);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;

        // Stamp 3: [0, 1, 2, 3, 4, 5, 6]
        vec.push(6);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(3))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4, 5, 6]);

        // Rollback to stamp 2
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4, 5]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(2));

        // Rollback to stamp 1
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_then_save_new_state<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: [0, 1, 2, 3, 4, 5]
        vec.push(5);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;

        // Rollback to stamp 1
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);

        // Now save a different state 2: [0, 1, 2, 3, 4, 99]
        vec.push(99);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4, 99]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(2));

        Ok(())
    }

    fn run_rollback_with_updates<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: [0, 99, 2, 88, 4] - update multiple values
        vec.deref_mut().update(1, 99)?;
        vec.deref_mut().update(3, 88)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 99, 2, 88, 4]);

        // Rollback to stamp 1 - should restore original values
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_with_holes<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: delete some items (creating holes)
        let _ = vec.deref_mut().take(1);
        let _ = vec.deref_mut().take(3);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 2, 4]);

        // Rollback to stamp 1 - should restore deleted items
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_with_truncation_and_updates<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: extend + update
        vec.deref_mut().update(1, 99)?;
        vec.push(5);
        vec.push(6);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 99, 2, 3, 4, 5, 6]);

        // Rollback - should restore length AND value
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_with_holes_and_updates<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: delete + update
        let _ = vec.deref_mut().take(1);
        vec.deref_mut().update(2, 99)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 99, 3, 4]);

        // Rollback - should restore deleted item AND original value
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_multiple_updates_to_same_index<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: [100, 1, 2, 3, 4]
        vec.deref_mut().update(0, 100)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;

        // Stamp 3: [200, 1, 2, 3, 4]
        vec.deref_mut().update(0, 200)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(3))?;

        // Stamp 4: [300, 1, 2, 3, 4]
        vec.deref_mut().update(0, 300)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(4))?;
        assert_eq!(vec.deref_mut().collect(), vec![300, 1, 2, 3, 4]);

        // Rollback to stamp 3
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![200, 1, 2, 3, 4]);

        // Rollback to stamp 2
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![100, 1, 2, 3, 4]);

        // Rollback to stamp 1
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);

        Ok(())
    }

    fn run_complex_mixed_operations<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        for i in 0..10 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: Complex operations
        // - Delete indices 1, 3, 5
        // - Update indices 2, 6, 8
        // - Push new values 100, 101
        let _ = vec.deref_mut().take(1);
        let _ = vec.deref_mut().take(3);
        let _ = vec.deref_mut().take(5);
        vec.deref_mut().update(2, 222)?;
        vec.deref_mut().update(6, 666)?;
        vec.deref_mut().update(8, 888)?;
        vec.push(100);
        vec.push(101);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(
            vec.deref_mut().collect(),
            vec![0, 222, 4, 666, 7, 888, 9, 100, 101]
        );

        // Rollback - should restore everything
        vec.deref_mut().rollback()?;
        assert_eq!(
            vec.deref_mut().collect(),
            vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        );

        Ok(())
    }

    fn run_rollback_to_empty<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: []
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.deref_mut().collect(), Vec::<u32>::new());

        // Stamp 2: [0, 1, 2]
        vec.push(0);
        vec.push(1);
        vec.push(2);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2]);

        // Rollback to empty
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), Vec::<u32>::new());

        Ok(())
    }

    fn run_reset<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Add initial data and flush
        for i in 0..10 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.len(), 10);
        assert_eq!(vec.deref_mut().stored_len(), 10);
        assert_eq!(vec.pushed_len(), 0);
        assert_eq!(
            vec.deref_mut().collect(),
            vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        );

        // Add more data without flushing
        vec.push(10);
        vec.push(11);
        assert_eq!(vec.len(), 12);
        assert_eq!(vec.deref_mut().stored_len(), 10);
        assert_eq!(vec.pushed_len(), 2);

        // Reset should clear everything
        vec.reset()?;
        assert_eq!(vec.len(), 0);
        assert_eq!(vec.deref_mut().stored_len(), 0);
        assert_eq!(vec.pushed_len(), 0);
        assert_eq!(vec.deref_mut().collect(), Vec::<u32>::new());

        // Should be able to add new data after reset
        vec.push(100);
        vec.push(101);
        vec.push(102);
        assert_eq!(vec.len(), 3);
        assert_eq!(vec.deref_mut().stored_len(), 0);
        assert_eq!(vec.pushed_len(), 3);
        assert_eq!(vec.deref_mut().collect(), vec![100, 101, 102]);

        // Flush the new data
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.len(), 3);
        assert_eq!(vec.deref_mut().stored_len(), 3);
        assert_eq!(vec.pushed_len(), 0);
        assert_eq!(vec.deref_mut().collect(), vec![100, 101, 102]);

        Ok(())
    }

    fn run_deep_rollback_chain<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Build a chain of 10 stamps with different operations
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?; // []

        vec.push(0);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?; // [0]

        vec.push(1);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(3))?; // [0, 1]

        vec.deref_mut().update(0, 10)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(4))?; // [10, 1]

        vec.push(2);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(5))?; // [10, 1, 2]

        let _ = vec.deref_mut().take(1);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(6))?; // [10, 2]

        vec.push(3);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(7))?; // [10, 2, 3]

        vec.deref_mut().update(0, 20)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(8))?; // [20, 2, 3]

        vec.push(4);
        vec.push(5);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(9))?; // [20, 2, 3, 4, 5]

        vec.deref_mut().update(2, 33)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(10))?; // [20, 33, 3, 4, 5]
        assert_eq!(vec.deref_mut().collect(), vec![20, 33, 3, 4, 5]);

        // Rollback through the chain
        vec.deref_mut().rollback()?; // -> 9
        assert_eq!(vec.deref_mut().collect(), vec![20, 2, 3, 4, 5]);

        vec.deref_mut().rollback()?; // -> 8
        assert_eq!(vec.deref_mut().collect(), vec![20, 2, 3]);

        vec.deref_mut().rollback()?; // -> 7
        assert_eq!(vec.deref_mut().collect(), vec![10, 2, 3]);

        vec.deref_mut().rollback()?; // -> 6
        assert_eq!(vec.deref_mut().collect(), vec![10, 2]);

        vec.deref_mut().rollback()?; // -> 5
        assert_eq!(vec.deref_mut().collect(), vec![10, 1, 2]);

        vec.deref_mut().rollback()?; // -> 4
        assert_eq!(vec.deref_mut().collect(), vec![10, 1]);

        vec.deref_mut().rollback()?; // -> 3
        assert_eq!(vec.deref_mut().collect(), vec![0, 1]);

        vec.deref_mut().rollback()?; // -> 2
        assert_eq!(vec.deref_mut().collect(), vec![0]);

        vec.deref_mut().rollback()?; // -> 1
        assert_eq!(vec.deref_mut().collect(), Vec::<u32>::new());

        Ok(())
    }

    fn run_rollback_all_elements_updated<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4]
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: Update ALL elements
        for i in 0..5 {
            vec.deref_mut().update(i, (i * 100) as u32)?;
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 100, 200, 300, 400]);

        // Rollback - should restore all original values
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4]);

        Ok(())
    }

    fn run_multiple_holes_then_rollback<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        for i in 0..10 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Stamp 2: Delete every other element
        for i in (0..10).step_by(2) {
            let _ = vec.deref_mut().take(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![1, 3, 5, 7, 9]);

        // Rollback - should restore all deleted items
        vec.deref_mut().rollback()?;
        assert_eq!(
            vec.deref_mut().collect(),
            vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        );

        Ok(())
    }

    fn run_rollback_before<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Build stamps 1-5
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        vec.push(5);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;

        vec.push(6);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(3))?;

        vec.push(7);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(4))?;

        vec.push(8);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(5))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4, 5, 6, 7, 8]);

        // Rollback before stamp 4 (should go to stamp 3)
        let _ = vec.deref_mut().rollback_before(Stamp::new(4))?;
        assert_eq!(vec.deref_mut().collect(), vec![0, 1, 2, 3, 4, 5, 6]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(3));

        Ok(())
    }

    /// Regression test: rollback-after-rollback with delete_at losing entries.
    ///
    /// After the first rollback, restored entries sit in `updated.current`.
    /// If `delete_at` removes one from `updated.current` during reprocessing,
    /// and `serialize_changes` only iterated `updated.current` keys (the old bug),
    /// the entry's prev value would be lost from the change file.
    /// On a second rollback, the slot would contain stale on-disk data
    /// instead of the correct rolled-back value.
    fn run_rollback_after_rollback_with_delete<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

        // Stamp 1 (baseline): [10, 20, 30, 40, 50]
        for &v in &[10, 20, 30, 40, 50] {
            vec.push(v);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;
        assert_eq!(vec.deref_mut().collect(), vec![10, 20, 30, 40, 50]);

        // Stamp 2: update slot 2 (30 → 99), delete slot 1 (creates hole)
        vec.deref_mut().update(2, 99)?;
        let _ = vec.deref_mut().take(1);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;
        assert_eq!(vec.deref_mut().collect(), vec![10, 99, 40, 50]);

        // First rollback → back to stamp 1
        vec.deref_mut().rollback()?;
        assert_eq!(vec.deref_mut().collect(), vec![10, 20, 30, 40, 50]);
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        // Now reprocess: delete slot 2 (the one we just restored), update slot 3
        // This simulates an address becoming empty during reprocessing
        let _ = vec.deref_mut().take(2); // removes 30 from updated.current
        vec.deref_mut().update(3, 88)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(3))?;
        assert_eq!(vec.deref_mut().collect(), vec![10, 20, 88, 50]);

        // Second rollback → must go back to stamp 1 values
        vec.deref_mut().rollback()?;
        let result = vec.deref_mut().collect();
        assert_eq!(
            result,
            vec![10, 20, 30, 40, 50],
            "Second rollback must restore all original values. \
             Slot 2 was deleted during reprocessing but its prev value (30) \
             must still be tracked in the change file."
        );
        assert_eq!(vec.deref_mut().stamp(), Stamp::new(1));

        Ok(())
    }

    fn run_rollback_after_untracked_checkpoint<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps + AnyStoredVec,
    {
        let (db, _temp) = setup_db()?;
        let (mut vec, _) = V::import_with_changes(&db, "test", 10)?;

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

        AnyStoredVec::any_stamped_write_maybe_with_changes(vec.deref_mut(), Stamp::new(1), false)?;

        vec.deref_mut().update(65, 999)?;
        AnyStoredVec::any_stamped_write_maybe_with_changes(vec.deref_mut(), Stamp::new(2), true)?;

        vec.deref_mut().rollback()?;

        assert_eq!(vec.len(), 100);
        assert_eq!(vec.deref_mut().collect()[65], 65);
        assert_eq!(RollbackOps::stamp(vec.deref_mut()), Stamp::new(1));

        Ok(())
    }

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

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

        #[test]
        fn basic_single_rollback() -> Result<()> {
            run_basic_single_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_with_updates() -> Result<()> {
            run_rollback_with_updates::<V>()
        }
        #[test]
        fn rollback_with_holes() -> Result<()> {
            run_rollback_with_holes::<V>()
        }
        #[test]
        fn rollback_with_truncation_and_updates() -> Result<()> {
            run_rollback_with_truncation_and_updates::<V>()
        }
        #[test]
        fn rollback_with_holes_and_updates() -> Result<()> {
            run_rollback_with_holes_and_updates::<V>()
        }
        #[test]
        fn multiple_updates_to_same_index() -> Result<()> {
            run_multiple_updates_to_same_index::<V>()
        }
        #[test]
        fn complex_mixed_operations() -> Result<()> {
            run_complex_mixed_operations::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_all_elements_updated() -> Result<()> {
            run_rollback_all_elements_updated::<V>()
        }
        #[test]
        fn multiple_holes_then_rollback() -> Result<()> {
            run_multiple_holes_then_rollback::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
        #[test]
        fn rollback_after_rollback_with_delete() -> Result<()> {
            run_rollback_after_rollback_with_delete::<V>()
        }
        #[test]
        fn rollback_after_untracked_checkpoint() -> Result<()> {
            run_rollback_after_untracked_checkpoint::<V>()
        }
    }

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

        #[test]
        fn basic_single_rollback() -> Result<()> {
            run_basic_single_rollback::<V>()
        }
        #[test]
        fn rollback_with_truncation() -> Result<()> {
            run_rollback_with_truncation::<V>()
        }
        #[test]
        fn multiple_sequential_rollbacks() -> Result<()> {
            run_multiple_sequential_rollbacks::<V>()
        }
        #[test]
        fn rollback_then_save_new_state() -> Result<()> {
            run_rollback_then_save_new_state::<V>()
        }
        #[test]
        fn rollback_with_updates() -> Result<()> {
            run_rollback_with_updates::<V>()
        }
        #[test]
        fn rollback_with_holes() -> Result<()> {
            run_rollback_with_holes::<V>()
        }
        #[test]
        fn rollback_with_truncation_and_updates() -> Result<()> {
            run_rollback_with_truncation_and_updates::<V>()
        }
        #[test]
        fn rollback_with_holes_and_updates() -> Result<()> {
            run_rollback_with_holes_and_updates::<V>()
        }
        #[test]
        fn multiple_updates_to_same_index() -> Result<()> {
            run_multiple_updates_to_same_index::<V>()
        }
        #[test]
        fn complex_mixed_operations() -> Result<()> {
            run_complex_mixed_operations::<V>()
        }
        #[test]
        fn rollback_to_empty() -> Result<()> {
            run_rollback_to_empty::<V>()
        }
        #[test]
        fn deep_rollback_chain() -> Result<()> {
            run_deep_rollback_chain::<V>()
        }
        #[test]
        fn rollback_all_elements_updated() -> Result<()> {
            run_rollback_all_elements_updated::<V>()
        }
        #[test]
        fn multiple_holes_then_rollback() -> Result<()> {
            run_multiple_holes_then_rollback::<V>()
        }
        #[test]
        fn rollback_before() -> Result<()> {
            run_rollback_before::<V>()
        }
        #[test]
        fn reset() -> Result<()> {
            run_reset::<V>()
        }
        #[test]
        fn rollback_after_rollback_with_delete() -> Result<()> {
            run_rollback_after_rollback_with_delete::<V>()
        }
        #[test]
        fn rollback_after_untracked_checkpoint() -> Result<()> {
            run_rollback_after_untracked_checkpoint::<V>()
        }
    }
} // end mod raw_rollback

// ============================================================================
// PART 3: Checkpoint Rollback Tests (ALL vec types)
// ============================================================================

mod checkpoint_rollback {
    use super::*;

    fn run<V>() -> Result<()>
    where
        V: StoredVec<I = usize, T = u32>,
    {
        let (db, _temp) = setup_db()?;
        let options = ImportOptions::new(&db, "test", Version::TWO).with_saved_stamped_changes(10);
        let mut vec = V::forced_import_with(options)?;

        for i in 0..100 {
            vec.push(i);
        }
        AnyStoredVec::any_stamped_write_maybe_with_changes(&mut vec, Stamp::new(1), false)?;

        vec.push(100);
        AnyStoredVec::any_stamped_write_maybe_with_changes(&mut vec, Stamp::new(2), true)?;
        WritableVec::rollback(&mut vec)?;

        assert_eq!(vec.collect(), (0..100).collect::<Vec<_>>());
        assert_eq!(AnyStoredVec::stamp(&vec), Stamp::new(1));

        Ok(())
    }

    #[test]
    fn bytes() -> Result<()> {
        run::<vecdb::BytesVec<usize, u32>>()
    }

    #[cfg(feature = "zerocopy")]
    #[test]
    fn zerocopy() -> Result<()> {
        run::<vecdb::ZeroCopyVec<usize, u32>>()
    }

    #[cfg(feature = "pco")]
    #[test]
    fn pco() -> Result<()> {
        run::<vecdb::PcoVec<usize, u32>>()
    }

    #[cfg(feature = "lz4")]
    #[test]
    fn lz4() -> Result<()> {
        run::<vecdb::LZ4Vec<usize, u32>>()
    }

    #[cfg(feature = "zstd")]
    #[test]
    fn zstd() -> Result<()> {
        run::<vecdb::ZstdVec<usize, u32>>()
    }

    #[cfg(feature = "zerocopy")]
    #[test]
    fn eager_zerocopy() -> Result<()> {
        run::<vecdb::EagerVec<vecdb::ZeroCopyVec<usize, u32>>>()
    }

    #[cfg(feature = "pco")]
    #[test]
    fn eager_pco() -> Result<()> {
        run::<vecdb::EagerVec<vecdb::PcoVec<usize, u32>>>()
    }
}

// ============================================================================
// PART 4: Comprehensive Integration Test
// ============================================================================
// Complex rollback + flush + reopen test with file integrity verification.

mod integration {
    use crate::raw_rollback::{RollbackOps, RollbackVec};

    use super::*;
    use sha2::{Digest, Sha256};
    use std::fs;
    use std::path::Path;

    /// Compute SHA-256 hash of the vecdb data file and regions directory
    /// Only hashes data (file) and regions/*, ignoring changes directory
    fn compute_directory_hash(dir: &Path) -> Result<String> {
        use std::path::PathBuf;

        let mut hasher = Sha256::new();

        // Collect all files in sorted order for deterministic hashing
        let mut files: Vec<PathBuf> = Vec::new();

        // Hash the data file if it exists
        let data_file = dir.join("data");
        if data_file.exists() && data_file.is_file() {
            files.push(data_file);
        }

        // Hash files in the regions directory, excluding changes subdirectory
        let regions_dir = dir.join("regions");
        if regions_dir.exists() {
            fn collect_files(dir: &Path, files: &mut Vec<PathBuf>) {
                let Ok(entries) = fs::read_dir(dir) else {
                    return;
                };
                for entry in entries.filter_map(|e| e.ok()) {
                    let path = entry.path();
                    if path.components().any(|c| c.as_os_str() == "changes") {
                        continue;
                    }
                    if path.is_dir() {
                        collect_files(&path, files);
                    } else if path.is_file() {
                        files.push(path);
                    }
                }
            }
            collect_files(&regions_dir, &mut files);
        }

        files.sort();

        // Hash each file's relative path and contents
        for file_path in &files {
            // Hash the relative path
            if let Ok(rel_path) = file_path.strip_prefix(dir) {
                hasher.update(rel_path.to_string_lossy().as_bytes());
            }

            // Hash the file contents
            let contents = fs::read(file_path)?;
            hasher.update(&contents);
        }

        let hash = hasher.finalize();
        Ok(hash.iter().map(|b| format!("{:02x}", b)).collect())
    }

    /// Comprehensive integration test: rollback + flush + reopen with integrity verification.
    ///
    /// This test verifies that after rollback + flush + close + reopen:
    /// 1. Data can be correctly read back using individual gets
    /// 2. Data can be correctly read back using iterators
    /// 3. Redo operations produce the same readable state
    fn run_data_integrity_rollback_flush_reopen<V>() -> Result<()>
    where
        V: RollbackVec,
        V::Target: RollbackOps,
    {
        // Create database
        let (database, temp) = setup_db()?;
        let test_path = temp.path();

        let (mut vec, _) = V::import_with_changes(&database, "vec", 10)?;

        // Phase 1: Initial work
        for i in 0..5 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(1))?;

        // Phase 2: More work
        for i in 5..10 {
            vec.push(i);
        }
        vec.deref_mut().stamped_write_with_changes(Stamp::new(2))?;

        // Checkpoint 1
        let checkpoint1_data = vec.deref_mut().collect_holed();
        let checkpoint1_stamp = vec.deref_mut().stamp();
        let _checkpoint1_hash = compute_directory_hash(test_path)?;

        // Phase 3: Three more operations with flush
        vec.deref_mut().update(2, 100)?;
        vec.deref_mut().update(7, 200)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(3))?;

        vec.push(20);
        vec.push(21);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(4))?;

        let _ = vec.deref_mut().take(5);
        vec.push(30);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(5))?;

        // Checkpoint 2
        let checkpoint2_data = vec.deref_mut().collect_holed();
        let checkpoint2_stamp = vec.deref_mut().stamp();
        let _checkpoint2_hash = compute_directory_hash(test_path)?;

        // Undo last 3 operations
        vec.deref_mut().rollback()?;
        vec.deref_mut().rollback()?;
        vec.deref_mut().rollback()?;

        // Verify in-memory data matches checkpoint1
        let after_undo_data = vec.deref_mut().collect_holed();
        let after_undo_stamp = vec.deref_mut().stamp();

        assert_eq!(after_undo_stamp, checkpoint1_stamp);
        assert_eq!(after_undo_data, checkpoint1_data);

        // Flush and close
        vec.deref_mut()
            .stamped_write_with_changes(checkpoint1_stamp)?;
        let _after_flush_hash = compute_directory_hash(test_path)?;

        drop(vec);

        // Reopen
        let (mut vec, _) = V::import_with_changes(&database, "vec", 10)?;

        // Verify using individual gets
        let reader = vec.deref_mut().reader();
        let mut data_via_gets = Vec::new();
        for i in 0..vec.len() {
            let value = vec.get_with_reader(i, &reader);
            data_via_gets.push(value);
        }
        drop(reader);

        assert_eq!(data_via_gets, checkpoint1_data);

        // Verify using iterator
        let data_via_iter = vec.deref_mut().collect_holed();
        assert_eq!(data_via_iter, checkpoint1_data);

        // Redo the same 3 operations
        vec.deref_mut().update(2, 100)?;
        vec.deref_mut().update(7, 200)?;
        vec.deref_mut().stamped_write_with_changes(Stamp::new(3))?;

        vec.push(20);
        vec.push(21);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(4))?;

        let _ = vec.deref_mut().take(5);
        vec.push(30);
        vec.deref_mut().stamped_write_with_changes(Stamp::new(5))?;

        // Verify in-memory data matches checkpoint2
        let after_redo_data = vec.deref_mut().collect_holed();
        let after_redo_stamp = vec.deref_mut().stamp();

        assert_eq!(after_redo_stamp, checkpoint2_stamp);
        assert_eq!(after_redo_data, checkpoint2_data);

        // Flush and close
        vec.deref_mut()
            .stamped_write_with_changes(checkpoint2_stamp)?;
        drop(vec);

        // Reopen again
        let (vec, _) = V::import_with_changes(&database, "vec", 10)?;

        // Verify using individual gets
        let reader = vec.deref().reader();
        let mut data_via_gets = Vec::new();
        for i in 0..vec.len() {
            let value = vec.get_with_reader(i, &reader);
            data_via_gets.push(value);
        }
        drop(reader);

        assert_eq!(data_via_gets, checkpoint2_data);

        // Verify using iterator
        let data_via_iter = vec.deref().collect_holed();
        assert_eq!(data_via_iter, checkpoint2_data);

        Ok(())
    }

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

        #[test]
        fn data_integrity_rollback_flush_reopen() -> Result<()> {
            run_data_integrity_rollback_flush_reopen::<V>()
        }
    }

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

        #[test]
        fn data_integrity_rollback_flush_reopen() -> Result<()> {
            run_data_integrity_rollback_flush_reopen::<V>()
        }
    }
}
