//! pagination — Pagination helpers.
//!
//! Every paginated list endpoint returns a single [`Page<T>`] via
//! `.send().await` or an auto-paginating stream via `.stream()`.

use serde::Deserialize;

/// A single page of paginated results.
///
/// `items` holds the rows for the current page. `total` is the server's
/// count of all matching rows across every page. `limit` is the effective
/// page size the server applied. `next_page_token` is present when more
/// pages remain.
///
/// # Examples
///
/// ```no_run
/// # async fn example() -> ticksupply::Result<()> {
/// let client = ticksupply::Client::new()?;
/// let page = client.subscriptions().list().limit(25).send().await?;
/// println!("fetched {} of {:?}", page.items.len(), page.total);
/// if let Some(token) = page.next_page_token.as_deref() {
///     let _next = client.subscriptions().list().page_token(token).send().await?;
/// }
/// # Ok(()) }
/// ```
#[derive(Debug, Clone, Deserialize)]
pub struct Page<T> {
    /// Rows in this page.
    pub items: Vec<T>,

    /// Total count across all pages.
    #[serde(default)]
    pub total: Option<u64>,

    /// Effective page size applied by the server.
    #[serde(default)]
    pub limit: Option<u32>,

    /// Opaque token for the next page; `None` on the last page.
    #[serde(default)]
    pub next_page_token: Option<String>,
}

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

    #[derive(Debug, Deserialize, PartialEq, Eq)]
    struct Thing {
        id: String,
    }

    #[test]
    fn deserializes_full_page() {
        let json =
            r#"{"items":[{"id":"a"},{"id":"b"}],"total":42,"limit":50,"next_page_token":"tok_1"}"#;
        let page: Page<Thing> = serde_json::from_str(json).unwrap();
        assert_eq!(page.items.len(), 2);
        assert_eq!(page.total, Some(42));
        assert_eq!(page.limit, Some(50));
        assert_eq!(page.next_page_token.as_deref(), Some("tok_1"));
    }

    #[test]
    fn deserializes_final_page_without_token() {
        let json = r#"{"items":[{"id":"z"}],"total":1,"limit":50}"#;
        let page: Page<Thing> = serde_json::from_str(json).unwrap();
        assert_eq!(page.items, vec![Thing { id: "z".into() }]);
        assert_eq!(page.next_page_token, None);
    }
}
