use crate::ecs::ui::state::UiStateTrait as _;
use nalgebra_glm::{Vec2, Vec4};
use winit::keyboard::KeyCode;

use crate::ecs::world::World;

use super::handle_scroll::{ScrollFrameInputs, apply_scroll_frame};
use super::snapshot_interaction;

pub(super) struct TreeViewContext<'a> {
    pub ctrl_held: bool,
    pub frame_keys: &'a [(KeyCode, bool)],
    pub focused_entity: Option<freecs::Entity>,
    pub scroll_delta: Vec2,
    pub mouse_position: Vec2,
    pub dpi_scale: f32,
}

pub(super) fn handle_tree_view(
    world: &mut World,
    entity: freecs::Entity,
    data: &crate::ecs::ui::components::UiTreeViewData,
    ctx: &TreeViewContext<'_>,
) {
    let ctrl_held = ctx.ctrl_held;
    let frame_keys = ctx.frame_keys;
    let focused_entity = ctx.focused_entity;

    if let Some(widget_data) = world.ui.get_ui_tree_view_mut(entity) {
        widget_data.changed = false;
        widget_data.context_menu_node = None;
    }

    let node_entities = data.node_entities.clone();
    let multi_select = data.multi_select;
    let tree_entity = entity;

    for node_entity in &node_entities {
        let Some(tree_node) = world.ui.get_ui_tree_node(*node_entity).cloned() else {
            continue;
        };

        let row_interaction = snapshot_interaction(world, tree_node.row_entity);

        let arrow_clicked = row_interaction.clicked
            && world
                .ui
                .get_ui_layout_node(tree_node.arrow_entity)
                .map(|node| {
                    node.computed_rect
                        .contains(world.resources.input.mouse.position)
                })
                .unwrap_or(false);

        if row_interaction.clicked && !arrow_clicked {
            if !multi_select || !ctrl_held {
                let previously_selected = data.selected_nodes.clone();
                for prev in &previously_selected {
                    if *prev != *node_entity
                        && let Some(prev_node) = world.ui.get_ui_tree_node(*prev).cloned()
                    {
                        if let Some(color) = world.ui.get_ui_node_color_mut(prev_node.row_entity) {
                            color.colors[crate::ecs::ui::state::UiSelected::INDEX] = None;
                        }
                        if let Some(weights) =
                            world.ui.get_ui_state_weights_mut(prev_node.row_entity)
                        {
                            weights.weights[crate::ecs::ui::state::UiSelected::INDEX] = 0.0;
                        }
                        if let Some(widget_data) = world.ui.get_ui_tree_node_mut(*prev) {
                            widget_data.selected = false;
                        }
                    }
                }
            }

            let new_selected = if ctrl_held && multi_select {
                !tree_node.selected
            } else {
                true
            };

            let accent = world
                .resources
                .retained_ui
                .theme_state
                .active_theme()
                .accent_color;
            let selected_bg = Vec4::new(accent.x, accent.y, accent.z, 0.3);

            if let Some(color) = world.ui.get_ui_node_color_mut(tree_node.row_entity) {
                color.colors[crate::ecs::ui::state::UiSelected::INDEX] = if new_selected {
                    Some(selected_bg)
                } else {
                    None
                };
            }
            if let Some(weights) = world.ui.get_ui_state_weights_mut(tree_node.row_entity) {
                weights.weights[crate::ecs::ui::state::UiSelected::INDEX] =
                    if new_selected { 1.0 } else { 0.0 };
            }
            if let Some(widget_data) = world.ui.get_ui_tree_node_mut(*node_entity) {
                widget_data.selected = new_selected;
            }

            let mut new_selection: Vec<freecs::Entity> = Vec::new();
            for candidate_entity in &node_entities {
                if let Some(node_data) = world.ui.get_ui_tree_node(*candidate_entity)
                    && node_data.selected
                {
                    new_selection.push(*candidate_entity);
                }
            }
            if let Some(widget_data) = world.ui.get_ui_tree_view_mut(tree_entity) {
                widget_data.selected_nodes = new_selection;
                widget_data.changed = true;
            }

            world.resources.retained_ui.events_for_active_mut().push(
                crate::ecs::ui::resources::UiEvent::TreeNodeSelected {
                    tree: tree_entity,
                    node: *node_entity,
                    selected: new_selected,
                },
            );
        }

        if arrow_clicked || row_interaction.double_clicked {
            let new_expanded = !tree_node.expanded;

            if new_expanded && tree_node.lazy && !tree_node.lazy_loaded {
                world.resources.retained_ui.events_for_active_mut().push(
                    crate::ecs::ui::resources::UiEvent::TreeNodeExpandRequested {
                        tree: tree_entity,
                        node: *node_entity,
                        user_data: tree_node.user_data,
                    },
                );
            } else {
                world.resources.text.cache.set_text(
                    tree_node.arrow_text_slot,
                    if new_expanded { "\u{25BC}" } else { "\u{25B6}" },
                );
                if let Some(node) = world
                    .ui
                    .get_ui_layout_node_mut(tree_node.children_container)
                {
                    node.visible = new_expanded;
                }
                if let Some(widget_data) = world.ui.get_ui_tree_node_mut(*node_entity) {
                    widget_data.expanded = new_expanded;
                }
                world.resources.retained_ui.events_for_active_mut().push(
                    crate::ecs::ui::resources::UiEvent::TreeNodeToggled {
                        tree: tree_entity,
                        node: *node_entity,
                        expanded: new_expanded,
                    },
                );
            }
        }

        if row_interaction.right_clicked {
            let mouse_position = world.resources.input.mouse.position;
            if let Some(widget_data) = world.ui.get_ui_tree_view_mut(tree_entity) {
                widget_data.context_menu_node = Some(*node_entity);
            }
            world.resources.retained_ui.events_for_active_mut().push(
                crate::ecs::ui::resources::UiEvent::TreeNodeContextMenu {
                    tree: tree_entity,
                    node: *node_entity,
                    position: mouse_position,
                },
            );
        }
    }

    if focused_entity == Some(entity) || focused_entity == Some(data.content_entity) {
        let visible_nodes: Vec<freecs::Entity> = node_entities
            .iter()
            .filter(|candidate_entity| {
                if let Some(tree_node) = world.ui.get_ui_tree_node(**candidate_entity).cloned() {
                    let mut current_parent = tree_node.parent_node;
                    while let Some(parent_entity) = current_parent {
                        if let Some(parent_data) = world.ui.get_ui_tree_node(parent_entity) {
                            if !parent_data.expanded {
                                return false;
                            }
                            current_parent = parent_data.parent_node;
                        } else {
                            break;
                        }
                    }
                    true
                } else {
                    false
                }
            })
            .copied()
            .collect();

        let current_focused = data
            .selected_nodes
            .first()
            .copied()
            .or_else(|| visible_nodes.first().copied());

        let current_index =
            current_focused.and_then(|cf| visible_nodes.iter().position(|n| *n == cf));

        for &(key, pressed) in frame_keys {
            if !pressed {
                continue;
            }
            let new_focus = match key {
                KeyCode::ArrowDown => current_index
                    .map(|idx| (idx + 1).min(visible_nodes.len().saturating_sub(1)))
                    .or(Some(0)),
                KeyCode::ArrowUp => current_index.map(|idx| idx.saturating_sub(1)).or(Some(0)),
                KeyCode::ArrowRight => {
                    if let Some(focus) = current_focused
                        && let Some(tree_node) = world.ui.get_ui_tree_node(focus).cloned()
                        && !tree_node.expanded
                    {
                        world
                            .resources
                            .text
                            .cache
                            .set_text(tree_node.arrow_text_slot, "\u{25BC}");
                        if let Some(node) = world
                            .ui
                            .get_ui_layout_node_mut(tree_node.children_container)
                        {
                            node.visible = true;
                        }
                        if let Some(widget_data) = world.ui.get_ui_tree_node_mut(focus) {
                            widget_data.expanded = true;
                        }
                        world.resources.retained_ui.events_for_active_mut().push(
                            crate::ecs::ui::resources::UiEvent::TreeNodeToggled {
                                tree: tree_entity,
                                node: focus,
                                expanded: true,
                            },
                        );
                    }
                    None
                }
                KeyCode::ArrowLeft => {
                    if let Some(focus) = current_focused
                        && let Some(tree_node) = world.ui.get_ui_tree_node(focus).cloned()
                    {
                        if tree_node.expanded {
                            world
                                .resources
                                .text
                                .cache
                                .set_text(tree_node.arrow_text_slot, "\u{25B6}");
                            if let Some(node) = world
                                .ui
                                .get_ui_layout_node_mut(tree_node.children_container)
                            {
                                node.visible = false;
                            }
                            if let Some(widget_data) = world.ui.get_ui_tree_node_mut(focus) {
                                widget_data.expanded = false;
                            }
                            world.resources.retained_ui.events_for_active_mut().push(
                                crate::ecs::ui::resources::UiEvent::TreeNodeToggled {
                                    tree: tree_entity,
                                    node: focus,
                                    expanded: false,
                                },
                            );
                            None
                        } else if let Some(parent) = tree_node.parent_node {
                            visible_nodes.iter().position(|n| *n == parent)
                        } else {
                            None
                        }
                    } else {
                        None
                    }
                }
                KeyCode::Enter | KeyCode::Space => {
                    if let Some(focus) = current_focused
                        && let Some(tree_node) = world.ui.get_ui_tree_node(focus).cloned()
                    {
                        let new_expanded = !tree_node.expanded;
                        world.resources.text.cache.set_text(
                            tree_node.arrow_text_slot,
                            if new_expanded { "\u{25BC}" } else { "\u{25B6}" },
                        );
                        if let Some(node) = world
                            .ui
                            .get_ui_layout_node_mut(tree_node.children_container)
                        {
                            node.visible = new_expanded;
                        }
                        if let Some(widget_data) = world.ui.get_ui_tree_node_mut(focus) {
                            widget_data.expanded = new_expanded;
                        }
                        world.resources.retained_ui.events_for_active_mut().push(
                            crate::ecs::ui::resources::UiEvent::TreeNodeToggled {
                                tree: tree_entity,
                                node: focus,
                                expanded: new_expanded,
                            },
                        );
                    }
                    None
                }
                _ => None,
            };

            if let Some(new_idx) = new_focus
                && new_idx < visible_nodes.len()
            {
                let new_node = visible_nodes[new_idx];

                if let Some(old) = current_focused
                    && let Some(old_tn) = world.ui.get_ui_tree_node(old).cloned()
                {
                    if let Some(color) = world.ui.get_ui_node_color_mut(old_tn.row_entity) {
                        color.colors[crate::ecs::ui::state::UiSelected::INDEX] = None;
                    }
                    if let Some(weights) = world.ui.get_ui_state_weights_mut(old_tn.row_entity) {
                        weights.weights[crate::ecs::ui::state::UiSelected::INDEX] = 0.0;
                    }
                    if let Some(widget_data) = world.ui.get_ui_tree_node_mut(old) {
                        widget_data.selected = false;
                    }
                }

                let accent = world
                    .resources
                    .retained_ui
                    .theme_state
                    .active_theme()
                    .accent_color;
                let selected_bg = Vec4::new(accent.x, accent.y, accent.z, 0.3);

                if let Some(new_tn) = world.ui.get_ui_tree_node(new_node).cloned() {
                    if let Some(color) = world.ui.get_ui_node_color_mut(new_tn.row_entity) {
                        color.colors[crate::ecs::ui::state::UiSelected::INDEX] = Some(selected_bg);
                    }
                    if let Some(weights) = world.ui.get_ui_state_weights_mut(new_tn.row_entity) {
                        weights.weights[crate::ecs::ui::state::UiSelected::INDEX] = 1.0;
                    }
                }
                if let Some(widget_data) = world.ui.get_ui_tree_node_mut(new_node) {
                    widget_data.selected = true;
                }

                if let Some(widget_data) = world.ui.get_ui_tree_view_mut(tree_entity) {
                    widget_data.selected_nodes = vec![new_node];
                    widget_data.changed = true;
                }

                world.resources.retained_ui.events_for_active_mut().push(
                    crate::ecs::ui::resources::UiEvent::TreeNodeSelected {
                        tree: tree_entity,
                        node: new_node,
                        selected: true,
                    },
                );
            }
        }
    }

    let result = apply_scroll_frame(
        world,
        ScrollFrameInputs {
            entity,
            content_entity: data.content_entity,
            thumb_entity: data.thumb_entity,
            track_entity: data.track_entity,
            scroll_offset: data.scroll_offset,
            thumb_dragging: data.thumb_dragging,
            thumb_drag_start_offset: data.thumb_drag_start_offset,
            snap_interval: None,
            scroll_delta: ctx.scroll_delta,
            mouse_position: ctx.mouse_position,
            dpi_scale: ctx.dpi_scale,
        },
    );

    if let Some(widget_data) = world.ui.get_ui_tree_view_mut(entity) {
        widget_data.scroll_offset = result.scroll_offset;
        widget_data.thumb_dragging = result.thumb_dragging;
        widget_data.thumb_drag_start_offset = result.thumb_drag_start_offset;
    }
}

pub(super) fn handle_modal_dialog(
    world: &mut World,
    entity: freecs::Entity,
    data: &crate::ecs::ui::components::UiModalDialogData,
    frame_keys: &[(KeyCode, bool)],
) {
    if !world
        .ui
        .get_ui_layout_node(entity)
        .is_some_and(|n| n.visible)
    {
        if let Some(widget_data) = world.ui.get_ui_modal_dialog_mut(entity) {
            widget_data.result = None;
        }
        return;
    }

    let mut result = None;

    if let Some(ok) = data.ok_button
        && world
            .ui
            .get_ui_node_interaction(ok)
            .is_some_and(|i| i.clicked)
    {
        result = Some(true);
    }
    if let Some(cancel) = data.cancel_button
        && world
            .ui
            .get_ui_node_interaction(cancel)
            .is_some_and(|i| i.clicked)
    {
        result = Some(false);
    }
    if world
        .ui
        .get_ui_node_interaction(data.backdrop_entity)
        .is_some_and(|i| i.clicked)
    {
        result = Some(false);
    }
    for (key, is_pressed) in frame_keys {
        if *is_pressed && *key == KeyCode::Escape {
            result = Some(false);
        }
    }

    if let Some(confirmed) = result {
        if let Some(node) = world.ui.get_ui_layout_node_mut(data.backdrop_entity) {
            node.visible = false;
        }
        if let Some(node) = world.ui.get_ui_layout_node_mut(entity) {
            node.visible = false;
        }
        if let Some(widget_data) = world.ui.get_ui_modal_dialog_mut(entity) {
            widget_data.result = Some(confirmed);
        }
        world.resources.retained_ui.overlays.active_modal = None;
        world
            .resources
            .retained_ui
            .frame
            .events
            .push(crate::ecs::ui::resources::UiEvent::ModalClosed { entity, confirmed });
    }
}
