use crate::main_window::MainWindow;
use crate::settings::dialog::keybinding_editor::KeybindingEditor;
use crate::settings::keybindings::Keybindings;
use glib::{Object, Properties, prelude::*, subclass};
use gtk4::{
    Accessible, Actionable, Buildable, CompositeTemplate, ConstraintTarget, Label, ListBoxRow, Widget, prelude::*,
    subclass::prelude::*,
};
use libadwaita::{ActionRow, PreferencesRow, prelude::*, subclass::prelude::*};
use std::cell::RefCell;

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate, Properties)]
    #[properties(wrapper_type = super::KeybindRow)]
    #[template(file = "data/resources/ui_templates/settings/keybind_row.blp")]
    pub struct KeybindRow {
        #[template_child]
        pub key_label: TemplateChild<Label>,

        #[property(get, set = Self::set_obj, name = "settings-obj", nullable)]
        pub settings_obj: RefCell<Option<Object>>,

        #[property(get, set = Self::set_settings_property, name = "settings-property")]
        pub settings_property: RefCell<String>,
    }

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

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

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

    #[glib::derived_properties]
    impl ObjectImpl for KeybindRow {}

    impl WidgetImpl for KeybindRow {}

    impl ListBoxRowImpl for KeybindRow {}

    impl PreferencesRowImpl for KeybindRow {}

    impl ActionRowImpl for KeybindRow {}

    #[gtk4::template_callbacks]
    impl KeybindRow {
        #[template_callback]
        fn on_activation(&self) {
            let editor = KeybindingEditor::new(
                self.obj().title().as_str(),
                self.settings_obj.borrow().clone(),
                self.settings_property.borrow().as_str(),
            );
            editor.set_transient_for(Some(&MainWindow::instance()));
            editor.present();
        }

        fn set_obj(&self, obj: Option<Object>) {
            self.settings_obj.replace(obj);
            self.bind_settings_property();
        }

        fn set_settings_property(&self, name: String) {
            self.settings_property.replace(name);
            self.bind_settings_property();
        }

        fn bind_settings_property(&self) {
            let Some(obj) = self.settings_obj.borrow().clone() else {
                return;
            };

            obj.bind_property(&self.settings_property.borrow(), &*self.key_label, "label")
                .transform_to(|_binding, keybinding: Option<String>| match keybinding {
                    Some(keybinding) => Keybindings::parse_shortcut_string(&keybinding),
                    None => Some("Disabled".to_owned()),
                })
                .sync_create()
                .build();

            obj.bind_property(&self.settings_property.borrow(), &*self.key_label, "sensitive")
                .transform_to(|_binding, keybinding: Option<String>| Some(keybinding.is_some()))
                .sync_create()
                .build();
        }
    }
}

glib::wrapper! {
    pub struct KeybindRow(ObjectSubclass<imp::KeybindRow>)
        @extends Widget, PreferencesRow, ActionRow, ListBoxRow,
        @implements Accessible, Actionable, Buildable, ConstraintTarget;
}

impl Default for KeybindRow {
    fn default() -> Self {
        glib::Object::new::<Self>()
    }
}
