use crate::alphabet::Alphabet;

#[allow(clippy::upper_case_acronyms)]
pub enum Rotor {
    I,
    II,
    III,
    IV,
    V,
    VI,
    VII,
    VIII,
    BETA,
}

impl TryFrom<u8> for Rotor {
    type Error = anyhow::Error;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        Ok(match value {
            1 => Self::I,
            2 => Self::II,
            3 => Self::III,
            4 => Self::IV,
            5 => Self::V,
            6 => Self::VI,
            7 => Self::VII,
            8 => Self::VIII,
            9 => Self::BETA,
            _ => anyhow::bail!("Rotor number out of range: {value}"),
        })
    }
}

pub trait TryIntoRotors {
    fn try_into_rotors(self) -> anyhow::Result<(Rotor, Rotor, Rotor)>;
}

impl TryIntoRotors for (u8, u8, u8) {
    fn try_into_rotors(self) -> anyhow::Result<(Rotor, Rotor, Rotor)> {
        Ok((self.0.try_into()?, self.1.try_into()?, self.2.try_into()?))
    }
}

impl Rotor {
    pub fn alphabet(&self) -> Alphabet {
        Alphabet::new(match self {
            Self::I => "EKMFLGDQVZNTOWYHXUSPAIBRCJ",
            Self::II => "AJDKSIRUXBLHWTMCQGZNPYFVOE",
            Self::III => "BDFHJLCPRTXVZNYEIWGAKMUSQO",
            Self::IV => "ESOVPZJAYQUIRHXLNFTGKDCMWB",
            Self::V => "VZBRGITYUPSDNHLXAWMJQOFECK",
            Self::VI => "JPGVOUMFYQBENHZRDKASXLICTW",
            Self::VII => "NZJHGRCXMYSWBOUFAIVLPEKQDT",
            Self::VIII => "FKQHTLXOCBJSPDZRAMEWNIUYGV",
            Self::BETA => "LEYJVCNIXWPBQMDRTAKZGFUHOS",
        })
        .unwrap()
    }

    pub const fn notches(&self) -> &'static [char] {
        match self {
            Self::I => &['Q'],
            Self::II => &['E'],
            Self::III => &['V'],
            Self::IV => &['J'],
            Self::V => &['Z'],
            Self::VI => &['M', 'Z'],
            Self::VII => &['M', 'Z'],
            Self::VIII => &['M', 'Z'],
            Self::BETA => &[],
        }
    }
}
