use std::collections::HashMap;
use std::path::{Path, PathBuf};

use crate::error::{Error, Result};
use crate::format::messages::data_layout::LayoutClass;
use crate::hl::plist::dataset_create::{
    IrregularHyperslabBlockInfo, VirtualMappingInfo, VirtualSelectionInfo,
};

use super::{usize_from_u64, Dataset, DatasetAccess, DatasetInfo, VdsMissingSourcePolicy, VdsView};

#[derive(Debug, Clone)]
pub(super) struct VirtualMapping {
    pub(super) file_name: String,
    pub(super) dataset_name: String,
    pub(super) source_select: VirtualSelection,
    pub(super) virtual_select: VirtualSelection,
}

struct VirtualSourceCacheEntry {
    dataset: Dataset,
    info: DatasetInfo,
    raw: Option<Vec<u8>>,
}

struct VirtualSourceCache {
    indexes: HashMap<PathBuf, Vec<VirtualSourceCacheDatasetIndex>>,
    entries: Vec<VirtualSourceCacheEntry>,
}

struct VirtualSourceCacheDatasetIndex {
    dataset_name: String,
    index: usize,
}

impl VirtualSourceCache {
    fn new() -> Self {
        Self {
            indexes: HashMap::new(),
            entries: Vec::new(),
        }
    }

    fn source_info(
        &mut self,
        file_path: Option<&Path>,
        mapping: &VirtualMapping,
        access: &DatasetAccess,
    ) -> Result<&DatasetInfo> {
        let index = self.source_index(file_path, mapping, access)?;
        Ok(&self.entries[index].info)
    }

    fn source_raw(
        &mut self,
        file_path: Option<&Path>,
        mapping: &VirtualMapping,
        dest_info: &DatasetInfo,
        access: &DatasetAccess,
    ) -> Result<(&DatasetInfo, &[u8])> {
        let index = self.source_index(file_path, mapping, access)?;
        let entry = &mut self.entries[index];
        if entry.raw.is_none() {
            let (_, _, source_bytes) = Dataset::raw_read_size(&entry.info)?;
            let mut source_raw = vec![0; source_bytes];
            entry
                .dataset
                .read_raw_into_with_access(access, &mut source_raw)?;
            entry.raw = Some(crate::hl::conversion::convert_between_datatypes(
                &source_raw,
                &entry.info.datatype,
                &dest_info.datatype,
            )?);
        }
        let raw = entry
            .raw
            .as_deref()
            .expect("virtual source raw data must be cached after read");
        Ok((&entry.info, raw))
    }

    fn source_index(
        &mut self,
        file_path: Option<&Path>,
        mapping: &VirtualMapping,
        access: &DatasetAccess,
    ) -> Result<usize> {
        let source_path =
            Dataset::resolve_virtual_source_path(file_path, &mapping.file_name, access)?;
        if let Some(indexes) = self.indexes.get(&source_path) {
            if let Some(index) = indexes
                .iter()
                .find(|entry| entry.dataset_name == mapping.dataset_name.as_str())
                .map(|entry| entry.index)
            {
                return Ok(index);
            }
        }

        let source = crate::hl::file::File::open(&source_path)?;
        let dataset = source.dataset(&mapping.dataset_name)?;
        let info = dataset.info()?;
        let index = self.entries.len();
        self.entries.push(VirtualSourceCacheEntry {
            dataset,
            info,
            raw: None,
        });
        self.indexes
            .entry(source_path)
            .or_default()
            .push(VirtualSourceCacheDatasetIndex {
                dataset_name: mapping.dataset_name.clone(),
                index,
            });
        Ok(index)
    }
}

enum VirtualSourceElementIndexes<'a> {
    All { len: usize },
    Borrowed(&'a [Vec<u64>]),
    Owned(Vec<usize>),
}

impl VirtualSourceElementIndexes<'_> {
    fn len(&self) -> usize {
        match self {
            Self::All { len } => *len,
            Self::Borrowed(points) => points.len(),
            Self::Owned(indexes) => indexes.len(),
        }
    }

    fn linear_index(&self, index: usize, strides: &[usize]) -> Result<Option<usize>> {
        match self {
            Self::All { len } => Ok((index < *len).then_some(index)),
            Self::Borrowed(points) => points
                .get(index)
                .map(|point| Dataset::linear_index(point, strides))
                .transpose(),
            Self::Owned(indexes) => Ok(indexes.get(index).copied()),
        }
    }
}

#[derive(Debug, Clone)]
pub(super) enum VirtualSelection {
    All,
    Points(Vec<Vec<u64>>),
    Regular(RegularHyperslab),
    Irregular(Vec<IrregularHyperslabBlock>),
}

#[derive(Debug, Clone)]
pub(super) struct RegularHyperslab {
    pub(super) start: Vec<u64>,
    pub(super) stride: Vec<u64>,
    pub(super) count: Vec<u64>,
    pub(super) block: Vec<u64>,
}

#[derive(Debug, Clone)]
pub(super) struct IrregularHyperslabBlock {
    pub(super) start: Vec<u64>,
    pub(super) block: Vec<u64>,
}

impl Dataset {
    pub(crate) fn virtual_mapping_infos_with_info_into(
        &self,
        info: &DatasetInfo,
        out: &mut Vec<VirtualMappingInfo>,
    ) -> Result<()> {
        out.clear();
        if info.layout.layout_class != LayoutClass::Virtual {
            return Ok(());
        }
        let mut guard = self.inner.lock();
        let heap_addr = info.layout.virtual_heap_addr.ok_or_else(|| {
            Error::InvalidFormat("virtual dataset missing global heap address".into())
        })?;
        let heap_index = info.layout.virtual_heap_index.ok_or_else(|| {
            Error::InvalidFormat("virtual dataset missing global heap index".into())
        })?;
        let mut heap_data = Vec::new();
        crate::format::global_heap::read_global_heap_object_into(
            &mut guard.reader,
            &crate::format::global_heap::GlobalHeapRef {
                collection_addr: heap_addr,
                object_index: heap_index,
            },
            &mut heap_data,
        )?;
        let sizeof_size = usize::from(guard.reader.sizeof_size());
        drop(guard);

        let mappings = Self::decode_virtual_mappings(&heap_data, sizeof_size)?;
        out.extend(
            mappings
                .into_iter()
                .map(Self::virtual_mapping_info_from_mapping),
        );
        Ok(())
    }

    fn virtual_mapping_info_from_mapping(mapping: VirtualMapping) -> VirtualMappingInfo {
        VirtualMappingInfo {
            file_name: mapping.file_name,
            dataset_name: mapping.dataset_name,
            source_select: Self::virtual_selection_info_from_selection(mapping.source_select),
            virtual_select: Self::virtual_selection_info_from_selection(mapping.virtual_select),
        }
    }

    fn virtual_selection_info_from_selection(selection: VirtualSelection) -> VirtualSelectionInfo {
        match selection {
            VirtualSelection::All => VirtualSelectionInfo::All,
            VirtualSelection::Points(points) => VirtualSelectionInfo::Points(points),
            VirtualSelection::Regular(regular) => VirtualSelectionInfo::Regular {
                start: regular.start,
                stride: regular.stride,
                count: regular.count,
                block: regular.block,
            },
            VirtualSelection::Irregular(blocks) => VirtualSelectionInfo::Irregular(
                blocks
                    .into_iter()
                    .map(|block| IrregularHyperslabBlockInfo {
                        start: block.start,
                        block: block.block,
                    })
                    .collect(),
            ),
        }
    }

    pub(super) fn virtual_shape_with_info(
        &self,
        info: &DatasetInfo,
        access: &DatasetAccess,
    ) -> Result<Vec<u64>> {
        let mut guard = self.inner.lock();
        let heap_addr = info.layout.virtual_heap_addr.ok_or_else(|| {
            Error::InvalidFormat("virtual dataset missing global heap address".into())
        })?;
        let heap_index = info.layout.virtual_heap_index.ok_or_else(|| {
            Error::InvalidFormat("virtual dataset missing global heap index".into())
        })?;
        let path = guard.path.clone();
        let mut heap_data = Vec::new();
        crate::format::global_heap::read_global_heap_object_into(
            &mut guard.reader,
            &crate::format::global_heap::GlobalHeapRef {
                collection_addr: heap_addr,
                object_index: heap_index,
            },
            &mut heap_data,
        )?;
        let sizeof_size = usize::from(guard.reader.sizeof_size());
        drop(guard);

        let mappings = Self::decode_virtual_mappings(&heap_data, sizeof_size)?;
        let mut source_cache = VirtualSourceCache::new();
        Self::virtual_output_dims_with_cache(
            &mappings,
            path.as_deref(),
            info,
            access,
            &mut source_cache,
        )
    }

    pub(super) fn read_virtual_dataset(
        heap_data: &[u8],
        sizeof_size: usize,
        file_path: Option<&Path>,
        info: &DatasetInfo,
        access: &DatasetAccess,
    ) -> Result<Vec<u8>> {
        let mappings = Self::decode_virtual_mappings(heap_data, sizeof_size)?;
        let element_size = usize_from_u64(u64::from(info.datatype.size), "datatype size")?;

        let mut source_cache = VirtualSourceCache::new();
        let output_dims = Self::virtual_output_dims_with_cache(
            &mappings,
            file_path,
            info,
            access,
            &mut source_cache,
        )?;
        let total_elements = usize_from_u64(
            Self::dataspace_element_count(info.dataspace.space_type, &output_dims)?,
            "virtual dataset element count",
        )?;
        let mut output = Self::filled_data(total_elements, element_size, info)?;
        Self::populate_virtual_dataset_output(
            mappings,
            file_path,
            info,
            access,
            &output_dims,
            element_size,
            &mut output,
            &mut source_cache,
        )?;
        Ok(output)
    }

    pub(super) fn read_virtual_dataset_into(
        heap_data: &[u8],
        sizeof_size: usize,
        file_path: Option<&Path>,
        info: &DatasetInfo,
        access: &DatasetAccess,
        output: &mut [u8],
    ) -> Result<()> {
        let mappings = Self::decode_virtual_mappings(heap_data, sizeof_size)?;
        let element_size = usize_from_u64(u64::from(info.datatype.size), "datatype size")?;

        let mut source_cache = VirtualSourceCache::new();
        let output_dims = Self::virtual_output_dims_with_cache(
            &mappings,
            file_path,
            info,
            access,
            &mut source_cache,
        )?;
        let total_elements = usize_from_u64(
            Self::dataspace_element_count(info.dataspace.space_type, &output_dims)?,
            "virtual dataset element count",
        )?;
        let expected = total_elements
            .checked_mul(element_size)
            .ok_or_else(|| Error::InvalidFormat("virtual dataset byte size overflow".into()))?;
        if output.len() != expected {
            return Err(Error::InvalidFormat(format!(
                "raw output buffer has {} bytes, expected {expected}",
                output.len()
            )));
        }
        Self::filled_data_into(total_elements, element_size, info, output)?;
        Self::populate_virtual_dataset_output(
            mappings,
            file_path,
            info,
            access,
            &output_dims,
            element_size,
            output,
            &mut source_cache,
        )
    }

    fn populate_virtual_dataset_output(
        mappings: Vec<VirtualMapping>,
        file_path: Option<&Path>,
        info: &DatasetInfo,
        access: &DatasetAccess,
        output_dims: &[u64],
        element_size: usize,
        output: &mut [u8],
        source_cache: &mut VirtualSourceCache,
    ) -> Result<()> {
        let virtual_strides = Self::row_major_strides(&output_dims)?;

        for mapping in mappings {
            let (source_info, source_raw) =
                match source_cache.source_raw(file_path, &mapping, info, access) {
                    Ok(source) => source,
                    Err(err) if Self::should_fill_missing_virtual_source(&err, access) => {
                        continue;
                    }
                    Err(err) => return Err(err),
                };
            Self::copy_virtual_mapping(
                &mapping,
                source_raw,
                &source_info.dataspace.dims,
                &virtual_strides,
                output_dims,
                element_size,
                output,
            )?;
        }
        Ok(())
    }

    fn should_fill_missing_virtual_source(err: &Error, access: &DatasetAccess) -> bool {
        access.virtual_missing_source_policy() == VdsMissingSourcePolicy::Fill
            && matches!(err, Error::Io(io_err) if io_err.kind() == std::io::ErrorKind::NotFound)
    }

    fn copy_virtual_mapping(
        mapping: &VirtualMapping,
        source_raw: &[u8],
        source_dims: &[u64],
        virtual_strides: &[usize],
        output_dims: &[u64],
        element_size: usize,
        output: &mut [u8],
    ) -> Result<()> {
        let source_strides = Self::row_major_strides(source_dims)?;
        let source_indexes = Self::virtual_source_element_indexes(
            &mapping.source_select,
            source_dims,
            &source_strides,
        )?;
        let mut copied_points = 0usize;
        Self::visit_virtual_selection_points(&mapping.virtual_select, output_dims, |dst| {
            let src_index = source_indexes
                .linear_index(copied_points, &source_strides)?
                .ok_or_else(|| {
                    Error::InvalidFormat(
                        "virtual dataset source and destination selections differ in size".into(),
                    )
                })?;
            let dst_index = Self::linear_index(dst, virtual_strides)?;
            copied_points += 1;
            Self::copy_virtual_element(source_raw, src_index, dst_index, element_size, output)
        })?;
        if copied_points != source_indexes.len() {
            return Err(Error::InvalidFormat(
                "virtual dataset source and destination selections differ in size".into(),
            ));
        }
        Ok(())
    }

    fn virtual_source_element_indexes<'a>(
        selection: &'a VirtualSelection,
        dims: &[u64],
        strides: &[usize],
    ) -> Result<VirtualSourceElementIndexes<'a>> {
        match selection {
            VirtualSelection::All => Ok(VirtualSourceElementIndexes::All {
                len: usize_from_u64(
                    dims.iter().try_fold(1u64, |total, dim| {
                        total.checked_mul(*dim).ok_or_else(|| {
                            Error::InvalidFormat("virtual source element count overflow".into())
                        })
                    })?,
                    "virtual source element count",
                )?,
            }),
            VirtualSelection::Points(points) => {
                Self::validate_virtual_point_coords(points, dims)?;
                Ok(VirtualSourceElementIndexes::Borrowed(points))
            }
            _ => Ok(VirtualSourceElementIndexes::Owned(
                Self::materialize_virtual_selection_linear_indexes(selection, dims, strides)?,
            )),
        }
    }

    fn materialize_virtual_selection_linear_indexes(
        selection: &VirtualSelection,
        dims: &[u64],
        strides: &[usize],
    ) -> Result<Vec<usize>> {
        let mut indexes = Vec::new();
        Self::visit_virtual_selection_points(selection, dims, |point| {
            indexes.push(Self::linear_index(point, strides)?);
            Ok(())
        })?;
        Ok(indexes)
    }

    fn copy_virtual_element(
        source_raw: &[u8],
        src_index: usize,
        dst_index: usize,
        element_size: usize,
        output: &mut [u8],
    ) -> Result<()> {
        let src_start = src_index
            .checked_mul(element_size)
            .ok_or_else(|| Error::InvalidFormat("virtual source byte offset overflow".into()))?;
        let dst_start = dst_index.checked_mul(element_size).ok_or_else(|| {
            Error::InvalidFormat("virtual destination byte offset overflow".into())
        })?;
        let Some(src) = checked_byte_window(
            source_raw,
            src_start,
            element_size,
            "virtual source byte range",
        )?
        else {
            return Ok(());
        };
        let Some(dst) = checked_byte_window_mut(
            output,
            dst_start,
            element_size,
            "virtual destination byte range",
        )?
        else {
            return Ok(());
        };
        dst.copy_from_slice(src);
        Ok(())
    }

    #[cfg(test)]
    pub(super) fn virtual_output_dims(
        mappings: &[VirtualMapping],
        file_path: Option<&Path>,
        info: &DatasetInfo,
        access: &DatasetAccess,
    ) -> Result<Vec<u64>> {
        let mut source_cache = VirtualSourceCache::new();
        Self::virtual_output_dims_with_cache(mappings, file_path, info, access, &mut source_cache)
    }

    fn virtual_output_dims_with_cache(
        mappings: &[VirtualMapping],
        file_path: Option<&Path>,
        info: &DatasetInfo,
        access: &DatasetAccess,
        source_cache: &mut VirtualSourceCache,
    ) -> Result<Vec<u64>> {
        let mut output_dims = info.dataspace.dims.clone();
        if output_dims.iter().all(|&dim| dim != 0) {
            return Ok(output_dims);
        }
        let mut unlimited_extents: Vec<Option<(u64, u64)>> = vec![None; output_dims.len()];
        for mapping in mappings {
            let source_info = match source_cache.source_info(file_path, mapping, access) {
                Ok(source_info) => source_info,
                Err(err) if Self::should_fill_missing_virtual_source(&err, access) => {
                    for dim in 0..output_dims.len() {
                        if output_dims[dim] != 0 {
                            continue;
                        }
                        if let Some(extent) = Self::virtual_mapping_declared_output_extent(
                            &mapping.virtual_select,
                            dim,
                        )? {
                            Self::update_virtual_output_extent(
                                info,
                                &mut output_dims,
                                &mut unlimited_extents,
                                dim,
                                extent,
                            );
                        }
                    }
                    continue;
                }
                Err(err) => return Err(err),
            };
            for dim in 0..output_dims.len() {
                if output_dims[dim] != 0 {
                    continue;
                }
                let extent = Self::virtual_mapping_output_extent(
                    &mapping.source_select,
                    &mapping.virtual_select,
                    &source_info.dataspace.dims,
                    dim,
                )?;
                Self::update_virtual_output_extent(
                    info,
                    &mut output_dims,
                    &mut unlimited_extents,
                    dim,
                    extent,
                );
            }
        }
        for (dim, extents) in unlimited_extents.into_iter().enumerate() {
            if output_dims[dim] != 0 {
                continue;
            }
            if let Some((min_extent, max_extent)) = extents {
                output_dims[dim] = match access.virtual_view() {
                    VdsView::LastAvailable => max_extent,
                    VdsView::FirstMissing => min_extent,
                };
            }
        }
        Ok(output_dims)
    }

    fn update_virtual_output_extent(
        info: &DatasetInfo,
        output_dims: &mut [u64],
        unlimited_extents: &mut [Option<(u64, u64)>],
        dim: usize,
        extent: u64,
    ) {
        if Self::is_unlimited_vds_dim(info, dim) {
            let entry = &mut unlimited_extents[dim];
            match entry {
                Some((min_extent, max_extent)) => {
                    *min_extent = (*min_extent).min(extent);
                    *max_extent = (*max_extent).max(extent);
                }
                None => *entry = Some((extent, extent)),
            }
        } else {
            output_dims[dim] = output_dims[dim].max(extent);
        }
    }

    fn is_unlimited_vds_dim(info: &DatasetInfo, dim: usize) -> bool {
        info.dataspace
            .max_dims
            .as_ref()
            .and_then(|max_dims| max_dims.get(dim))
            .copied()
            == Some(u64::MAX)
    }

    pub(super) fn virtual_mapping_output_extent(
        source_select: &VirtualSelection,
        virtual_select: &VirtualSelection,
        source_dims: &[u64],
        dim: usize,
    ) -> Result<u64> {
        match virtual_select {
            VirtualSelection::All => Ok(source_dims[dim]),
            VirtualSelection::Points(points) => {
                let mut max_extent = 0u64;
                for point in points {
                    let extent = point[dim].checked_add(1).ok_or_else(|| {
                        Error::InvalidFormat("virtual point-selection extent overflow".into())
                    })?;
                    max_extent = max_extent.max(extent);
                }
                Ok(max_extent)
            }
            VirtualSelection::Regular(_) => Self::virtual_selection_start(virtual_select, dim)
                .checked_add(Self::virtual_selection_span(
                    source_select,
                    source_dims,
                    dim,
                )?)
                .ok_or_else(|| Error::InvalidFormat("virtual selection extent overflow".into())),
            VirtualSelection::Irregular(blocks) => {
                Ok(blocks.iter().try_fold(0u64, |max_extent, block| {
                    block.start[dim]
                        .checked_add(block.block[dim])
                        .map(|extent| max_extent.max(extent))
                        .ok_or_else(|| {
                            Error::InvalidFormat(
                                "virtual irregular-selection extent overflow".into(),
                            )
                        })
                })?)
            }
        }
    }

    pub(super) fn virtual_mapping_declared_output_extent(
        virtual_select: &VirtualSelection,
        dim: usize,
    ) -> Result<Option<u64>> {
        match virtual_select {
            VirtualSelection::All => Ok(None),
            VirtualSelection::Points(points) => {
                let mut max_extent = 0u64;
                for point in points {
                    let extent = point[dim].checked_add(1).ok_or_else(|| {
                        Error::InvalidFormat(
                            "virtual declared point-selection extent overflow".into(),
                        )
                    })?;
                    max_extent = max_extent.max(extent);
                }
                Ok(Some(max_extent))
            }
            VirtualSelection::Regular(selection) => {
                if selection.count[dim] == u64::MAX || selection.block[dim] == u64::MAX {
                    return Ok(None);
                }
                if selection.count[dim] == 0 {
                    return Ok(Some(selection.start[dim]));
                }
                let stride = selection.stride[dim].max(1);
                let selected_span = selection.count[dim]
                    .checked_sub(1)
                    .and_then(|count| count.checked_mul(stride))
                    .and_then(|offset| offset.checked_add(selection.block[dim]))
                    .ok_or_else(|| {
                        Error::InvalidFormat("virtual declared selection extent overflow".into())
                    })?;
                Ok(Some(
                    selection.start[dim]
                        .checked_add(selected_span)
                        .ok_or_else(|| {
                            Error::InvalidFormat(
                                "virtual declared selection extent overflow".into(),
                            )
                        })?,
                ))
            }
            VirtualSelection::Irregular(blocks) => {
                let mut max_extent = 0u64;
                for block in blocks {
                    let extent =
                        block.start[dim]
                            .checked_add(block.block[dim])
                            .ok_or_else(|| {
                                Error::InvalidFormat(
                                    "virtual declared irregular-selection extent overflow".into(),
                                )
                            })?;
                    max_extent = max_extent.max(extent);
                }
                Ok(Some(max_extent))
            }
        }
    }

    #[cfg(test)]
    pub(super) fn materialize_virtual_selection_points(
        selection: &VirtualSelection,
        dims: &[u64],
    ) -> Result<Vec<Vec<u64>>> {
        match selection {
            VirtualSelection::All => {
                let all = RegularHyperslab {
                    start: vec![0; dims.len()],
                    stride: vec![1; dims.len()],
                    count: vec![1; dims.len()],
                    block: dims.to_vec(),
                };
                Self::materialize_regular_hyperslab_points(&all, dims)
            }
            VirtualSelection::Points(points) => {
                Self::validate_virtual_point_coords(points, dims)?;
                Ok(points.clone())
            }
            VirtualSelection::Regular(selection) => {
                Self::materialize_regular_hyperslab_points(selection, dims)
            }
            VirtualSelection::Irregular(blocks) => {
                Self::materialize_irregular_hyperslab_points(blocks, dims)
            }
        }
    }

    fn visit_virtual_selection_points<F>(
        selection: &VirtualSelection,
        dims: &[u64],
        mut visit: F,
    ) -> Result<()>
    where
        F: FnMut(&[u64]) -> Result<()>,
    {
        match selection {
            VirtualSelection::All => {
                let mut current = vec![0u64; dims.len()];
                Self::visit_all_selection_points(dims, 0, &mut current, &mut visit)
            }
            VirtualSelection::Points(points) => {
                Self::validate_virtual_point_coords(points, dims)?;
                for point in points {
                    visit(point)?;
                }
                Ok(())
            }
            VirtualSelection::Regular(selection) => {
                let mut current = vec![0u64; dims.len()];
                Self::visit_regular_hyperslab_points(selection, dims, 0, &mut current, &mut visit)
            }
            VirtualSelection::Irregular(blocks) => {
                let mut current = vec![0u64; dims.len()];
                for block in blocks {
                    if block.start.len() != dims.len() || block.block.len() != dims.len() {
                        return Err(Error::InvalidFormat(
                            "virtual hyperslab rank does not match dataspace".into(),
                        ));
                    }
                    Self::visit_irregular_block_points(block, dims, 0, &mut current, &mut visit)?;
                }
                Ok(())
            }
        }
    }

    #[cfg(test)]
    fn materialize_regular_hyperslab_points(
        selection: &RegularHyperslab,
        dims: &[u64],
    ) -> Result<Vec<Vec<u64>>> {
        if selection.start.len() != dims.len() {
            return Err(Error::InvalidFormat(
                "virtual hyperslab rank does not match dataspace".into(),
            ));
        }
        let mut points = Vec::new();
        let mut current = vec![0u64; dims.len()];
        Self::push_hyperslab_points(selection, dims, 0, &mut current, &mut points)?;
        Ok(points)
    }

    fn visit_all_selection_points<F>(
        dims: &[u64],
        dim: usize,
        current: &mut [u64],
        visit: &mut F,
    ) -> Result<()>
    where
        F: FnMut(&[u64]) -> Result<()>,
    {
        if dim == dims.len() {
            return visit(current);
        }
        for coord in 0..dims[dim] {
            current[dim] = coord;
            Self::visit_all_selection_points(dims, dim + 1, current, visit)?;
        }
        Ok(())
    }

    pub(super) fn virtual_selection_start(selection: &VirtualSelection, dim: usize) -> u64 {
        match selection {
            VirtualSelection::All => 0,
            VirtualSelection::Points(points) => {
                points.iter().map(|point| point[dim]).min().unwrap_or(0)
            }
            VirtualSelection::Regular(selection) => selection.start[dim],
            VirtualSelection::Irregular(blocks) => blocks
                .iter()
                .map(|block| block.start[dim])
                .min()
                .unwrap_or(0),
        }
    }

    pub(super) fn virtual_selection_span(
        selection: &VirtualSelection,
        dims: &[u64],
        dim: usize,
    ) -> Result<u64> {
        match selection {
            VirtualSelection::All => Ok(dims[dim]),
            VirtualSelection::Points(points) => {
                if points.is_empty() {
                    return Ok(0);
                }
                let start = Self::virtual_selection_start(selection, dim);
                let end = points.iter().map(|point| point[dim]).max().ok_or_else(|| {
                    Error::InvalidFormat("virtual point-selection is empty".into())
                })?;
                end.checked_add(1)
                    .and_then(|extent| extent.checked_sub(start))
                    .ok_or_else(|| {
                        Error::InvalidFormat("virtual point-selection span overflow".into())
                    })
            }
            VirtualSelection::Regular(selection) => {
                Self::regular_hyperslab_selected_span(selection, dims, dim)
            }
            VirtualSelection::Irregular(blocks) => {
                if blocks.is_empty() {
                    return Ok(0);
                }
                let start = Self::virtual_selection_start(selection, dim);
                let end = blocks.iter().try_fold(0u64, |max_extent, block| {
                    block.start[dim]
                        .checked_add(block.block[dim])
                        .map(|extent| max_extent.max(extent))
                        .ok_or_else(|| {
                            Error::InvalidFormat("virtual irregular-selection span overflow".into())
                        })
                })?;
                end.checked_sub(start).ok_or_else(|| {
                    Error::InvalidFormat("virtual irregular-selection span overflow".into())
                })
            }
        }
    }

    fn regular_hyperslab_selected_span(
        selection: &RegularHyperslab,
        dims: &[u64],
        dim: usize,
    ) -> Result<u64> {
        let start = selection.start[dim];
        let stride = selection.stride[dim].max(1);
        let count = if selection.count[dim] == u64::MAX {
            let remaining = Self::virtual_hyperslab_remaining(dims[dim], start)?;
            Self::ceil_div_u64(remaining, stride, "virtual regular hyperslab span")?
        } else {
            selection.count[dim]
        };
        let block = if selection.block[dim] == u64::MAX {
            Self::virtual_hyperslab_remaining(dims[dim], start)?
        } else {
            selection.block[dim]
        };
        if count == 0 {
            Ok(0)
        } else {
            count
                .checked_sub(1)
                .and_then(|value| value.checked_mul(stride))
                .and_then(|value| value.checked_add(block))
                .ok_or_else(|| {
                    Error::InvalidFormat("virtual regular hyperslab span overflow".into())
                })
        }
    }

    #[cfg(test)]
    fn push_hyperslab_points(
        selection: &RegularHyperslab,
        dims: &[u64],
        dim: usize,
        current: &mut [u64],
        points: &mut Vec<Vec<u64>>,
    ) -> Result<()> {
        if dim == dims.len() {
            points.push(current.to_vec());
            return Ok(());
        }
        let start = selection.start[dim];
        let stride = selection.stride[dim].max(1);
        let count = if selection.count[dim] == u64::MAX {
            let remaining = Self::virtual_hyperslab_remaining(dims[dim], start)?;
            Self::ceil_div_u64(remaining, stride, "virtual hyperslab point count")?
        } else {
            selection.count[dim]
        };
        let block = if selection.block[dim] == u64::MAX {
            Self::virtual_hyperslab_remaining(dims[dim], start)?
        } else {
            selection.block[dim]
        };

        for count_idx in 0..count {
            let base = count_idx
                .checked_mul(stride)
                .and_then(|offset| start.checked_add(offset))
                .ok_or_else(|| {
                    Error::InvalidFormat("virtual hyperslab coordinate overflow".into())
                })?;
            for block_idx in 0..block {
                let coord = base.checked_add(block_idx).ok_or_else(|| {
                    Error::InvalidFormat("virtual hyperslab coordinate overflow".into())
                })?;
                if coord < dims[dim] {
                    current[dim] = coord;
                    Self::push_hyperslab_points(selection, dims, dim + 1, current, points)?;
                }
            }
        }
        Ok(())
    }

    fn visit_regular_hyperslab_points<F>(
        selection: &RegularHyperslab,
        dims: &[u64],
        dim: usize,
        current: &mut [u64],
        visit: &mut F,
    ) -> Result<()>
    where
        F: FnMut(&[u64]) -> Result<()>,
    {
        if selection.start.len() != dims.len() {
            return Err(Error::InvalidFormat(
                "virtual hyperslab rank does not match dataspace".into(),
            ));
        }
        if dim == dims.len() {
            return visit(current);
        }
        let start = selection.start[dim];
        let stride = selection.stride[dim].max(1);
        let count = if selection.count[dim] == u64::MAX {
            let remaining = Self::virtual_hyperslab_remaining(dims[dim], start)?;
            Self::ceil_div_u64(remaining, stride, "virtual hyperslab point count")?
        } else {
            selection.count[dim]
        };
        let block = if selection.block[dim] == u64::MAX {
            Self::virtual_hyperslab_remaining(dims[dim], start)?
        } else {
            selection.block[dim]
        };

        for count_idx in 0..count {
            let base = count_idx
                .checked_mul(stride)
                .and_then(|offset| start.checked_add(offset))
                .ok_or_else(|| {
                    Error::InvalidFormat("virtual hyperslab coordinate overflow".into())
                })?;
            for block_idx in 0..block {
                let coord = base.checked_add(block_idx).ok_or_else(|| {
                    Error::InvalidFormat("virtual hyperslab coordinate overflow".into())
                })?;
                if coord < dims[dim] {
                    current[dim] = coord;
                    Self::visit_regular_hyperslab_points(selection, dims, dim + 1, current, visit)?;
                }
            }
        }
        Ok(())
    }

    fn virtual_hyperslab_remaining(dim_extent: u64, start: u64) -> Result<u64> {
        dim_extent.checked_sub(start).ok_or_else(|| {
            Error::InvalidFormat("virtual regular hyperslab start exceeds dataspace extent".into())
        })
    }

    fn ceil_div_u64(value: u64, divisor: u64, context: &str) -> Result<u64> {
        if divisor == 0 {
            return Err(Error::InvalidFormat(format!("{context} divisor is zero")));
        }
        if value == 0 {
            return Ok(0);
        }
        value
            .checked_sub(1)
            .and_then(|v| v.checked_div(divisor))
            .and_then(|v| v.checked_add(1))
            .ok_or_else(|| Error::InvalidFormat(format!("{context} overflow")))
    }

    #[cfg(test)]
    fn materialize_irregular_hyperslab_points(
        blocks: &[IrregularHyperslabBlock],
        dims: &[u64],
    ) -> Result<Vec<Vec<u64>>> {
        let mut points = Vec::new();
        for block in blocks {
            if block.start.len() != dims.len() || block.block.len() != dims.len() {
                return Err(Error::InvalidFormat(
                    "virtual hyperslab rank does not match dataspace".into(),
                ));
            }
            let mut current = vec![0u64; dims.len()];
            Self::push_irregular_block_points(block, dims, 0, &mut current, &mut points)?;
        }
        Ok(points)
    }

    #[cfg(test)]
    fn push_irregular_block_points(
        block: &IrregularHyperslabBlock,
        dims: &[u64],
        dim: usize,
        current: &mut [u64],
        points: &mut Vec<Vec<u64>>,
    ) -> Result<()> {
        if dim == dims.len() {
            points.push(current.to_vec());
            return Ok(());
        }
        for offset in 0..block.block[dim] {
            let coord = block.start[dim].checked_add(offset).ok_or_else(|| {
                Error::InvalidFormat("virtual irregular hyperslab coordinate overflow".into())
            })?;
            if coord < dims[dim] {
                current[dim] = coord;
                Self::push_irregular_block_points(block, dims, dim + 1, current, points)?;
            }
        }
        Ok(())
    }

    fn visit_irregular_block_points<F>(
        block: &IrregularHyperslabBlock,
        dims: &[u64],
        dim: usize,
        current: &mut [u64],
        visit: &mut F,
    ) -> Result<()>
    where
        F: FnMut(&[u64]) -> Result<()>,
    {
        if dim == dims.len() {
            return visit(current);
        }
        for offset in 0..block.block[dim] {
            let coord = block.start[dim].checked_add(offset).ok_or_else(|| {
                Error::InvalidFormat("virtual irregular hyperslab coordinate overflow".into())
            })?;
            if coord < dims[dim] {
                current[dim] = coord;
                Self::visit_irregular_block_points(block, dims, dim + 1, current, visit)?;
            }
        }
        Ok(())
    }

    fn validate_virtual_point_coords(points: &[Vec<u64>], dims: &[u64]) -> Result<()> {
        for point in points {
            if point.len() != dims.len() {
                return Err(Error::InvalidFormat(
                    "virtual point-selection rank does not match dataspace".into(),
                ));
            }
            for (&coord, &dim_extent) in point.iter().zip(dims) {
                if coord >= dim_extent {
                    return Err(Error::InvalidFormat(
                        "virtual point-selection coordinate exceeds dataspace extent".into(),
                    ));
                }
            }
        }
        Ok(())
    }
}

fn checked_byte_window<'a>(
    data: &'a [u8],
    offset: usize,
    len: usize,
    context: &str,
) -> Result<Option<&'a [u8]>> {
    let end = offset
        .checked_add(len)
        .ok_or_else(|| Error::InvalidFormat(format!("{context} overflow")))?;
    Ok(data.get(offset..end))
}

fn checked_byte_window_mut<'a>(
    data: &'a mut [u8],
    offset: usize,
    len: usize,
    context: &str,
) -> Result<Option<&'a mut [u8]>> {
    let end = offset
        .checked_add(len)
        .ok_or_else(|| Error::InvalidFormat(format!("{context} overflow")))?;
    Ok(data.get_mut(offset..end))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn checked_byte_window_rejects_offset_overflow() {
        let err = checked_byte_window(&[], usize::MAX, 1, "virtual test range").unwrap_err();
        assert!(
            err.to_string().contains("virtual test range overflow"),
            "unexpected error: {err}"
        );
    }

    #[test]
    fn checked_byte_window_mut_rejects_offset_overflow() {
        let mut data = [];
        let err =
            checked_byte_window_mut(&mut data, usize::MAX, 1, "virtual test range").unwrap_err();
        assert!(
            err.to_string().contains("virtual test range overflow"),
            "unexpected error: {err}"
        );
    }
}
