#[cfg(feature = "async")]
mod async_tests {
    use ndarray::Array2;
    use std::collections::HashMap;
    use taco_format::{
        AsyncReader, AsyncWriter, AtomMetadata, CompressionSettings, Frame, FrameData,
        PrecisionMode, Reader, Result, SimulationMetadata, Writer,
    };
    use tempfile::NamedTempFile;

    #[tokio::test]
    async fn test_async_write_read() -> Result<()> {
        // Create a temporary file
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        // Create test data
        let num_atoms = 5; // Same as working test
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default(); // Same as working test

        // Create frames to write
        let mut frames = Vec::new();
        for i in 0..3 {
            // Same number as working test
            // Create position data - simple linear values
            let mut positions_data = vec![0.0f32; num_atoms as usize * 3];
            for j in 0..num_atoms as usize {
                positions_data[j * 3] = (i + j) as f32; // x
                positions_data[j * 3 + 1] = i as f32; // y
                positions_data[j * 3 + 2] = j as f32; // z
            }
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write frames asynchronously
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            for frame in frames.clone() {
                writer.write_frame(frame).await?;
            }

            writer.finish().await?;
        }

        // Read frames asynchronously
        {
            let mut reader = AsyncReader::open(&path).await?;

            assert_eq!(reader.num_frames(), 3);
            assert_eq!(reader.num_atoms(), num_atoms);

            // Read first frame
            let frame = reader.read_frame(0).await?;
            assert_eq!(frame.frame_number, 0);
            if let Some(positions) = &frame.data.positions {
                assert_eq!(positions[[0, 0]], 0.0); // First atom x coordinate
                assert_eq!(positions[[0, 1]], 0.0); // First atom y coordinate
            }
        }

        // Read frames asynchronously with fresh reader
        {
            let mut reader = AsyncReader::open(&path).await?;

            // Read last frame
            let frame = reader.read_frame(2).await?;
            assert_eq!(frame.frame_number, 2);
            if let Some(positions) = &frame.data.positions {
                assert_eq!(positions[[0, 0]], 2.0); // First atom x coordinate in frame 2 (2+0=2)
                assert_eq!(positions[[0, 1]], 2.0); // First atom y coordinate in frame 2 (i=2)
            }

            // Test sequential reading
            reader.reset().await?;
            let frame = reader.next_frame().await?.unwrap();
            assert_eq!(frame.frame_number, 0);

            // Test range reading
            let range_frames = reader.read_frame_range(1, 3).await?;
            assert_eq!(range_frames.len(), 2);
            assert_eq!(range_frames[0].frame_number, 1);
            assert_eq!(range_frames[1].frame_number, 2);

            // Test specific frames reading
            let specific_frames = reader.read_frames(&[0, 2]).await?;
            assert_eq!(specific_frames.len(), 2);
            assert_eq!(specific_frames[0].frame_number, 0);
            assert_eq!(specific_frames[1].frame_number, 2);
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_write_multiple_frames() -> Result<()> {
        // Create a temporary file
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        // Create test data
        let num_atoms = 5;
        let time_step = 0.002;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create frames to write
        let mut frames = Vec::new();
        for i in 0..3 {
            // Create position data
            let positions_data = vec![i as f32; num_atoms as usize * 3];
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write frames asynchronously using write_frames
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frames(frames.clone()).await?;
            writer.finish().await?;
        }

        // Verify the data was written correctly
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 3);

            for i in 0..3 {
                let frame = reader.read_frame(i).await?;
                assert_eq!(frame.frame_number, i);
                if let Some(positions) = &frame.data.positions {
                    assert_eq!(positions[[0, 0]], i as f32);
                    assert_eq!(positions[[0, 1]], i as f32);
                    assert_eq!(positions[[0, 2]], i as f32);
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_larger_dataset() -> Result<()> {
        // Create a temporary file
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        // Test with larger parameters that were failing
        let num_atoms = 10;
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default(); // Use default first

        // Create frames to write
        let mut frames = Vec::new();
        for i in 0..5 {
            // Create position data - simple linear values
            let mut positions_data = vec![0.0f32; num_atoms as usize * 3];
            for j in 0..num_atoms as usize {
                positions_data[j * 3] = (i + j) as f32; // x
                positions_data[j * 3 + 1] = i as f32; // y
                positions_data[j * 3 + 2] = j as f32; // z
            }
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write frames asynchronously
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            for frame in frames.clone() {
                writer.write_frame(frame).await?;
            }

            writer.finish().await?;
        }

        // Read and verify
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 5);
            assert_eq!(reader.num_atoms(), num_atoms);

            // Test reading a few frames
            let frame = reader.read_frame(0).await?;
            assert_eq!(frame.frame_number, 0);

            let frame = reader.read_frame(4).await?;
            assert_eq!(frame.frame_number, 4);
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_precision_modes() -> Result<()> {
        // Test that PrecisionMode::Full works with smaller datasets
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 3; // Very small dataset
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings {
            precision: PrecisionMode::Full,
            ..Default::default()
        };

        // Create a single frame
        let positions_data = vec![1.0f32; num_atoms as usize * 3];
        let positions = Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

        let frame_data = FrameData {
            positions: Some(positions),
            velocities: None,
            forces: None,
            stress: None,
            extra: HashMap::new(),
        };

        let frame = Frame::new(0, 0.0, frame_data);

        // Write and read with Full precision
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frame(frame).await?;
            writer.finish().await?;
        }

        {
            let mut reader = AsyncReader::open(&path).await?;
            let read_frame = reader.read_frame(0).await?;
            assert_eq!(read_frame.frame_number, 0);
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_sync_vs_async_consistency() -> Result<()> {
        // Test that sync and async implementations produce identical results
        let temp_file_sync = NamedTempFile::new().unwrap();
        let temp_file_async = NamedTempFile::new().unwrap();
        let path_sync = temp_file_sync.path().to_path_buf();
        let path_async = temp_file_async.path().to_path_buf();

        let num_atoms = 8;
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create test frames
        let mut frames = Vec::new();
        for i in 0..4 {
            let mut positions_data = vec![0.0f32; num_atoms as usize * 3];
            for j in 0..num_atoms as usize {
                positions_data[j * 3] = (i * 2 + j) as f32;
                positions_data[j * 3 + 1] = i as f32 + 0.5;
                positions_data[j * 3 + 2] = j as f32 * 0.1;
            }
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write with sync implementation
        {
            let mut writer = Writer::create(
                &path_sync,
                num_atoms,
                time_step,
                simulation_metadata.clone(),
                atom_metadata.clone(),
                compression_settings.clone(),
            )?;

            for frame in frames.clone() {
                writer.write_frame(frame)?;
            }

            writer.finish()?;
        }

        // Write with async implementation
        {
            let mut writer = AsyncWriter::create(
                &path_async,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            for frame in frames {
                writer.write_frame(frame).await?;
            }

            writer.finish().await?;
        }

        // Read and compare results
        let mut sync_reader = Reader::open(&path_sync)?;
        let mut async_reader = AsyncReader::open(&path_async).await?;

        assert_eq!(sync_reader.num_frames(), async_reader.num_frames());
        assert_eq!(sync_reader.num_atoms(), async_reader.num_atoms());

        // Compare frame by frame
        for i in 0..sync_reader.num_frames() {
            let sync_frame = sync_reader.read_frame(i)?;
            let async_frame = async_reader.read_frame(i).await?;

            assert_eq!(sync_frame.frame_number, async_frame.frame_number);
            assert_eq!(sync_frame.time, async_frame.time);

            if let (Some(sync_pos), Some(async_pos)) =
                (&sync_frame.data.positions, &async_frame.data.positions)
            {
                assert_eq!(sync_pos.shape(), async_pos.shape());
                for j in 0..sync_pos.nrows() {
                    for k in 0..sync_pos.ncols() {
                        assert!((sync_pos[[j, k]] - async_pos[[j, k]]).abs() < 1e-6);
                    }
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_with_velocities_and_forces() -> Result<()> {
        // Test async implementation with velocities and forces
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 6;
        let time_step = 0.002;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create frames with positions, velocities, and forces
        let mut frames = Vec::new();
        for i in 0..3 {
            let mut positions_data = vec![0.0f32; num_atoms as usize * 3];
            let mut velocities_data = vec![0.0f32; num_atoms as usize * 3];
            let mut forces_data = vec![0.0f32; num_atoms as usize * 3];

            for j in 0..num_atoms as usize {
                // Positions
                positions_data[j * 3] = (i + j) as f32;
                positions_data[j * 3 + 1] = i as f32 * 0.5;
                positions_data[j * 3 + 2] = j as f32 * 0.1;

                // Velocities
                velocities_data[j * 3] = i as f32 * 0.01;
                velocities_data[j * 3 + 1] = j as f32 * 0.02;
                velocities_data[j * 3 + 2] = (i + j) as f32 * 0.005;

                // Forces
                forces_data[j * 3] = (i * j) as f32 * 0.1;
                forces_data[j * 3 + 1] = i as f32 * 0.2;
                forces_data[j * 3 + 2] = j as f32 * 0.3;
            }

            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();
            let velocities =
                Array2::from_shape_vec((num_atoms as usize, 3), velocities_data).unwrap();
            let forces = Array2::from_shape_vec((num_atoms as usize, 3), forces_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: Some(velocities),
                forces: Some(forces),
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write frames
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frames(frames.clone()).await?;
            writer.finish().await?;
        }

        // Read and verify
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 3);

            for (i, original_frame) in frames.iter().enumerate() {
                let read_frame = reader.read_frame(i as u64).await?;
                assert_eq!(read_frame.frame_number, i as u64);

                // Check positions
                if let (Some(orig_pos), Some(read_pos)) =
                    (&original_frame.data.positions, &read_frame.data.positions)
                {
                    assert_eq!(orig_pos.shape(), read_pos.shape());
                }

                // Check velocities
                if let (Some(orig_vel), Some(read_vel)) =
                    (&original_frame.data.velocities, &read_frame.data.velocities)
                {
                    assert_eq!(orig_vel.shape(), read_vel.shape());
                }

                // Check forces
                if let (Some(orig_force), Some(read_force)) =
                    (&original_frame.data.forces, &read_frame.data.forces)
                {
                    assert_eq!(orig_force.shape(), read_force.shape());
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_sequential_vs_random_access() -> Result<()> {
        // Test that sequential and random access produce same results
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 4;
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create frames
        let mut frames = Vec::new();
        for i in 0..6 {
            let positions_data = vec![(i * 10) as f32; num_atoms as usize * 3];
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write frames
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frames(frames).await?;
            writer.finish().await?;
        }

        // Read sequentially
        let mut sequential_frames = Vec::new();
        {
            let mut reader = AsyncReader::open(&path).await?;
            reader.reset().await?;
            while let Some(frame) = reader.next_frame().await? {
                sequential_frames.push(frame);
            }
        }

        // Read randomly
        let mut random_frames = Vec::new();
        {
            let mut reader = AsyncReader::open(&path).await?;
            let indices = vec![5, 1, 3, 0, 4, 2]; // Random order
            for &idx in &indices {
                random_frames.push(reader.read_frame(idx).await?);
            }
            // Sort back to original order
            random_frames.sort_by_key(|f| f.frame_number);
        }

        // Compare results
        assert_eq!(sequential_frames.len(), random_frames.len());
        for (seq_frame, rand_frame) in sequential_frames.iter().zip(random_frames.iter()) {
            assert_eq!(seq_frame.frame_number, rand_frame.frame_number);
            assert_eq!(seq_frame.time, rand_frame.time);

            if let (Some(seq_pos), Some(rand_pos)) =
                (&seq_frame.data.positions, &rand_frame.data.positions)
            {
                assert_eq!(seq_pos, rand_pos);
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_error_handling() -> Result<()> {
        // Test error handling in async implementations
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 3;
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Write a small file first
        {
            let positions_data = vec![1.0f32; num_atoms as usize * 3];
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            let frame = Frame::new(0, 0.0, frame_data);

            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frame(frame).await?;
            writer.finish().await?;
        }

        // Test reading non-existent frames
        {
            let mut reader = AsyncReader::open(&path).await?;

            // Should error when reading frame beyond bounds
            let result = reader.read_frame(10).await;
            assert!(result.is_err());

            // Should error when reading negative frame (as u64 this would be huge)
            let result = reader.read_frame(u64::MAX).await;
            assert!(result.is_err());
        }

        // Test opening non-existent file
        {
            let non_existent_path = "/tmp/non_existent_file_12345.taco";
            let result = AsyncReader::open(non_existent_path).await;
            assert!(result.is_err());
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_large_batch_write() -> Result<()> {
        // Test writing a larger batch of frames
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 5;
        let time_step = 0.001;
        let num_frames = 20;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create many frames
        let mut frames = Vec::new();
        for i in 0..num_frames {
            let mut positions_data = vec![0.0f32; num_atoms as usize * 3];
            for j in 0..num_atoms as usize {
                positions_data[j * 3] = (i + j) as f32;
                positions_data[j * 3 + 1] = (i as f32).sin();
                positions_data[j * 3 + 2] = (j as f32).cos();
            }
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write all frames at once
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frames(frames).await?;
            writer.finish().await?;
        }

        // Verify by reading random frames
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), num_frames as u64);

            // Test range reading
            let range_frames = reader.read_frame_range(5, 15).await?;
            assert_eq!(range_frames.len(), 10);
            assert_eq!(range_frames[0].frame_number, 5);
            assert_eq!(range_frames[9].frame_number, 14);

            // Test specific frame reading
            let specific_frames = reader.read_frames(&[0, 5, 10, 15, 19]).await?;
            assert_eq!(specific_frames.len(), 5);
            assert_eq!(specific_frames[0].frame_number, 0);
            assert_eq!(specific_frames[4].frame_number, 19);
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_sync_comprehensive() -> Result<()> {
        // Comprehensive test of sync implementation
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 7;
        let time_step = 0.002;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings {
            precision: PrecisionMode::Half,
            ..Default::default()
        };

        // Create frames with varying complexity
        let mut frames = Vec::new();
        for i in 0..8 {
            let mut positions_data = vec![0.0f32; num_atoms * 3];
            let mut velocities_data = vec![0.0f32; num_atoms * 3];

            for j in 0..num_atoms {
                let base = (i * num_atoms + j) as f32;
                positions_data[j * 3] = base * 0.1;
                positions_data[j * 3 + 1] = base * 0.2 + (i as f32).sin();
                positions_data[j * 3 + 2] = base * 0.3 + (j as f32).cos();

                velocities_data[j * 3] = (i as f32) * 0.01;
                velocities_data[j * 3 + 1] = (j as f32) * 0.02;
                velocities_data[j * 3 + 2] = (i + j) as f32 * 0.005;
            }

            let positions = Array2::from_shape_vec((num_atoms, 3), positions_data).unwrap();
            let velocities = Array2::from_shape_vec((num_atoms, 3), velocities_data).unwrap();

            let mut frame = Frame::new(
                i as u64,
                i as f64 * time_step,
                FrameData {
                    positions: Some(positions),
                    velocities: Some(velocities),
                    forces: None,
                    stress: None,
                    extra: HashMap::new(),
                },
            );

            // Add some metadata to every other frame
            if i % 2 == 0 {
                frame.potential_energy = Some(100.0 + i as f32);
                frame.kinetic_energy = Some(50.0 + i as f32 * 0.5);
                frame.temperature = Some(300.0 + i as f32);
                frame.pressure = Some(1.0 + i as f32 * 0.1);
            }

            frames.push(frame);
        }

        // Write with sync
        {
            let mut writer = Writer::create(
                &path,
                num_atoms as u32,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )?;

            // Write frames individually
            for frame in &frames[0..4] {
                writer.write_frame(frame.clone())?;
            }

            // Write remaining frames as batch
            writer.write_frames(frames[4..].to_vec())?;
            writer.finish()?;
        }

        // Read and verify with sync
        {
            let mut reader = Reader::open(&path)?;
            assert_eq!(reader.num_frames(), 8);
            assert_eq!(reader.num_atoms(), num_atoms as u32);

            // Test iterator
            let mut iter_frames = Vec::new();
            for frame_result in reader.iter_frames() {
                iter_frames.push(frame_result?);
            }
            assert_eq!(iter_frames.len(), 8);

            // Reset and test random access
            reader.reset()?;
            let frame_3 = reader.read_frame(3)?;
            assert_eq!(frame_3.frame_number, 3);

            let frame_7 = reader.read_frame(7)?;
            assert_eq!(frame_7.frame_number, 7);
            // Note: metadata preservation depends on the format implementation
            // Just check that the frame was read successfully

            // Test batch reading
            let batch_frames = reader.read_frames(&[1, 3, 5, 7])?;
            assert_eq!(batch_frames.len(), 4);
            assert_eq!(batch_frames[0].frame_number, 1);
            assert_eq!(batch_frames[3].frame_number, 7);
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_empty_frames() -> Result<()> {
        // Test handling of frames with minimal data
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 1;
        let time_step = 1.0;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Frame with only positions (minimal required data)
        let positions_data = vec![0.0f32; 3];
        let positions = Array2::from_shape_vec((1, 3), positions_data).unwrap();

        let frame_data = FrameData {
            positions: Some(positions),
            velocities: None,
            forces: None,
            stress: None,
            extra: HashMap::new(),
        };

        let frame = Frame::new(0, 0.0, frame_data);

        // Write and read
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frame(frame).await?;
            writer.finish().await?;
        }

        {
            let mut reader = AsyncReader::open(&path).await?;
            let read_frame = reader.read_frame(0).await?;
            assert_eq!(read_frame.frame_number, 0);
            assert!(read_frame.data.positions.is_some());
            assert!(read_frame.data.velocities.is_none());
            assert!(read_frame.data.forces.is_none());
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_single_atom_trajectory() -> Result<()> {
        // Test with a single atom over many frames
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 1;
        let time_step = 0.001;
        let num_frames = 100;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create trajectory with single atom moving in a circle
        let mut frames = Vec::new();
        for i in 0..num_frames {
            let angle = 2.0 * std::f32::consts::PI * i as f32 / num_frames as f32;
            let positions_data = vec![
                angle.cos(),     // x
                angle.sin(),     // y
                i as f32 * 0.01, // z
            ];
            let positions = Array2::from_shape_vec((1, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write all frames
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frames(frames).await?;
            writer.finish().await?;
        }

        // Read and verify trajectory
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), num_frames as u64);

            // Check first and last frames
            let first_frame = reader.read_frame(0).await?;
            let last_frame = reader.read_frame((num_frames - 1) as u64).await?;

            if let Some(first_pos) = &first_frame.data.positions {
                assert!((first_pos[[0, 0]] - 1.0).abs() < 0.1); // Should be ~1.0
                assert!(first_pos[[0, 1]].abs() < 0.1); // Should be ~0.0
            }

            if let Some(last_pos) = &last_frame.data.positions {
                assert!(last_pos[[0, 2]] > 0.9); // z should have increased
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_high_precision_data() -> Result<()> {
        // Test with high precision floating point data
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 5;
        let time_step = 1e-15; // Very small time step
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings {
            precision: PrecisionMode::Full,
            ..Default::default()
        };

        // Create frame with high precision values
        let mut positions_data = Vec::new();
        for i in 0..num_atoms as usize {
            positions_data.push(i as f32 + 0.123_456_79); // x
            positions_data.push(i as f32 * std::f32::consts::PI); // y
            positions_data.push((i as f32).sqrt() * 1e-6); // z - very small
        }
        let positions = Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

        let frame_data = FrameData {
            positions: Some(positions.clone()),
            velocities: None,
            forces: None,
            stress: None,
            extra: HashMap::new(),
        };

        let frame = Frame::new(0, 0.0, frame_data);

        // Write and read with full precision
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frame(frame).await?;
            writer.finish().await?;
        }

        {
            let mut reader = AsyncReader::open(&path).await?;
            let read_frame = reader.read_frame(0).await?;

            if let Some(read_pos) = &read_frame.data.positions {
                // With full precision, we should get reasonable accuracy
                for i in 0..num_atoms as usize {
                    let expected_x = i as f32 + 0.123_456_79;
                    let actual_x = read_pos[[i, 0]];
                    assert!(
                        (expected_x - actual_x).abs() < 0.01,
                        "Expected {expected_x}, got {actual_x} for atom {i} x coordinate"
                    );
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_metadata_preservation() -> Result<()> {
        // Test that frame metadata is preserved correctly
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 3;
        let time_step = 0.002;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create frames with various metadata
        let mut frames = Vec::new();
        for i in 0..5 {
            let positions_data = vec![(i as f32) * 0.1; num_atoms as usize * 3];
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            let mut frame = Frame::new(i as u64, i as f64 * time_step, frame_data);

            // Add different metadata to each frame
            match i {
                0 => {
                    frame.potential_energy = Some(100.0);
                    frame.kinetic_energy = Some(50.0);
                }
                1 => {
                    frame.temperature = Some(298.15);
                    frame.pressure = Some(1.01325);
                }
                2 => {
                    frame.potential_energy = Some(105.5);
                    frame.kinetic_energy = Some(45.2);
                    frame.temperature = Some(310.0);
                }
                3 => {
                    frame.pressure = Some(2.5);
                }
                4 => {
                    frame.potential_energy = Some(95.0);
                    frame.kinetic_energy = Some(55.0);
                    frame.temperature = Some(290.0);
                    frame.pressure = Some(0.8);
                }
                _ => {}
            }

            frames.push(frame);
        }

        // Write frames
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frames(frames.clone()).await?;
            writer.finish().await?;
        }

        // Read and verify metadata
        {
            let mut reader = AsyncReader::open(&path).await?;

            for (i, original_frame) in frames.iter().enumerate() {
                let read_frame = reader.read_frame(i as u64).await?;

                // Note: Metadata preservation may depend on the format implementation
                // For now, just verify the frames can be read successfully
                assert_eq!(read_frame.frame_number, original_frame.frame_number);

                // Check that positions are preserved correctly
                if let (Some(orig_pos), Some(read_pos)) =
                    (&original_frame.data.positions, &read_frame.data.positions)
                {
                    assert_eq!(orig_pos.shape(), read_pos.shape());
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_concurrent_readers() -> Result<()> {
        // Test multiple concurrent readers
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 4;
        let time_step = 0.001;
        let num_frames = 10;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create test data
        let mut frames = Vec::new();
        for i in 0..num_frames {
            let positions_data = vec![i as f32; num_atoms as usize * 3];
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write data
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            writer.write_frames(frames).await?;
            writer.finish().await?;
        }

        // Test concurrent reading
        let path_clone = path.clone();
        let task1 = tokio::spawn(async move {
            let mut reader = AsyncReader::open(&path_clone).await?;
            let mut results = Vec::new();
            for i in 0..num_frames {
                let frame = reader.read_frame(i as u64).await?;
                results.push(frame.frame_number);
            }
            Ok::<Vec<u64>, taco_format::Error>(results)
        });

        let path_clone2 = path.clone();
        let task2 = tokio::spawn(async move {
            let mut reader = AsyncReader::open(&path_clone2).await?;
            let mut results = Vec::new();
            // Read in reverse order
            for i in (0..num_frames).rev() {
                let frame = reader.read_frame(i as u64).await?;
                results.push(frame.frame_number);
            }
            Ok::<Vec<u64>, taco_format::Error>(results)
        });

        let (result1, result2) = tokio::try_join!(task1, task2).unwrap();
        let frames1 = result1?;
        let frames2 = result2?;

        assert_eq!(frames1.len(), num_frames);
        assert_eq!(frames2.len(), num_frames);

        // Verify forward reading
        for (i, &frame_num) in frames1.iter().enumerate() {
            assert_eq!(frame_num, i as u64);
        }

        // Verify reverse reading
        for (i, &frame_num) in frames2.iter().enumerate() {
            assert_eq!(frame_num, (num_frames - 1 - i) as u64);
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_sync_mixed_write_operations() -> Result<()> {
        // Test mixing individual writes and batch writes in sync mode
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 6;
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create frames with simple pattern for debugging
        let mut all_frames = Vec::new();
        for i in 0..12 {
            let positions_data = vec![i as f32 * 0.5; num_atoms as usize * 3];
            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

            let frame_data = FrameData {
                positions: Some(positions),
                velocities: None,
                forces: None,
                stress: None,
                extra: HashMap::new(),
            };

            all_frames.push(Frame::new(i as u64, i as f64 * time_step, frame_data));
        }

        // Write with mixed operations
        {
            let mut writer = Writer::create(
                &path,
                num_atoms as u32,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )?;

            // Write first 3 frames individually
            for frame in &all_frames[0..3] {
                writer.write_frame(frame.clone())?;
            }

            // Write next 4 frames as batch
            writer.write_frames(all_frames[3..7].to_vec())?;

            // Write another 2 frames individually
            for frame in &all_frames[7..9] {
                writer.write_frame(frame.clone())?;
            }

            // Write final 3 frames as batch
            writer.write_frames(all_frames[9..12].to_vec())?;

            writer.finish()?;
        }

        // Verify all frames were written correctly
        {
            let mut reader = Reader::open(&path)?;
            assert_eq!(reader.num_frames(), 12);

            for i in 0..12 {
                let frame = reader.read_frame(i)?;
                assert_eq!(frame.frame_number, i);
                if let Some(positions) = &frame.data.positions {
                    let expected = i as f32 * 0.5;
                    let actual = positions[[0, 0]];
                    assert!(
                        (expected - actual).abs() < 0.01,
                        "Expected position {expected}, got {actual} for frame {i}"
                    );
                }
            }

            // Test batch reading of all frames
            let batch_frames =
                reader.read_frames(&(0..12).map(|x| x as u64).collect::<Vec<_>>())?;
            assert_eq!(batch_frames.len(), 12);

            // Test range reading
            let range_frames = reader.read_frame_range(4, 8)?;
            assert_eq!(range_frames.len(), 4);
            assert_eq!(range_frames[0].frame_number, 4);
            assert_eq!(range_frames[3].frame_number, 7);
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_sync_comprehensive_stress() -> Result<()> {
        // Comprehensive stress test for sync implementation
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 20;
        let time_step = 0.0005;
        let num_frames = 50;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings {
            precision: PrecisionMode::Half,
            ..Default::default()
        };

        // Create complex trajectory
        let mut frames = Vec::new();
        for i in 0..num_frames {
            let mut positions_data = vec![0.0f32; num_atoms as usize * 3];
            let mut velocities_data = vec![0.0f32; num_atoms as usize * 3];
            let mut forces_data = vec![0.0f32; num_atoms as usize * 3];

            for j in 0..num_atoms as usize {
                let phase = 2.0 * std::f32::consts::PI * (i as f32) / (num_frames as f32);
                let atom_offset = j as f32 * 0.5;

                // Complex motion pattern
                positions_data[j * 3] = (phase + atom_offset).sin() * 5.0;
                positions_data[j * 3 + 1] = (phase * 2.0 + atom_offset).cos() * 3.0;
                positions_data[j * 3 + 2] = (i as f32) * 0.01 + (atom_offset * phase).sin();

                velocities_data[j * 3] = (phase + atom_offset).cos() * 0.1;
                velocities_data[j * 3 + 1] = -(phase * 2.0 + atom_offset).sin() * 0.2;
                velocities_data[j * 3 + 2] = 0.01 + (atom_offset * phase).cos() * 0.05;

                forces_data[j * 3] = (i + j) as f32 * 0.001;
                forces_data[j * 3 + 1] = (i as f32).sin() * j as f32 * 0.002;
                forces_data[j * 3 + 2] = (j as f32).cos() * 0.003;
            }

            let positions =
                Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();
            let velocities =
                Array2::from_shape_vec((num_atoms as usize, 3), velocities_data).unwrap();
            let forces = Array2::from_shape_vec((num_atoms as usize, 3), forces_data).unwrap();

            let mut frame = Frame::new(
                i as u64,
                i as f64 * time_step,
                FrameData {
                    positions: Some(positions),
                    velocities: Some(velocities),
                    forces: Some(forces),
                    stress: None,
                    extra: HashMap::new(),
                },
            );

            // Add thermodynamic data
            frame.potential_energy = Some(1000.0 + (i as f32 * 0.1).sin() * 100.0);
            frame.kinetic_energy = Some(500.0 + (i as f32 * 0.2).cos() * 50.0);
            frame.temperature = Some(300.0 + (i as f32 * 0.05).sin() * 20.0);
            frame.pressure = Some(1.0 + (i as f32 * 0.1).cos() * 0.2);

            frames.push(frame);
        }

        // Write frames
        {
            let mut writer = Writer::create(
                &path,
                num_atoms as u32,
                time_step,
                simulation_metadata,
                atom_metadata,
                compression_settings,
            )?;

            writer.write_frames(frames.clone())?;
            writer.finish()?;
        }

        // Comprehensive reading tests
        {
            let mut reader = Reader::open(&path)?;
            assert_eq!(reader.num_frames(), num_frames as u64);
            assert_eq!(reader.num_atoms(), num_atoms as u32);

            // Test sequential access
            let mut sequential_frames = Vec::new();
            reader.reset()?;
            for frame_result in reader.iter_frames() {
                sequential_frames.push(frame_result?);
            }
            assert_eq!(sequential_frames.len(), num_frames);

            // Test random access patterns
            let random_indices = vec![49, 0, 25, 10, 35, 5, 40, 15, 30, 20];
            for &idx in &random_indices {
                let frame = reader.read_frame(idx)?;
                assert_eq!(frame.frame_number, idx);
                assert!(frame.potential_energy.is_some());
                assert!(frame.data.positions.is_some());
                assert!(frame.data.velocities.is_some());
                assert!(frame.data.forces.is_some());
            }

            // Test large batch reads
            let large_batch = (0..num_frames)
                .step_by(5)
                .map(|x| x as u64)
                .collect::<Vec<_>>();
            let batch_frames = reader.read_frames(&large_batch)?;
            assert_eq!(batch_frames.len(), large_batch.len());

            // Test overlapping range reads
            let range1 = reader.read_frame_range(10, 20)?;
            let range2 = reader.read_frame_range(15, 25)?;
            assert_eq!(range1.len(), 10);
            assert_eq!(range2.len(), 10);

            // Verify overlap consistency
            for i in 0..5 {
                assert_eq!(range1[15 - 10 + i].frame_number, range2[i].frame_number);
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_error_recovery_and_edge_cases() -> Result<()> {
        // Test various error conditions and edge cases
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let num_atoms = 2;
        let time_step = 0.001;
        let simulation_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Test 1: Empty trajectory (0 frames)
        {
            let writer = AsyncWriter::create(
                &path,
                num_atoms as u32,
                time_step,
                simulation_metadata.clone(),
                atom_metadata.clone(),
                compression_settings.clone(),
            )
            .await?;

            writer.finish().await?;

            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 0);

            // Reading from empty trajectory should error
            let result = reader.read_frame(0).await;
            assert!(result.is_err());
        }

        // Test 2: Write a few frames for further testing
        {
            let mut writer = AsyncWriter::create(
                &path,
                num_atoms as u32,
                time_step,
                simulation_metadata.clone(),
                atom_metadata.clone(),
                compression_settings.clone(),
            )
            .await?;

            for i in 0..3 {
                let positions_data = vec![i as f32; num_atoms as usize * 3];
                let positions =
                    Array2::from_shape_vec((num_atoms as usize, 3), positions_data).unwrap();

                let frame_data = FrameData {
                    positions: Some(positions),
                    velocities: None,
                    forces: None,
                    stress: None,
                    extra: HashMap::new(),
                };

                writer
                    .write_frame(Frame::new(i as u64, i as f64 * time_step, frame_data))
                    .await?;
            }

            writer.finish().await?;
        }

        // Test 3: Out-of-bounds access
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 3);

            // Valid access
            let frame = reader.read_frame(2).await?;
            assert_eq!(frame.frame_number, 2);

            // Invalid access - beyond bounds
            let result = reader.read_frame(3).await;
            assert!(result.is_err());

            let result = reader.read_frame(100).await;
            assert!(result.is_err());
        }

        // Test 4: Invalid range reads
        {
            let mut reader = AsyncReader::open(&path).await?;

            // Valid range
            let frames = reader.read_frame_range(0, 2).await?;
            assert_eq!(frames.len(), 2);

            // Invalid range - end beyond bounds
            let result = reader.read_frame_range(1, 5).await;
            // This might succeed but return fewer frames, or error - depends on implementation
            // Just ensure it doesn't panic
            let _ = result;

            // Invalid range - start beyond bounds
            let result = reader.read_frame_range(10, 15).await;
            assert!(result.is_err() || result.unwrap().is_empty());
        }

        // Test 5: Test with sync reader for comparison
        {
            let mut sync_reader = Reader::open(&path)?;
            assert_eq!(sync_reader.num_frames(), 3);

            // Same out-of-bounds tests
            let result = sync_reader.read_frame(3);
            assert!(result.is_err());

            let result = sync_reader.read_frame(100);
            assert!(result.is_err());
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_append_basic() -> Result<()> {
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let sim_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create initial file with 5 frames
        {
            let mut writer = AsyncWriter::create(
                &path,
                3,
                0.001,
                sim_metadata.clone(),
                atom_metadata.clone(),
                compression_settings.clone(),
            )
            .await?;

            let mut positions = Array2::<f32>::zeros((3, 3));
            for i in 0..5 {
                for j in 0..3 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) * 0.1 + (j as f32) + (k as f32) * 0.01;
                    }
                }
                let frame = Frame::new(i, i as f64 * 0.001, FrameData::new(positions.clone()));
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // Append 3 more frames
        {
            let mut writer = AsyncWriter::append(&path).await?;
            let mut positions = Array2::<f32>::zeros((3, 3));
            for i in 5..8 {
                for j in 0..3 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) * 0.1 + (j as f32) + (k as f32) * 0.01;
                    }
                }
                let frame = Frame::new(i, i as f64 * 0.001, FrameData::new(positions.clone()));
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // Verify all 8 frames
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 8);

            for i in 0..8 {
                let frame = reader.read_frame(i).await?;
                assert_eq!(frame.frame_number, i);

                if let Some(pos) = &frame.data.positions {
                    for j in 0..3 {
                        for k in 0..3 {
                            let expected = (i as f32) * 0.1 + (j as f32) + (k as f32) * 0.01;
                            let actual = pos[[j, k]];
                            assert!(
                                (actual - expected).abs() < 0.001,
                                "Frame {}, atom {}, coord {}: expected {}, got {}",
                                i,
                                j,
                                k,
                                expected,
                                actual
                            );
                        }
                    }
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_append_multiple_times() -> Result<()> {
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let sim_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create initial file with 2 frames
        {
            let mut writer = AsyncWriter::create(
                &path,
                2,
                0.001,
                sim_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            let mut positions = Array2::<f32>::zeros((2, 3));
            for i in 0..2 {
                for j in 0..2 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) * 10.0 + (j as f32) + (k as f32) * 0.1;
                    }
                }
                let frame = Frame::new(i, i as f64 * 0.001, FrameData::new(positions.clone()));
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // First append: 2 more frames
        {
            let mut writer = AsyncWriter::append(&path).await?;
            let mut positions = Array2::<f32>::zeros((2, 3));
            for i in 2..4 {
                for j in 0..2 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) * 10.0 + (j as f32) + (k as f32) * 0.1;
                    }
                }
                let frame = Frame::new(i, i as f64 * 0.001, FrameData::new(positions.clone()));
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // Second append: 3 more frames
        {
            let mut writer = AsyncWriter::append(&path).await?;
            let mut positions = Array2::<f32>::zeros((2, 3));
            for i in 4..7 {
                for j in 0..2 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) * 10.0 + (j as f32) + (k as f32) * 0.1;
                    }
                }
                let frame = Frame::new(i, i as f64 * 0.001, FrameData::new(positions.clone()));
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // Verify all 7 frames
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 7);

            for i in 0..7 {
                let frame = reader.read_frame(i).await?;
                assert_eq!(frame.frame_number, i);

                if let Some(pos) = &frame.data.positions {
                    for j in 0..2 {
                        for k in 0..3 {
                            let expected = (i as f32) * 10.0 + (j as f32) + (k as f32) * 0.1;
                            let actual = pos[[j, k]];
                            assert!(
                                (actual - expected).abs() < 0.01,
                                "Frame {}, atom {}, coord {}: expected {}, got {}",
                                i,
                                j,
                                k,
                                expected,
                                actual
                            );
                        }
                    }
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_append_with_velocities_and_forces() -> Result<()> {
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let sim_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create initial file with 3 frames including velocities and forces
        {
            let mut writer = AsyncWriter::create(
                &path,
                2,
                0.001,
                sim_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;

            for i in 0..3 {
                let mut positions = Array2::<f32>::zeros((2, 3));
                let mut velocities = Array2::<f32>::zeros((2, 3));
                let mut forces = Array2::<f32>::zeros((2, 3));

                for j in 0..2 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) + (j as f32) * 0.1 + (k as f32) * 0.01;
                        velocities[[j, k]] = (i as f32) * 0.5 + (j as f32) * 0.05;
                        forces[[j, k]] = (i as f32) * 2.0 + (k as f32) * 0.2;
                    }
                }

                let frame_data = FrameData {
                    positions: Some(positions),
                    velocities: Some(velocities),
                    forces: Some(forces),
                    stress: None,
                    extra: HashMap::new(),
                };

                let frame = Frame::new(i, i as f64 * 0.001, frame_data);
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // Append 2 more frames with all data
        {
            let mut writer = AsyncWriter::append(&path).await?;

            for i in 3..5 {
                let mut positions = Array2::<f32>::zeros((2, 3));
                let mut velocities = Array2::<f32>::zeros((2, 3));
                let mut forces = Array2::<f32>::zeros((2, 3));

                for j in 0..2 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) + (j as f32) * 0.1 + (k as f32) * 0.01;
                        velocities[[j, k]] = (i as f32) * 0.5 + (j as f32) * 0.05;
                        forces[[j, k]] = (i as f32) * 2.0 + (k as f32) * 0.2;
                    }
                }

                let frame_data = FrameData {
                    positions: Some(positions),
                    velocities: Some(velocities),
                    forces: Some(forces),
                    stress: None,
                    extra: HashMap::new(),
                };

                let frame = Frame::new(i, i as f64 * 0.001, frame_data);
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // Verify all 5 frames
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 5);

            for i in 0..5 {
                let frame = reader.read_frame(i).await?;
                assert_eq!(frame.frame_number, i);

                // Check positions
                if let Some(pos) = &frame.data.positions {
                    for j in 0..2 {
                        for k in 0..3 {
                            let expected = (i as f32) + (j as f32) * 0.1 + (k as f32) * 0.01;
                            let actual = pos[[j, k]];
                            assert!(
                                (actual - expected).abs() < 0.001,
                                "Frame {} position mismatch",
                                i
                            );
                        }
                    }
                }

                // Check velocities
                if let Some(vel) = &frame.data.velocities {
                    for j in 0..2 {
                        for k in 0..3 {
                            let expected = (i as f32) * 0.5 + (j as f32) * 0.05;
                            let actual = vel[[j, k]];
                            assert!(
                                (actual - expected).abs() < 0.01,
                                "Frame {} velocity mismatch",
                                i
                            );
                        }
                    }
                }

                // Check forces
                if let Some(force) = &frame.data.forces {
                    for j in 0..2 {
                        for k in 0..3 {
                            let expected = (i as f32) * 2.0 + (k as f32) * 0.2;
                            let actual = force[[j, k]];
                            assert!(
                                (actual - expected).abs() < 0.01,
                                "Frame {} force mismatch",
                                i
                            );
                        }
                    }
                }
            }
        }

        Ok(())
    }

    #[tokio::test]
    async fn test_async_append_empty_file() -> Result<()> {
        let temp_file = NamedTempFile::new().unwrap();
        let path = temp_file.path().to_path_buf();

        let sim_metadata = SimulationMetadata::default();
        let atom_metadata = AtomMetadata::default();
        let compression_settings = CompressionSettings::default();

        // Create empty file (0 frames)
        {
            let writer = AsyncWriter::create(
                &path,
                2,
                0.001,
                sim_metadata,
                atom_metadata,
                compression_settings,
            )
            .await?;
            writer.finish().await?;
        }

        // Append frames to empty file
        {
            let mut writer = AsyncWriter::append(&path).await?;
            let mut positions = Array2::<f32>::zeros((2, 3));
            for i in 0..3 {
                for j in 0..2 {
                    for k in 0..3 {
                        positions[[j, k]] = (i as f32) + (j as f32) * 0.1;
                    }
                }
                let frame = Frame::new(i, i as f64 * 0.001, FrameData::new(positions.clone()));
                writer.write_frame(frame).await?;
            }
            writer.finish().await?;
        }

        // Verify
        {
            let mut reader = AsyncReader::open(&path).await?;
            assert_eq!(reader.num_frames(), 3);

            for i in 0..3 {
                let frame = reader.read_frame(i).await?;
                assert_eq!(frame.frame_number, i);
            }
        }

        Ok(())
    }
}
