use std::cell::OnceCell;

use adw::prelude::*;
use adw::subclass::prelude::*;
use glib::Properties;
use gtk::glib;
use gtk::CompositeTemplate;

use crate::data::KrItem;
use crate::widgets::KrItemDialog;
use crate::{app, data};

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate, Properties)]
    #[properties(wrapper_type = super::KrItemRow)]
    #[template(file = "item_row.ui")]
    pub struct KrItemRow {
        #[template_child]
        icon: TemplateChild<gtk::Image>,
        #[property(get, set, construct_only)]
        item: OnceCell<KrItem>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for KrItemRow {
        const NAME: &'static str = "KrItemRow";
        type Type = super::KrItemRow;
        type ParentType = adw::ActionRow;

        fn class_init(klass: &mut Self::Class) {
            klass.bind_template();
            klass.bind_template_callbacks();
        }

        fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
            obj.init_template();
        }
    }

    #[glib::derived_properties]
    impl ObjectImpl for KrItemRow {
        fn constructed(&self) {
            self.parent_constructed();
            let obj = self.obj();
            let item = obj.item();

            item.bind_property("title", &*obj, "title")
                .sync_create()
                .build();

            item.bind_property("subtitle", &*obj, "subtitle")
                .sync_create()
                .build();

            item.bind_property("icon-name", &*self.icon, "icon-name")
                .sync_create()
                .build();
        }
    }

    impl WidgetImpl for KrItemRow {}

    impl ListBoxRowImpl for KrItemRow {}

    impl PreferencesRowImpl for KrItemRow {}

    impl ActionRowImpl for KrItemRow {}

    #[gtk::template_callbacks]
    impl KrItemRow {
        #[template_callback]
        fn on_activated(&self) {
            let dialog = KrItemDialog::new(self.obj().item());
            dialog.present(&app().window());
        }
    }
}

glib::wrapper! {
    pub struct KrItemRow(ObjectSubclass<imp::KrItemRow>)
        @extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow, adw::ActionRow,
        @implements gtk::Actionable;
}

impl KrItemRow {
    pub fn new(item: data::KrItem) -> Self {
        glib::Object::builder().property("item", item).build()
    }
}
