use crate::ecs::EditorWorld;
use crate::systems::retained_ui::{Action, UiHandles};
use nightshade::prelude::*;
use std::collections::HashMap;

const TAG_MANAGER_RECT: Rect = Rect {
    min: Vec2::new(180.0, 180.0),
    max: Vec2::new(560.0, 620.0),
};

const MAX_TAG_ROWS: usize = 32;

#[derive(Clone)]
pub struct TagRow {
    pub tag: String,
    pub label: Entity,
    pub focus_button: Entity,
    pub add_button: Entity,
    pub remove_button: Entity,
}

#[derive(Default, Clone)]
pub struct TagManagerHandles {
    pub panel: Entity,
    pub status_label: Entity,
    pub filter_input: Entity,
    pub apply_filter_button: Entity,
    pub clear_filter_button: Entity,
    pub current_filter_label: Entity,
    pub list_rows: Vec<TagRow>,
    pub current_filter: Option<String>,
}

pub fn build(tree: &mut UiTreeBuilder) -> TagManagerHandles {
    let panel = tree.add_floating_panel("tag_manager", "Tags", TAG_MANAGER_RECT);
    ui_set_visible(tree.world_mut(), panel, false);
    let content = super::panel_content(tree, panel);
    let mut status_label = Entity::default();
    let mut filter_input = Entity::default();
    let mut apply_filter_button = Entity::default();
    let mut clear_filter_button = Entity::default();
    let mut current_filter_label = Entity::default();
    let mut list_rows: Vec<TagRow> = Vec::with_capacity(MAX_TAG_ROWS);

    tree.in_parent(content, |tree| {
        let theme = tree
            .world_mut()
            .resources
            .retained_ui
            .theme_state
            .active_theme();
        let font = theme.font_size;
        let dim = vec4(0.7, 0.7, 0.75, 1.0);

        status_label = tree
            .add_node()
            .size(100.pct(), (18.0).px())
            .with_text("0 tags", font * 0.85)
            .text_left()
            .color_raw::<UiBase>(dim)
            .entity();

        current_filter_label = tree
            .add_node()
            .size(100.pct(), (18.0).px())
            .with_text("Filter: (none)", font * 0.85)
            .text_left()
            .color_raw::<UiBase>(vec4(0.85, 0.85, 0.6, 1.0))
            .entity();

        let filter_row = tree
            .add_node()
            .size(100.pct(), (28.0).px())
            .flow_with_alignment(
                FlowDirection::Horizontal,
                0.0,
                4.0,
                FlowAlignment::Start,
                FlowAlignment::Center,
            )
            .entity();
        tree.in_parent(filter_row, |tree| {
            let input_wrapper = tree
                .add_node()
                .flow_child(Ab(vec2(0.0, 24.0)))
                .flex_grow(1.0)
                .entity();
            tree.in_parent(input_wrapper, |tree| {
                filter_input = tree.add_text_input("filter (substring)");
            });
            apply_filter_button = tree
                .add_node()
                .flow_child(Ab(vec2(70.0, 24.0)))
                .with_text("Apply", font * 0.85)
                .text_center()
                .color_raw::<UiBase>(vec4(0.75, 0.85, 0.9, 1.0))
                .color_raw::<UiHover>(vec4(1.0, 1.0, 1.0, 1.0))
                .with_interaction()
                .with_cursor_icon(winit::window::CursorIcon::Pointer)
                .entity();
            clear_filter_button = tree
                .add_node()
                .flow_child(Ab(vec2(60.0, 24.0)))
                .with_text("Clear", font * 0.85)
                .text_center()
                .color_raw::<UiBase>(dim)
                .color_raw::<UiHover>(vec4(1.0, 1.0, 1.0, 1.0))
                .with_interaction()
                .with_cursor_icon(winit::window::CursorIcon::Pointer)
                .entity();
        });

        let wrapper = tree.add_node().fill_width().flex_grow(1.0).entity();
        let scroll = tree.in_parent(wrapper, |tree| tree.add_scroll_area_fill(4.0, 4.0));
        let list_root = widget::<UiScrollAreaData>(tree.world_mut(), scroll)
            .map(|d| d.content_entity)
            .unwrap_or(scroll);
        tree.in_parent(list_root, |tree| {
            for _ in 0..MAX_TAG_ROWS {
                let row = tree
                    .add_node()
                    .size(100.pct(), (22.0).px())
                    .flow_with_alignment(
                        FlowDirection::Horizontal,
                        0.0,
                        6.0,
                        FlowAlignment::Start,
                        FlowAlignment::Center,
                    )
                    .with_visible(false)
                    .entity();
                let mut label = Entity::default();
                let mut focus_button = Entity::default();
                let mut add_button = Entity::default();
                let mut remove_button = Entity::default();
                tree.in_parent(row, |tree| {
                    label = tree
                        .add_node()
                        .flow_child(Ab(vec2(0.0, 18.0)))
                        .flex_grow(1.0)
                        .with_text("", font * 0.85)
                        .text_left()
                        .color_raw::<UiBase>(vec4(0.9, 0.9, 0.9, 1.0))
                        .entity();
                    add_button = tree
                        .add_node()
                        .flow_child(Ab(vec2(50.0, 20.0)))
                        .with_text("+", font * 0.85)
                        .text_center()
                        .color_raw::<UiBase>(vec4(0.65, 1.0, 0.65, 1.0))
                        .color_raw::<UiHover>(vec4(1.0, 1.0, 1.0, 1.0))
                        .with_interaction()
                        .with_cursor_icon(winit::window::CursorIcon::Pointer)
                        .entity();
                    remove_button = tree
                        .add_node()
                        .flow_child(Ab(vec2(50.0, 20.0)))
                        .with_text("-", font * 0.85)
                        .text_center()
                        .color_raw::<UiBase>(vec4(1.0, 0.65, 0.65, 1.0))
                        .color_raw::<UiHover>(vec4(1.0, 1.0, 1.0, 1.0))
                        .with_interaction()
                        .with_cursor_icon(winit::window::CursorIcon::Pointer)
                        .entity();
                    focus_button = tree
                        .add_node()
                        .flow_child(Ab(vec2(70.0, 20.0)))
                        .with_text("Filter", font * 0.8)
                        .text_center()
                        .color_raw::<UiBase>(vec4(0.65, 0.8, 1.0, 1.0))
                        .color_raw::<UiHover>(vec4(1.0, 1.0, 1.0, 1.0))
                        .with_interaction()
                        .with_cursor_icon(winit::window::CursorIcon::Pointer)
                        .entity();
                });
                list_rows.push(TagRow {
                    tag: String::new(),
                    label,
                    focus_button,
                    add_button,
                    remove_button,
                });
            }
        });
    });

    TagManagerHandles {
        panel,
        status_label,
        filter_input,
        apply_filter_button,
        clear_filter_button,
        current_filter_label,
        list_rows,
        current_filter: None,
    }
}

pub fn poll(editor_world: &mut EditorWorld, world: &mut World, handles: &UiHandles) {
    let apply_button = handles.tag_manager.apply_filter_button;
    let clear_button = handles.tag_manager.clear_filter_button;
    let filter_input = handles.tag_manager.filter_input;
    let focus_buttons: Vec<(Entity, String)> = handles
        .tag_manager
        .list_rows
        .iter()
        .map(|row| (row.focus_button, row.tag.clone()))
        .collect();
    let add_buttons: Vec<(Entity, String)> = handles
        .tag_manager
        .list_rows
        .iter()
        .map(|row| (row.add_button, row.tag.clone()))
        .collect();
    let remove_buttons: Vec<(Entity, String)> = handles
        .tag_manager
        .list_rows
        .iter()
        .map(|row| (row.remove_button, row.tag.clone()))
        .collect();

    let mut new_filter: Option<Option<String>> = None;
    let mut add_tag: Option<String> = None;
    let mut remove_tag: Option<String> = None;
    let mut new_tag_from_input: Option<String> = None;
    for event in ui_events(world) {
        if let UiEvent::ButtonClicked(entity) = event {
            if *entity == apply_button {
                let text = widget::<UiTextInputData>(world, filter_input)
                    .map(|data| data.text.clone())
                    .unwrap_or_default();
                if text.is_empty() {
                    new_filter = Some(None);
                } else {
                    new_filter = Some(Some(text.clone()));
                    new_tag_from_input = Some(text);
                }
            } else if *entity == clear_button {
                new_filter = Some(None);
            } else {
                for (button, tag) in &focus_buttons {
                    if *entity == *button && !tag.is_empty() {
                        new_filter = Some(Some(tag.clone()));
                        break;
                    }
                }
                for (button, tag) in &add_buttons {
                    if *entity == *button && !tag.is_empty() {
                        add_tag = Some(tag.clone());
                        break;
                    }
                }
                for (button, tag) in &remove_buttons {
                    if *entity == *button && !tag.is_empty() {
                        remove_tag = Some(tag.clone());
                        break;
                    }
                }
            }
        }
    }

    if let Some(filter) = new_filter {
        editor_world.resources.ui_handles.tag_manager.current_filter = filter;
    }
    if let Some(tag) = add_tag
        && editor_world.resources.ui.selected_entity.is_some()
    {
        editor_world
            .resources
            .ui_interaction
            .actions
            .push(Action::AddTagToSelected(tag));
    }
    if let Some(tag) = remove_tag
        && editor_world.resources.ui.selected_entity.is_some()
    {
        editor_world
            .resources
            .ui_interaction
            .actions
            .push(Action::RemoveTagFromSelected(tag));
    }
    if let Some(tag) = new_tag_from_input
        && editor_world.resources.ui.selected_entity.is_some()
    {
        editor_world
            .resources
            .ui_interaction
            .actions
            .push(Action::AddTagToSelected(tag));
    }
}

pub fn update(editor_world: &mut EditorWorld, world: &mut World) {
    let panel = editor_world.resources.ui_handles.tag_manager.panel;
    if !world
        .ui
        .get_ui_layout_node(panel)
        .map(|node| node.visible)
        .unwrap_or(false)
    {
        return;
    }

    let filter = editor_world
        .resources
        .ui_handles
        .tag_manager
        .current_filter
        .clone();

    let mut counts: HashMap<String, u32> = HashMap::new();
    for tags in world.resources.entities.tags.values() {
        for tag in tags {
            *counts.entry(tag.clone()).or_insert(0) += 1;
        }
    }
    let mut sorted: Vec<(String, u32)> = counts.into_iter().collect();
    sorted.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0)));

    let status = editor_world.resources.ui_handles.tag_manager.status_label;
    let filter_label = editor_world
        .resources
        .ui_handles
        .tag_manager
        .current_filter_label;
    ui_set_text(world, status, &format!("{} tags", sorted.len()));
    ui_set_text(
        world,
        filter_label,
        &format!("Filter: {}", filter.as_deref().unwrap_or("(none)")),
    );

    let row_count = editor_world
        .resources
        .ui_handles
        .tag_manager
        .list_rows
        .len();
    for index in 0..row_count {
        let entry = sorted.get(index);
        match entry {
            Some((label_text, count)) => {
                let mut owned_rows =
                    std::mem::take(&mut editor_world.resources.ui_handles.tag_manager.list_rows);
                if let Some(row) = owned_rows.get_mut(index) {
                    row.tag = label_text.clone();
                    let display = format!("{label_text}  x{count}");
                    ui_set_text(world, row.label, &display);
                    ui_set_visible(world, row.label, true);
                    ui_set_visible(world, row.focus_button, true);
                    ui_set_visible(world, row.add_button, true);
                    ui_set_visible(world, row.remove_button, true);
                }
                editor_world.resources.ui_handles.tag_manager.list_rows = owned_rows;
            }
            None => {
                let mut owned_rows =
                    std::mem::take(&mut editor_world.resources.ui_handles.tag_manager.list_rows);
                if let Some(row) = owned_rows.get_mut(index) {
                    row.tag.clear();
                    ui_set_visible(world, row.label, false);
                    ui_set_visible(world, row.focus_button, false);
                    ui_set_visible(world, row.add_button, false);
                    ui_set_visible(world, row.remove_button, false);
                }
                editor_world.resources.ui_handles.tag_manager.list_rows = owned_rows;
            }
        }
    }
}
