use crate::gobject_models::{GArticle, GArticleID};
use glib::{Object, subclass::prelude::*};
use news_flash::models::{Article, Feed, Tag};
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Display;

mod imp {
    use super::*;

    #[derive(Default)]
    pub struct ArticleListModel {
        pub(super) models: RefCell<Vec<GArticle>>,
        pub(super) index: RefCell<HashMap<GArticleID, GArticle>>,
    }

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

    impl ObjectImpl for ArticleListModel {}
}

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

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

impl Display for ArticleListModel {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let imp = self.imp();

        for (i, article) in imp.models.borrow().iter().enumerate() {
            writeln!(f, "{i} {:?} (id: {})", article.title(), article.article_id())?;
        }

        Ok(())
    }
}

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

    pub fn add(&self, articles: Vec<(Article, Option<&Feed>, Vec<Tag>)>) {
        let imp = self.imp();

        for (article, feed, tags) in articles {
            if imp.index.borrow().contains_key(&article.article_id.clone().into()) {
                //warn!("Listmodel already contains id {}", article.article_id);
                continue;
            }
            let article = GArticle::from_article(article, feed, tags, vec![], None, None);
            imp.index.borrow_mut().insert(article.article_id(), article.clone());
            imp.models.borrow_mut().push(article);
        }
    }

    pub fn append(&self, models: Vec<GArticle>) {
        let imp = self.imp();

        for model in models {
            let article_id = model.article_id();
            if imp.index.borrow().contains_key(&article_id) {
                //warn!("Listmodel already contains id {}", model.id);
                continue;
            }
            imp.index.borrow_mut().insert(article_id, model.clone());
            imp.models.borrow_mut().push(model);
        }
    }

    pub fn get(&self, article_id: &GArticleID) -> Option<GArticle> {
        self.imp().index.borrow().get(article_id).cloned()
    }

    pub fn get_ids(&self) -> Vec<GArticleID> {
        self.imp().index.borrow().keys().cloned().collect()
    }

    pub fn is_empty(&self) -> bool {
        self.imp().models.borrow().is_empty()
    }

    pub fn articles(&self) -> Vec<GArticle> {
        self.imp().models.borrow().clone()
    }
}
