use crate::gobject_models::{GCategoryID, GFeedListItemID};
use crate::sidebar::FeedListItem;
use gio::{ListStore, prelude::*};
use glib::{Object, Properties};
use gtk4::subclass::prelude::*;
use std::cell::{Cell, RefCell};

mod imp {
    use super::*;

    #[derive(Debug, Default, Properties)]
    #[properties(wrapper_type = super::GFeedListItem)]
    pub struct GFeedListItem {
        #[property(get, set, name = "item-id")]
        pub id: RefCell<GFeedListItemID>,

        #[property(get, set, name = "parent-id")]
        pub parent_id: RefCell<GCategoryID>,

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

        #[property(get, set, name = "item-count")]
        pub item_count: Cell<u32>,

        #[property(get, set, name = "error-message")]
        pub error_message: RefCell<String>,

        #[property(get, set, name = "sort-index")]
        pub sort_index: Cell<i32>,

        #[property(get, set, nullable)]
        pub children: RefCell<Option<ListStore>>,

        #[property(get, set)]
        pub is_category: Cell<bool>,
    }

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

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

glib::wrapper! {
    pub struct GFeedListItem(ObjectSubclass<imp::GFeedListItem>);
}

impl Default for GFeedListItem {
    fn default() -> Self {
        Object::new()
    }
}

impl From<&FeedListItem> for GFeedListItem {
    fn from(item: &FeedListItem) -> Self {
        let gobject = Self::new();
        let imp = gobject.imp();

        imp.id.replace(item.id.clone().into());
        imp.label.replace(item.label.clone());
        imp.parent_id.replace(item.parent_id.clone().into());
        imp.item_count.set(item.item_count);
        imp.sort_index.set(item.sort_index);
        imp.error_message
            .replace(item.error_message.clone().unwrap_or_default());
        imp.is_category.set(item.id.is_category());

        let list_store = if item.id.is_feed() {
            None
        } else {
            let list_store = ListStore::new::<GFeedListItem>();
            for child in &item.children {
                let item: GFeedListItem = child.into();
                list_store.append(&item);
            }
            Some(list_store)
        };

        imp.children.replace(list_store);

        gobject
    }
}

impl GFeedListItem {
    pub fn new() -> Self {
        Self::default()
    }
}
