use adw::subclass::prelude::ObjectSubclassIsExt;
use gettextrs::pgettext;
use glib::object::{CastNone, ObjectExt};
use gtk::{
    glib,
    prelude::{TextViewExt, WidgetExt},
};

use crate::{consts::ACTION_FIND_IN_TEXT, widget::app_window::AppWindow};
mod imp;

glib::wrapper! {
    pub struct TextSearchBar(ObjectSubclass<imp::TextSearchBarImp>)
        @extends gtk::Box, gtk::Widget,
        @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Orientable;
}

impl TextSearchBar {
    pub fn new(text_view: &gtk::TextView) -> TextSearchBar {
        let obj: TextSearchBar = glib::Object::new();

        obj.imp().set_text_view(text_view);

        obj
    }

    pub fn grab_focus_on_search_entry(&self) {
        self.imp().grab_focus_on_search_entry();
    }

    pub fn clear_tags(&self) {
        self.imp().clear_tags();
    }

    pub fn find_text(&self) {
        self.imp().new_find_in_text();
    }

    pub fn new_added_text(
        &self,
        buff: &gtk::TextBuffer,
        start_iter: gtk::TextIter,
        end_iter: gtk::TextIter,
    ) {
        self.imp().new_added_text(buff, start_iter, end_iter);
    }
}

pub fn create_menu_item() -> gio::MenuItem {
    // Find in text Menu item
    let menu_label = pgettext("text_find", "Find in Text");

    gio::MenuItem::new(Some(&menu_label), Some(ACTION_FIND_IN_TEXT))
}

pub fn text_search_construct(
    text_view: &gtk::TextView,
    text_search_bar: &gtk::SearchBar,
    find_text_button: &gtk::ToggleButton,
    add_menu: bool,
) {
    add_menu_fn(text_view, add_menu);

    let text_search_bar_content = TextSearchBar::new(text_view);

    text_search_bar.set_child(Some(&text_search_bar_content));

    //find_text_button.set_action_target(Some(&format!("win.{action_name_base}")));
    //find_text_button.set_action_target_value(Some(&true.to_variant()));
    find_text_button
        .bind_property("active", text_search_bar, "search-mode-enabled")
        .bidirectional()
        .build();

    //toggle button tooltip text
    let tooltip_text = pgettext("text_find", "Open Find in Text");
    find_text_button.set_tooltip_text(Some(&tooltip_text));

    text_search_bar.connect_search_mode_enabled_notify(|search_bar| {
        if let Some(text_search_bar) = search_bar.child().and_downcast_ref::<TextSearchBar>() {
            if search_bar.is_search_mode() {
                text_search_bar.find_text();
            } else {
                text_search_bar.clear_tags();
            }
        };
    });
}

pub fn on_new_text(search_bar: &gtk::SearchBar) {
    if !search_bar.is_search_mode() {
        return;
    }

    if let Some(text_search_bar) = search_bar.child().and_downcast_ref::<TextSearchBar>() {
        text_search_bar.find_text();
    }
}

pub fn update_text_view(
    text_search_bar: &gtk::SearchBar,
    text_view: &gtk::TextView,
    add_menu: bool,
) {
    add_menu_fn(text_view, add_menu);

    if let Some(search_bar) = text_search_bar.child().and_downcast_ref::<TextSearchBar>() {
        search_bar.imp().set_text_view(text_view);
    }
}

fn add_menu_fn(text_view: &gtk::TextView, add_menu: bool) {
    if !add_menu {
        return;
    }

    let menu = gio::Menu::new();
    let item = create_menu_item();
    menu.append_item(&item);

    let menu_sec = gio::Menu::new();

    menu_sec.append_section(None, &menu);
    text_view.set_extra_menu(Some(&menu_sec));
}

pub fn new_added_text(
    text_search_bar: &gtk::SearchBar,
    buff: &gtk::TextBuffer,
    start_iter: gtk::TextIter,
    end_iter: gtk::TextIter,
) {
    if let Some(search_bar) = text_search_bar.child().and_downcast_ref::<TextSearchBar>() {
        search_bar.imp().new_added_text(buff, start_iter, end_iter);
    }
}

pub fn create_action_entry(
    text_search_bar: &gtk::SearchBar,
    action_name: &str,
) -> gio::ActionEntry<AppWindow> {
    let text_search_bar = text_search_bar.clone();
    //let is_search_mode = !text_search_bar.is_search_mode();
    let text_search_bar_action_entry: gio::ActionEntry<AppWindow> =
        gio::ActionEntry::builder(action_name)
            .activate(move |_app_window: &AppWindow, _simple_action, _variant| {
                //if let Some(state) = simple_action.state()
                //    && let Some(state) = state.get::<bool>()
                //{
                text_search_bar.set_search_mode(true);
                if let Some(search) = text_search_bar.child().and_downcast_ref::<TextSearchBar>() {
                    search.grab_focus_on_search_entry();
                }
            })
            .build();

    text_search_bar_action_entry
}
