use crate::config;
use crate::widgets::Window;
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{gio, glib};

mod imp {
    use super::*;

    #[derive(Default, Debug)]
    pub struct Application {
        pub windows: gtk::WindowGroup,
    }

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

    impl ObjectImpl for Application {}
    impl ApplicationImpl for Application {
        fn startup(&self) {
            self.parent_startup();
            let app = self.obj();

            gtk::Window::set_default_icon_name(config::APP_ID);
            app.style_manager().set_color_scheme(adw::ColorScheme::PreferDark);
            app.setup_actions();
        }

        fn activate(&self) {
            self.parent_activate();
            let window = self.obj().create_window();
            window.present();
            log::info!("Created application window.");
        }

        fn open(&self, files: &[gio::File], _hint: &str) {
            for file in files.iter() {
                let window = self.obj().create_window();
                window.set_open_file(file);
                window.present();
            }
        }
    }

    impl GtkApplicationImpl for Application {
        fn window_removed(&self, window: &gtk::Window) {
            self.parent_window_removed(window);
            self.windows.remove_window(window);
        }
    }

    impl AdwApplicationImpl for Application {}
}

glib::wrapper! {
    pub struct Application(ObjectSubclass<imp::Application>)
     @extends gio::Application, gtk::Application, adw::Application,
     @implements gio::ActionMap, gio::ActionGroup;
}

impl Application {
    pub fn run() -> glib::ExitCode {
        log::info!("Obfuscate({})", config::APP_ID);
        log::info!("Version: {} ({})", config::VERSION, config::PROFILE);
        log::info!("Datadir: {}", config::PKGDATADIR);

        // Create new GObject and downcast it into Application
        glib::Object::builder::<Self>()
            .property("application-id", config::APP_ID)
            .property("flags", gio::ApplicationFlags::HANDLES_OPEN)
            .property("resource-base-path", "/com/belmoussaoui/Obfuscate")
            .build()
            .run()
    }

    fn create_window(&self) -> Window {
        let window = Window::new(self);
        self.imp().windows.add_window(&window);
        window
    }

    fn show_about_dialog(&self) {
        adw::AboutWindow::builder()
            .application_name(gettext("Obfuscate"))
            .comments(gettext("Censor private information"))
            .application_icon(config::APP_ID)
            .license_type(gtk::License::Gpl30)
            .website("https://gitlab.gnome.org/World/obfuscate/")
            .version(config::VERSION)
            .transient_for(&self.window())
            .modal(true)
            .translator_credits(gettext("translator-credits"))
            .developers(vec!["Bilal Elmoussaoui", "Alexander Mikhaylenko"])
            .artists(vec!["Jakub Steiner", "Tobias Bernard"])
            .build()
            .present();
    }

    fn window(&self) -> Window {
        self.active_window().expect("Failed to get a GtkWindow").downcast().unwrap()
    }

    fn setup_actions(&self) {
        // Quit
        let quit = gio::ActionEntry::builder("quit").activate(|app: &Self, _, _| app.quit()).build();
        // About
        let about = gio::ActionEntry::builder("about").activate(|app: &Self, _, _| app.show_about_dialog()).build();
        // New Window
        let new_window = gio::ActionEntry::builder("new-window")
            .activate(|app: &Self, _, _| {
                let window = app.create_window();
                window.present();
            })
            .build();

        self.add_action_entries([quit, about, new_window]);

        self.set_accels_for_action("app.new-window", &["<primary>n"]);
        self.set_accels_for_action("app.quit", &["<primary>q"]);
        self.set_accels_for_action("window.close", &["<primary>w"]);
        self.set_accels_for_action("win.open", &["<primary>o"]);
        self.set_accels_for_action("win.save", &["<primary>s"]);
        self.set_accels_for_action("win.undo", &["<primary>z"]);
        self.set_accels_for_action("win.redo", &["<primary><shift>z"]);
        self.set_accels_for_action("win.paste", &["<primary>v"]);
        self.set_accels_for_action("win.copy", &["<primary>c"]);
        self.set_accels_for_action("win.zoom_in", &["<primary>plus"]);
        self.set_accels_for_action("win.zoom_out", &["<primary>minus"]);
        self.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
    }
}
