use gtk::{
    glib::{self, clone},
    prelude::*,
    subclass::prelude::*,
};

use super::group::IconsGroupWidget;
use crate::{application::Application, icons::Category, project::Project};

mod imp {
    use super::*;

    #[derive(Debug, Default)]
    pub struct IconsSetView {
        pub(super) listbox: gtk::ListBox,
    }

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

        fn class_init(klass: &mut Self::Class) {
            klass.set_layout_manager_type::<gtk::BinLayout>();
            klass.set_css_name("icons-set-view");
        }
    }

    impl ObjectImpl for IconsSetView {
        fn constructed(&self) {
            self.parent_constructed();
            self.listbox.set_parent(&*self.obj());
        }

        fn dispose(&self) {
            self.listbox.unparent();
        }
    }
    impl WidgetImpl for IconsSetView {}
}

glib::wrapper! {
    pub struct IconsSetView(ObjectSubclass<imp::IconsSetView>) @extends gtk::Widget, gtk::Box;
}

impl IconsSetView {
    pub fn load(&self, project: &Project) {
        let filter =
            gtk::CustomFilter::new(|a| a.downcast_ref::<Category>().unwrap().is_rendered());
        let set = project.set().unwrap();
        set.connect_category_parsed(
            clone!(@strong filter, @strong self as obj, @strong project => move |_| {
                let window = obj.root().and_downcast::<gtk::Window>().unwrap();
                let app = window.application().and_downcast::<Application>().unwrap();
                let theme = &app.imp().icon_theme.get().unwrap();
                theme.add_search_path(project.icon_theme_dir());

                filter.changed(gtk::FilterChange::Different);
            }),
        );
        let filter_model = gtk::FilterListModel::new(Some(set), Some(filter));
        let sorter = gtk::StringSorter::new(Some(Category::this_expression("name")));

        let sort_model = gtk::SortListModel::new(Some(filter_model), Some(sorter));
        self.imp()
            .listbox
            .bind_model(Some(&sort_model), move |obj| {
                let category = obj.downcast_ref::<Category>().unwrap();
                IconsGroupWidget::new(category).upcast()
            });
    }
}
