use serde::{Deserialize, Serialize};

use super::geometry::{LayoutPx, LayoutSize};
use super::retained::ScrollOffset;

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ScrollAxes {
    Horizontal,
    Vertical,
    Both,
}

impl ScrollAxes {
    #[must_use]
    pub const fn allows_horizontal(self) -> bool {
        matches!(self, Self::Horizontal | Self::Both)
    }

    #[must_use]
    pub const fn allows_vertical(self) -> bool {
        matches!(self, Self::Vertical | Self::Both)
    }
}

#[must_use]
pub fn clamp_scroll(
    requested: ScrollOffset,
    viewport: LayoutSize,
    content: LayoutSize,
    axes: ScrollAxes,
) -> ScrollOffset {
    ScrollOffset {
        x: clamp_axis(
            requested.x,
            viewport.width,
            content.width,
            axes.allows_horizontal(),
        ),
        y: clamp_axis(
            requested.y,
            viewport.height,
            content.height,
            axes.allows_vertical(),
        ),
    }
}

fn clamp_axis(
    requested: LayoutPx,
    viewport: LayoutPx,
    content: LayoutPx,
    allowed: bool,
) -> LayoutPx {
    if !allowed {
        return LayoutPx::ZERO;
    }
    let max = (content.value() - viewport.value()).max(0.0);
    LayoutPx::new(requested.value().clamp(0.0, max))
}
