// Create a new Icon Set Dialog
use std::path::PathBuf;

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

use crate::{
    icons::validate_project_name,
    project::{Project, ProjectType},
    widgets::Window,
};

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

    use super::*;

    #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
    #[properties(wrapper_type = super::NewProjectWindow)]
    #[template(resource = "/org/gnome/design/SymbolicPreview/new_project.ui")]
    pub struct NewProjectWindow {
        #[template_child]
        pub(super) name_label: TemplateChild<gtk::Label>,
        #[template_child]
        pub(super) name_desc_label: TemplateChild<gtk::Label>,
        #[template_child]
        pub(super) source_label: TemplateChild<gtk::Label>,
        #[template_child]
        pub(super) name_entry: TemplateChild<gtk::Entry>,
        #[template_child]
        pub(super) path_entry: TemplateChild<gtk::Entry>,
        #[template_child]
        pub(super) create_btn: TemplateChild<gtk::Button>,
        #[property(get, set, construct_only, builder(ProjectType::default()))]
        pub(super) project_type: Cell<ProjectType>,
    }

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

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

            klass.install_action_async(
                "new-project.select-location",
                None,
                |win, _, _| async move {
                    win.select_destination().await;
                },
            );
        }

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

    #[glib::derived_properties]
    impl ObjectImpl for NewProjectWindow {
        fn constructed(&self) {
            self.parent_constructed();
            let obj = self.obj();
            let project_type = self.obj().project_type();
            match project_type {
                ProjectType::Symbolic => {
                    obj.set_title(Some(&gettext("New Symbolic Icon")));
                    self.name_label.set_label(&gettext("Icon Name"));
                    self.source_label
                        .set_label(&gettext("Icon Source Location"));
                    self.name_desc_label.set_label(&gettext(
                        "All-lowercase, with dashes between words, e.g. list-add",
                    ));
                }
                ProjectType::IconsSet => {
                    obj.set_title(Some(&gettext("New Icons Set")));
                    self.name_label.set_label(&gettext("Icons Set Name"));
                    self.source_label
                        .set_label(&gettext("Icons Set Source Location"));
                    self.name_desc_label.set_label("");
                    self.name_entry.set_text("icons-set");
                }
            };
        }
    }
    impl WidgetImpl for NewProjectWindow {}
    impl WindowImpl for NewProjectWindow {}
    impl AdwWindowImpl for NewProjectWindow {}
}

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

#[gtk::template_callbacks]
impl NewProjectWindow {
    pub fn new(project_type: ProjectType) -> Self {
        glib::Object::builder()
            .property("project-type", project_type)
            .build()
    }

    #[template_callback]
    fn on_entry_validate(&self, _entry: &gtk::Entry) {
        let imp = self.imp();
        let project_name = imp.name_entry.text();
        let project_dest = PathBuf::from(imp.path_entry.text());
        let project_type = self.project_type();
        let is_valid = validate_project_name(&project_name, project_type) && project_dest.exists();
        imp.create_btn.set_sensitive(is_valid);
    }

    #[template_callback]
    async fn on_create_btn_clicked(&self, _btn: gtk::Button) {
        let imp = self.imp();
        let project_dest: String = imp.path_entry.text().to_string();
        let project_type = imp.project_type.get();
        let mut project_path: PathBuf = project_dest.into();

        let project_name = imp.name_entry.text();

        let project_name = match project_type {
            ProjectType::Symbolic => format!("{project_name}-symbolic.svg"),
            ProjectType::IconsSet => format!("{project_name}.svg"),
        };

        project_path.push(project_name);

        // TODO: handle the errors during project creation
        if let Ok(project) = Project::create(project_path, project_type).await {
            let parent = self.transient_for().and_downcast::<Window>().unwrap();
            let _ = project.open(self).await; // Open the project in the default svg editor/viewer
            parent.set_open_project(project);
        }
        self.destroy();
    }

    async fn select_destination(&self) {
        let file_dialog = gtk::FileDialog::new();
        if let Ok(destination) = file_dialog.select_folder_future(Some(self)).await {
            self.imp()
                .path_entry
                .set_text(destination.path().unwrap().to_str().unwrap());
        }
    }
}
