use rand::Rng;

const VOWELS: usize = 5;
const CONSONANTS: usize = 11;
const OBS: &str = "";

type KanaCharacters<'a> = [[&'a str; VOWELS]; CONSONANTS];
#[derive(Clone)]
pub enum Kanas {
    Romaji,
    Hiragana,
    Katakana,
}

impl Default for Kanas {
    fn default() -> Self {
        Kanas::Romaji
    }
}

impl std::fmt::Display for Kanas {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Kanas::Romaji => "Romaji",
                Kanas::Hiragana => "Hiragana",
                Kanas::Katakana => "Katakana",
            }
        )
    }
}
#[derive(Default)]
pub struct Hieroglyph {
    syllable: String,
    row: usize,
    column: usize,
}

impl Hieroglyph {
    pub fn get_kana(&self) -> Kanas {
        for row in ROMAJI {
            if row.contains(&(self.syllable).as_str()) {
                return Kanas::Romaji;
            }
        }
        for row in HIRAGANA {
            if row.contains(&(self.syllable).as_str()) {
                return Kanas::Hiragana;
            }
        }
        for row in KATAKANA {
            if row.contains(&(self.syllable).as_str()) {
                return Kanas::Katakana;
            }
        }
        Kanas::Romaji // /shrug
    }
}

impl std::fmt::Display for Hieroglyph {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.syllable)
    }
}

impl std::fmt::Debug for Hieroglyph {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Hieroglyph: {} => ({}, {})",
            self.syllable, self.row, self.column
        )
    }
}

const ROMAJI: KanaCharacters = [
    ["a", "i", "u", "e", "o"],
    ["ka", "ki", "ku", "ke", "ko"],
    ["sa", "si", "su", "se", "so"],
    ["ta", "ti", "tu", "te", "to"],
    ["na", "ni", "nu", "ne", "no"],
    ["ha", "hi", "hu", "he", "ho"],
    ["ma", "mi", "mu", "me", "mo"],
    ["ya", OBS, "yu", OBS, "yo"],
    ["ra", "ri", "ru", "re", "ro"],
    ["wa", OBS, OBS, OBS, "wo"],
    ["n", OBS, OBS, OBS, OBS],
];

const HIRAGANA: KanaCharacters = [
    ["あ", "い", "う", "え", "お"],
    ["か", "き", "く", "け", "こ"],
    ["さ", "し", "す", "せ", "そ"],
    ["た", "ち", "つ", "て", "と"],
    ["な", "に", "ぬ", "ね", "の"],
    ["は", "ひ", "ふ", "へ", "ほ"],
    ["ま", "み", "む", "め", "も"],
    ["や", OBS, "ゆ", OBS, "よ"],
    ["ら", "り", "る", "れ", "ろ"],
    ["わ", OBS, OBS, OBS, "を"],
    ["ん", OBS, OBS, OBS, OBS],
];

const KATAKANA: KanaCharacters = [
    ["ア", "イ", "ウ", "エ", "オ"],
    ["カ", "キ", "ク", "ケ", "コ"],
    ["サ", "シ", "ス", "セ", "ソ"],
    ["タ", "チ", "ツ", "テ", "ト"],
    ["ナ", "ニ", "ヌ", "ネ", "ノ"],
    ["ハ", "ヒ", "フ", "ヘ", "ホ"],
    ["マ", "ミ", "ム", "メ", "モ"],
    ["ヤ", OBS, "ユ", OBS, "ヨ"],
    ["ラ", "リ", "ル", "レ", "ロ"],
    ["ワ", OBS, OBS, OBS, "ヲ"],
    ["ン", OBS, OBS, OBS, OBS],
];

fn get_characters_for_kana(k: &Kanas) -> KanaCharacters {
    match k {
        Kanas::Hiragana => HIRAGANA,
        Kanas::Katakana => KATAKANA,
        Kanas::Romaji => ROMAJI,
    }
}

pub fn get_kana_pair_for_hieroglyph(k: &Kanas, h: &Hieroglyph) -> Hieroglyph {
    Hieroglyph {
        syllable: get_characters_for_kana(&k)[h.row][h.column].to_string(),
        row: h.row,
        column: h.column,
    }
}

pub fn generate_random_hieroglyph(k: Kanas) -> Hieroglyph {
    let row: usize = rand::thread_rng().gen_range(0..CONSONANTS);
    let column: usize = rand::thread_rng().gen_range(0..VOWELS);

    let syllable: String = get_characters_for_kana(&k)[row][column].to_string();

    if syllable == OBS {
        return generate_random_hieroglyph(k);
    }
    Hieroglyph {
        syllable,
        row,
        column,
    }
}

pub fn random_kana(hiragana: bool, katakana: bool) -> Hieroglyph {
    if hiragana && katakana {
        generate_random_hieroglyph(if rand::thread_rng().gen_bool(0.5) {
            Kanas::Katakana
        } else {
            Kanas::Hiragana
        })
    } else {
        generate_random_hieroglyph(if hiragana {
            Kanas::Hiragana
        } else {
            Kanas::Katakana
        })
    }
}

pub fn ask(ktr: bool, rtk: bool, hiragana: bool, katakana: bool) -> Hieroglyph {
    if ktr && rtk {
        return if rand::thread_rng().gen_bool(0.5) {
            random_kana(hiragana, katakana)
        } else {
            generate_random_hieroglyph(Kanas::Romaji)
        };
    } else if ktr {
        return random_kana(hiragana, katakana);
    } else {
        return generate_random_hieroglyph(Kanas::Romaji);
    }
}

pub fn generate_question_text(question: &Hieroglyph, exact_kana: &Kanas) -> String {
    return String::from(match question.get_kana() {
        Kanas::Romaji => match exact_kana {
            Kanas::Hiragana => {
                format!("Name corresponding hiragana for {}", question.to_string())
            }
            Kanas::Katakana => {
                format!("Name corresponding katakana for {}", question.to_string())
            }
            _ => {
                panic!("HOW DID YOU GET HERE!?");
            }
        },
        Kanas::Hiragana => {
            format!(
                "Name corresponding romaji for hiragana {}",
                question.to_string()
            )
        }
        Kanas::Katakana => {
            format!(
                "Name corresponding romaji for katakana {}",
                question.to_string()
            )
        }
    });
}
