use crate::ecs::world::World;
use nalgebra_glm::{Vec2, Vec4};

use crate::ecs::ui::state::{UiBase, UiStateTrait};
use crate::ecs::ui::units::Rl;

use super::range_slider_visuals::{RangeSliderVisualUpdate, update_range_slider_visuals};

use crate::prelude::*;
pub fn measure_ui_text_width(world: &mut World, text: &str, font_size: f32) -> f32 {
    crate::ecs::ui::widget_systems::measure_text_width(
        &mut world.resources.text.font_engine,
        text,
        font_size,
    )
}

pub fn widget<T: crate::ecs::ui::components::WidgetData>(
    world: &World,
    entity: freecs::Entity,
) -> Option<&T> {
    T::get(world, entity)
}

pub fn ui_changed(world: &World, entity: freecs::Entity) -> bool {
    if let Some(d) = world.ui.get_ui_slider(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_range_slider(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_toggle(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_checkbox(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_radio(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_tab_bar(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_breadcrumb(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_splitter(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_text_input(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_dropdown(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_multi_select(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_date_picker(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_color_picker(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_selectable_label(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_drag_value(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_tree_view(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_text_area(entity) {
        return d.changed;
    }
    if let Some(d) = world.ui.get_ui_rich_text_editor(entity) {
        return d.changed;
    }
    false
}

pub fn ui_slider_value(world: &World, entity: freecs::Entity) -> Option<f32> {
    world.ui.get_ui_slider(entity).map(|data| data.value)
}

pub fn ui_slider_value_changed(world: &World, entity: freecs::Entity) -> Option<f32> {
    if let Some(data) = world.ui.get_ui_slider(entity)
        && data.changed
    {
        Some(data.value)
    } else {
        None
    }
}

pub fn ui_drag_value(world: &World, entity: freecs::Entity) -> Option<f32> {
    world.ui.get_ui_drag_value(entity).map(|data| data.value)
}

pub fn ui_drag_value_changed(world: &World, entity: freecs::Entity) -> Option<f32> {
    if let Some(data) = world.ui.get_ui_drag_value(entity)
        && data.changed
    {
        Some(data.value)
    } else {
        None
    }
}

pub fn ui_toggle_value(world: &World, entity: freecs::Entity) -> Option<bool> {
    world.ui.get_ui_toggle(entity).map(|data| data.value)
}

pub fn ui_toggle_changed(world: &World, entity: freecs::Entity) -> Option<bool> {
    if let Some(data) = world.ui.get_ui_toggle(entity)
        && data.changed
    {
        Some(data.value)
    } else {
        None
    }
}

pub fn ui_checkbox_value(world: &World, entity: freecs::Entity) -> Option<bool> {
    world.ui.get_ui_checkbox(entity).map(|data| data.value)
}

pub fn ui_checkbox_changed(world: &World, entity: freecs::Entity) -> Option<bool> {
    if let Some(data) = world.ui.get_ui_checkbox(entity)
        && data.changed
    {
        Some(data.value)
    } else {
        None
    }
}

pub fn ui_text_input_text(world: &World, entity: freecs::Entity) -> Option<&str> {
    if let Some(data) = world.ui.get_ui_text_input(entity) {
        Some(data.text.as_str())
    } else {
        None
    }
}

pub fn ui_text_input_changed(world: &World, entity: freecs::Entity) -> Option<&str> {
    if let Some(data) = world.ui.get_ui_text_input(entity)
        && data.changed
    {
        Some(data.text.as_str())
    } else {
        None
    }
}

pub fn ui_dropdown_selected(world: &World, entity: freecs::Entity) -> Option<usize> {
    world
        .ui
        .get_ui_dropdown(entity)
        .map(|data| data.selected_index)
}

pub fn ui_dropdown_selected_changed(world: &World, entity: freecs::Entity) -> Option<usize> {
    if let Some(data) = world.ui.get_ui_dropdown(entity)
        && data.changed
    {
        Some(data.selected_index)
    } else {
        None
    }
}

pub fn ui_color_picker_color(world: &World, entity: freecs::Entity) -> Option<nalgebra_glm::Vec4> {
    world.ui.get_ui_color_picker(entity).map(|data| data.color)
}

pub fn ui_color_picker_changed(
    world: &World,
    entity: freecs::Entity,
) -> Option<nalgebra_glm::Vec4> {
    if let Some(data) = world.ui.get_ui_color_picker(entity)
        && data.changed
    {
        Some(data.color)
    } else {
        None
    }
}

pub fn ui_radio_selected(world: &World, group_id: u32) -> Option<usize> {
    let entities = world
        .resources
        .retained_ui
        .groups
        .radio
        .get(&group_id)?
        .clone();
    for entity in entities {
        if let Some(data) = world.ui.get_ui_radio(entity)
            && data.selected
        {
            return Some(data.option_index);
        }
    }
    None
}

pub fn ui_tree_view_selected(world: &World, entity: freecs::Entity) -> Vec<freecs::Entity> {
    if let Some(data) = world.ui.get_ui_tree_view(entity) {
        data.selected_nodes.clone()
    } else {
        Vec::new()
    }
}

pub fn ui_collapsing_header_open(world: &World, entity: freecs::Entity) -> Option<bool> {
    world
        .ui
        .get_ui_collapsing_header(entity)
        .map(|data| data.open)
}

pub fn ui_tab_bar_selected(world: &World, entity: freecs::Entity) -> Option<usize> {
    world
        .ui
        .get_ui_tab_bar(entity)
        .map(|data| data.selected_tab)
}

pub fn ui_button_set_text(world: &mut World, entity: freecs::Entity, text: &str) {
    if let Some(data) = world.ui.get_ui_button(entity)
        && let Some(slot) = data.text_slot
    {
        world.resources.text.cache.set_text(slot, text);
    }
}

pub fn ui_slider_set_value(world: &mut World, entity: freecs::Entity, value: f32) {
    let update = if let Some(data) = world.ui.get_ui_slider(entity) {
        let normalized = if data.logarithmic && data.min > 0.0 && data.max > data.min {
            ((value / data.min).ln() / (data.max / data.min).ln()).clamp(0.0, 1.0)
        } else {
            ((value - data.min) / (data.max - data.min)).clamp(0.0, 1.0)
        };
        Some((
            data.fill_entity,
            data.text_slot,
            data.min,
            data.max,
            normalized,
            data.logarithmic,
        ))
    } else {
        None
    };

    if let Some((fill_entity, text_slot, min, max, normalized, logarithmic)) = update {
        let clamped = if logarithmic && min > 0.0 && max > min {
            min * (max / min).powf(normalized)
        } else {
            min + normalized * (max - min)
        };
        if let Some(fill_node) = world.ui.get_ui_layout_node_mut(fill_entity)
            && let Some(crate::ecs::ui::layout_types::UiLayoutType::Boundary(boundary)) =
                fill_node.base_layout.as_mut()
        {
            boundary.position_2 = Rl(Vec2::new(normalized * 100.0, 100.0)).into();
        }
        let precision = if logarithmic { 3 } else { 1 };
        world
            .resources
            .text
            .cache
            .set_text(text_slot, format!("{:.prec$}", clamped, prec = precision));
        if let Some(data) = world.ui.get_ui_slider_mut(entity) {
            data.value = clamped;
        }
    }
}

pub fn ui_range_slider_set_values(world: &mut World, entity: freecs::Entity, low: f32, high: f32) {
    let update = if let Some(data) = world.ui.get_ui_range_slider(entity) {
        let range = data.max - data.min;
        if range.abs() > f32::EPSILON {
            let low_n = ((low - data.min) / range).clamp(0.0, 1.0);
            let high_n = ((high - data.min) / range).clamp(0.0, 1.0);
            Some((
                data.fill_entity,
                data.low_thumb_entity,
                data.high_thumb_entity,
                data.text_slot,
                data.precision,
                data.thumb_half_size,
                low_n,
                high_n,
                data.min + low_n * range,
                data.min + high_n * range,
            ))
        } else {
            None
        }
    } else {
        None
    };

    if let Some((
        fill_entity,
        low_thumb,
        high_thumb,
        text_slot,
        precision,
        thumb_half,
        low_n,
        high_n,
        clamped_low,
        clamped_high,
    )) = update
    {
        update_range_slider_visuals(
            world,
            &RangeSliderVisualUpdate {
                fill_entity,
                low_thumb,
                high_thumb,
                text_slot,
                precision,
                low_normalized: low_n,
                high_normalized: high_n,
                low_value: clamped_low,
                high_value: clamped_high,
                thumb_half,
            },
        );
        if let Some(data) = world.ui.get_ui_range_slider_mut(entity) {
            data.low_value = clamped_low;
            data.high_value = clamped_high;
        }
    }
}

pub fn ui_breadcrumb_set_segments(world: &mut World, entity: freecs::Entity, segments: &[&str]) {
    let text_slots: Vec<usize> = if let Some(data) = world.ui.get_ui_breadcrumb_mut(entity) {
        data.segments = segments.iter().map(|s| s.to_string()).collect();
        data.segment_text_slots.clone()
    } else {
        return;
    };
    for (index, text_slot) in text_slots.iter().enumerate() {
        if index < segments.len() {
            world
                .resources
                .text
                .cache
                .set_text(*text_slot, segments[index]);
        }
    }
}

pub fn ui_toggle_set_value(world: &mut World, entity: freecs::Entity, value: bool) {
    if let Some(data) = world.ui.get_ui_toggle_mut(entity) {
        data.value = value;
    }
}

pub fn ui_radio_group_value(world: &World, group_id: u32) -> Option<usize> {
    ui_radio_selected(world, group_id)
}

pub fn ui_progress_bar_set_value(world: &mut World, entity: freecs::Entity, value: f32) {
    let update = world
        .ui
        .get_ui_progress_bar(entity)
        .map(|data| data.fill_entity);

    if let Some(fill_entity) = update {
        let normalized = value.clamp(0.0, 1.0);
        if let Some(fill_node) = world.ui.get_ui_layout_node_mut(fill_entity)
            && let Some(crate::ecs::ui::layout_types::UiLayoutType::Boundary(boundary)) =
                fill_node.base_layout.as_mut()
        {
            boundary.position_2 = Rl(Vec2::new(normalized * 100.0, 100.0)).into();
        }
        if let Some(data) = world.ui.get_ui_progress_bar_mut(entity) {
            data.value = normalized;
        }
        ui_mark_layout_dirty(world);
    }
}

pub fn ui_scroll_area_set_offset(world: &mut World, entity: freecs::Entity, offset: f32) {
    if let Some(data) = world.ui.get_ui_scroll_area_mut(entity) {
        data.scroll_offset = offset;
        ui_mark_layout_dirty(world);
    }
}

pub fn ui_scroll_area_set_snap(world: &mut World, entity: freecs::Entity, interval: Option<f32>) {
    if let Some(data) = world.ui.get_ui_scroll_area_mut(entity) {
        data.snap_interval = interval;
    }
}

pub fn ui_virtual_list_set_count(world: &mut World, entity: freecs::Entity, count: usize) {
    if let Some(data) = world.ui.get_ui_virtual_list_mut(entity) {
        data.total_items = count;
        ui_mark_layout_dirty(world);
    }
}

pub fn ui_virtual_list_selection_changed(world: &World, entity: freecs::Entity) -> bool {
    if let Some(data) = world.ui.get_ui_virtual_list(entity) {
        data.selection_changed
    } else {
        false
    }
}

pub fn ui_virtual_list_populate(
    world: &mut World,
    entity: freecs::Entity,
    source: &dyn crate::ecs::ui::components::VirtualListDataSource,
) {
    let count = source.item_count();
    ui_virtual_list_set_count(world, entity, count);
    let (visible_start, pool_items) = match world.ui.get_ui_virtual_list(entity) {
        Some(data) => (data.visible_start, data.pool_items.clone()),
        None => return,
    };
    for (pool_index, pool_item) in pool_items.iter().enumerate() {
        let item_index = visible_start + pool_index;
        if item_index < count {
            source.bind_item(world, item_index, pool_item.container_entity);
        }
    }
}

pub fn ui_virtual_list_populate_fn(
    world: &mut World,
    entity: freecs::Entity,
    count: usize,
    bind: impl Fn(&mut crate::ecs::world::World, usize, freecs::Entity),
) {
    ui_virtual_list_set_count(world, entity, count);
    let (visible_start, pool_items) = match world.ui.get_ui_virtual_list(entity) {
        Some(data) => (data.visible_start, data.pool_items.clone()),
        None => return,
    };
    for (pool_index, pool_item) in pool_items.iter().enumerate() {
        let item_index = visible_start + pool_index;
        if item_index < count {
            bind(world, item_index, pool_item.container_entity);
        }
    }
}

pub fn ui_tab_bar_set_value(world: &mut World, entity: freecs::Entity, index: usize) {
    let update = if let Some(data) = world.ui.get_ui_tab_bar(entity) {
        if index < data.tab_entities.len() && index != data.selected_tab {
            Some((
                data.tab_entities[data.selected_tab],
                data.tab_entities[index],
            ))
        } else {
            None
        }
    } else {
        None
    };

    if let Some((old_entity, new_entity)) = update {
        let theme = world.resources.retained_ui.theme_state.active_theme();
        let active_bg = theme.accent_color;
        let inactive_bg = theme.background_color;
        if let Some(color) = world.ui.get_ui_node_color_mut(old_entity) {
            color.colors[crate::ecs::ui::state::UiBase::INDEX] = Some(inactive_bg);
        }
        if let Some(color) = world.ui.get_ui_node_color_mut(new_entity) {
            color.colors[crate::ecs::ui::state::UiBase::INDEX] = Some(active_bg);
        }
        if let Some(data) = world.ui.get_ui_tab_bar_mut(entity) {
            data.selected_tab = index;
        }
    }
}

pub fn ui_text_input_set_value(world: &mut World, entity: freecs::Entity, text: &str) {
    let (text_slot, placeholder_entity, password) =
        if let Some(data) = world.ui.get_ui_text_input(entity) {
            (Some(data.text_slot), data.placeholder_entity, data.password)
        } else {
            (None, None, false)
        };

    if let Some(slot) = text_slot {
        world
            .resources
            .text
            .cache
            .set_text(slot, masked_input_display(text, password));
        if let Some(data) = world.ui.get_ui_text_input_mut(entity) {
            data.text = text.to_string();
            data.cursor_position = text.chars().count();
            data.selection_start = None;
        }
        if let Some(ph_entity) = placeholder_entity
            && let Some(node) = world.ui.get_ui_layout_node_mut(ph_entity)
        {
            node.visible = text.is_empty();
        }
    }
}

pub fn ui_text_input_set_mask(
    world: &mut World,
    entity: freecs::Entity,
    mask: crate::ecs::ui::components::InputMask,
) {
    if let Some(data) = world.ui.get_ui_text_input_mut(entity) {
        data.input_mask = mask;
    }
}

pub fn ui_text_input_set_password(world: &mut World, entity: freecs::Entity, password: bool) {
    let update = if let Some(data) = world.ui.get_ui_text_input_mut(entity) {
        if data.password == password {
            return;
        }
        data.password = password;
        Some((data.text_slot, data.text.clone()))
    } else {
        None
    };
    if let Some((slot, text)) = update {
        world
            .resources
            .text
            .cache
            .set_text(slot, masked_input_display(&text, password));
    }
}

pub fn ui_text_input_submitted(world: &World, entity: freecs::Entity) -> Option<String> {
    for event in &world.resources.retained_ui.frame.events {
        if let crate::ecs::ui::resources::UiEvent::TextInputSubmitted {
            entity: event_entity,
            text,
        } = event
            && *event_entity == entity
        {
            return Some(text.clone());
        }
    }
    None
}

pub fn ui_dropdown_set_value(world: &mut World, entity: freecs::Entity, index: usize) {
    let update = if let Some(data) = world.ui.get_ui_dropdown(entity) {
        if index < data.options.len() && index != data.selected_index {
            Some((data.header_text_slot, data.options[index].clone()))
        } else {
            None
        }
    } else {
        None
    };

    if let Some((text_slot, selected_text)) = update {
        world
            .resources
            .text
            .cache
            .set_text(text_slot, selected_text);
        if let Some(data) = world.ui.get_ui_dropdown_mut(entity) {
            data.selected_index = index;
        }
    }
}

pub fn ui_panel_set_pinned(world: &mut World, entity: freecs::Entity, pinned: bool) {
    if let Some(data) = world.ui.get_ui_panel_mut(entity) {
        data.pinned = pinned;
    }
}

pub fn ui_panel_set_header_visible(world: &mut World, entity: freecs::Entity, visible: bool) {
    if let Some(data) = world.ui.get_ui_panel_mut(entity) {
        let header = data.header_entity;
        let content = data.content_entity;
        data.header_visible = visible;
        ui_set_visible(world, header, visible);
        if let Some(node) = world.ui.get_ui_layout_node_mut(content)
            && let Some(crate::ecs::ui::layout_types::UiLayoutType::Boundary(ref mut boundary)) =
                node.base_layout
        {
            let offset_y = if visible { 32.0 } else { 0.0 };
            boundary.position_1 = crate::ecs::ui::units::Ab(Vec2::new(0.0, offset_y)).into();
        }
        ui_mark_layout_dirty(world);
    }
}

pub fn ui_reserved_areas(world: &World) -> &crate::ecs::ui::resources::ReservedAreas {
    &world
        .resources
        .retained_ui
        .dock_state
        .primary
        .reserved_areas
}

pub fn ui_dock_layout(world: &World) -> &crate::ecs::ui::resources::WindowDockLayout {
    &world.resources.retained_ui.dock_state.primary
}

pub fn ui_dock_state(world: &World) -> &crate::ecs::ui::resources::DockState {
    &world.resources.retained_ui.dock_state
}

pub fn ui_capture_dock_state(world: &World) -> crate::ecs::ui::resources::DockState {
    world.resources.retained_ui.dock_state.clone()
}

/// Serializes the current dock state to a JSON string. Pair with
/// [`ui_load_dock_state_from_str`] to round-trip layouts through any
/// storage layer (filesystem, network, browser localStorage, etc.).
pub fn ui_save_dock_state_to_str(world: &World) -> Result<String, String> {
    serde_json::to_string_pretty(&world.resources.retained_ui.dock_state)
        .map_err(|err| err.to_string())
}

/// Parses a dock state JSON string and applies it via
/// [`ui_apply_dock_state`].
pub fn ui_load_dock_state_from_str(world: &mut World, json: &str) -> Result<(), String> {
    let state: crate::ecs::ui::resources::DockState =
        serde_json::from_str(json).map_err(|err| err.to_string())?;
    ui_apply_dock_state(world, &state);
    Ok(())
}

/// Writes the current dock state to a file at `path` as pretty JSON.
/// Native-only.
#[cfg(not(target_arch = "wasm32"))]
pub fn ui_save_dock_state_to_path(
    world: &World,
    path: impl AsRef<std::path::Path>,
) -> Result<(), String> {
    let json = ui_save_dock_state_to_str(world)?;
    std::fs::write(path, json).map_err(|err| err.to_string())
}

/// Reads a dock state JSON file at `path` and applies it. Returns
/// `Ok(false)` when the file is absent (no error). Native-only.
#[cfg(not(target_arch = "wasm32"))]
pub fn ui_load_dock_state_from_path(
    world: &mut World,
    path: impl AsRef<std::path::Path>,
) -> Result<bool, String> {
    let path = path.as_ref();
    if !path.exists() {
        return Ok(false);
    }
    let json = std::fs::read_to_string(path).map_err(|err| err.to_string())?;
    ui_load_dock_state_from_str(world, &json)?;
    Ok(true)
}

pub fn ui_set_window_menu_bar(world: &mut World, entity: freecs::Entity) {
    world.resources.retained_ui.window_chrome.menu_bar = Some(entity);
}

pub fn ui_set_window_toolbar(world: &mut World, entity: freecs::Entity) {
    world.resources.retained_ui.window_chrome.toolbar = Some(entity);
}

pub fn ui_set_window_status_bar(world: &mut World, entity: freecs::Entity) {
    world.resources.retained_ui.window_chrome.status_bar = Some(entity);
}

pub fn ui_clear_window_chrome(world: &mut World) {
    world.resources.retained_ui.window_chrome = Default::default();
}

pub fn ui_window_menu_bar(world: &World) -> Option<freecs::Entity> {
    world.resources.retained_ui.window_chrome.menu_bar
}

pub fn ui_window_toolbar(world: &World) -> Option<freecs::Entity> {
    world.resources.retained_ui.window_chrome.toolbar
}

pub fn ui_window_status_bar(world: &World) -> Option<freecs::Entity> {
    world.resources.retained_ui.window_chrome.status_bar
}

pub fn ui_register_window_shortcut(
    world: &mut World,
    binding: crate::ecs::ui::components::ShortcutBinding,
    command_index: usize,
) {
    world.resources.retained_ui.window_chrome.shortcuts.push(
        crate::ecs::ui::resources::WindowShortcut {
            binding,
            command_index,
        },
    );
}

pub fn ui_apply_dock_state(world: &mut World, state: &crate::ecs::ui::resources::DockState) {
    let panel_entities: Vec<freecs::Entity> = world
        .ui
        .query_entities(crate::ecs::world::UI_PANEL)
        .collect();
    for entity in panel_entities {
        let Some(data) = world.ui.get_ui_panel(entity) else {
            continue;
        };
        let layout = &state.primary;
        let id = data.id.clone();
        if id.is_empty() {
            continue;
        }
        let Some(config) = layout.panels.iter().find(|panel| panel.id == id) else {
            continue;
        };
        let new_dock_size = config.size;
        let new_collapsed = config.collapsed;
        let new_visible = config.visible;
        let new_kind = config.kind;
        let new_floating_position = config.floating_position;
        let new_floating_size = config.floating_size;
        if let Some(panel) = world.ui.get_ui_panel_mut(entity) {
            panel.default_dock_size = new_dock_size;
            panel.collapsed = new_collapsed;
            panel.panel_kind = new_kind;
        }
        if let Some(node) = world.ui.get_ui_layout_node_mut(entity) {
            node.visible = new_visible;
            if new_kind == crate::ecs::ui::components::UiPanelKind::Floating
                && let Some(crate::ecs::ui::layout_types::UiLayoutType::Window(window)) =
                    node.base_layout.as_mut()
            {
                if let Some(position) = new_floating_position {
                    window.position = crate::ecs::ui::units::Ab(nalgebra_glm::Vec2::new(
                        position[0],
                        position[1],
                    ))
                    .into();
                }
                if let Some(size) = new_floating_size {
                    window.size =
                        crate::ecs::ui::units::Ab(nalgebra_glm::Vec2::new(size[0], size[1])).into();
                }
            }
        }
    }
}

pub fn ui_pointer_over_widget(world: &World) -> bool {
    world
        .resources
        .retained_ui
        .interaction
        .hovered_entity
        .is_some()
        || world
            .resources
            .retained_ui
            .interaction
            .focused_entity
            .is_some()
}

pub fn ui_color_picker_set_value(world: &mut World, entity: freecs::Entity, color: Vec4) {
    let update = if let Some(data) = world.ui.get_ui_color_picker(entity) {
        let sliders = data.slider_entities;
        let mode = data.mode;
        let swatch = data.swatch_entity;
        Some((sliders, mode, swatch))
    } else {
        None
    };

    if let Some((sliders, mode, swatch)) = update {
        match mode {
            crate::ecs::ui::components::ColorPickerMode::Rgb => {
                ui_slider_set_value(world, sliders[0], color.x);
                ui_slider_set_value(world, sliders[1], color.y);
                ui_slider_set_value(world, sliders[2], color.z);
                ui_slider_set_value(world, sliders[3], color.w);
            }
            crate::ecs::ui::components::ColorPickerMode::Hsv => {
                let hsv = crate::ecs::ui::color::Hsva::from_rgba(color);
                ui_slider_set_value(world, sliders[0], hsv.hue);
                ui_slider_set_value(world, sliders[1], hsv.saturation);
                ui_slider_set_value(world, sliders[2], hsv.value);
                ui_slider_set_value(world, sliders[3], color.w);
            }
        }

        if let Some(swatch_color) = world.ui.get_ui_node_color_mut(swatch) {
            swatch_color.colors[UiBase::INDEX] = Some(color);
        }

        if let Some(data) = world.ui.get_ui_color_picker_mut(entity) {
            data.color = color;
        }
    }
}

pub(crate) fn masked_input_display(text: &str, password: bool) -> String {
    if password {
        "*".repeat(text.chars().count())
    } else {
        text.to_string()
    }
}
