//! Shared pagination bounds for the `/_ops` list handlers.
//!
//! Centralised so every list endpoint clamps to the same page sizes and
//! shares one scan ceiling — the limits are a contract on response size, not
//! per-handler magic numbers.

/// Page size applied when a caller omits `limit`.
pub(crate) const DEFAULT_LIMIT: usize = 50;

/// Hard upper bound on `limit`; a larger caller value is clamped down so a
/// single request can never ask the store for an unbounded page.
pub(crate) const MAX_LIMIT: usize = 200;

/// Largest number of rows a handler will scan before it must paginate at the
/// store layer instead. Stores MUST treat this as a simple row limit, never an
/// unbounded query; handlers that exceed it in memory log a warning.
pub(crate) const AGGREGATION_SCAN_LIMIT: usize = 10_000;

/// Clamp a caller-supplied `limit` to the `[_, MAX_LIMIT]` page bound,
/// defaulting an absent value to [`DEFAULT_LIMIT`].
pub(crate) fn clamp_limit(limit: Option<usize>) -> usize {
    limit.unwrap_or(DEFAULT_LIMIT).min(MAX_LIMIT)
}

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

    #[test]
    fn clamp_limit_defaults_when_absent() {
        assert_eq!(clamp_limit(None), DEFAULT_LIMIT);
    }

    #[test]
    fn clamp_limit_caps_at_max() {
        assert_eq!(clamp_limit(Some(MAX_LIMIT + 1_000)), MAX_LIMIT);
    }

    #[test]
    fn clamp_limit_keeps_value_under_max() {
        assert_eq!(clamp_limit(Some(7)), 7);
    }
}
