// SPDX-License-Identifier: GPL-3.0-or-later

//! The basic button component
use std::rc::Rc;

use glib::Cast;
use grx_macros::{gtk_component, props};
use gtk::glib;
use gtk::traits::WidgetExt;

use crate::{handlers::Handler, new_gc, Component};

use super::gtk_props::apply;

#[props]
#[derive(Default)]
pub struct Props {
    pub visible_child: Option<&'static str>,
    pub on_fold: Option<Handler<Leaflet>>,
    pub fold_threshold_natural: bool,
}

impl std::fmt::Debug for Props {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Props")
            .field("id", &self.id)
            .field("classes", &self.classes)
            .field("styles", &self.styles)
            .field("children", &self.children)
            .field("visible_child", &self.visible_child)
            .field("on_fold", &"...")
            .finish()
    }
}

pub fn leaflet(mut props: Props) -> Rc<Leaflet> {
    let leaflet = libadwaita::Leaflet::builder().build();
    if props.fold_threshold_natural {
        leaflet.set_fold_threshold_policy(libadwaita::FoldThresholdPolicy::Natural);
    } else {
        leaflet.set_fold_threshold_policy(libadwaita::FoldThresholdPolicy::Minimum);
    }

    let widget = leaflet.clone().upcast();

    let visible_child = props.visible_child;
    let on_fold = props.on_fold.take();

    let component = new_gc!(Leaflet { widget, props });

    for c in component.children().iter() {
        component.append_internal(c.clone());
    }

    if let Some(on_fold) = on_fold {
        let moved_c = component.clone();
        leaflet.connect_folded_notify(move |_| {
            let f = on_fold.as_ref();
            f(moved_c.clone());
        });
    }
    if let Some(name) = visible_child {
        leaflet.set_visible_child_name(name);
    }
    apply(component.clone());

    component
}

#[gtk_component(libadwaita::Leaflet)]
#[derive(Debug)]
pub struct Leaflet {}

impl Leaflet {
    pub fn on_fold(self: &Rc<Self>, callback: impl Fn(Rc<Self>) + 'static) {
        let leaflet: &libadwaita::Leaflet = &self.widget;
        let s = self.clone();
        leaflet.connect_folded_notify(move |_| {
            callback(s.clone());
        });
    }
    pub fn is_folded(self: &Rc<Self>) -> bool {
        self.widget.is_folded()
    }
    pub fn append(self: &Rc<Self>, child: crate::grx::Component) {
        self.append_internal(child.clone());
        self.children.borrow_mut().push(child);
    }

    pub fn append_internal(self: &Rc<Self>, child: crate::grx::Component) {
        let inner = child.clone().inner();
        let w: &gtk::Widget = inner.downcast_ref().unwrap();
        let page = self.widget.append(w);
        page.set_name(Some(w.widget_name().as_str()));
    }

    pub fn children<'a>(self: &'a Rc<Self>) -> std::cell::Ref<'a, Vec<Component>> {
        self.children.borrow()
    }
    pub fn clear(self: &Rc<Self>) {
        let widget = &self.widget;
        let mut child = widget.first_child();
        while let Some(c) = child {
            child = c.next_sibling();
            widget.remove(&c);
        }
    }
}

impl Leaflet {}
