pub use 五行::*;

/// 木火土金水
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum 五行 {
    /// 木曰曲直
    木,
    /// 火曰炎上
    火,
    /// 土曰稼穡
    土,
    /// 金曰從革
    金,
    /// 水曰潤下
    水,
}

impl 五行 {
    /// - 木生火
    /// - 火生土
    /// - 土生金
    /// - 金生水
    /// - 水生木
    pub const fn 生(self) -> Self {
        match self {
            木 => 火,
            火 => 土,
            土 => 金,
            金 => 水,
            水 => 木,
        }
    }

    /// - 木克土
    /// - 火克金
    /// - 土克水
    /// - 金克木
    /// - 水克火
    pub const fn 克(self) -> Self {
        match self {
            木 => 土,
            火 => 金,
            土 => 水,
            金 => 木,
            水 => 火,
        }
    }

    /// - 木克土，土克於木
    /// - 火克金，金克於火
    /// - 土克水，水克於土
    /// - 金克木，木克於金
    /// - 水克火，火克於水
    pub const fn 克於(self) -> Self {
        match self {
            木 => 金,
            火 => 水,
            土 => 木,
            金 => 火,
            水 => 土,
        }
    }

    /// - 木生水，水生於木
    /// - 火生木，木生於火
    /// - 土生火，火生於土
    /// - 金生土，土生於金
    /// - 水生金，金生於水
    pub const fn 生於(self) -> Self {
        match self {
            木 => 水,
            火 => 木,
            土 => 火,
            金 => 土,
            水 => 金,
        }
    }
}

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

    #[test]
    fn 測試_生() {
        assert_eq!(木.生(), 火);
        assert_eq!(火.生(), 土);
        assert_eq!(土.生(), 金);
        assert_eq!(金.生(), 水);
        assert_eq!(水.生(), 木);

        assert_eq!(火.生於(), 木);
        assert_eq!(土.生於(), 火);
        assert_eq!(金.生於(), 土);
        assert_eq!(水.生於(), 金);
        assert_eq!(木.生於(), 水);
    }

    #[test]
    fn 測試_克() {
        assert_eq!(木.克(), 土);
        assert_eq!(火.克(), 金);
        assert_eq!(土.克(), 水);
        assert_eq!(金.克(), 木);
        assert_eq!(水.克(), 火);

        assert_eq!(土.克於(), 木);
        assert_eq!(金.克於(), 火);
        assert_eq!(水.克於(), 土);
        assert_eq!(木.克於(), 金);
        assert_eq!(火.克於(), 水);
    }
}
