/// Breakpoints — named viewport width thresholds.
///
/// These are provided for the rare cases where you need explicit breakpoint
/// logic. For most cases, use the automatic layout in VStack/HStack/Grid.

/// Named breakpoint sizes (in dp/logical pixels).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Breakpoint {
    /// Default — any width (the base / mobile-first value).
    Base,
    /// Small — 640dp+ (large phones, landscape phones).
    Sm,
    /// Medium — 768dp+ (tablets, small laptops).
    Md,
    /// Large — 1024dp+ (laptops, most desktops).
    Lg,
    /// Extra large — 1280dp+ (large desktops, wide monitors).
    Xl,
}

impl Breakpoint {
    /// The minimum width (dp) at which this breakpoint activates.
    pub fn min_width(&self) -> f32 {
        match self {
            Breakpoint::Base => 0.0,
            Breakpoint::Sm => 640.0,
            Breakpoint::Md => 768.0,
            Breakpoint::Lg => 1024.0,
            Breakpoint::Xl => 1280.0,
        }
    }

    /// Classify a container width into its active breakpoint.
    pub fn for_width(width: f32) -> Self {
        if width >= 1280.0 {
            Breakpoint::Xl
        } else if width >= 1024.0 {
            Breakpoint::Lg
        } else if width >= 768.0 {
            Breakpoint::Md
        } else if width >= 640.0 {
            Breakpoint::Sm
        } else {
            Breakpoint::Base
        }
    }

    /// True if this breakpoint is at least as wide as `other`.
    pub fn at_least(&self, other: Breakpoint) -> bool {
        self >= &other
    }
}

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

    #[test]
    fn breakpoint_for_small_width() {
        assert_eq!(Breakpoint::for_width(320.0), Breakpoint::Base);
    }

    #[test]
    fn breakpoint_for_tablet_width() {
        assert_eq!(Breakpoint::for_width(800.0), Breakpoint::Md);
    }

    #[test]
    fn breakpoint_for_desktop_width() {
        assert_eq!(Breakpoint::for_width(1440.0), Breakpoint::Xl);
    }

    #[test]
    fn breakpoint_ordering() {
        assert!(Breakpoint::Xl > Breakpoint::Base);
        assert!(Breakpoint::Lg > Breakpoint::Sm);
    }

    #[test]
    fn at_least() {
        assert!(Breakpoint::Lg.at_least(Breakpoint::Md));
        assert!(!Breakpoint::Sm.at_least(Breakpoint::Md));
    }

    #[test]
    fn min_widths_ascending() {
        let bps = [
            Breakpoint::Base,
            Breakpoint::Sm,
            Breakpoint::Md,
            Breakpoint::Lg,
            Breakpoint::Xl,
        ];
        for i in 1..bps.len() {
            assert!(bps[i].min_width() > bps[i - 1].min_width());
        }
    }
}
