// SPDX-License-Identifier: GPL-3.0-or-later
use gtk::{gio, glib, prelude::*, subclass::prelude::*};

use crate::qrcode::QRCode;

mod imp {
    use std::cell::RefCell;

    use super::*;

    #[derive(Default, Debug)]
    pub struct QRCodeModel(pub RefCell<Vec<QRCode>>);

    #[glib::object_subclass]
    impl ObjectSubclass for QRCodeModel {
        const NAME: &'static str = "QRCodeModel";
        type Type = super::QRCodeModel;
        type ParentType = glib::Object;
        type Interfaces = (gio::ListModel,);
    }
    impl ObjectImpl for QRCodeModel {}
    impl ListModelImpl for QRCodeModel {
        fn item_type(&self) -> glib::Type {
            QRCode::static_type()
        }
        fn n_items(&self) -> u32 {
            self.0.borrow().len() as u32
        }
        fn item(&self, position: u32) -> Option<glib::Object> {
            self.0
                .borrow()
                .get(position as usize)
                .map(|o| o.clone().upcast::<glib::Object>())
        }
    }
}

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

impl QRCodeModel {
    pub fn position(&self, code_a: &QRCode) -> Option<u32> {
        for pos in 0..self.n_items() {
            let obj = self.item(pos)?;
            let code = obj.downcast::<QRCode>().unwrap();
            if code.id() == code_a.id() {
                return Some(pos);
            }
        }
        None
    }

    pub fn append(&self, code: &QRCode) {
        self.imp().0.borrow_mut().insert(0, code.clone());
        self.items_changed(0, 0, 1);
    }

    pub fn remove(&self, pos: u32) {
        self.imp().0.borrow_mut().remove(pos as usize);
        self.items_changed(pos, 1, 0);
    }

    pub async fn init(&self) {
        // fill in the codes from the database
        QRCode::load()
            .await
            // TODO Handle better
            .expect("Failed to load codes from the database")
            .for_each(|code| {
                self.append(&code);
            });
    }
}

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