//! Standalone project-scene bootstrap.

use bevy::prelude::*;
use bevy::world_serialization::DynamicWorld;
use settings::ProjectSettings;

/// Runtime root for the standalone project's configured default level.
#[derive(Component, Debug)]
pub struct ProjectDefaultLevelRoot;

pub(crate) fn spawn_project_default_level(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    settings: Res<ProjectSettings>,
    existing: Query<(), With<ProjectDefaultLevelRoot>>,
) {
    if !existing.is_empty() {
        return;
    }

    let configured_path = settings.default_level.trim();
    if configured_path.is_empty() {
        error!("Project default_level is empty; standalone scene startup was skipped");
        return;
    }

    let asset_path = shared::asset_server_path(configured_path);
    let handle: Handle<DynamicWorld> = asset_server.load(asset_path.clone());
    commands.spawn((
        Name::new(format!("Project Default Level ({configured_path})")),
        ProjectDefaultLevelRoot,
        DynamicWorldRoot(handle),
    ));
    info!("Loading project default level {configured_path} ({asset_path})");
}

#[cfg(test)]
mod tests {
    use super::*;
    use bevy::asset::AssetPlugin;
    use bevy::world_serialization::WorldSerializationPlugin;

    fn test_app(default_level: &str) -> App {
        let mut app = App::new();
        app.add_plugins((
            MinimalPlugins,
            AssetPlugin::default(),
            WorldSerializationPlugin,
        ));
        app.insert_resource(ProjectSettings {
            default_level: default_level.to_string(),
            ..Default::default()
        });
        app
    }

    #[test]
    fn standalone_bootstrap_uses_the_project_default_level() {
        let mut app = test_app("assets/levels/editor_scene.scn.ron");
        app.add_systems(Startup, spawn_project_default_level);

        app.update();

        let world = app.world_mut();
        let mut roots = world.query_filtered::<&DynamicWorldRoot, With<ProjectDefaultLevelRoot>>();
        let root = roots.single(world).expect("one standalone scene root");
        let path = world
            .resource::<AssetServer>()
            .get_path(root.0.id())
            .expect("default level handle retains its asset path");
        assert_eq!(path.to_string(), "levels/editor_scene.scn.ron");
    }

    #[test]
    fn empty_default_level_does_not_create_a_runtime_root() {
        let mut app = test_app("   ");
        app.add_systems(Startup, spawn_project_default_level);

        app.update();

        let world = app.world_mut();
        let mut roots = world.query_filtered::<Entity, With<ProjectDefaultLevelRoot>>();
        assert_eq!(roots.iter(world).count(), 0);
    }
}
