use super::kaomoji_data::{get_all_kaomojis, KaomojiCategory, KaomojiObject};
use gtk4::prelude::*;
use gtk4::{
    gio, glib, Box, CustomFilter, FilterListModel, GridView, Orientation, PolicyType,
    ScrolledWindow, SignalListItemFactory, SingleSelection, ToggleButton,
};
use std::cell::RefCell;
use std::rc::Rc;

pub fn create_kaomoji_grid(search_entry: &gtk4::SearchEntry) -> Box {
    let container = Box::new(Orientation::Horizontal, 0);
    container.set_css_classes(&["emoji-page"]); // Re-use styling

    // 1. Sidebar (Categories)
    let sidebar = Box::new(Orientation::Vertical, 6);
    sidebar.set_margin_start(6);
    sidebar.set_margin_end(6);
    sidebar.set_margin_top(6);
    sidebar.set_margin_bottom(6);

    // 2. Store
    let store = gio::ListStore::new::<KaomojiObject>();
    store.extend_from_slice(&get_all_kaomojis());

    // 3. Filter
    let current_category = Rc::new(RefCell::new(KaomojiCategory::Joy));
    let current_query = Rc::new(RefCell::new(String::new()));

    let filter = CustomFilter::new(glib::clone!(
        #[strong]
        current_category,
        #[strong]
        current_query,
        move |obj| {
            let kao = obj.downcast_ref::<KaomojiObject>().unwrap();
            let query = current_query.borrow();

            if !query.is_empty() {
                // Search name/text
                return kao.text().contains(query.as_str())
                    || kao.name().to_lowercase().contains(query.as_str());
            }

            // Show "Actions" as default for SafeMode/Actions combined? Or strict?
            // Let's be strict for now.
            kao.category() == *current_category.borrow()
        }
    ));

    let filter_model = FilterListModel::new(Some(store), Some(filter.clone()));
    let selection_model = SingleSelection::new(Some(filter_model));

    // Connect Search with debounce (150ms)
    let debounce_source: Rc<RefCell<Option<glib::SourceId>>> = Rc::new(RefCell::new(None));
    search_entry.connect_search_changed(glib::clone!(
        #[weak]
        filter,
        #[strong]
        current_query,
        #[strong]
        debounce_source,
        move |entry| {
            // Cancel previous debounce timer if still pending
            if let Some(source_id) = debounce_source.borrow_mut().take() {
                let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
                    source_id.remove();
                }));
            }

            let query = entry.text().to_string().to_lowercase();
            let current_query_clone = current_query.clone();
            let filter_weak = filter.downgrade();
            let debounce_source_clone = debounce_source.clone();

            let source_id =
                glib::timeout_add_local_once(std::time::Duration::from_millis(150), move || {
                    *debounce_source_clone.borrow_mut() = None;
                    *current_query_clone.borrow_mut() = query;
                    if let Some(f) = filter_weak.upgrade() {
                        f.changed(gtk4::FilterChange::Different);
                    }
                });
            *debounce_source.borrow_mut() = Some(source_id);
        }
    ));

    // Buttons
    let categories = vec![
        ("😂", KaomojiCategory::Joy, "Joy"),
        ("❤", KaomojiCategory::Love, "Love"),
        ("😳", KaomojiCategory::Embarrassment, "Embarrassed"),
        ("💢", KaomojiCategory::Anger, "Anger"),
        ("😥", KaomojiCategory::Sorrow, "Sorrow"),
        ("┻━┻", KaomojiCategory::Actions, "Actions"),
    ];

    let mut first_btn: Option<ToggleButton> = None;
    for (icon, cat, tooltip) in categories {
        let btn = ToggleButton::builder()
            .label(icon)
            .tooltip_text(tooltip)
            .css_classes(["category-btn", "flat"])
            .build();

        if let Some(ref first) = first_btn {
            btn.set_group(Some(first));
        } else {
            first_btn = Some(btn.clone());
            btn.set_active(true);
        }

        let cat_val = cat;
        btn.connect_toggled(glib::clone!(
            #[strong]
            current_category,
            #[weak]
            filter,
            move |b| {
                if b.is_active() {
                    *current_category.borrow_mut() = cat_val;
                    filter.changed(gtk4::FilterChange::Different);
                }
            }
        ));
        sidebar.append(&btn);
    }
    container.append(&sidebar);

    // 4. Grid Factory
    let factory = SignalListItemFactory::new();
    factory.connect_setup(move |_factory, item| {
        let item = item.downcast_ref::<gtk4::ListItem>().unwrap();
        let button = gtk4::Button::builder()
            .css_classes(["kaomoji-btn", "flat"])
            .build(); // New class
        item.set_child(Some(&button));
        button.connect_clicked(move |btn| {
            let text = btn.label().unwrap_or_default().to_string();
            super::insert_text(text, crate::close_on_select());
        });
    });

    factory.connect_bind(move |_factory, item| {
        let item = item.downcast_ref::<gtk4::ListItem>().unwrap();
        let button = item.child().unwrap().downcast::<gtk4::Button>().unwrap();
        let entry = item.item().unwrap().downcast::<KaomojiObject>().unwrap();
        button.set_label(&entry.text());
        button.set_tooltip_text(Some(&entry.name()));
    });

    // Kaomoji are wide text
    // As the scale grows each item needs more width or the glyphs get clipped
    // (the scrolled window has no horizontal scrollbar)
    // Drop to fewer columns at higher scales so each item stays wide enough
    let scale = crate::scale();
    let (min_cols, max_cols) = if scale <= 1.0 {
        (2, 3)
    } else if scale <= 1.5 {
        (1, 2)
    } else {
        (1, 1)
    };
    let grid_view = GridView::builder()
        .model(&selection_model)
        .factory(&factory)
        .max_columns(max_cols)
        .min_columns(min_cols)
        .enable_rubberband(false)
        .build();

    let scrolled = ScrolledWindow::builder()
        .child(&grid_view)
        .hscrollbar_policy(PolicyType::Never)
        .hexpand(true)
        .vexpand(true)
        .build();

    container.append(&scrolled);

    // Enter in the search box = select the first visible item and close.
    super::on_search_enter_commit::<KaomojiObject, _>(
        search_entry,
        &container,
        &selection_model,
        &debounce_source,
        &current_query,
        &filter,
        |o| o.text(),
    );

    container
}
