use egui::{Align, Direction, Layout, Resize, Slider, Ui, vec2};

#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct LayoutTest {
    // Identical to contents of `egui::Layout`
    layout: LayoutSettings,

    // Extra for testing wrapping:
    wrap_column_width: f32,
    wrap_row_height: f32,
}

impl Default for LayoutTest {
    fn default() -> Self {
        Self {
            layout: LayoutSettings::top_down(),
            wrap_column_width: 150.0,
            wrap_row_height: 20.0,
        }
    }
}

#[derive(Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serde", serde(default))]
pub struct LayoutSettings {
    // Similar to the contents of `egui::Layout`
    main_dir: Direction,
    main_wrap: bool,
    cross_align: Align,
    cross_justify: bool,
}

impl Default for LayoutSettings {
    fn default() -> Self {
        Self::top_down()
    }
}

impl LayoutSettings {
    fn top_down() -> Self {
        Self {
            main_dir: Direction::TopDown,
            main_wrap: false,
            cross_align: Align::Min,
            cross_justify: false,
        }
    }

    fn top_down_justified_centered() -> Self {
        Self {
            main_dir: Direction::TopDown,
            main_wrap: false,
            cross_align: Align::Center,
            cross_justify: true,
        }
    }

    fn horizontal_wrapped() -> Self {
        Self {
            main_dir: Direction::LeftToRight,
            main_wrap: true,
            cross_align: Align::Center,
            cross_justify: false,
        }
    }

    fn layout(&self) -> Layout {
        Layout::from_main_dir_and_cross_align(self.main_dir, self.cross_align)
            .with_main_wrap(self.main_wrap)
            .with_cross_justify(self.cross_justify)
    }
}

impl crate::Demo for LayoutTest {
    fn name(&self) -> &'static str {
        "Layout Test"
    }

    fn show(&mut self, ui: &mut egui::Ui, open: &mut bool) {
        egui::Window::new(self.name())
            .open(open)
            .resizable(false)
            .constrain_to(ui.available_rect_before_wrap())
            .show(ui, |ui| {
                use crate::View as _;
                self.ui(ui);
            });
    }
}

impl crate::View for LayoutTest {
    fn ui(&mut self, ui: &mut Ui) {
        ui.label("Tests and demonstrates the limits of the egui layouts");
        self.content_ui(ui);
        Resize::default()
            .default_size([150.0, 200.0])
            .show(ui, |ui| {
                if self.layout.main_wrap {
                    if self.layout.main_dir.is_horizontal() {
                        ui.allocate_ui(
                            vec2(ui.available_size_before_wrap().x, self.wrap_row_height),
                            |ui| ui.with_layout(self.layout.layout(), demo_ui),
                        );
                    } else {
                        ui.allocate_ui(
                            vec2(self.wrap_column_width, ui.available_size_before_wrap().y),
                            |ui| ui.with_layout(self.layout.layout(), demo_ui),
                        );
                    }
                } else {
                    ui.with_layout(self.layout.layout(), demo_ui);
                }
            });
        ui.label("Resize to see effect");

        ui.vertical_centered(|ui| {
            ui.add(crate::egui_github_link_file!());
        });
    }
}

impl LayoutTest {
    pub fn content_ui(&mut self, ui: &mut Ui) {
        ui.horizontal(|ui| {
            ui.selectable_value(&mut self.layout, LayoutSettings::top_down(), "Top-down");
            ui.selectable_value(
                &mut self.layout,
                LayoutSettings::top_down_justified_centered(),
                "Top-down, centered and justified",
            );
            ui.selectable_value(
                &mut self.layout,
                LayoutSettings::horizontal_wrapped(),
                "Horizontal wrapped",
            );
        });

        ui.horizontal(|ui| {
            ui.label("Main Direction:");
            for &dir in &[
                Direction::LeftToRight,
                Direction::RightToLeft,
                Direction::TopDown,
                Direction::BottomUp,
            ] {
                ui.radio_value(&mut self.layout.main_dir, dir, format!("{dir:?}"));
            }
        });

        ui.horizontal(|ui| {
            ui.checkbox(&mut self.layout.main_wrap, "Main wrap")
                .on_hover_text("Wrap when next widget doesn't fit the current row/column");

            if self.layout.main_wrap {
                if self.layout.main_dir.is_horizontal() {
                    ui.add(Slider::new(&mut self.wrap_row_height, 0.0..=200.0).text("Row height"));
                } else {
                    ui.add(
                        Slider::new(&mut self.wrap_column_width, 0.0..=200.0).text("Column width"),
                    );
                }
            }
        });

        ui.horizontal(|ui| {
            ui.label("Cross Align:");
            for &align in &[Align::Min, Align::Center, Align::Max] {
                ui.radio_value(&mut self.layout.cross_align, align, format!("{align:?}"));
            }
        });

        ui.checkbox(&mut self.layout.cross_justify, "Cross Justified")
            .on_hover_text("Try to fill full width/height (e.g. buttons)");
    }
}

fn demo_ui(ui: &mut Ui) {
    ui.add(egui::Label::new("Wrapping text followed by example widgets:").wrap());
    let mut dummy = false;
    ui.checkbox(&mut dummy, "checkbox");
    ui.radio_value(&mut dummy, false, "radio");
    let _ = ui.button("button");
}
