use std::collections::BTreeSet;

#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct TreeShellUiState {
    pub expanded: BTreeSet<String>,
    pub selected: Option<String>,
    pub focused: Option<String>,
    pub keyboard_anchor: Option<String>,
    pub dragging: Option<String>,
    pub drop_target: Option<String>,
}

impl TreeShellUiState {
    pub fn from_defaults(expanded: &[String]) -> Self {
        Self {
            expanded: expanded.iter().cloned().collect(),
            ..Self::default()
        }
    }

    pub fn toggle_expanded(&mut self, node_id: &str) {
        if !self.expanded.insert(node_id.to_string()) {
            self.expanded.remove(node_id);
        }
    }

    pub fn select(&mut self, node_id: &str) {
        self.selected = Some(node_id.to_string());
        self.keyboard_anchor = Some(node_id.to_string());
    }

    pub fn focus(&mut self, node_id: &str) {
        self.focused = Some(node_id.to_string());
    }

    pub fn start_drag(&mut self, node_id: &str) {
        self.dragging = Some(node_id.to_string());
    }

    pub fn set_drop_target(&mut self, node_id: Option<&str>) {
        self.drop_target = node_id.map(ToOwned::to_owned);
    }

    pub fn clear_drag(&mut self) {
        self.dragging = None;
        self.drop_target = None;
    }
}

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

    #[test]
    fn tree_shell_interaction_state_tracks_selection_focus_keyboard_and_dragging() {
        let mut state = TreeShellUiState::from_defaults(&["page_root".into()]);
        state.toggle_expanded("page_child");
        state.select("page_child");
        state.focus("page_child");
        state.start_drag("page_child");
        state.set_drop_target(Some("page_root"));

        assert!(state.expanded.contains("page_root"));
        assert!(state.expanded.contains("page_child"));
        assert_eq!(state.selected.as_deref(), Some("page_child"));
        assert_eq!(state.focused.as_deref(), Some("page_child"));
        assert_eq!(state.keyboard_anchor.as_deref(), Some("page_child"));
        assert_eq!(state.dragging.as_deref(), Some("page_child"));
        assert_eq!(state.drop_target.as_deref(), Some("page_root"));

        state.clear_drag();
        assert!(state.dragging.is_none());
        assert!(state.drop_target.is_none());
    }
}
