//! Selection delete/duplicate and camera focus helpers.

use bevy::prelude::*;
use bevy_inspector_egui::bevy_inspector::hierarchy::SelectedEntities;
use shared::{HydratedPrefabMember, LevelObject};

use crate::camera::EditorCamera;
use crate::history::{
    delete_entities_with_history, duplicate_entities_with_history, set_transform_group_with_history,
};
use crate::selection::SelectedEntity;
use crate::ui::UiState;

fn is_locked(world: &World, entity: Entity) -> bool {
    world
        .get_resource::<crate::ui::hierarchy_state::HierarchyPanelState>()
        .is_some_and(|state| state.locked.contains(&entity))
}

pub fn is_linked_read_only(world: &World, entity: Entity) -> bool {
    world.get::<HydratedPrefabMember>(entity).is_some()
        || world
            .get::<crate::scene_io::ComposedSceneMember>(entity)
            .is_some()
}

pub fn is_mutable_level_object(world: &World, entity: Entity) -> bool {
    is_level_object(world, entity)
        && !is_locked(world, entity)
        && !is_linked_read_only(world, entity)
}

pub fn focus_editor_camera_on_selection(world: &mut World) {
    let Some(entity) = world.resource::<SelectedEntity>().0 else {
        return;
    };
    let Some(target) = world.get::<GlobalTransform>(entity) else {
        return;
    };
    let center = target.translation();
    let mut cameras = world.query_filtered::<&mut Transform, With<EditorCamera>>();
    for mut transform in cameras.iter_mut(world) {
        let offset = transform.translation - center;
        let distance = offset.length().max(8.0);
        transform.translation = center - transform.forward().as_vec3() * distance;
        transform.look_at(center, Vec3::Y);
    }
}

pub fn selected_level_entities(world: &World, selected: &SelectedEntities) -> Vec<Entity> {
    selected
        .iter()
        .filter(|entity| {
            world
                .get_entity(*entity)
                .is_ok_and(|entity_ref| entity_ref.contains::<LevelObject>())
        })
        .collect()
}

pub fn entity_name(world: &World, entity: Entity) -> String {
    world
        .get::<Name>(entity)
        .map(|name| name.as_str().to_string())
        .unwrap_or_else(|| format!("{entity:?}"))
}

pub fn is_level_object(world: &World, entity: Entity) -> bool {
    world
        .get_entity(entity)
        .is_ok_and(|entity_ref| entity_ref.contains::<LevelObject>())
}

pub fn delete_selection(world: &mut World, selected: &SelectedEntities) {
    let entities: Vec<_> = selected_level_entities(world, selected)
        .into_iter()
        .filter(|entity| is_mutable_level_object(world, *entity))
        .collect();
    delete_entities_with_history(world, &entities);
}

pub fn duplicate_selection(world: &mut World, selected: &SelectedEntities) {
    let entities: Vec<_> = selected_level_entities(world, selected)
        .into_iter()
        .filter(|entity| is_mutable_level_object(world, *entity))
        .collect();
    duplicate_entities_with_history(world, &entities);
}

pub fn reset_selected_transforms(world: &mut World) {
    let changes: Vec<_> = world
        .resource::<UiState>()
        .selected_entities
        .iter()
        .filter(|entity| is_mutable_level_object(world, *entity))
        .filter_map(|entity| {
            world
                .get::<Transform>(entity)
                .copied()
                .map(|old| (entity, old, Transform::default()))
        })
        .collect();
    set_transform_group_with_history(world, changes);
}
