//! Dashboard layout for multi-pane TUI applications
//!
//! Implements R-RESPONSIVE-LAYOUT: Percentage-based constraints that adapt
//! to terminal size changes automatically.

use ratatui::prelude::*;

/// Dashboard layout areas
///
/// Typical layout:
/// ```text
/// ┌─────────────────────────────────────┐
/// │        Title Bar (10%)               │
/// ├──────────────┬──────────────────────┤
/// │              │                      │
/// │  Sidebar     │   Main Content       │
/// │  (25%)       │   (75%)              │
/// │              │                      │
/// │              │                      │
/// ├──────────────┴──────────────────────┤
/// │      Status Bar (5%)                 │
/// └─────────────────────────────────────┘
/// ```
#[derive(Clone, Copy, Debug)]
pub struct DashboardAreas {
    /// Title bar area (top)
    pub title: Rect,
    /// Sidebar area (left)
    pub sidebar: Rect,
    /// Main content area (right)
    pub main: Rect,
    /// Status bar area (bottom)
    pub status: Rect,
}

impl DashboardAreas {
    /// Calculate dashboard areas based on the given space
    ///
    /// Uses percentage-based constraints:
    /// - Title: 10% of height
    /// - Sidebar: 25% of width
    /// - Main: 75% of width
    /// - Status: 5% of height
    #[must_use]
    pub fn new(area: Rect) -> Self {
        // Title bar: top 10%
        let title_height = (area.height / 10).max(1);
        let title = Rect {
            x: area.x,
            y: area.y,
            width: area.width,
            height: title_height,
        };

        // Status bar: bottom 5%
        let status_height = (area.height / 20).max(1);
        let status = Rect {
            x: area.x,
            y: area.y + area.height - status_height,
            width: area.width,
            height: status_height,
        };

        // Content area (between title and status)
        let content_height = area
            .height
            .saturating_sub(title_height)
            .saturating_sub(status_height);

        // Sidebar: 25% of width
        let sidebar_width = (area.width / 4).max(10);
        let sidebar = Rect {
            x: area.x,
            y: area.y + title_height,
            width: sidebar_width,
            height: content_height,
        };

        // Main: remaining width
        let main = Rect {
            x: area.x + sidebar_width,
            y: area.y + title_height,
            width: area.width.saturating_sub(sidebar_width),
            height: content_height,
        };

        Self {
            title,
            sidebar,
            main,
            status,
        }
    }
}

/// Dashboard layout manager
///
/// Provides a standard multi-pane layout with responsive sizing.
///
/// # Example
///
/// ```ignore
/// let layout = DashboardLayout::new("Tools Dashboard".to_string());
/// let areas = layout.areas(frame.size());
///
/// // Render into each area
/// frame.render_widget(title_widget, areas.title);
/// frame.render_widget(sidebar_widget, areas.sidebar);
/// frame.render_widget(main_widget, areas.main);
/// frame.render_widget(status_widget, areas.status);
/// ```
#[derive(Clone, Debug)]
pub struct DashboardLayout {
    /// Dashboard title
    title: String,
    /// Show borders between panes
    show_borders: bool,
}

impl DashboardLayout {
    /// Create a new dashboard layout
    #[must_use]
    pub const fn new(title: String) -> Self {
        Self {
            title,
            show_borders: true,
        }
    }

    /// Set whether to show borders
    #[must_use]
    pub const fn show_borders(mut self, show: bool) -> Self {
        self.show_borders = show;
        self
    }

    /// Get the dashboard title
    #[must_use]
    pub fn title(&self) -> &str {
        &self.title
    }

    /// Calculate areas for the given space
    #[must_use]
    pub fn areas(&self, area: Rect) -> DashboardAreas {
        DashboardAreas::new(area)
    }

    /// Draw dividing lines between panes (optional)
    pub const fn render_dividers(&self, _frame: &mut Frame, _areas: &DashboardAreas) {
        if !self.show_borders {}

        // Vertical divider between sidebar and main
        // This would require block-level rendering
        // For now, dividers are implicit in widget borders
    }
}

impl Default for DashboardLayout {
    fn default() -> Self {
        Self::new("Dashboard".to_string())
    }
}

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

    #[test]
    fn test_dashboard_areas_new() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };

        let areas = DashboardAreas::new(area);

        // Title should be ~10% of height
        assert!(areas.title.height > 0);
        assert!(areas.title.height <= 5);

        // Status should be ~5% of height
        assert!(areas.status.height > 0);

        // Sidebar should be ~25% of width
        assert!(areas.sidebar.width > 0);
        assert!(areas.sidebar.width <= 30);

        // Main should be remaining width
        assert_eq!(areas.sidebar.width + areas.main.width, area.width);
    }

    #[test]
    fn test_dashboard_areas_small_terminal() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 20,
            height: 10,
        };

        let areas = DashboardAreas::new(area);

        // All areas should be present even on small terminal
        assert!(areas.title.height > 0);
        assert!(areas.main.width > 0);
        assert!(areas.sidebar.width > 0);
    }

    #[test]
    fn test_dashboard_layout_new() {
        let layout = DashboardLayout::new("Test".to_string());
        assert_eq!(layout.title(), "Test");
        assert!(layout.show_borders);
    }

    #[test]
    fn test_dashboard_layout_show_borders() {
        let layout = DashboardLayout::new("Test".to_string()).show_borders(false);
        assert!(!layout.show_borders);
    }

    #[test]
    fn test_dashboard_layout_default() {
        let layout = DashboardLayout::default();
        assert_eq!(layout.title(), "Dashboard");
    }

    #[test]
    fn test_dashboard_areas_title_position() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };

        let areas = DashboardAreas::new(area);

        assert_eq!(areas.title.x, 0);
        assert_eq!(areas.title.y, 0);
        assert_eq!(areas.title.width, 100);
    }

    #[test]
    fn test_dashboard_areas_sidebar_position() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };

        let areas = DashboardAreas::new(area);

        assert_eq!(areas.sidebar.x, 0);
        assert!(areas.sidebar.y > 0); // Below title
    }

    #[test]
    fn test_dashboard_areas_main_position() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };

        let areas = DashboardAreas::new(area);

        assert!(areas.main.x > 0); // Right of sidebar
        assert_eq!(areas.main.y, areas.sidebar.y);
    }

    #[test]
    fn test_dashboard_areas_status_position() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };

        let areas = DashboardAreas::new(area);

        assert_eq!(areas.status.x, 0);
        assert!(areas.status.y + areas.status.height >= area.y + area.height);
    }

    #[test]
    fn test_dashboard_areas_no_overlap() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };

        let areas = DashboardAreas::new(area);

        // Title and content should not overlap
        assert_eq!(areas.title.y + areas.title.height, areas.sidebar.y);
    }

    #[test]
    fn test_dashboard_layout_clone() {
        let layout1 = DashboardLayout::new("Test".to_string());
        let layout2 = layout1.clone();
        assert_eq!(layout1.title(), layout2.title());
    }

    #[test]
    fn test_dashboard_areas_clone() {
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };
        let areas1 = DashboardAreas::new(area);
        let areas2 = areas1;
        assert_eq!(areas1.title.width, areas2.title.width);
    }

    #[test]
    fn test_dashboard_layout_areas_method() {
        let layout = DashboardLayout::new("Test".to_string());
        let area = Rect {
            x: 0,
            y: 0,
            width: 100,
            height: 50,
        };

        let areas = layout.areas(area);
        assert!(areas.title.height > 0);
    }
}
