use adw::subclass::prelude::*;
use gettextrs::gettext;
use gtk::{gio, glib, prelude::*};

use crate::{icons::Icon, utils::make_ascii_titlecase};

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

    use super::*;

    #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
    #[template(resource = "/org/gnome/design/SymbolicPreview/export_dialog.ui")]
    #[properties(wrpaper_type = super::ExportDialog)]
    pub struct ExportDialog {
        #[template_child]
        pub(super) icon_size_16: TemplateChild<gtk::Image>,
        #[template_child]
        pub(super) icon_size_32: TemplateChild<gtk::Image>,
        #[template_child]
        pub(super) icon_size_64: TemplateChild<gtk::Image>,
        #[template_child]
        pub(super) tags_label: TemplateChild<gtk::Label>,
        #[property(get, set = Self::set_icon, construct_only)]
        pub(super) icon: OnceCell<Icon>,
    }

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

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

            klass.install_action_async("export.copy-clipboard", None, |win, _, _| async move {
                if let Err(err) = win.icon().copy().await {
                    tracing::error!("Failed to copy the icon {err}");
                }
            });

            klass.install_action_async("export.save-as", None, |win, _, _| async move {
                if let Err(err) = win.save_as().await {
                    tracing::error!("Failed to save the icon {err}");
                }
            });
        }

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

    #[glib::derived_properties]
    impl ObjectImpl for ExportDialog {}
    impl WidgetImpl for ExportDialog {}
    impl WindowImpl for ExportDialog {}
    impl AdwWindowImpl for ExportDialog {}

    impl ExportDialog {
        fn set_icon(&self, icon: Icon) {
            self.icon_size_16
                .set_from_icon_name(Some(&format!("{}-symbolic", icon.name())));
            self.icon_size_32
                .set_from_icon_name(Some(&format!("{}-symbolic", icon.name())));
            self.icon_size_64
                .set_from_icon_name(Some(&format!("{}-symbolic", icon.name())));

            let window_title = icon.name().replace("-symbolic", "");
            self.obj().set_title(Some(&window_title));

            let keywords = icon.keywords();
            let keywords = keywords
                .to_vec()
                .iter_mut()
                .map(|keyword| {
                    make_ascii_titlecase(keyword);
                    keyword.clone()
                })
                .collect::<Vec<String>>()
                .join(", ");
            self.tags_label.set_text(&keywords);
            self.icon.set(icon).unwrap();
        }
    }
}

glib::wrapper! {
    pub struct ExportDialog(ObjectSubclass<imp::ExportDialog>)
        @extends gtk::Widget, gtk::Window, adw::Window,
        @implements gtk::Root;
}

impl ExportDialog {
    pub fn new(icon: Icon) -> Self {
        glib::Object::builder().property("icon", icon).build()
    }

    async fn save_as(&self) -> anyhow::Result<()> {
        let svg_filter = gtk::FileFilter::new();
        svg_filter.set_name(Some(&gettext("SVG images")));
        svg_filter.add_mime_type("image/svg+xml");

        let filters = gio::ListStore::new::<gtk::FileFilter>();
        filters.append(&svg_filter);

        let icon = self.icon();
        let dialog = gtk::FileDialog::builder()
            .title(gettext("Export a symbolic icon"))
            .accept_label(gettext("Export"))
            .modal(true)
            .filters(&filters)
            .initial_name(format!("{}-symbolic.svg", icon.name()))
            .build();

        let destination = dialog.save_future(Some(self)).await?;
        icon.save(destination).await?;
        Ok(())
    }
}
