use glib::{Properties, subclass};
use gtk4::{
    Accessible, Box, Buildable, CompositeTemplate, ConstraintTarget, Label, Widget, prelude::*, subclass::prelude::*,
};
use std::cell::{Cell, RefCell};

mod imp {
    use super::*;

    #[derive(Debug, CompositeTemplate, Default, Properties)]
    #[properties(wrapper_type = super::ListRevealer)]
    #[template(file = "data/resources/ui_templates/sidebar/list_revealer.blp")]
    pub struct ListRevealer {
        #[template_child]
        pub label_widget: TemplateChild<Label>,

        #[property(get, set, name = "is-expanded", default_value = true)]
        pub is_expanded: Cell<bool>,

        #[property(get, set)]
        pub label: RefCell<String>,

        #[property(get, set, nullable)]
        pub child: RefCell<Option<Widget>>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for ListRevealer {
        const NAME: &'static str = "ListRevealer";
        type ParentType = Box;
        type Type = super::ListRevealer;

        fn class_init(klass: &mut Self::Class) {
            klass.bind_template();
            klass.bind_template_callbacks();
        }

        fn instance_init(obj: &subclass::InitializingObject<Self>) {
            obj.init_template();
        }
    }

    #[glib::derived_properties]
    impl ObjectImpl for ListRevealer {}

    impl WidgetImpl for ListRevealer {}

    impl BoxImpl for ListRevealer {}

    #[gtk4::template_callbacks]
    impl ListRevealer {
        #[template_callback]
        fn on_enter(&self) {
            self.label_widget.remove_css_class("dim-label");
        }

        #[template_callback]
        fn on_leave(&self) {
            self.label_widget.add_css_class("dim-label");
        }

        #[template_callback]
        fn on_clicked(&self, _times: i32, _x: f64, _y: f64) {
            self.obj().set_is_expanded(!self.is_expanded.get());
        }
    }
}

glib::wrapper! {
    pub struct ListRevealer(ObjectSubclass<imp::ListRevealer>)
        @extends Widget, Box,
        @implements Accessible, Buildable, ConstraintTarget;
}

impl Default for ListRevealer {
    fn default() -> Self {
        glib::Object::new::<Self>()
    }
}
