/// 千日手の状態を表すenum
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum RepetitionState {
    /// 千日手でない
    #[default]
    None,
    /// 連続王手の千日手で相手が負け（自分の勝ち）
    Win,
    /// 連続王手の千日手で自分が負け
    Lose,
    /// 通常の千日手（引き分け）
    Draw,
    /// 優等局面（持ち駒が過去局面より優れている）
    Superior,
    /// 劣等局面（持ち駒が過去局面より劣っている）
    Inferior,
}

/// 千日手状態の総数
pub const REPETITION_NB: usize = 6;

impl RepetitionState {
    /// YaneuraOu互換のUSI拡張文字列を返す。
    #[must_use]
    pub const fn to_usi_string(self) -> &'static str {
        match self {
            Self::None => "rep_none",
            Self::Win => "rep_win",
            Self::Lose => "rep_lose",
            Self::Draw => "rep_draw",
            Self::Superior => "rep_sup",
            Self::Inferior => "rep_inf",
        }
    }
}

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

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

    #[test]
    fn test_repetition_state_derives() {
        // Cloneのテスト
        let state = RepetitionState::Win;
        let cloned = state;
        assert_eq!(state, cloned);

        // Copyのテスト
        let state2 = RepetitionState::Lose;
        let copied = state2;
        assert_eq!(state2, copied);

        // PartialEqのテスト
        assert_eq!(RepetitionState::None, RepetitionState::None);
        assert_ne!(RepetitionState::Win, RepetitionState::Lose);

        // Debugのテスト
        let debug_str = format!("{:?}", RepetitionState::Draw);
        assert_eq!(debug_str, "Draw");
    }

    #[test]
    fn test_all_states_are_unique() {
        let states = [
            RepetitionState::None,
            RepetitionState::Win,
            RepetitionState::Lose,
            RepetitionState::Draw,
            RepetitionState::Superior,
            RepetitionState::Inferior,
        ];

        // 全ての状態が異なることを確認
        for (i, state1) in states.iter().enumerate() {
            for (j, state2) in states.iter().enumerate() {
                if i == j {
                    assert_eq!(state1, state2);
                } else {
                    assert_ne!(state1, state2);
                }
            }
        }
    }

    #[test]
    fn test_default_is_none() {
        let state = RepetitionState::default();
        assert_eq!(state, RepetitionState::None);
    }

    #[test]
    fn test_repetition_state_usi_string() {
        assert_eq!(RepetitionState::None.to_usi_string(), "rep_none");
        assert_eq!(RepetitionState::Win.to_usi_string(), "rep_win");
        assert_eq!(RepetitionState::Lose.to_usi_string(), "rep_lose");
        assert_eq!(RepetitionState::Draw.to_usi_string(), "rep_draw");
        assert_eq!(RepetitionState::Superior.to_usi_string(), "rep_sup");
        assert_eq!(RepetitionState::Inferior.to_usi_string(), "rep_inf");
    }
}
