use bone_types::SketchEntityId;

#[derive(Default, Clone, Debug, PartialEq, Eq)]
pub struct Selection(Vec<SketchEntityId>);

impl Selection {
    #[must_use]
    pub fn ids(&self) -> &[SketchEntityId] {
        &self.0
    }

    #[must_use]
    pub fn picked(self, id: Option<SketchEntityId>, additive: bool) -> Self {
        match (id, additive) {
            (Some(id), true) => self.toggled(id),
            (Some(id), false) => Self(vec![id]),
            (None, false) => Self::default(),
            (None, true) => self,
        }
    }

    fn toggled(mut self, id: SketchEntityId) -> Self {
        match self.0.iter().position(|x| *x == id) {
            Some(idx) => {
                self.0.remove(idx);
            }
            None => self.0.push(id),
        }
        self
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::sketch_mode::Plane;
    use crate::tools::add_point;
    use bone_document::Sketch;
    use bone_types::Point2;

    fn three_ids() -> (SketchEntityId, SketchEntityId, SketchEntityId) {
        let s = Sketch::new(Plane::Xy.basis());
        let (s, a) = add_point(s, Point2::from_mm(0.0, 0.0));
        let (s, b) = add_point(s, Point2::from_mm(1.0, 0.0));
        let (_, c) = add_point(s, Point2::from_mm(2.0, 0.0));
        (a, b, c)
    }

    #[test]
    fn default_selection_is_empty() {
        assert!(Selection::default().ids().is_empty());
    }

    #[test]
    fn pick_replace_overwrites_existing() {
        let (a, b, _) = three_ids();
        let s = Selection::default()
            .picked(Some(a), false)
            .picked(Some(b), false);
        assert_eq!(s.ids(), &[b]);
    }

    #[test]
    fn pick_additive_extends_then_toggles_off() {
        let (a, b, _) = three_ids();
        let s = Selection::default()
            .picked(Some(a), true)
            .picked(Some(b), true);
        assert_eq!(s.ids(), &[a, b]);
        let s = s.picked(Some(a), true);
        assert_eq!(s.ids(), &[b]);
    }

    #[test]
    fn pick_replace_with_none_clears() {
        let (a, b, _) = three_ids();
        let s = Selection::default()
            .picked(Some(a), true)
            .picked(Some(b), true)
            .picked(None, false);
        assert!(s.ids().is_empty());
    }

    #[test]
    fn pick_additive_with_none_preserves() {
        let (a, _, _) = three_ids();
        let s = Selection::default()
            .picked(Some(a), true)
            .picked(None, true);
        assert_eq!(s.ids(), &[a]);
    }
}
