//! Generic pagination helpers behind the `stream` feature.
//!
//! Most CNB list endpoints take `page` + `page_size` query parameters and
//! return a JSON array of items (sometimes wrapped in a typed `Vec<T>` DTO).
//! [`paginate`] turns any such "give me page N" closure into a
//! `futures::Stream` that transparently advances pages until the server
//! returns a short page or an empty page.
//!
//! Generated resource modules expose `*_stream(...)` variants that wrap their
//! single-page method with this helper.
//!
//! # Example
//!
//! ```ignore
//! use cnb::{ApiClient, pagination::paginate};
//! use futures::StreamExt;
//!
//! let client = ApiClient::new()?;
//! let stream = paginate(50, |page, page_size| {
//!     let c = client.clone();
//!     async move {
//!         let q = cnb::repositories::GetReposQuery::new()
//!             .page(page)
//!             .page_size(page_size);
//!         c.repositories().get_repos(&q).await
//!     }
//! });
//! futures::pin_mut!(stream);
//! while let Some(item) = stream.next().await {
//!     let item = item?;
//!     println!("{item:?}");
//! }
//! # Ok::<_, cnb::ApiError>(())
//! ```

#[cfg(feature = "stream")]
use std::future::Future;

#[cfg(feature = "stream")]
use crate::error::Result;

/// Paginate a list endpoint into an `impl Stream<Item = Result<T>>`.
///
/// `page_size` is forwarded to the closure. Pagination stops when the server
/// returns fewer than `page_size` items or an empty page. Errors short-circuit
/// the stream.
#[cfg(feature = "stream")]
pub fn paginate<T, F, Fut>(
    page_size: i64,
    mut fetch_page: F,
) -> impl futures::Stream<Item = Result<T>>
where
    T: 'static,
    F: FnMut(i64, i64) -> Fut + 'static,
    Fut: Future<Output = Result<Vec<T>>> + 'static,
{
    async_stream::try_stream! {
        let mut page: i64 = 1;
        loop {
            let chunk = fetch_page(page, page_size).await?;
            let len = chunk.len();
            for item in chunk {
                yield item;
            }
            if (len as i64) < page_size {
                break;
            }
            page += 1;
        }
    }
}
