use nalgebra_glm::{Vec2, Vec4};

use crate::ecs::text::components::{TextAlignment, VerticalAlignment};
use crate::ecs::ui::builder::UiTreeBuilder;
use crate::ecs::ui::components::*;
use crate::ecs::ui::layout_types::{FlowAlignment, FlowDirection};
use crate::ecs::ui::state::{UiBase, UiHover, UiStateTrait};
use crate::ecs::ui::types::{Anchor, Rect};
use crate::ecs::ui::units::{Ab, Rl};

use super::tile_builder::TileBuilder;

use crate::prelude::*;
impl<'a> UiTreeBuilder<'a> {
    pub fn add_property_grid(&mut self, label_width: f32) -> freecs::Entity {
        let grid_entity = self
            .add_node()
            .flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, 0.0)))
            .flow(FlowDirection::Vertical, 4.0, 2.0)
            .auto_height()
            .with_interaction()
            .entity();

        self.world_mut().ui.set_ui_property_grid(
            grid_entity,
            UiPropertyGridData {
                label_width,
                row_entities: Vec::new(),
                label_entities: Vec::new(),
                resize_active: false,
                resize_start_x: 0.0,
                resize_start_width: 0.0,
            },
        );
        if let Some(interaction) = self.world_mut().ui.get_ui_node_interaction_mut(grid_entity) {
            interaction.accessible_role = Some(AccessibleRole::Grid);
        }

        grid_entity
    }

    pub fn add_property_row(
        &mut self,
        grid: freecs::Entity,
        parent: freecs::Entity,
        label: &str,
    ) -> freecs::Entity {
        let label_width = if let Some(data) = self.world_mut().ui.get_ui_property_grid(grid) {
            data.label_width
        } else {
            100.0
        };

        let theme = self.active_theme();
        let font_size = theme.font_size;
        let row_height = theme.button_height;

        let label_slot = self.world_mut().resources.text.cache.add_text(label);

        let row_entity = self
            .add_node()
            .flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, row_height)))
            .auto_height()
            .flow_with_alignment(
                FlowDirection::Horizontal,
                4.0,
                4.0,
                FlowAlignment::Start,
                FlowAlignment::Center,
            )
            .entity();

        if let Some(p) = self.world_mut().core.get_parent_mut(row_entity) {
            *p = crate::ecs::transform::components::Parent(Some(parent));
        }
        self.world_mut()
            .resources
            .transform_state
            .children_cache_valid = false;

        self.push_parent(row_entity);

        let label_entity = self
            .add_node()
            .flow_child(Ab(Vec2::new(label_width, row_height)))
            .with_text_slot(label_slot, font_size * 0.9)
            .with_text_alignment(TextAlignment::Right, VerticalAlignment::Middle)
            .with_text_overflow(crate::ecs::ui::components::TextOverflow::Ellipsis)
            .with_theme_color::<UiBase>(ThemeColor::TextDisabled)
            .entity();

        let widget_area = self
            .add_node()
            .flow_child(Ab(Vec2::new(0.0, row_height)))
            .auto_height()
            .flex_grow(1.0)
            .flow_with_alignment(
                FlowDirection::Horizontal,
                0.0,
                4.0,
                FlowAlignment::Start,
                FlowAlignment::Center,
            )
            .entity();

        self.pop_parent();

        if let Some(data) = self.world_mut().ui.get_ui_property_grid_mut(grid) {
            data.row_entities.push(row_entity);
            data.label_entities.push(label_entity);
        }

        widget_area
    }

    pub fn add_property_slider(
        &mut self,
        grid: freecs::Entity,
        parent: freecs::Entity,
        label: &str,
        min: f32,
        max: f32,
        initial: f32,
    ) -> freecs::Entity {
        let widget_area = self.add_property_row(grid, parent, label);
        self.push_parent(widget_area);
        let widget = self.add_slider(min, max, initial);
        self.pop_parent();
        widget
    }

    pub fn add_property_toggle(
        &mut self,
        grid: freecs::Entity,
        parent: freecs::Entity,
        label: &str,
        initial: bool,
    ) -> freecs::Entity {
        let widget_area = self.add_property_row(grid, parent, label);
        self.push_parent(widget_area);
        let widget = self.add_toggle(initial);
        self.pop_parent();
        widget
    }

    pub fn add_property_text_input(
        &mut self,
        grid: freecs::Entity,
        parent: freecs::Entity,
        label: &str,
        placeholder: &str,
    ) -> freecs::Entity {
        let widget_area = self.add_property_row(grid, parent, label);
        self.push_parent(widget_area);
        let widget = self.add_text_input(placeholder);
        self.pop_parent();
        widget
    }

    pub fn add_property_dropdown(
        &mut self,
        grid: freecs::Entity,
        parent: freecs::Entity,
        label: &str,
        options: &[&str],
        initial: usize,
    ) -> freecs::Entity {
        let widget_area = self.add_property_row(grid, parent, label);
        self.push_parent(widget_area);
        let widget = self.add_dropdown(options, initial);
        self.pop_parent();
        widget
    }

    pub fn add_property_checkbox(
        &mut self,
        grid: freecs::Entity,
        parent: freecs::Entity,
        label: &str,
        initial: bool,
    ) -> freecs::Entity {
        let widget_area = self.add_property_row(grid, parent, label);
        self.push_parent(widget_area);
        let widget = self.add_checkbox(label, initial);
        self.pop_parent();
        widget
    }

    pub fn add_property_drag_value(
        &mut self,
        grid: freecs::Entity,
        parent: freecs::Entity,
        label: &str,
        min: f32,
        max: f32,
        initial: f32,
    ) -> freecs::Entity {
        let widget_area = self.add_property_row(grid, parent, label);
        self.push_parent(widget_area);
        let widget = self.add_drag_value(min, max, initial);
        self.pop_parent();
        widget
    }

    /// Creates a rich text node composed of multiple inline spans, each with
    /// independent color and font-size overrides.
    ///
    /// Returns the container entity. Use
    /// [`ui_rich_text_set_span_text`](crate::ecs::world::World::ui_rich_text_set_span_text)
    /// and related methods to update spans at runtime.
    pub(super) fn build_text_span(
        &mut self,
        span: &TextSpan,
        font_size: f32,
        text_color: Vec4,
        fixed_height: Option<f32>,
        allow_underline: bool,
    ) -> (freecs::Entity, usize) {
        let text_slot = self.world_mut().resources.text.cache.add_text(&span.text);
        let mut span_font_size = span.font_size_override.unwrap_or(font_size);
        let span_color = span.color.unwrap_or(text_color);
        let span_font_index = span.font_index.unwrap_or(0);

        if span.bold {
            span_font_size *= 1.05;
        }

        let outline_width = if span.bold { 0.4 } else { 0.0 };
        let outline_color = if span.bold {
            span_color
        } else {
            Vec4::new(0.0, 0.0, 0.0, 0.0)
        };

        let wrapper_height = fixed_height.unwrap_or(span_font_size * 1.5);

        let span_wrapper = self
            .add_node()
            .flow_child(Ab(Vec2::new(0.0, wrapper_height)))
            .auto_size(crate::ecs::ui::components::AutoSizeMode::Width)
            .flow(FlowDirection::Vertical, 0.0, 0.0)
            .entity();

        self.push_parent(span_wrapper);

        let entity = self.add_node().entity();
        if let Some(content) = self.world_mut().ui.get_ui_node_content_mut(entity) {
            *content = crate::ecs::ui::components::UiNodeContent::Text {
                text_slot,
                font_index: span_font_index,
                font_size_override: Some(span_font_size),
                outline_color,
                outline_width,
                alignment: TextAlignment::Left,
                vertical_alignment: VerticalAlignment::Middle,
                overflow: crate::ecs::ui::components::TextOverflow::default(),
                monospace_width: None,
                font_kind: crate::ecs::text::resources::font_engine::FontKind::Default,
            };
        }
        if let Some(node) = self.world_mut().ui.get_ui_layout_node_mut(entity) {
            node.flow_child_size = Some(Ab(Vec2::new(0.0, wrapper_height)).into());
            node.auto_size = crate::ecs::ui::components::AutoSizeMode::Width;
            node.pointer_events = false;
        }
        if let Some(color) = self.world_mut().ui.get_ui_node_color_mut(entity) {
            color.colors[UiBase::INDEX] = Some(span_color);
        }
        if span.color.is_none() {
            let mut binding = crate::ecs::ui::components::UiThemeBinding::default();
            binding.color_roles[UiBase::INDEX] = Some(ThemeColor::Text);
            self.world_mut().ui.set_ui_theme_binding(entity, binding);
        }

        if allow_underline && span.underline {
            if span.color.is_none() {
                self.add_node()
                    .flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, 1.0)))
                    .with_rect(0.0, 0.0, Vec4::zeros())
                    .with_theme_color::<UiBase>(ThemeColor::Text)
                    .entity();
            } else {
                self.add_node()
                    .flow_child(Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, 1.0)))
                    .with_rect(0.0, 0.0, Vec4::zeros())
                    .color_raw::<UiBase>(span_color)
                    .entity();
            }
        }

        self.pop_parent();

        (span_wrapper, text_slot)
    }

    pub fn add_rich_text(&mut self, spans: &[TextSpan]) -> freecs::Entity {
        let theme = self.active_theme();
        let font_size = theme.font_size;
        let text_color = theme.text_color;

        let container = self
            .add_node()
            .flow_child(Rl(Vec2::new(100.0, 0.0)))
            .auto_size(crate::ecs::ui::components::AutoSizeMode::Height)
            .flow(FlowDirection::Horizontal, 0.0, 0.0)
            .flow_wrap()
            .entity();

        self.push_parent(container);

        let mut span_entities = Vec::with_capacity(spans.len());
        let mut span_text_slots = Vec::with_capacity(spans.len());

        for span in spans {
            let (span_wrapper, text_slot) =
                self.build_text_span(span, font_size, text_color, None, true);
            span_entities.push(span_wrapper);
            span_text_slots.push(text_slot);
        }

        self.pop_parent();

        self.world_mut().ui.set_ui_rich_text(
            container,
            UiRichTextData {
                span_entities,
                span_text_slots,
            },
        );

        container
    }

    pub fn add_property_section(&mut self, parent: freecs::Entity, label: &str) -> freecs::Entity {
        let header = self.add_collapsing_header(label, true);

        let reparent_entity = self
            .world_mut()
            .core
            .get_parent(header)
            .and_then(|p| p.0)
            .unwrap_or(header);

        if let Some(p) = self.world_mut().core.get_parent_mut(reparent_entity) {
            *p = crate::ecs::transform::components::Parent(Some(parent));
        }
        self.world_mut()
            .resources
            .transform_state
            .children_cache_valid = false;

        widget::<UiCollapsingHeaderData>(self.world_mut(), header)
            .map(|d| d.content_entity)
            .unwrap_or(header)
    }

    pub fn add_table(&mut self, headers: &[&str], widths: &[f32]) -> freecs::Entity {
        let columns: Vec<DataGridColumn> = headers
            .iter()
            .zip(widths.iter())
            .map(|(header, width)| DataGridColumn::new(header, *width))
            .collect();
        self.add_data_grid(&columns, 20)
    }

    /// Creates a data grid with virtual scrolling, sortable column headers,
    /// and multi-selection support.
    ///
    /// The grid uses a pool of pre-allocated row nodes. Only visible rows are
    /// populated. Each frame, call
    /// [`ui_data_grid_set_row_count`](crate::ecs::world::World::ui_data_grid_set_row_count),
    /// query [`ui_data_grid_visible_range`](crate::ecs::world::World::ui_data_grid_visible_range),
    /// and set cell text with
    /// [`ui_data_grid_set_cell`](crate::ecs::world::World::ui_data_grid_set_cell).
    ///
    /// # Arguments
    ///
    /// * `columns` - Column definitions with labels, widths, and sort flags.
    /// * `pool_size` - Maximum number of simultaneously visible rows.
    pub fn add_data_grid(
        &mut self,
        columns: &[DataGridColumn],
        pool_size: usize,
    ) -> freecs::Entity {
        let theme = self.active_theme();
        let font_size = theme.font_size;
        let row_height = font_size * 1.8;

        let total_width: f32 = columns.iter().map(|c| c.width).sum();

        let root = self
            .add_node()
            .boundary(Rl(Vec2::new(0.0, 0.0)), Rl(Vec2::new(100.0, 100.0)))
            .flow_child(Rl(Vec2::new(100.0, 100.0)))
            .with_rect(0.0, 0.0, Vec4::zeros())
            .with_theme_color::<UiBase>(ThemeColor::Panel)
            .entity();

        self.push_parent(root);

        let header_row = self
            .add_node()
            .boundary(
                Rl(Vec2::new(0.0, 0.0)),
                Rl(Vec2::new(100.0, 0.0)) + Ab(Vec2::new(0.0, row_height)),
            )
            .flow(FlowDirection::Horizontal, 0.0, 0.0)
            .with_rect(0.0, 0.0, Vec4::zeros())
            .with_theme_color::<UiBase>(ThemeColor::PanelHeader)
            .entity();

        self.push_parent(header_row);

        let mut header_entities = Vec::with_capacity(columns.len());
        let mut header_text_slots = Vec::with_capacity(columns.len());
        for column in columns {
            let text_slot = self
                .world_mut()
                .resources
                .text
                .cache
                .add_text(&column.label);
            header_text_slots.push(text_slot);

            let header_cell = if column.sortable {
                let entity = self
                    .add_node()
                    .flow_child(Ab(Vec2::new(column.width, row_height)))
                    .with_text_slot(text_slot, font_size)
                    .with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
                    .with_theme_color::<UiBase>(ThemeColor::Text)
                    .with_theme_color::<UiHover>(ThemeColor::TextAccent)
                    .with_interaction()
                    .entity();
                if let Some(interaction) = self.world_mut().ui.get_ui_node_interaction_mut(entity) {
                    interaction.cursor_icon = Some(winit::window::CursorIcon::Pointer);
                }
                entity
            } else {
                self.add_node()
                    .flow_child(Ab(Vec2::new(column.width, row_height)))
                    .with_text_slot(text_slot, font_size)
                    .with_text_alignment(TextAlignment::Left, VerticalAlignment::Middle)
                    .with_theme_color::<UiBase>(ThemeColor::Text)
                    .entity()
            };

            header_entities.push(header_cell);
        }

        self.pop_parent();

        let scroll_wrapper = self
            .add_node()
            .boundary(Ab(Vec2::new(0.0, row_height)), Rl(Vec2::new(100.0, 100.0)))
            .entity();
        self.push_parent(scroll_wrapper);

        let scroll = self.add_scroll_area_fill(0.0, 0.0);
        let scroll_entity = scroll;
        let body_entity = widget::<UiScrollAreaData>(self.world_mut(), scroll)
            .map(|d| d.content_entity)
            .unwrap_or(scroll);

        self.pop_parent();

        self.push_parent(body_entity);

        let top_spacer = self
            .add_node()
            .flow_child(Ab(Vec2::new(total_width, 0.0)))
            .entity();

        let mut pool_rows = Vec::with_capacity(pool_size);
        let accent_color = self.active_theme().accent_color;
        let selected_bg = Vec4::new(accent_color.x, accent_color.y, accent_color.z, 0.3);
        let has_editable = columns.iter().any(|c| c.editable);

        for _ in 0..pool_size {
            let mut row_builder = self
                .add_node()
                .flow_child(Ab(Vec2::new(total_width, row_height)))
                .flow(FlowDirection::Horizontal, 0.0, 0.0)
                .with_rect(0.0, 0.0, Vec4::zeros())
                .color_raw::<UiBase>(Vec4::new(0.0, 0.0, 0.0, 0.0))
                .color_raw::<crate::ecs::ui::state::UiSelected>(selected_bg)
                .with_interaction();
            if has_editable {
                row_builder = row_builder.with_cursor_icon(winit::window::CursorIcon::Cell);
            }
            let row_entity = row_builder.entity();

            self.push_parent(row_entity);

            let mut cell_text_slots = Vec::with_capacity(columns.len());
            let mut cell_entities = Vec::with_capacity(columns.len());
            for column in columns {
                let text_slot = self.world_mut().resources.text.cache.add_text("");

                let cell_entity = self
                    .add_node()
                    .flow_child(Ab(Vec2::new(column.width, row_height)))
                    .with_text_slot(text_slot, font_size)
                    .with_text_alignment(column.alignment, VerticalAlignment::Middle)
                    .with_theme_color::<UiBase>(ThemeColor::Text)
                    .entity();

                cell_text_slots.push(text_slot);
                cell_entities.push(cell_entity);
            }

            self.pop_parent();

            if let Some(node) = self.world_mut().ui.get_ui_layout_node_mut(row_entity) {
                node.visible = false;
            }

            pool_rows.push(DataGridPoolRow {
                row_entity,
                cell_text_slots,
                cell_entities,
            });
        }

        let bottom_spacer = self
            .add_node()
            .flow_child(Ab(Vec2::new(total_width, 0.0)))
            .entity();

        self.pop_parent();
        self.pop_parent();

        self.push_parent(root);
        let editing_input_entity = self.add_text_input("");
        if let Some(node) = self
            .world_mut()
            .ui
            .get_ui_layout_node_mut(editing_input_entity)
        {
            node.visible = false;
            node.flow_child_size = None;
            node.base_layout = Some(crate::ecs::ui::layout_types::UiLayoutType::Window(
                crate::ecs::ui::layout_types::WindowLayout {
                    position: Ab(Vec2::new(0.0, 0.0)).into(),
                    size: Ab(Vec2::new(100.0, row_height)).into(),
                    anchor: crate::ecs::ui::types::Anchor::TopLeft,
                },
            ));
        }
        self.pop_parent();

        self.world_mut().ui.set_ui_data_grid(
            root,
            UiDataGridData {
                columns: columns.to_vec(),
                row_height,
                pool_size,
                total_rows: 0,
                scroll_entity,
                body_entity,
                header_entities,
                header_text_slots,
                top_spacer,
                bottom_spacer,
                pool_rows,
                visible_start: 0,
                sort_column: None,
                sort_ascending: true,
                sort_changed: false,
                selected_rows: std::collections::HashSet::new(),
                selection_anchor: None,
                selection_changed: false,
                focused: false,
                resize_column: None,
                resize_start_x: 0.0,
                resize_start_width: 0.0,
                filtered_indices: None,
                header_divider_entities: Vec::new(),
                filter_row_entity: None,
                filter_input_entities: Vec::new(),
                filter_texts: Vec::new(),
                editing_cell: None,
                editing_input_entity: Some(editing_input_entity),
            },
        );
        if let Some(interaction) = self.world_mut().ui.get_ui_node_interaction_mut(root) {
            interaction.accessible_role = Some(AccessibleRole::Grid);
        }

        root
    }

    pub fn add_tile_container(&mut self, size: Vec2) -> freecs::Entity {
        let container = self
            .add_node()
            .window(Ab(Vec2::new(0.0, 0.0)), Ab(size), Anchor::TopLeft)
            .with_rect(0.0, 0.0, Vec4::new(0.0, 0.0, 0.0, 0.0))
            .with_theme_color::<UiBase>(ThemeColor::Panel)
            .with_clip()
            .entity();

        let root_tabs = TileNode::Tabs {
            panes: Vec::new(),
            active: 0,
        };

        let tiles: Vec<Option<TileNode>> = vec![Some(root_tabs)];

        let data = UiTileContainerData {
            tiles,
            root: TileId(0),
            rects: vec![Rect::default()],
            dragging_splitter: None,
            pending_tab_drag: None,
            dragging_tab: None,
            drop_preview: None,
            container_entity: container,
            splitter_width: 4.0,
            tab_bar_height: 26.0,
            next_free: Vec::new(),
            hovered_close: None,
        };

        self.world_mut().ui.set_ui_tile_container(container, data);

        container
    }

    pub fn build_tiles(
        &mut self,
        container: freecs::Entity,
        f: impl FnOnce(&mut TileBuilder<'_, 'a>),
    ) {
        let mut builder = TileBuilder {
            tree: self,
            container,
        };
        f(&mut builder);
    }
}
