mod imp {
    use crate::diff_model::DiffModel;
    use gtk::{gio, glib};
    use gtk::prelude::*;
    use gtk::subclass::prelude::*;
    use patchpal::ui::format::Formatted;
    use std::cell::{Cell, OnceCell};

    #[derive(Default)]
    pub(crate) struct FilesModelItem {
        pub(crate) name: OnceCell<Formatted>,
        pub(crate) unacked: Cell<u32>,
    }

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

    impl ObjectImpl for FilesModelItem {}

    #[derive(Default)]
    pub(crate) struct FilesModel {
        pub(crate) diff_model: OnceCell<DiffModel>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for FilesModel {
        const NAME: &'static str = "BackportFilesModel";
        type Type = super::FilesModel;
        type ParentType = glib::Object;
        type Interfaces = (gio::ListModel,);
    }

    impl ObjectImpl for FilesModel {}

    impl ListModelImpl for FilesModel {
        fn item_type(&self) -> glib::Type {
            glib::Object::static_type()
        }

        fn n_items(&self) -> u32 {
            self.diff_model.get().unwrap().len() as u32
        }

        fn item(&self, index: u32) -> Option<glib::Object> {
            let diff_model = self.diff_model.get().unwrap();
            if index < self.n_items() {
                Some(super::FilesModelItem::new(
                    diff_model.workspace().commit().unwrap().format_filename(index as usize),
                    diff_model.workspace().count_file_unacked(index as usize),
                ).upcast())
            } else {
                None
            }
        }
    }
}

use crate::diff_model::DiffModel;
use gtk::{gio, glib};
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use patchpal::ui::format::Formatted;

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

impl FilesModelItem {
    fn new(name: Formatted, unacked: usize) -> Self {
        let result: Self = glib::Object::builder().build();
        let imp = result.imp();
        imp.name.set(name).unwrap();
        imp.unacked.set(unacked as u32);
        result
    }

    pub(crate) fn name(&self) -> &Formatted {
        self.imp().name.get().unwrap()
    }

    pub(crate) fn unacked(&self) -> u32 {
        self.imp().unacked.get()
    }
}

glib::wrapper! {
    pub(crate) struct FilesModel(ObjectSubclass<imp::FilesModel>)
        @implements gio::ListModel;
}

impl FilesModel {
    pub(crate) fn new(diff_model: &DiffModel) -> Self {
        let result: Self = glib::Object::builder().build();
        result.imp().diff_model.set(diff_model.clone()).unwrap();
        result
    }

    pub(crate) fn update_unacked(&self, index: usize) {
        self.items_changed(index as u32, 1, 1);
    }
}
