use std::cell::RefCell;

use gio::prelude::*;
use gio::subclass::prelude::*;
use indexmap::map::IndexMap;

use crate::TrFile;

mod imp {
    use super::*;

    #[derive(Debug, Default)]
    pub struct TrRelatedModel {
        pub map: RefCell<IndexMap<String, TrFile>>,
    }

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

    impl ObjectImpl for TrRelatedModel {}

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

        fn n_items(&self) -> u32 {
            self.map.borrow().len() as u32
        }

        fn item(&self, position: u32) -> Option<glib::Object> {
            self.map
                .borrow()
                .get_index(position.try_into().unwrap())
                .map(|(_, o)| o.clone().upcast::<glib::Object>())
        }
    }

    impl TrRelatedModel {}
}

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

impl TrRelatedModel {
    pub fn new() -> Self {
        glib::Object::new()
    }

    pub(crate) fn add_file(&self, file: &TrFile) {
        let pos = {
            let mut map = self.imp().map.borrow_mut();
            if map.contains_key(&file.name()) {
                warn!(
                    "Model already contains file {} with name {}",
                    file.title(),
                    file.name()
                );
                return;
            }

            map.insert(file.name(), file.clone());
            (map.len() - 1) as u32
        };

        self.items_changed(pos, 0, 1);
    }
}

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