use bone_types::SketchEntityId;
use serde::{Deserialize, Serialize};

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum SketchRelation {
    Coincident(SketchEntityId, SketchEntityId),
    Horizontal(SketchEntityId),
    Vertical(SketchEntityId),
    Parallel(SketchEntityId, SketchEntityId),
    Perpendicular(SketchEntityId, SketchEntityId),
    Tangent(SketchEntityId, SketchEntityId),
    Equal(SketchEntityId, SketchEntityId),
    Concentric(SketchEntityId, SketchEntityId),
    Midpoint {
        point: SketchEntityId,
        line: SketchEntityId,
    },
    Fix(SketchEntityId),
}

impl SketchRelation {
    #[must_use]
    pub const fn references(&self) -> RelationRefs {
        match *self {
            Self::Coincident(a, b)
            | Self::Parallel(a, b)
            | Self::Perpendicular(a, b)
            | Self::Tangent(a, b)
            | Self::Equal(a, b)
            | Self::Concentric(a, b) => RelationRefs([Some(a), Some(b)]),
            Self::Midpoint { point, line } => RelationRefs([Some(point), Some(line)]),
            Self::Horizontal(a) | Self::Vertical(a) | Self::Fix(a) => RelationRefs([Some(a), None]),
        }
    }

    #[must_use]
    pub const fn pair(&self) -> Option<(SketchEntityId, SketchEntityId)> {
        match *self {
            Self::Coincident(a, b)
            | Self::Parallel(a, b)
            | Self::Perpendicular(a, b)
            | Self::Tangent(a, b)
            | Self::Equal(a, b)
            | Self::Concentric(a, b) => Some((a, b)),
            Self::Midpoint { point, line } => Some((point, line)),
            Self::Horizontal(_) | Self::Vertical(_) | Self::Fix(_) => None,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct RelationRefs([Option<SketchEntityId>; 2]);

impl IntoIterator for RelationRefs {
    type Item = SketchEntityId;
    type IntoIter = core::iter::Flatten<core::array::IntoIter<Option<SketchEntityId>, 2>>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter().flatten()
    }
}
