use crate::{
    PersyId,
    address::segment::segment_page_iterator::SegmentPageIterator,
    id::SegmentId,
    persy::PersyImpl,
    snapshots::SnapshotRef,
    transaction::{iter::TransactionInsertIterator, tx_impl::TransactionImpl},
};

pub struct SegmentRawIter {
    segment_id: SegmentId,
    iterator: SegmentPageIterator,
}

impl SegmentRawIter {
    pub fn new(segment_id: SegmentId, iterator: SegmentPageIterator) -> Self {
        Self { segment_id, iterator }
    }
    pub fn next(&mut self, persy_impl: &PersyImpl) -> Option<(PersyId, Vec<u8>)> {
        while let Some(id) = self.iterator.next(persy_impl.address()) {
            if let Ok(Some(val)) = persy_impl.read(self.segment_id, &id) {
                return Some((PersyId(id), val));
            }
        }
        None
    }
}

pub struct SegmentSnapshotRawIter {
    segment_id: SegmentId,
    iterator: SegmentPageIterator,
    snapshot_ref: SnapshotRef,
}

impl SegmentSnapshotRawIter {
    pub fn new(segment_id: SegmentId, iterator: SegmentPageIterator, snapshot_ref: &SnapshotRef) -> Self {
        Self {
            segment_id,
            iterator,
            snapshot_ref: snapshot_ref.clone(),
        }
    }
    pub fn next(&mut self, persy_impl: &PersyImpl) -> Option<(PersyId, Vec<u8>)> {
        while let Some(id) = self.iterator.next(persy_impl.address()) {
            if let Ok(Some(val)) = persy_impl.read_snap(self.segment_id, &id, &self.snapshot_ref) {
                return Some((PersyId(id), val));
            }
        }
        None
    }
}

pub struct TxSegmentRawIter {
    segment_id: SegmentId,
    tx_iterator: TransactionInsertIterator,
    iterator: SegmentPageIterator,
    snapshot_ref: SnapshotRef,
}

impl TxSegmentRawIter {
    pub fn new(
        tx: &TransactionImpl,
        segment_id: SegmentId,
        iterator: SegmentPageIterator,
        snapshot_ref: SnapshotRef,
    ) -> Self {
        let iter = tx.scan_insert(segment_id).into_iter();
        Self {
            segment_id,
            tx_iterator: iter,
            iterator,
            snapshot_ref,
        }
    }
    pub fn next(&mut self, persy_impl: &PersyImpl, tx: &TransactionImpl) -> Option<(PersyId, Vec<u8>, u16)> {
        let _one = &self.snapshot_ref;
        while let Some(id) = self
            .iterator
            .next(persy_impl.address())
            .or_else(|| self.tx_iterator.next())
        {
            if let Ok(Some((val, version))) = persy_impl.read_tx_internal(tx, self.segment_id, &id) {
                return Some((PersyId(id), val, version));
            }
        }
        None
    }
}
