/// GridLayout — a responsive column grid.
///
/// The auto column mode (GridColumns::Auto) automatically computes how many
/// columns fit given a minimum column width. No breakpoints needed.
/// Fixed column count (GridColumns::Fixed) puts exactly N columns in a row.

use el_style::modifier::{StyleModifier, StyleSet};

/// How to determine the number of grid columns.
#[derive(Debug, Clone, PartialEq)]
pub enum GridColumns {
    /// A fixed number of equally-wide columns.
    Fixed(u32),
    /// As many columns as fit with each column at least `min_width` dp wide.
    /// This is how you get responsive grids without breakpoints.
    Auto { min_width: f32 },
}

impl GridColumns {
    /// Compute the actual column count given a container width.
    pub fn count_for_width(&self, container_width: f32) -> u32 {
        match self {
            GridColumns::Fixed(n) => *n,
            GridColumns::Auto { min_width } => {
                if container_width <= 0.0 || *min_width <= 0.0 {
                    return 1;
                }
                let cols = (container_width / min_width).floor() as u32;
                cols.max(1)
            }
        }
    }

    /// Compute the width of each column given container width and gap.
    pub fn column_width(&self, container_width: f32, gap: f32) -> f32 {
        let cols = self.count_for_width(container_width) as f32;
        let total_gap = gap * (cols - 1.0).max(0.0);
        ((container_width - total_gap) / cols).max(0.0)
    }
}

/// Row height specification.
#[derive(Debug, Clone, PartialEq)]
pub enum GridRows {
    /// All rows are the same height (dp).
    Fixed(f32),
    /// Rows take the height of their tallest item.
    Auto,
}

/// A responsive grid layout.
#[derive(Debug, Clone)]
pub struct GridLayout {
    pub columns: GridColumns,
    pub rows: GridRows,
    /// Horizontal gap between columns (dp).
    pub column_gap: u32,
    /// Vertical gap between rows (dp).
    pub row_gap: u32,
    pub style: StyleSet,
}

impl Default for GridLayout {
    fn default() -> Self {
        Self {
            columns: GridColumns::Auto { min_width: 200.0 },
            rows: GridRows::Auto,
            column_gap: 16,
            row_gap: 16,
            style: StyleSet::default(),
        }
    }
}

impl GridLayout {
    pub fn new() -> Self {
        Self::default()
    }

    /// Set a fixed column count.
    pub fn columns_fixed(mut self, n: u32) -> Self {
        self.columns = GridColumns::Fixed(n);
        self
    }

    /// Set auto columns with a minimum column width.
    pub fn columns_auto(mut self, min_width: f32) -> Self {
        self.columns = GridColumns::Auto { min_width };
        self
    }

    /// Set gap (same for both axes).
    pub fn gap(mut self, dp: u32) -> Self {
        self.column_gap = dp;
        self.row_gap = dp;
        self
    }

    /// Set column and row gaps separately.
    pub fn gap_xy(mut self, column_gap: u32, row_gap: u32) -> Self {
        self.column_gap = column_gap;
        self.row_gap = row_gap;
        self
    }

    /// How many columns are active at a given container width?
    pub fn active_columns(&self, container_width: f32) -> u32 {
        self.columns.count_for_width(container_width)
    }
}

impl StyleModifier for GridLayout {
    fn style_mut(&mut self) -> &mut StyleSet {
        &mut self.style
    }
}

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

    #[test]
    fn fixed_columns_always_returns_n() {
        let cols = GridColumns::Fixed(3);
        assert_eq!(cols.count_for_width(100.0), 3);
        assert_eq!(cols.count_for_width(2000.0), 3);
    }

    #[test]
    fn auto_columns_small_container() {
        let cols = GridColumns::Auto { min_width: 200.0 };
        assert_eq!(cols.count_for_width(300.0), 1);
    }

    #[test]
    fn auto_columns_medium_container() {
        let cols = GridColumns::Auto { min_width: 200.0 };
        assert_eq!(cols.count_for_width(500.0), 2);
    }

    #[test]
    fn auto_columns_wide_container() {
        let cols = GridColumns::Auto { min_width: 200.0 };
        assert_eq!(cols.count_for_width(1200.0), 6);
    }

    #[test]
    fn auto_columns_minimum_one() {
        let cols = GridColumns::Auto { min_width: 500.0 };
        assert_eq!(cols.count_for_width(100.0), 1);
    }

    #[test]
    fn column_width_with_gap() {
        let cols = GridColumns::Fixed(3);
        // 300px wide, 3 cols, 16px gap between each = 2 gaps
        // (300 - 32) / 3 = 268/3 ≈ 89.33
        let w = cols.column_width(300.0, 16.0);
        assert!((w - (300.0 - 32.0) / 3.0).abs() < 0.01);
    }

    #[test]
    fn grid_defaults() {
        let grid = GridLayout::new();
        assert_eq!(grid.column_gap, 16);
        assert_eq!(grid.row_gap, 16);
    }

    #[test]
    fn grid_active_columns_auto() {
        let grid = GridLayout::new().columns_auto(200.0);
        assert_eq!(grid.active_columns(600.0), 3);
    }

    #[test]
    fn grid_active_columns_fixed() {
        let grid = GridLayout::new().columns_fixed(4);
        assert_eq!(grid.active_columns(100.0), 4);
    }

    #[test]
    fn grid_gap_xy() {
        let grid = GridLayout::new().gap_xy(8, 24);
        assert_eq!(grid.column_gap, 8);
        assert_eq!(grid.row_gap, 24);
    }
}
