//! Hierarchy panel UI state and user-preference persistence.

use std::collections::HashSet;

use bevy::prelude::*;
use serde::{Deserialize, Serialize};

use crate::project_io::{write_user_preferences, UserPreferences};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum HierarchySort {
    #[default]
    Manual,
    Name,
    Type,
}

#[derive(Resource, Debug)]
pub struct HierarchyPanelState {
    pub expanded: HashSet<Entity>,
    pub filter: String,
    pub show_generated: bool,
    pub show_runtime: bool,
    pub sort_mode: HierarchySort,
    /// Editor-session lock: prevents selection and gizmo manipulation.
    pub locked: HashSet<Entity>,
    /// Active hierarchy drag (release payload for egui 0.33+).
    pub active_drag: Option<Vec<Entity>>,
    save_timer: f32,
    dirty: bool,
}

impl Default for HierarchyPanelState {
    fn default() -> Self {
        Self {
            expanded: HashSet::new(),
            filter: String::new(),
            show_generated: true,
            show_runtime: false,
            sort_mode: HierarchySort::default(),
            locked: HashSet::new(),
            active_drag: None,
            save_timer: 0.0,
            dirty: false,
        }
    }
}

impl HierarchyPanelState {
    pub fn from_prefs(prefs: &UserPreferences) -> Self {
        Self {
            filter: prefs.hierarchy_filter.clone(),
            show_generated: prefs.hierarchy_show_generated,
            show_runtime: prefs.hierarchy_show_runtime,
            sort_mode: prefs.hierarchy_sort_mode,
            ..Self::default()
        }
    }

    pub fn mark_dirty(&mut self) {
        self.dirty = true;
        self.save_timer = 1.0;
    }

    pub fn toggle_expanded(&mut self, entity: Entity, path: &str, prefs: &mut UserPreferences) {
        if self.expanded.contains(&entity) {
            self.expanded.remove(&entity);
            prefs.hierarchy_expanded_paths.retain(|entry| entry != path);
        } else {
            self.expanded.insert(entity);
            if !prefs
                .hierarchy_expanded_paths
                .iter()
                .any(|entry| entry == path)
            {
                prefs.hierarchy_expanded_paths.push(path.to_string());
            }
        }
        self.mark_dirty();
    }

    pub fn sync_expanded_from_paths(&mut self, world: &mut World, paths: &[String]) {
        self.expanded = expanded_entities_for_paths(world, paths);
    }

    fn flush_prefs(&mut self, prefs: &mut UserPreferences) {
        prefs.hierarchy_filter = self.filter.clone();
        prefs.hierarchy_show_generated = self.show_generated;
        prefs.hierarchy_show_runtime = self.show_runtime;
        prefs.hierarchy_sort_mode = self.sort_mode;
    }
}

pub fn expanded_entities_for_paths(world: &mut World, paths: &[String]) -> HashSet<Entity> {
    use super::hierarchy_ops::entity_hierarchy_path;

    let mut expanded = HashSet::new();
    if paths.is_empty() {
        return expanded;
    }
    let mut query = world.query_filtered::<Entity, With<shared::LevelObject>>();
    for entity in query.iter(world) {
        let path = entity_hierarchy_path(world, entity);
        if paths.iter().any(|entry| entry == &path) {
            expanded.insert(entity);
        }
    }
    expanded
}

pub fn tick_hierarchy_prefs_save(
    mut state: ResMut<HierarchyPanelState>,
    mut prefs: ResMut<UserPreferences>,
    time: Res<Time>,
) {
    if !state.dirty {
        return;
    }
    state.save_timer -= time.delta_secs();
    if state.save_timer > 0.0 {
        return;
    }
    state.flush_prefs(&mut prefs);
    if let Err(err) = write_user_preferences(&prefs) {
        warn!("Failed to save hierarchy preferences: {err}");
    } else {
        state.dirty = false;
    }
}

pub fn apply_hierarchy_prefs(world: &mut World, prefs: &UserPreferences) {
    if !world.contains_resource::<HierarchyPanelState>() {
        return;
    }
    let paths = prefs.hierarchy_expanded_paths.clone();
    let expanded = expanded_entities_for_paths(world, &paths);
    let mut state = world.resource_mut::<HierarchyPanelState>();
    state.filter = prefs.hierarchy_filter.clone();
    state.show_generated = prefs.hierarchy_show_generated;
    state.show_runtime = prefs.hierarchy_show_runtime;
    state.sort_mode = prefs.hierarchy_sort_mode;
    state.expanded = expanded;
}
