use adw::{prelude::*, subclass::prelude::*};
use ashpd::documents::Documents;
use gtk::glib::{self, clone};

use super::spawn_tokio;
use crate::widgets::{PortalPage, PortalPageImpl};

mod imp {
    use super::*;

    #[derive(Debug, gtk::CompositeTemplate, Default)]
    #[template(resource = "/com/belmoussaoui/ashpd/demo/documents.ui")]
    pub struct DocumentsPage {
        #[template_child]
        pub mount_point: TemplateChild<gtk::Label>,
    }

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

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

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

    impl WidgetImpl for DocumentsPage {
        fn map(&self) {
            let widget = self.obj();
            glib::spawn_future_local(clone!(
                #[weak]
                widget,
                async move {
                    if let Err(err) = widget.refresh().await {
                        tracing::error!("Failed to call a method on Documents portal{}", err);
                    }
                }
            ));

            glib::spawn_future_local(glib::clone!(
                #[weak]
                widget,
                async move {
                    if let Ok(proxy) = spawn_tokio(async { Documents::new().await }).await {
                        widget.set_property("portal-version", proxy.version());
                    }
                }
            ));
            self.parent_map();
        }
    }
    impl BinImpl for DocumentsPage {}
    impl PortalPageImpl for DocumentsPage {}
}

glib::wrapper! {
    pub struct DocumentsPage(ObjectSubclass<imp::DocumentsPage>)
        @extends gtk::Widget, adw::Bin, PortalPage,
        @implements gtk::ConstraintTarget, gtk::Buildable, gtk::Accessible;
}

impl DocumentsPage {
    async fn refresh(&self) -> ashpd::Result<()> {
        let mount_point = spawn_tokio(async move {
            let proxy = Documents::new().await?;

            proxy.mount_point().await
        })
        .await?;

        self.imp()
            .mount_point
            .set_label(mount_point.as_ref().to_str().unwrap());

        Ok(())
    }
}
