use adw::prelude::*;
use adw::subclass::prelude::*;
use gtk::gio;
use std::cell::OnceCell;

use crate::config::APP_ID;
use crate::window::DriftwoodWindow;

mod imp {
    use super::*;

    pub struct DriftwoodApplication {
        pub settings: OnceCell<gio::Settings>,
    }

    impl Default for DriftwoodApplication {
        fn default() -> Self {
            Self {
                settings: OnceCell::new(),
            }
        }
    }

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

    impl ObjectImpl for DriftwoodApplication {}

    impl ApplicationImpl for DriftwoodApplication {
        fn startup(&self) {
            self.parent_startup();
            let app = self.obj();
            app.setup_css();
            app.setup_theme();
            app.setup_actions();
        }

        fn activate(&self) {
            self.parent_activate();
            let app = self.obj();

            // Present existing window or create a new one
            if let Some(window) = app.active_window() {
                window.present();
            } else {
                let window = DriftwoodWindow::new(&*app);
                window.present();
            }
        }
    }

    impl GtkApplicationImpl for DriftwoodApplication {}
    impl AdwApplicationImpl for DriftwoodApplication {}
}

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

impl DriftwoodApplication {
    pub fn new(app_id: &str, flags: &gio::ApplicationFlags) -> Self {
        glib::Object::builder()
            .property("application-id", app_id)
            .property("flags", flags)
            .build()
    }

    fn setup_css(&self) {
        let provider = gtk::CssProvider::new();
        provider.load_from_resource("/app/driftwood/Driftwood/style.css");
        gtk::style_context_add_provider_for_display(
            &gtk::gdk::Display::default().expect("Could not get default display"),
            &provider,
            gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
        );
    }

    fn setup_theme(&self) {
        let settings = gio::Settings::new(APP_ID);
        Self::apply_color_scheme(&settings);

        settings.connect_changed(Some("color-scheme"), |settings, _| {
            Self::apply_color_scheme(settings);
        });

        // Store settings on the imp struct so it stays alive
        // (otherwise the connect_changed signal gets dropped)
        self.imp()
            .settings
            .set(settings)
            .expect("Theme settings already initialized");
    }

    fn apply_color_scheme(settings: &gio::Settings) {
        let value = settings.string("color-scheme");
        let scheme = match value.as_str() {
            "force-light" => adw::ColorScheme::ForceLight,
            "force-dark" => adw::ColorScheme::ForceDark,
            _ => adw::ColorScheme::Default,
        };
        adw::StyleManager::default().set_color_scheme(scheme);
    }

    fn setup_actions(&self) {
        // Quit action (Ctrl+Q)
        let quit_action = gio::ActionEntry::builder("quit")
            .activate(|app: &Self, _, _| {
                if let Some(window) = app.active_window() {
                    window.close();
                }
                app.quit();
            })
            .build();

        self.add_action_entries([quit_action]);
        self.set_accels_for_action("app.quit", &["<Control>q"]);
    }

}
