use crate::alphabet::ALPHABET;
use strum::IntoEnumIterator;

#[derive(strum_macros::EnumIter, PartialEq, Eq, Hash)]
pub enum Reflector {
    A,
    B,
    C,
    BThin,
    CThin,
    Ukwr,
    Ukwk,
}

static REFLECTORS: std::sync::OnceLock<std::collections::HashMap<Reflector, std::collections::HashMap<char, char>>> = std::sync::OnceLock::new();

impl Reflector {
    pub fn alphabet(&self) -> &std::collections::HashMap<char, char> {
        REFLECTORS
            .get_or_init(|| {
                let mut reflectors = std::collections::HashMap::new();
                for reflector in Self::iter() {
                    let alphabet = match self {
                        Self::A => "EJMZALYXVBWFCRQUONTSPIKHGD",
                        Self::B => "YRUHQSLDPXNGOKMIEBFZCWVJAT",
                        Self::C => "FVPJIAOYEDRZXWGCTKUQSBNMHL",
                        Self::BThin => "ENKQAUYWJICOPBLMDXZVFTHRGS",
                        Self::CThin => "RDOBJNTKVEHMLFCWZAXGYIPSUQ",
                        Self::Ukwr => "QYHOGNECVPUZTFDJAXWMKISRBL",
                        Self::Ukwk => "IMETCGFRAYSQBZXWLHKDVUPOJN",
                    };

                    let mut map = std::collections::HashMap::new();
                    for (letter, reflected_letter) in ALPHABET.letters().chars().zip(alphabet.chars()) {
                        map.insert(letter, reflected_letter);
                        map.insert(reflected_letter, letter);
                    }
                    reflectors.insert(reflector, map);
                }
                reflectors
            })
            .get(self)
            .unwrap()
    }
}

impl TryFrom<&str> for Reflector {
    type Error = anyhow::Error;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        Ok(match value.to_lowercase().as_str() {
            "a" => Self::A,
            "b" => Self::B,
            "c" => Self::C,
            "bthin" => Self::BThin,
            "cthin" => Self::CThin,
            "ukwr" => Self::Ukwr,
            "ukwk" => Self::Ukwk,
            _ => anyhow::bail!("Invalid reflector: {value}"),
        })
    }
}
