//! Node Palette UI
//!
//! Left sidebar showing available node types organized by category

use super::node_types::{NodeCategory, NodeTypeRegistry};
use eframe::egui;

/// Node palette state
pub struct NodePalette {
    /// Node type registry
    registry: NodeTypeRegistry,

    /// Category collapse states
    collapsed_categories: std::collections::HashSet<NodeCategory>,

    /// Search filter text
    search_filter: String,
}

impl NodePalette {
    pub fn new() -> Self {
        Self {
            registry: NodeTypeRegistry::new(),
            collapsed_categories: std::collections::HashSet::new(),
            search_filter: String::new(),
        }
    }

    /// Render the palette UI
    ///
    /// The `on_node_clicked` callback is called when the user clicks a node type to add it
    pub fn render<F>(&mut self, ui: &mut egui::Ui, rect: egui::Rect, mut on_node_clicked: F)
    where
        F: FnMut(&str),
    {
        // Draw background
        ui.painter()
            .rect_filled(rect, 0.0, egui::Color32::from_rgb(30, 30, 30));

        // Create UI within the palette rect
        ui.scope_builder(egui::UiBuilder::new().max_rect(rect), |ui| {
            ui.vertical(|ui| {
                ui.add_space(8.0);

                // Title
                ui.heading("Node Palette");
                ui.add_space(4.0);

                // Search box
                ui.horizontal(|ui| {
                    ui.label("Search:");
                    ui.text_edit_singleline(&mut self.search_filter);
                });

                ui.add_space(8.0);
                ui.separator();
                ui.add_space(8.0);

                // Scrollable node list
                egui::ScrollArea::vertical()
                    .id_salt("node_palette_scroll")
                    .show(ui, |ui| {
                        self.render_categories(ui, &mut on_node_clicked);
                    });
            });
        });
    }

    fn render_categories<F>(&mut self, ui: &mut egui::Ui, on_node_clicked: &mut F)
    where
        F: FnMut(&str),
    {
        let search_lower = self.search_filter.to_lowercase();

        for category in self.registry.all_categories() {
            // Get nodes in this category
            let mut nodes = self.registry.get_by_category(category);

            // Filter by search text (node names only)
            if !search_lower.is_empty() {
                nodes.retain(|node| {
                    node.display_name.to_lowercase().contains(&search_lower)
                });
            }

            // Skip empty categories
            if nodes.is_empty() {
                continue;
            }

            // Sort nodes by name
            nodes.sort_by(|a, b| a.display_name.cmp(&b.display_name));

            // Render category header
            let is_collapsed = self.collapsed_categories.contains(&category);
            let arrow = if is_collapsed { ">" } else { "v" };
            let label = format!("{} {} ({})", arrow, category.display_name(), nodes.len());

            let header_response = ui.selectable_label(false, label);

            // Toggle collapse on click
            if header_response.clicked() {
                if is_collapsed {
                    self.collapsed_categories.remove(&category);
                } else {
                    self.collapsed_categories.insert(category);
                }
            }

            // Render nodes if not collapsed
            if !is_collapsed {
                ui.indent(category.display_name(), |ui| {
                    for node in nodes {
                        self.render_node_button(ui, node.id.as_str(), &node.display_name, on_node_clicked);
                    }
                });
            }

            ui.add_space(4.0);
        }
    }

    fn render_node_button<F>(
        &self,
        ui: &mut egui::Ui,
        node_id: &str,
        display_name: &str,
        on_node_clicked: &mut F,
    ) where
        F: FnMut(&str),
    {
        // Use drag source to enable dragging
        let drag_id = egui::Id::new(format!("node_palette_{}", node_id));
        let response = ui.dnd_drag_source(
            drag_id,
            node_id.to_string(),
            |ui| {
                let button = egui::Button::new(display_name)
                    .min_size(egui::vec2(ui.available_width() - 8.0, 24.0))
                    .fill(egui::Color32::from_rgb(50, 50, 50));
                ui.add(button)
            },
        );

        // Handle click: detect clicks by checking if drag stopped with minimal movement
        // dnd_drag_source always sets is_being_dragged=true on press, so we can't use that
        if response.response.drag_stopped() {
            // Check if this was actually a drag or just a click (minimal movement)
            if let Some(start_pos) = response.response.interact_pointer_pos() {
                if let Some(current_pos) = ui.input(|i| i.pointer.interact_pos()) {
                    let drag_distance = (current_pos - start_pos).length();
                    if drag_distance < 5.0 {
                        // This was a click, not a drag
                        on_node_clicked(node_id);
                    }
                }
            }
        }

        // Show tooltip with description
        if let Some(node_info) = self.registry.get(node_id) {
            response.response.on_hover_text(&node_info.description);
        }
    }
}

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