use super::undo::{UndoHistory, UndoableOperation};
use nightshade::ecs::prefab::resources::mesh_cache_insert;
use nightshade::ecs::prefab::{import_gltf_from_path, spawn_prefab_node};
use nightshade::ecs::world::PREFAB_SOURCE;
use nightshade::prelude::*;
use std::path::Path;

pub struct WorldTreeUi;

impl WorldTreeUi {
    pub fn ui_with_pointers(
        world: *mut World,
        selected_entity: *mut Option<Entity>,
        undo_history: *mut UndoHistory,
        ui: &mut egui::Ui,
    ) {
        let world = unsafe { &mut *world };
        let selected_entity = unsafe { &mut *selected_entity };
        let undo_history = unsafe { &mut *undo_history };
        Self::ui_internal(world, selected_entity, undo_history, ui);
    }

    fn ui_internal(
        world: &mut World,
        selected_entity: &mut Option<Entity>,
        undo_history: &mut UndoHistory,
        ui: &mut egui::Ui,
    ) {
        ui.horizontal(|ui| {
            if ui.button("New Entity").clicked() {
                let entities = EntityBuilder::new()
                    .with_local_transform(LocalTransform::default())
                    .with_global_transform(GlobalTransform::default())
                    .spawn(world, 1);
                let new_entity = entities[0];
                world.set_name(new_entity, Name(format!("Entity {}", new_entity.id)));
                let hierarchy = Box::new(UndoHistory::capture_hierarchy(world, new_entity));
                undo_history.push(
                    UndoableOperation::EntityCreated {
                        hierarchy,
                        current_entity: new_entity,
                    },
                    "Create entity".to_string(),
                );
            }
            if ui.button("Expand All").clicked() {
                Self::set_all_expanded(world, ui.ctx(), true);
            }
            if ui.button("Collapse All").clicked() {
                Self::set_all_expanded(world, ui.ctx(), false);
            }
        });
        for entity in query_root_nodes(world) {
            Self::entity_tree_ui_internal(world, selected_entity, undo_history, ui, entity);
        }
    }

    fn entity_tree_ui_internal(
        world: &mut World,
        selected_entity: &mut Option<Entity>,
        undo_history: &mut UndoHistory,
        ui: &mut egui::Ui,
        entity: Entity,
    ) {
        if Self::is_gizmo_entity(world, entity) {
            return;
        }

        let id = egui::Id::new("scene_tree_entity").with(entity.id);
        egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true)
            .show_header(ui, |ui| {
                Self::entity_tree_header_ui_internal(
                    world,
                    selected_entity,
                    undo_history,
                    entity,
                    ui,
                );
            })
            .body(|ui| {
                for child in query_children(world, entity) {
                    Self::entity_tree_ui_internal(world, selected_entity, undo_history, ui, child);
                }
            });
    }

    fn entity_tree_header_ui_internal(
        world: &mut World,
        selected_entity: &mut Option<Entity>,
        undo_history: &mut UndoHistory,
        entity: Entity,
        ui: &mut egui::Ui,
    ) {
        let selected = *selected_entity == Some(entity);
        let name = if let Some(Name(name)) = world.get_name(entity) {
            name.to_string()
        } else {
            format!("Entity {}", entity.id)
        };

        ui.horizontal(|ui| {
            let prefix = "🔵";
            let response = ui.selectable_label(selected, format!("{} {}", prefix, name));
            if response.clicked() {
                *selected_entity = Some(entity);
            }

            let has_prefab_source = world.get_prefab_source(entity).is_some();

            response.context_menu(|ui| {
                if ui.button("Add Entity").clicked() {
                    Self::add_entity_internal(world, selected_entity, undo_history, entity);
                    ui.close();
                }

                if has_prefab_source && ui.button("Instantiate Prefab").clicked() {
                    Self::instantiate_prefab(world, entity);
                    ui.close();
                }

                if ui.button("Remove").clicked() {
                    let hierarchy = Box::new(UndoHistory::capture_hierarchy(world, entity));
                    let entity_name = world
                        .get_name(entity)
                        .map(|n| n.0.clone())
                        .unwrap_or_else(|| format!("Entity {}", entity.id));
                    undo_history.push(
                        UndoableOperation::EntityDeleted {
                            hierarchy,
                            deleted_entity: entity,
                        },
                        format!("Delete {}", entity_name),
                    );
                    despawn_recursive_immediate(world, entity);
                    *selected_entity = None;
                    ui.close();
                }
            });
        });
    }

    fn add_entity_internal(
        world: &mut World,
        selected_entity: &mut Option<Entity>,
        undo_history: &mut UndoHistory,
        parent_entity: Entity,
    ) {
        let entities = EntityBuilder::new()
            .with_name(Name(String::new()))
            .with_local_transform(LocalTransform::default())
            .with_global_transform(GlobalTransform::default())
            .with_parent(Parent(Some(parent_entity)))
            .spawn(world, 1);
        let new_entity = entities[0];

        if let Some(name) = world.get_name_mut(new_entity) {
            *name = Name(format!("Entity {}", new_entity.id));
        }

        let hierarchy = Box::new(UndoHistory::capture_hierarchy(world, new_entity));
        undo_history.push(
            UndoableOperation::EntityCreated {
                hierarchy,
                current_entity: new_entity,
            },
            format!("Create Entity {}", new_entity.id),
        );

        *selected_entity = Some(new_entity);
    }

    fn instantiate_prefab(world: &mut World, entity: Entity) {
        let prefab_source = match world.get_prefab_source(entity) {
            Some(source) => source.clone(),
            None => return,
        };

        let Some(source_path) = &prefab_source.source_path else {
            tracing::warn!(
                "Cannot instantiate prefab '{}': no source path",
                prefab_source.prefab_name
            );
            return;
        };

        let gltf_path = Path::new(source_path);
        let result = match import_gltf_from_path(gltf_path) {
            Ok(result) => result,
            Err(error) => {
                tracing::error!("Failed to load prefab from '{}': {}", source_path, error);
                return;
            }
        };

        for (name, (rgba_data, width, height)) in result.textures {
            world.queue_command(WorldCommand::LoadTexture {
                name,
                rgba_data,
                width,
                height,
            });
        }

        for (name, mesh) in result.meshes {
            mesh_cache_insert(&mut world.resources.mesh_cache, name, mesh);
        }

        let mut prefabs = result.prefabs;
        let prefab_index = prefabs
            .iter()
            .position(|p| p.name == prefab_source.prefab_name);
        let prefab = if let Some(index) = prefab_index {
            prefabs.remove(index)
        } else if !prefabs.is_empty() {
            tracing::warn!(
                "Prefab '{}' not found in '{}', using first available",
                prefab_source.prefab_name,
                source_path
            );
            prefabs.remove(0)
        } else {
            tracing::error!("No prefabs found in '{}'", source_path);
            return;
        };

        for root_node in &prefab.root_nodes {
            spawn_prefab_node(world, root_node, nalgebra_glm::Vec3::zeros(), Some(entity));
        }

        world.remove_components(entity, PREFAB_SOURCE);
        tracing::info!(
            "Instantiated prefab '{}' on entity {:?}",
            prefab_source.prefab_name,
            entity
        );
    }

    fn is_gizmo_entity(world: &World, entity: Entity) -> bool {
        if let Some(Name(name)) = world.get_name(entity) {
            name.ends_with("Gizmo")
        } else {
            false
        }
    }

    fn set_all_expanded(world: &World, ctx: &egui::Context, expanded: bool) {
        for entity in query_root_nodes(world) {
            Self::set_entity_expanded_recursive(world, ctx, entity, expanded);
        }
    }

    fn set_entity_expanded_recursive(
        world: &World,
        ctx: &egui::Context,
        entity: Entity,
        expanded: bool,
    ) {
        if Self::is_gizmo_entity(world, entity) {
            return;
        }

        let id = egui::Id::new("scene_tree_entity").with(entity.id);
        let mut state =
            egui::collapsing_header::CollapsingState::load_with_default_open(ctx, id, true);
        state.set_open(expanded);
        state.store(ctx);

        for child in query_children(world, entity) {
            Self::set_entity_expanded_recursive(world, ctx, child, expanded);
        }
    }
}
