// Generated by RustGObjectGenerator
// This file is licensed under the same terms as the project it belongs to

use crate::backends::supported_terminals::TerminalRepository;
use crate::i18n::gettext;
use crate::root_store::RootStore;
use adw::prelude::*;
use adw::subclass::prelude::*;
use glib::Properties;
use glib::clone;
use glib::subclass::Signal;
use gtk::{StringObject, glib};
use std::cell::RefCell;
use std::sync::OnceLock;

mod imp {
    use gtk::StringObject;

    use super::*;

    #[derive(Properties, Default)]
    #[properties(wrapper_type = super::TerminalComboRow)]
    pub struct TerminalComboRow {
        #[property(get, set)]
        root_store: RefCell<RootStore>,
        pub selected_item_signal_handler: RefCell<Option<glib::SignalHandlerId>>,
    }

    #[glib::derived_properties]
    impl ObjectImpl for TerminalComboRow {
        fn constructed(&self) {
            self.parent_constructed();
            let obj = self.obj();

            obj.set_title(&gettext("Preferred Terminal"));
            obj.set_use_subtitle(true);

            let signal_handler = obj.connect_selected_item_notify(clone!(
                #[weak]
                obj,
                move |combo| {
                    let Some(selected) = combo.selected_item().and_downcast::<StringObject>()
                    else {
                        return;
                    };

                    if let Some(terminal) = obj
                        .root_store()
                        .terminal_repository()
                        .terminal_by_name(&selected.string())
                    {
                        obj.root_store().set_selected_terminal_name(&terminal.name);
                    }
                }
            ));

            self.selected_item_signal_handler
                .replace(Some(signal_handler));

            obj.rebuild_terminals_list();

            obj.root_store().terminal_repository().connect_closure(
                "terminals-changed",
                false,
                glib::closure_local!(
                    #[strong]
                    obj,
                    move |_: TerminalRepository| {
                        obj.rebuild_terminals_list();
                    }
                ),
            );
        }

        fn signals() -> &'static [Signal] {
            static SIGNALS: OnceLock<Vec<Signal>> = OnceLock::new();
            SIGNALS.get_or_init(|| {
                vec![
                    // No signals defined
                ]
            })
        }
    }

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

    impl WidgetImpl for TerminalComboRow {
        fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
            self.parent_size_allocate(width, height, baseline);
        }

        fn snapshot(&self, snapshot: &gtk::Snapshot) {
            self.parent_snapshot(snapshot);
        }
    }

    // Generate Impl blocks for each parent class
    impl ComboRowImpl for TerminalComboRow {
        // Default implementations that forward to parent
    }

    impl ActionRowImpl for TerminalComboRow {
        // Default implementations that forward to parent
    }

    impl PreferencesRowImpl for TerminalComboRow {
        // Default implementations that forward to parent
    }

    impl ListBoxRowImpl for TerminalComboRow {
        // Default implementations that forward to parent
    }

    impl TerminalComboRow {
        // No template callbacks defined
    }
}

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

impl TerminalComboRow {
    pub fn new() -> Self {
        glib::Object::new()
    }

    pub fn new_with_params(root_store: RootStore) -> Self {
        glib::Object::builder()
            .property("root-store", root_store)
            .build()
    }

    pub fn set_selected_by_name(&self, name: &str) {
        let Some(terminals_strings) = self.model().unwrap().downcast::<gtk::StringList>().ok()
        else {
            return;
        };
        for i in 0..terminals_strings.n_items() {
            let Some(item) = terminals_strings.item(i).and_downcast::<StringObject>() else {
                continue;
            };
            if item.string() == name {
                self.set_selected(i);
                return;
            }
        }
    }
    pub fn rebuild_terminals_list(&self) {
        let terminals = self
            .root_store()
            .clone()
            .terminal_repository()
            .all_terminals();
        let terminals = terminals
            .iter()
            .map(|x| x.name.as_ref())
            .collect::<Vec<_>>();

        let terminal_list = gtk::StringList::new(&terminals);

        let signal_handler = self.imp().selected_item_signal_handler.borrow();
        self.block_signal(signal_handler.as_ref().unwrap());
        {
            self.set_model(Some(&terminal_list));
            if let Some(selected_terminal) = self.root_store().selected_terminal() {
                self.set_selected_by_name(&selected_terminal.name);
            }
        }
        self.unblock_signal(signal_handler.as_ref().unwrap());
    }
}

impl Default for TerminalComboRow {
    fn default() -> Self {
        Self::new()
    }
}
