use std::sync::Arc;

use super::axis::{Axis, CrossAxisAlign, MainAxisJustify};
use super::dock::{DockState, PanelId, SplitFraction};
use super::geometry::EdgeInsets;
use super::scroll::ScrollAxes;
use super::track::{FlexWeight, GridSpan, GridTrack};
use crate::theme::Spacing;
use crate::widget_id::WidgetId;

#[derive(Clone, Debug, PartialEq)]
pub struct GridChild {
    pub span: GridSpan,
    pub child: Layout,
}

#[derive(Clone, Debug, PartialEq)]
pub struct DockPanel {
    pub id: PanelId,
    pub child: Layout,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Layout {
    Row {
        gap: Spacing,
        justify: MainAxisJustify,
        cross: CrossAxisAlign,
        children: Vec<Layout>,
    },
    Column {
        gap: Spacing,
        justify: MainAxisJustify,
        cross: CrossAxisAlign,
        children: Vec<Layout>,
    },
    Stack {
        children: Vec<Layout>,
    },
    Grid {
        columns: Vec<GridTrack>,
        rows: Vec<GridTrack>,
        column_gap: Spacing,
        row_gap: Spacing,
        children: Vec<GridChild>,
    },
    Inset {
        padding: EdgeInsets,
        child: Box<Layout>,
    },
    Spacer {
        weight: FlexWeight,
    },
    Gap {
        size: Spacing,
    },
    ScrollRegion {
        id: WidgetId,
        axes: ScrollAxes,
        child: Box<Layout>,
    },
    Splitter {
        id: WidgetId,
        axis: Axis,
        default_fraction: SplitFraction,
        a: Box<Layout>,
        b: Box<Layout>,
    },
    DockHost {
        id: WidgetId,
        state: Arc<DockState>,
        panels: Vec<DockPanel>,
        tab_strip_height: Spacing,
    },
    Leaf {
        id: WidgetId,
    },
}

impl Layout {
    #[must_use]
    pub fn inset(padding: EdgeInsets, child: Layout) -> Self {
        Self::Inset {
            padding,
            child: Box::new(child),
        }
    }

    #[must_use]
    pub fn spacer() -> Self {
        Self::weighted_spacer(FlexWeight::ONE)
    }

    #[must_use]
    pub const fn weighted_spacer(weight: FlexWeight) -> Self {
        Self::Spacer { weight }
    }

    #[must_use]
    pub const fn leaf(id: WidgetId) -> Self {
        Self::Leaf { id }
    }

    #[must_use]
    pub fn scroll_region(id: WidgetId, axes: ScrollAxes, child: Layout) -> Self {
        Self::ScrollRegion {
            id,
            axes,
            child: Box::new(child),
        }
    }

    #[must_use]
    pub fn splitter(
        id: WidgetId,
        axis: Axis,
        default_fraction: SplitFraction,
        a: Layout,
        b: Layout,
    ) -> Self {
        Self::Splitter {
            id,
            axis,
            default_fraction,
            a: Box::new(a),
            b: Box::new(b),
        }
    }

    #[must_use]
    pub fn dock_host(
        id: WidgetId,
        state: Arc<DockState>,
        panels: Vec<DockPanel>,
        tab_strip_height: Spacing,
    ) -> Self {
        Self::DockHost {
            id,
            state,
            panels,
            tab_strip_height,
        }
    }
}
