use super::*;

pub(super) fn empty_content(ui: &mut egui::Ui, search: &str) {
    ui.add_space(24.0);
    ui.vertical_centered(|ui| {
        ui.label(
            egui::RichText::new(icons::FOLDER_OPEN.as_str()).font(egui::FontId::new(
                28.0,
                egui::FontFamily::Name("phosphor-regular".into()),
            )),
        );
        if search.trim().is_empty() {
            ui.label(egui::RichText::new("Folder is empty").color(TEXT_DIM));
        } else {
            ui.label(egui::RichText::new("No matching assets").color(TEXT_DIM));
        }
    });
}

pub(super) fn navigate_to_parent(world: &mut World) {
    let current = world.resource::<EditorAssets>().current_folder.clone();
    if let Some(parent) = current.rfind('/').map(|index| current[..index].to_string()) {
        navigate_content_folder(world, parent);
    }
}

pub(super) fn navigate_content_folder(world: &mut World, folder: String) {
    let current = world.resource::<EditorAssets>().current_folder.clone();
    if current == folder {
        return;
    }
    {
        let mut state = world.resource_mut::<AssetBrowserUiState>();
        state.navigation_back.push(current);
        state.navigation_forward.clear();
    }
    set_content_folder(world, folder);
}

pub(super) fn navigate_content_back(world: &mut World) {
    let Some(folder) = world
        .resource_mut::<AssetBrowserUiState>()
        .navigation_back
        .pop()
    else {
        return;
    };
    let current = world.resource::<EditorAssets>().current_folder.clone();
    world
        .resource_mut::<AssetBrowserUiState>()
        .navigation_forward
        .push(current);
    set_content_folder(world, folder);
}

pub(super) fn navigate_content_forward(world: &mut World) {
    let Some(folder) = world
        .resource_mut::<AssetBrowserUiState>()
        .navigation_forward
        .pop()
    else {
        return;
    };
    let current = world.resource::<EditorAssets>().current_folder.clone();
    world
        .resource_mut::<AssetBrowserUiState>()
        .navigation_back
        .push(current);
    set_content_folder(world, folder);
}

fn set_content_folder(world: &mut World, folder: String) {
    let mut assets = world.resource_mut::<EditorAssets>();
    assets.current_folder = folder.clone();
    assets.clear_selection();
    assets.clear_drag();
    assets.status = format!("Opened {folder}");
}

pub(super) fn locate_content_asset(world: &mut World, path: &str) {
    let normalized = path.replace('\\', "/");
    let selection = AssetSelection::File(normalized.clone());
    if !world
        .resource::<EditorAssets>()
        .selection_exists(&selection)
    {
        let status = format!("Referenced project asset is missing: {normalized}");
        world.resource_mut::<EditorAssets>().status = status.clone();
        if let Some(mut scene_io) = world.get_resource_mut::<SceneIo>() {
            scene_io.status = status;
        }
        return;
    }
    let parent = Path::new(&normalized)
        .parent()
        .map(|path| path.to_string_lossy().replace('\\', "/"))
        .unwrap_or_else(|| ASSETS_ROOT.to_string());
    navigate_content_folder(world, parent);
    let mut assets = world.resource_mut::<EditorAssets>();
    assets.select(selection);
    assets.status = format!("Located {normalized}");
}

pub(super) fn asset_matches_kind_filter(asset: &EditorAsset, filter: AssetKindFilter) -> bool {
    match filter {
        AssetKindFilter::All => true,
        AssetKindFilter::Model => matches!(asset.kind, EditorAssetKind::Model),
        AssetKindFilter::Texture => matches!(asset.kind, EditorAssetKind::Texture),
        AssetKindFilter::Material => matches!(asset.kind, EditorAssetKind::Material),
        AssetKindFilter::Audio => matches!(asset.kind, EditorAssetKind::AudioClip),
        AssetKindFilter::Level => matches!(asset.kind, EditorAssetKind::Level),
        AssetKindFilter::Prefab => matches!(asset.kind, EditorAssetKind::Prefab),
        AssetKindFilter::Builtin => asset.path.is_none(),
    }
}

pub(super) fn kind_filter_label(filter: AssetKindFilter) -> &'static str {
    match filter {
        AssetKindFilter::All => "All",
        AssetKindFilter::Model => "Models",
        AssetKindFilter::Texture => "Textures",
        AssetKindFilter::Material => "Materials",
        AssetKindFilter::Audio => "Audio",
        AssetKindFilter::Level => "Levels",
        AssetKindFilter::Prefab => "Prefabs",
        AssetKindFilter::Builtin => "Built-ins",
    }
}

pub(super) fn sort_label(sort: AssetSort) -> &'static str {
    match sort {
        AssetSort::Name => "Name",
        AssetSort::Kind => "Type",
        AssetSort::Modified => "Modified",
        AssetSort::Size => "Size",
    }
}

pub(super) fn kind_label(kind: &EditorAssetKind) -> &'static str {
    match kind {
        EditorAssetKind::Primitive(_) => "Primitive",
        EditorAssetKind::Light(_) => "Light",
        EditorAssetKind::Model => "Model",
        EditorAssetKind::Texture => "Texture",
        EditorAssetKind::Material => "Material",
        EditorAssetKind::AudioClip => "Audio Clip",
        EditorAssetKind::Level => "Level",
        EditorAssetKind::Prefab => "Prefab",
        EditorAssetKind::PostProcessVolume => "Post Process Volume",
        EditorAssetKind::PostProcessEffect => "Post FX",
        EditorAssetKind::RenderingProfile => "Rendering Profile",
        EditorAssetKind::ShaderSchema => "Shader Schema",
    }
}

pub(super) fn file_size(path: &str) -> Option<u64> {
    fs::metadata(path).ok().map(|metadata| metadata.len())
}

pub(super) fn audio_format_label(path: &str) -> &'static str {
    match Path::new(path)
        .extension()
        .and_then(|extension| extension.to_str())
        .map(str::to_ascii_lowercase)
        .as_deref()
    {
        Some("ogg" | "oga") => "Ogg audio",
        Some("spx") => "Speex",
        Some("wav") => "WAV",
        Some("mp3") => "MP3",
        Some("flac") => "FLAC",
        _ => "Unknown",
    }
}

pub(super) fn modified_time(path: &str) -> Option<SystemTime> {
    fs::metadata(path)
        .ok()
        .and_then(|metadata| metadata.modified().ok())
}

pub(super) fn format_bytes(bytes: u64) -> String {
    const KIB: f64 = 1024.0;
    const MIB: f64 = KIB * 1024.0;
    const GIB: f64 = MIB * 1024.0;
    let bytes = bytes as f64;
    if bytes >= GIB {
        format!("{:.1} GB", bytes / GIB)
    } else if bytes >= MIB {
        format!("{:.1} MB", bytes / MIB)
    } else if bytes >= KIB {
        format!("{:.1} KB", bytes / KIB)
    } else {
        format!("{bytes:.0} B")
    }
}

pub(super) fn format_modified(time: SystemTime) -> String {
    let Ok(duration) = SystemTime::now().duration_since(time) else {
        return "Just now".to_string();
    };
    let days = duration.as_secs() / 86_400;
    if days == 0 {
        "Today".to_string()
    } else if days == 1 {
        "Yesterday".to_string()
    } else if days < 30 {
        format!("{days} days ago")
    } else if days < 365 {
        format!("{} months ago", days / 30)
    } else {
        format!("{} years ago", days / 365)
    }
}

pub(super) fn natural_cmp(a: &str, b: &str) -> std::cmp::Ordering {
    a.to_ascii_lowercase().cmp(&b.to_ascii_lowercase())
}

pub(super) fn asset_context_menu(
    world: &mut World,
    ui: &mut egui::Ui,
    asset: &EditorAsset,
    selected_entities: &SelectedEntities,
) {
    let menu_selection = AssetSelection::from_asset(asset);
    prepare_context_menu_selection(world, menu_selection);
    let selected_count = world.resource::<EditorAssets>().selections.len();
    if selected_count > 1 {
        ui.label(egui::RichText::new(format!("{selected_count} items selected")).color(TEXT_DIM));
        batch_content_menu(world, ui);
        return;
    }
    if ui.button("Select").clicked() {
        world
            .resource_mut::<EditorAssets>()
            .select(AssetSelection::from_asset(asset));
        ui.close();
    }
    if matches!(
        asset.kind,
        EditorAssetKind::Primitive(_)
            | EditorAssetKind::Light(_)
            | EditorAssetKind::Model
            | EditorAssetKind::AudioClip
            | EditorAssetKind::Prefab
    ) && ui.button("Place at Origin").clicked()
    {
        place_asset_operator(world, asset.clone(), Vec3::ZERO);
        ui.close();
    }
    if matches!(asset.kind, EditorAssetKind::Level) && ui.button("Open Scene").clicked() {
        open_level_asset(world, asset);
        ui.close();
    }
    if matches!(asset.kind, EditorAssetKind::Model) && has_embedded_assets(world, asset) {
        let expanded = asset.path.as_deref().is_some_and(|path| {
            world
                .resource::<AssetBrowserUiState>()
                .expanded_assets
                .contains(path)
        });
        if ui
            .button(if expanded {
                "Collapse Contents"
            } else {
                "Expand Contents"
            })
            .clicked()
        {
            if let Some(path) = asset.path.as_ref() {
                toggle_asset_expanded(world, path);
            }
            ui.close();
        }
    }
    if matches!(asset.kind, EditorAssetKind::Texture)
        && ui.button("Apply as Base Color Texture").clicked()
    {
        apply_texture_operator(world, asset.clone(), selected_entities);
        ui.close();
    }
    if asset.path.is_some()
        && matches!(asset.kind, EditorAssetKind::Material)
        && ui.button("Apply Material To Selection").clicked()
    {
        apply_material_operator(world, asset.clone(), selected_entities);
        ui.close();
    }
    if matches!(asset.kind, EditorAssetKind::Material) {
        if let Some(path) = asset.path.as_deref() {
            if ui.button("Create Material Instance").clicked() {
                create_material_instance_from_base(world, path, &asset.label);
                ui.close();
            }
        }
    }
    if matches!(asset.kind, EditorAssetKind::Model) && ui.button("Reimport").clicked() {
        reimport_asset(world, asset);
        ui.close();
    }
    if matches!(
        asset.kind,
        EditorAssetKind::Texture | EditorAssetKind::Model | EditorAssetKind::Material
    ) && ui.button("Regenerate Thumbnail").clicked()
    {
        regenerate_asset_thumbnail(world, asset);
        ui.close();
    }
    if asset.path.is_some() {
        ui.separator();
        if ui.button("Rename").clicked() {
            begin_rename(world);
            ui.close();
        }
        if ui.button("Cut").clicked() {
            set_content_clipboard(world, true);
            ui.close();
        }
        if ui.button("Copy").clicked() {
            set_content_clipboard(world, false);
            ui.close();
        }
        if ui.button("Duplicate").clicked() {
            duplicate_selection(world);
            ui.close();
        }
        ui.separator();
        if ui.button("Move To Trash").clicked() {
            request_delete_for_asset(world, asset);
            ui.close();
        }
    }
}

pub(super) fn prepare_context_menu_selection(world: &mut World, selection: AssetSelection) {
    if !world.resource::<EditorAssets>().is_selected(&selection) {
        world.resource_mut::<EditorAssets>().select(selection);
    }
}

pub(super) fn batch_content_menu(world: &mut World, ui: &mut egui::Ui) {
    let authored_count = selected_content_paths(world).len();
    let (nested_count, unaffected_count) = collapsed_and_unaffected_selection_counts(world);
    let has_authored_content = authored_count > 0;
    if nested_count > 0 {
        ui.small(
            egui::RichText::new(format!(
                "{nested_count} nested item(s) already included by a selected parent"
            ))
            .color(TEXT_DIM),
        );
    }
    if unaffected_count > 0 {
        ui.small(
            egui::RichText::new(format!(
                "{unaffected_count} embedded, built-in, or protected item(s) unaffected"
            ))
            .color(TEXT_DIM),
        );
    }
    let can_undo = !world
        .resource::<AssetBrowserUiState>()
        .content_undo
        .is_empty();
    if ui
        .add_enabled(can_undo, egui::Button::new("Undo Last Content Operation"))
        .clicked()
    {
        undo_last_content_operation(world);
        ui.close();
    }
    ui.separator();
    if ui
        .add_enabled(
            has_authored_content,
            egui::Button::new(format!("Cut {authored_count} Item(s)")),
        )
        .clicked()
    {
        set_content_clipboard(world, true);
        ui.close();
    }
    if ui
        .add_enabled(
            has_authored_content,
            egui::Button::new(format!("Copy {authored_count} Item(s)")),
        )
        .clicked()
    {
        set_content_clipboard(world, false);
        ui.close();
    }
    if ui
        .add_enabled(
            has_authored_content,
            egui::Button::new(format!("Duplicate {authored_count} Item(s)")),
        )
        .clicked()
    {
        duplicate_selection(world);
        ui.close();
    }
    ui.separator();
    if ui
        .add_enabled(
            has_authored_content,
            egui::Button::new(format!("Move {authored_count} Item(s) To Trash")),
        )
        .clicked()
    {
        request_delete_for_selection(world);
        ui.close();
    }
}

pub(super) fn folder_context_menu(world: &mut World, ui: &mut egui::Ui, folder: &FolderSnapshot) {
    let selected_count = world.resource::<EditorAssets>().selections.len();
    if selected_count > 1 {
        ui.label(egui::RichText::new(format!("{selected_count} items selected")).color(TEXT_DIM));
        batch_content_menu(world, ui);
        return;
    }
    if ui.button("Open").clicked() {
        navigate_content_folder(world, folder.path.clone());
        ui.close();
    }
    if folder.path != BUILTINS_FOLDER {
        if ui.button("Import Here...").clicked() {
            request_import_to_destination(world, folder.path.clone());
            ui.close();
        }
        if ui.button("Import To...").clicked() {
            begin_import_to(world);
            ui.close();
        }
        if ui.button("Create Materials From Folder...").clicked() {
            begin_pbr_grouping(world, folder.path.clone());
            ui.close();
        }
        if ui.button("Create Material Here").clicked() {
            create_material_here(world, &folder.path);
            ui.close();
        }
        if ui.button("New Folder").clicked() {
            begin_new_folder(world, folder.path.clone());
            ui.close();
        }
        if ui.button("Open Trash...").clicked() {
            world.resource_mut::<AssetBrowserUiState>().show_trash = true;
            ui.close();
        }
        let can_paste = world.resource::<AssetBrowserUiState>().clipboard.is_some();
        if ui
            .add_enabled(can_paste, egui::Button::new("Paste Into"))
            .clicked()
        {
            paste_content_clipboard_into(world, &folder.path);
            ui.close();
        }
    }
    if !matches!(folder.path.as_str(), ASSETS_ROOT | BUILTINS_FOLDER) {
        ui.separator();
        if ui.button("Rename").clicked() {
            world
                .resource_mut::<EditorAssets>()
                .select(AssetSelection::Folder(folder.path.clone()));
            begin_rename(world);
            ui.close();
        }
        if ui.button("Cut").clicked() {
            set_content_clipboard(world, true);
            ui.close();
        }
        if ui.button("Copy").clicked() {
            set_content_clipboard(world, false);
            ui.close();
        }
        if ui.button("Duplicate").clicked() {
            duplicate_selection(world);
            ui.close();
        }
        if ui.button("Move To Trash").clicked() {
            request_delete_for_selection(world);
            ui.close();
        }
    }
}

pub(super) fn empty_space_context_menu(
    world: &mut World,
    ui: &mut egui::Ui,
    current_folder: &str,
    visible_order: &[AssetSelection],
) {
    if !world.resource::<EditorAssets>().selections.is_empty() {
        world.resource_mut::<EditorAssets>().clear_selection();
    }
    if current_folder != BUILTINS_FOLDER {
        if ui.button("Import Here...").clicked() {
            request_import_to_destination(world, current_folder.to_string());
            ui.close();
        }
        if ui.button("Import To...").clicked() {
            begin_import_to(world);
            ui.close();
        }
        if ui.button("Create Materials From Folder...").clicked() {
            begin_pbr_grouping(world, current_folder.to_string());
            ui.close();
        }
        if ui.button("Create Material Here").clicked() {
            create_material_here(world, current_folder);
            ui.close();
        }
        if ui.button("New Folder").clicked() {
            begin_new_folder(world, current_folder.to_string());
            ui.close();
        }
        if ui.button("Open Trash...").clicked() {
            world.resource_mut::<AssetBrowserUiState>().show_trash = true;
            ui.close();
        }
        let can_paste = world.resource::<AssetBrowserUiState>().clipboard.is_some();
        if ui
            .add_enabled(can_paste, egui::Button::new("Paste"))
            .clicked()
        {
            paste_content_clipboard(world);
            ui.close();
        }
        ui.separator();
    }
    let can_undo = !world
        .resource::<AssetBrowserUiState>()
        .content_undo
        .is_empty();
    if ui
        .add_enabled(can_undo, egui::Button::new("Undo Last Content Operation"))
        .clicked()
    {
        undo_last_content_operation(world);
        ui.close();
    }
    if ui
        .add_enabled(!visible_order.is_empty(), egui::Button::new("Select All"))
        .clicked()
    {
        world
            .resource_mut::<EditorAssets>()
            .select_all(visible_order);
        ui.close();
    }
    if ui.button("Refresh").clicked() {
        crate::assets::refresh_content_browser(world);
        ui.close();
    }
    ui.separator();
    let view = world.resource::<AssetBrowserUiState>().view;
    if ui
        .selectable_label(view == AssetBrowserView::Grid, "Grid View")
        .clicked()
    {
        world.resource_mut::<AssetBrowserUiState>().view = AssetBrowserView::Grid;
        ui.close();
    }
    if ui
        .selectable_label(view == AssetBrowserView::List, "List View")
        .clicked()
    {
        world.resource_mut::<AssetBrowserUiState>().view = AssetBrowserView::List;
        ui.close();
    }
}

pub(super) fn subasset_context_menu(
    world: &mut World,
    ui: &mut egui::Ui,
    embedded: &EmbeddedAsset,
    selected_entities: &SelectedEntities,
) {
    if ui.button("Select").clicked() {
        world
            .resource_mut::<EditorAssets>()
            .select(embedded.selection.clone());
        ui.close();
    }
    match embedded.kind {
        AssetSubAssetKind::Mesh => {
            if embedded.requires_skinned_hierarchy {
                if ui.button("Place Skinned Model at Origin").clicked() {
                    place_subasset_operator(world, embedded.selection.clone(), Vec3::ZERO);
                    ui.close();
                }
            } else if ui.button("Place at Origin").clicked() {
                place_subasset_operator(world, embedded.selection.clone(), Vec3::ZERO);
                ui.close();
            }
        }
        AssetSubAssetKind::Texture => {
            if ui.button("Apply as Base Color Texture").clicked() {
                if let Some(asset) =
                    texture_asset_from_subasset_selection(world, &Some(embedded.selection.clone()))
                {
                    apply_texture_operator(world, asset, selected_entities);
                }
                ui.close();
            }
        }
        AssetSubAssetKind::Material => {
            ui.label(egui::RichText::new("Embedded source material").color(TEXT_DIM));
        }
        AssetSubAssetKind::Skeleton => {
            ui.label(egui::RichText::new("Inspect-only rig metadata").color(TEXT_DIM));
        }
        AssetSubAssetKind::AnimationClip => {
            let animated_actor = selected_entities
                .as_slice()
                .iter()
                .copied()
                .find(|entity| world.get::<shared::SkinnedMeshRenderer>(*entity).is_some());
            let action = if animated_actor.is_some() {
                "Assign To Selected Actor"
            } else {
                "Create Animated Actor"
            };
            if ui.button(action).clicked() {
                if let Some(entity) = animated_actor {
                    assign_animation_clip_operator(world, embedded.selection.clone(), entity);
                } else {
                    place_subasset_operator(world, embedded.selection.clone(), Vec3::ZERO);
                }
                ui.close();
            }
        }
    }
    if matches!(
        embedded.kind,
        AssetSubAssetKind::Mesh | AssetSubAssetKind::Material | AssetSubAssetKind::Texture
    ) && ui.button("Regenerate Thumbnail").clicked()
    {
        regenerate_subasset_thumbnail(world, embedded);
        ui.close();
    }
    if let AssetSelection::SubAsset { parent_path, .. } = &embedded.selection {
        if ui.button("Select Parent Asset").clicked() {
            world
                .resource_mut::<EditorAssets>()
                .select(AssetSelection::File(parent_path.clone()));
            ui.close();
        }
    }
}

pub(super) fn regenerate_asset_thumbnail(world: &mut World, asset: &EditorAsset) {
    let Some(path) = asset.path.clone() else {
        return;
    };
    let key = asset_cache_key(asset);
    let kind = asset.kind.clone();
    let asset_server = world.resource::<AssetServer>().clone();
    crate::assets::retry_thumbnail(world, &key);
    world.resource_scope(|world, mut cache: Mut<AssetThumbnailCache>| match kind {
        EditorAssetKind::Texture => {
            cache.request_texture(key.clone(), path.clone(), &asset_server);
        }
        EditorAssetKind::Model => {
            world.resource_scope(|_world, mut studio: Mut<ThumbnailStudio>| {
                cache.request_model(key.clone(), path.clone(), &mut studio);
            });
        }
        EditorAssetKind::Material => {
            world.resource_scope(|_world, mut studio: Mut<ThumbnailStudio>| {
                cache.request_material_asset(key.clone(), path.clone(), &mut studio);
            });
        }
        _ => {}
    });
    world.resource_mut::<SceneIo>().status = format!("Regenerating thumbnail for {}", asset.label);
}

pub(super) fn regenerate_subasset_thumbnail(world: &mut World, embedded: &EmbeddedAsset) {
    let AssetSelection::SubAsset { parent_path, .. } = &embedded.selection else {
        return;
    };
    let key = embedded.thumbnail_key.clone();
    let asset_server = world.resource::<AssetServer>().clone();
    crate::assets::retry_thumbnail(world, &key);
    world.resource_scope(
        |world, mut cache: Mut<AssetThumbnailCache>| match embedded.kind {
            AssetSubAssetKind::Mesh => {
                let Some(mesh_label) = embedded.mesh_label.clone() else {
                    return;
                };
                world.resource_scope(|_world, mut studio: Mut<ThumbnailStudio>| {
                    cache.request_mesh_subasset(
                        key.clone(),
                        parent_path.clone(),
                        mesh_label,
                        embedded.material_label.clone(),
                        embedded.requires_skinned_hierarchy,
                        &mut studio,
                    );
                });
            }
            AssetSubAssetKind::Material => {
                let Some(material_label) = embedded.material_label.clone() else {
                    return;
                };
                world.resource_scope(|_world, mut studio: Mut<ThumbnailStudio>| {
                    cache.request_source_material(
                        key.clone(),
                        parent_path.clone(),
                        material_label,
                        &mut studio,
                    );
                });
            }
            AssetSubAssetKind::Texture => {
                if let Some(texture_path) = embedded.texture_path.clone() {
                    cache.request_texture(key.clone(), texture_path, &asset_server);
                }
            }
            AssetSubAssetKind::Skeleton | AssetSubAssetKind::AnimationClip => {}
        },
    );
    world.resource_mut::<SceneIo>().status =
        format!("Regenerating thumbnail for {}", embedded.label);
}

pub(super) fn reimport_asset(world: &mut World, asset: &EditorAsset) {
    let Some(path) = asset.path.as_deref() else {
        return;
    };
    let mut status = format!("Reimported {}", asset.label);
    if let Some(mut registry) = world.get_resource_mut::<crate::asset_db::AssetRegistry>() {
        if let Some(record) = find_asset_mut_by_path(&mut registry, path) {
            if let Err(error) = refresh_model_artifacts(record) {
                status = format!("Reimport failed for {}: {error}", asset.label);
                warn!("{status}");
            }
        }
        if let Err(error) = save_registry(&registry) {
            status = format!("Asset registry save failed: {error}");
            warn!("{status}");
        } else {
            registry.index_dirty = false;
        }
    }
    invalidate_on_catalog_refresh(world);
    world.resource_mut::<SceneIo>().status = status;
}

pub(super) fn selected_content_path(world: &World) -> Option<String> {
    let assets = world.resource::<EditorAssets>();
    assets
        .selected
        .as_ref()
        .and_then(authored_content_path)
        .map(str::to_string)
}

pub(super) fn authored_content_path(selection: &AssetSelection) -> Option<&str> {
    match selection {
        AssetSelection::Folder(path) | AssetSelection::File(path) => Some(path),
        AssetSelection::Builtin(_) | AssetSelection::SubAsset { .. } => None,
    }
}

pub(super) fn selected_content_paths(world: &World) -> Vec<String> {
    let assets = world.resource::<EditorAssets>();
    let mut paths: Vec<String> = assets
        .selections
        .iter()
        .filter_map(authored_content_path)
        .filter(|path| !matches!(*path, ASSETS_ROOT | BUILTINS_FOLDER))
        .map(str::to_string)
        .collect();
    paths.sort();
    paths.dedup();
    let all_paths = paths.clone();
    paths.retain(|candidate| {
        !all_paths.iter().any(|parent| {
            parent != candidate
                && candidate
                    .strip_prefix(parent)
                    .is_some_and(|suffix| suffix.starts_with('/'))
        })
    });
    paths
}

pub(super) fn collapsed_and_unaffected_selection_counts(world: &World) -> (usize, usize) {
    let assets = world.resource::<EditorAssets>();
    let raw_authored_count = assets
        .selections
        .iter()
        .filter_map(authored_content_path)
        .filter(|path| !matches!(*path, ASSETS_ROOT | BUILTINS_FOLDER))
        .count();
    let effective_count = selected_content_paths(world).len();
    (
        raw_authored_count.saturating_sub(effective_count),
        assets.selections.len().saturating_sub(raw_authored_count),
    )
}
