use bevy::picking::Pickable;
use bevy::prelude::*;

/// Marker for editor/runtime helper entities that are never authored content.
#[derive(Component, Reflect, Default, Debug, Clone, Copy)]
#[reflect(Component, Default, Debug)]
pub struct EditorOnly;

pub struct EditorInfraPlugin;

impl Plugin for EditorInfraPlugin {
    fn build(&self, app: &mut App) {
        app.register_type::<EditorOnly>()
            .add_systems(Update, make_editor_only_non_pickable);
    }
}

fn make_editor_only_non_pickable(
    mut commands: Commands,
    editor_only: Query<Entity, Added<EditorOnly>>,
) {
    for entity in &editor_only {
        // Editor helpers can be created and retired within the same update (for
        // example while a thumbnail studio refreshes).  A regular deferred
        // insert panics if another system queued the despawn first.
        commands.entity(entity).try_insert(Pickable::IGNORE);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn despawn_added_editor_only(
        mut commands: Commands,
        editor_only: Query<Entity, Added<EditorOnly>>,
    ) {
        for entity in &editor_only {
            commands.entity(entity).despawn();
        }
    }

    #[test]
    fn same_frame_helper_retirement_does_not_panic_during_pickable_tagging() {
        let mut app = App::new();
        app.add_plugins(EditorInfraPlugin).add_systems(
            Update,
            despawn_added_editor_only.before(make_editor_only_non_pickable),
        );
        let helper = app.world_mut().spawn(EditorOnly).id();

        app.update();

        assert!(app.world().get_entity(helper).is_err());
    }
}
