use crate::elements::Element;
use crate::widget_factory::WidgetBuilder;
use glib::ControlFlow;
use gtk4::glib::{self, clone};
use gtk4::{prelude::*, Orientation, Widget};
use std::cell::Cell;
use std::rc::Rc;

impl WidgetBuilder {
    pub(super) fn create_box(&self, mut elements: Vec<Element>, height: Option<i32>) -> Widget {
        let vbox = gtk4::Box::new(Orientation::Vertical, 2);
        elements.reverse();
        self.lazy_insert_element(&vbox, elements, height);
        vbox.upcast()
    }

    fn lazy_insert_element(
        &self,
        vbox: &gtk4::Box,
        mut elements: Vec<Element>,
        height: Option<i32>,
    ) {
        let current_height = Rc::new(Cell::new(0));

        glib::idle_add_local_full(
            glib::Priority::LOW,
            clone!(
                #[weak]
                vbox,
                #[strong]
                current_height,
                #[strong(rename_to = builder)]
                self,
                #[upgrade_or]
                ControlFlow::Break,
                move || {
                    if let Some(element) = elements.pop() {
                        let widget = builder.build_element(element, None, true);

                        if let Some(height) = height {
                            let (_, new_widget_height, _, _) =
                                widget.measure(Orientation::Vertical, height);
                            current_height.set(current_height.get() + new_widget_height);

                            let new_total_height = current_height.get();
                            tracing::debug!(new_total_height);

                            if new_total_height >= height {
                                tracing::debug!("abort building");
                                vbox.append(&widget);
                                return ControlFlow::Break;
                            }
                        }

                        vbox.append(&widget);
                        ControlFlow::Continue
                    } else {
                        builder.completed.set(true);
                        ControlFlow::Break
                    }
                }
            ),
        );
    }
}
