use std::path::PathBuf;

use common::counter::hardware_counter::HardwareCounterCell;
use common::universal_io::{OkNotFound, UniversalRead};
use gridstore::error::GridstoreError;
use gridstore::{Blob, GridstoreReader};

use super::super::MapIndexKey;
use super::super::inner::MutableMapIndexInner;
use super::ReadOnlyAppendableMapIndex;
use crate::common::operation_error::OperationResult;

impl<N: MapIndexKey + ?Sized, S: UniversalRead> ReadOnlyAppendableMapIndex<N, S>
where
    Vec<<N as MapIndexKey>::Owned>: Blob + Send + Sync,
{
    /// Open the appendable (Gridstore) map index read-only, threading every
    /// file open through the filesystem handle `fs`.
    ///
    /// Opens a [`GridstoreReader`] over the generic filesystem object, then
    /// rebuilds the in-memory state by feeding every stored value through
    /// [`MutableMapIndexInner::ingest`] — the exact reconstruction the writable
    /// [`MutableMapIndex::open_gridstore`][1] performs over a writable
    /// [`gridstore::Gridstore`]. No write path; the reader is retained for
    /// later `files` / `clear_cache` use.
    ///
    /// Returns [`Ok(None)`] when the on-disk directory doesn't exist, matching
    /// the `create_if_missing == false` branch of the writable counterpart —
    /// the read path never creates.
    ///
    /// [1]: super::super::MutableMapIndex::open_gridstore
    pub fn open(fs: &S::Fs, path: PathBuf) -> OperationResult<Option<Self>> {
        let Some(storage) =
            GridstoreReader::<Vec<<N as MapIndexKey>::Owned>, S>::open(fs, path).ok_not_found()?
        else {
            // Files don't exist, cannot load
            return Ok(None);
        };

        let mut inner = MutableMapIndexInner::<N>::empty();
        let hw_counter = HardwareCounterCell::disposable();
        storage.iter::<_, GridstoreError>(
            storage.max_point_offset(),
            |idx, values: Vec<_>| {
                for value in values {
                    inner.ingest(idx, value);
                }
                Ok(true)
            },
            hw_counter.ref_payload_index_io_write_counter(),
        )?;

        Ok(Some(Self { inner, storage }))
    }
}
