use termichart_core::{ChartConfig, Rect};

/// The number of columns reserved for the Y-axis labels and tick marks.
const Y_AXIS_WIDTH: u16 = 10;
/// The number of rows reserved for the X-axis line and labels.
const X_AXIS_HEIGHT: u16 = 2;
/// The number of rows reserved for the chart title.
const TITLE_HEIGHT: u16 = 1;

/// Describes how the total available area is partitioned into sub-regions for
/// the chart, axes, and title.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Layout {
    /// The rectangular area for the main chart plot.
    pub chart_area: Rect,
    /// The rectangular area for the Y-axis (left side).
    pub y_axis_area: Rect,
    /// The rectangular area for the X-axis (bottom).
    pub x_axis_area: Rect,
    /// The rectangular area for the title (top), if present.
    pub title_area: Option<Rect>,
}

impl Layout {
    /// Computes a layout given the total available width and height (in
    /// character cells) and the chart configuration.
    ///
    /// - If `config.show_axis` is `true`, 10 columns on the left are reserved
    ///   for the Y-axis labels and 2 rows at the bottom for the X-axis.
    /// - If `config.title` is `Some(...)`, 1 row at the top is reserved for
    ///   the title.
    /// - The chart area receives whatever remains.
    pub fn compute(total_width: u16, total_height: u16, config: &ChartConfig) -> Self {
        let mut top: u16 = 0;
        let mut left: u16 = 0;
        let mut bottom_reserved: u16 = 0;

        // Title row.
        let title_area = if config.title.is_some() {
            let area = Rect {
                x: 0,
                y: 0,
                width: total_width,
                height: TITLE_HEIGHT,
            };
            top += TITLE_HEIGHT;
            Some(area)
        } else {
            None
        };

        // Axis reservations.
        let (y_axis_area, x_axis_area) = if config.show_axis {
            let y_w = Y_AXIS_WIDTH.min(total_width);
            left = y_w;

            let x_h = X_AXIS_HEIGHT.min(total_height.saturating_sub(top));
            bottom_reserved = x_h;

            let y_area = Rect {
                x: 0,
                y: top,
                width: y_w,
                height: total_height.saturating_sub(top).saturating_sub(x_h),
            };

            let x_area = Rect {
                x: left,
                y: total_height.saturating_sub(x_h),
                width: total_width.saturating_sub(left),
                height: x_h,
            };

            (y_area, x_area)
        } else {
            let empty = Rect {
                x: 0,
                y: 0,
                width: 0,
                height: 0,
            };
            (empty, empty)
        };

        // Chart area: whatever is left.
        let chart_area = Rect {
            x: left,
            y: top,
            width: total_width.saturating_sub(left),
            height: total_height
                .saturating_sub(top)
                .saturating_sub(bottom_reserved),
        };

        Self {
            chart_area,
            y_axis_area,
            x_axis_area,
            title_area,
        }
    }
}
