use serde::{Deserialize, Serialize};

use crate::{FeatureId, SketchEntityId};

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct LoopIndex(u16);

impl LoopIndex {
    pub const OUTER: Self = Self(0);

    #[must_use]
    pub const fn new(value: u16) -> Self {
        Self(value)
    }

    #[must_use]
    pub const fn value(self) -> u16 {
        self.0
    }
}

impl core::fmt::Display for LoopIndex {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "loop#{}", self.0)
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct ImportOrdinal(u32);

impl ImportOrdinal {
    #[must_use]
    pub const fn new(value: u32) -> Self {
        Self(value)
    }

    #[must_use]
    pub const fn value(self) -> u32 {
        self.0
    }
}

impl core::fmt::Display for ImportOrdinal {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "import#{}", self.0)
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum SideKind {
    Corner,
    Seam,
}

impl SideKind {
    #[must_use]
    pub const fn label(self) -> &'static str {
        match self {
            Self::Corner => "corner",
            Self::Seam => "seam",
        }
    }
}

impl core::fmt::Display for SideKind {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.write_str(self.label())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum FaceRole {
    StartCap,
    Side {
        loop_index: LoopIndex,
        from: SketchEntityId,
    },
    EndCap,
    Imported {
        ordinal: ImportOrdinal,
    },
}

impl core::fmt::Display for FaceRole {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::StartCap => f.write_str("start_cap"),
            Self::Side { loop_index, from } => write!(f, "side({loop_index}, from={from:?})"),
            Self::EndCap => f.write_str("end_cap"),
            Self::Imported { ordinal } => write!(f, "imported({ordinal})"),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum EdgeRole {
    StartCapEdge {
        from: SketchEntityId,
    },
    SideEdge {
        from: SketchEntityId,
        side: SideKind,
    },
    EndCapEdge {
        from: SketchEntityId,
    },
    Imported {
        ordinal: ImportOrdinal,
    },
}

impl core::fmt::Display for EdgeRole {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::StartCapEdge { from } => write!(f, "start_cap_edge(from={from:?})"),
            Self::SideEdge { from, side } => write!(f, "side_edge({side}, from={from:?})"),
            Self::EndCapEdge { from } => write!(f, "end_cap_edge(from={from:?})"),
            Self::Imported { ordinal } => write!(f, "imported({ordinal})"),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum VertexRole {
    StartCapVertex {
        from: SketchEntityId,
        side: SideKind,
    },
    EndCapVertex {
        from: SketchEntityId,
        side: SideKind,
    },
    Imported {
        ordinal: ImportOrdinal,
    },
}

impl core::fmt::Display for VertexRole {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::StartCapVertex { from, side } => {
                write!(f, "start_cap_vertex({side}, from={from:?})")
            }
            Self::EndCapVertex { from, side } => {
                write!(f, "end_cap_vertex({side}, from={from:?})")
            }
            Self::Imported { ordinal } => write!(f, "imported({ordinal})"),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct FaceLabel {
    pub feature: FeatureId,
    pub role: FaceRole,
}

impl core::fmt::Display for FaceLabel {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "face[{:?}]:{}", self.feature, self.role)
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EdgeLabel {
    pub feature: FeatureId,
    pub role: EdgeRole,
}

impl core::fmt::Display for EdgeLabel {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "edge[{:?}]:{}", self.feature, self.role)
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VertexLabel {
    pub feature: FeatureId,
    pub role: VertexRole,
}

impl core::fmt::Display for VertexLabel {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "vertex[{:?}]:{}", self.feature, self.role)
    }
}
