// SPDX-FileCopyrightText: Politik im Blick developers
// SPDX-FileCopyrightText: Wolfgang Silbermayr <wolfgang@silbermayr.at>
//
// SPDX-License-Identifier: AGPL-3.0-or-later OR EUPL-1.2

use std::num::NonZero;

use snafu::{OptionExt, Snafu, ensure};

const PAGE_SIZE_MIN: NonZero<usize> = NonZero::new(1).unwrap();
const PAGE_SIZE_MAX: NonZero<usize> = NonZero::new(1000).unwrap();
const PAGE_SIZE_DEFAULT: NonZero<usize> = NonZero::new(100).unwrap();

#[derive(Debug, Snafu)]
#[snafu(display("Page size {value} is outside of valid range {PAGE_SIZE_MIN}..={PAGE_SIZE_MAX}"))]
pub struct TryFromPageSizeError {
    pub value: usize,
}

#[derive(
    Copy, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize,
)]
pub struct PageSize(NonZero<usize>);

impl PageSize {
    pub const DEFAULT: PageSize = Self(PAGE_SIZE_DEFAULT);
    pub const MIN: PageSize = Self(PAGE_SIZE_MIN);
    pub const MAX: PageSize = Self(PAGE_SIZE_MAX);
}

impl Default for PageSize {
    fn default() -> Self {
        Self(PAGE_SIZE_DEFAULT)
    }
}

impl TryFrom<usize> for PageSize {
    type Error = TryFromPageSizeError;

    fn try_from(value: usize) -> Result<Self, Self::Error> {
        let value = NonZero::new(value).context(TryFromPageSizeSnafu { value })?;
        ensure!(
            value <= PAGE_SIZE_MAX,
            TryFromPageSizeSnafu { value: value.get() }
        );
        Ok(Self(value))
    }
}

impl From<PageSize> for NonZero<usize> {
    fn from(PageSize(value): PageSize) -> Self {
        value
    }
}

impl From<PageSize> for usize {
    fn from(PageSize(value): PageSize) -> Self {
        value.into()
    }
}
