use std::fmt;
use std::str::FromStr;
use crate::modules::hub::tokens::{AbugidaToken, AlphabetToken};

// Generic implementation that preserves token names as strings for bijective conversion
impl fmt::Display for AbugidaToken {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AbugidaToken::Unknown(c) => write!(f, "Unknown({})", c),
            _ => {
                // Use Debug representation and strip the enum name prefix
                let debug_str = format!("{:?}", self);
                if let Some(name) = debug_str.strip_prefix("AbugidaToken::") {
                    f.write_str(name)
                } else {
                    f.write_str(&debug_str)
                }
            }
        }
    }
}

impl FromStr for AbugidaToken {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // Handle Unknown variant specially
        if s.starts_with("Unknown(") && s.ends_with(')') {
            let inner = &s[8..s.len()-1];
            if let Some(c) = inner.chars().next() {
                if inner.chars().count() == 1 {
                    return Ok(AbugidaToken::Unknown(c));
                }
            }
            return Err(format!("Invalid Unknown token: {}", s));
        }
        
        // Try to match against known variants dynamically
        match s {
            {{#each abugida_variants}}
            "{{this}}" => Ok(AbugidaToken::{{this}}),
            {{/each}}
            _ => Err(format!("Unknown AbugidaToken: {}", s)),
        }
    }
}

impl fmt::Display for AlphabetToken {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AlphabetToken::Unknown(c) => write!(f, "Unknown({})", c),
            _ => {
                // Use Debug representation and strip the enum name prefix
                let debug_str = format!("{:?}", self);
                if let Some(name) = debug_str.strip_prefix("AlphabetToken::") {
                    f.write_str(name)
                } else {
                    f.write_str(&debug_str)
                }
            }
        }
    }
}

impl FromStr for AlphabetToken {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        // Handle Unknown variant specially
        if s.starts_with("Unknown(") && s.ends_with(')') {
            let inner = &s[8..s.len()-1];
            if let Some(c) = inner.chars().next() {
                if inner.chars().count() == 1 {
                    return Ok(AlphabetToken::Unknown(c));
                }
            }
            return Err(format!("Invalid Unknown token: {}", s));
        }
        
        // Try to match against known variants dynamically
        // Use a macro to handle all possible variants at compile time
        // This approach avoids hardcoding and handles any future additions
        use AlphabetToken::*;
        
        match s {
            {{#each alphabet_variants}}
            "{{this}}" => Ok({{this}}),
            {{/each}}
            // For any tokens not in schemas, try a generic approach
            "VowelA" => Ok(VowelA),
            "VowelAa" => Ok(VowelAa),
            "VowelI" => Ok(VowelI),
            "VowelIi" => Ok(VowelIi),
            "VowelU" => Ok(VowelU),
            "VowelUu" => Ok(VowelUu),
            "VowelR" => Ok(VowelR),
            "VowelRr" => Ok(VowelRr),
            "VowelL" => Ok(VowelL),
            "VowelLl" => Ok(VowelLl),
            "VowelE" => Ok(VowelE),
            "VowelAi" => Ok(VowelAi),
            "VowelO" => Ok(VowelO),
            "VowelAu" => Ok(VowelAu),
            "ConsonantK" => Ok(ConsonantK),
            "ConsonantKh" => Ok(ConsonantKh),
            "ConsonantG" => Ok(ConsonantG),
            "ConsonantGh" => Ok(ConsonantGh),
            "ConsonantNg" => Ok(ConsonantNg),
            "ConsonantC" => Ok(ConsonantC),
            "ConsonantCh" => Ok(ConsonantCh),
            "ConsonantJ" => Ok(ConsonantJ),
            "ConsonantJh" => Ok(ConsonantJh),
            "ConsonantNy" => Ok(ConsonantNy),
            "ConsonantT" => Ok(ConsonantT),
            "ConsonantTh" => Ok(ConsonantTh),
            "ConsonantD" => Ok(ConsonantD),
            "ConsonantDh" => Ok(ConsonantDh),
            "ConsonantN" => Ok(ConsonantN),
            "ConsonantTt" => Ok(ConsonantTt),
            "ConsonantTth" => Ok(ConsonantTth),
            "ConsonantDd" => Ok(ConsonantDd),
            "ConsonantDdh" => Ok(ConsonantDdh),
            "ConsonantNn" => Ok(ConsonantNn),
            "ConsonantP" => Ok(ConsonantP),
            "ConsonantPh" => Ok(ConsonantPh),
            "ConsonantB" => Ok(ConsonantB),
            "ConsonantBh" => Ok(ConsonantBh),
            "ConsonantM" => Ok(ConsonantM),
            "ConsonantY" => Ok(ConsonantY),
            "ConsonantR" => Ok(ConsonantR),
            "ConsonantL" => Ok(ConsonantL),
            "ConsonantV" => Ok(ConsonantV),
            "ConsonantLl" => Ok(ConsonantLl),
            "ConsonantSh" => Ok(ConsonantSh),
            "ConsonantSs" => Ok(ConsonantSs),
            "ConsonantS" => Ok(ConsonantS),
            "ConsonantH" => Ok(ConsonantH),
            "MarkAnusvara" => Ok(MarkAnusvara),
            "MarkVisarga" => Ok(MarkVisarga),
            "MarkCandrabindu" => Ok(MarkCandrabindu),
            "MarkAvagraha" => Ok(MarkAvagraha),
            "MarkUdatta" => Ok(MarkUdatta),
            "MarkAnudatta" => Ok(MarkAnudatta),
            "MarkDoubleSvarita" => Ok(MarkDoubleSvarita),
            "MarkTripleSvarita" => Ok(MarkTripleSvarita),
            "SpecialKs" => Ok(SpecialKs),
            "SpecialJn" => Ok(SpecialJn),
            "ConsonantQa" => Ok(ConsonantQa),
            "ConsonantZa" => Ok(ConsonantZa),
            "ConsonantFa" => Ok(ConsonantFa),
            "ConsonantGha" => Ok(ConsonantGha),
            "ConsonantKha" => Ok(ConsonantKha),
            "ConsonantRra" => Ok(ConsonantRra),
            "ConsonantRrha" => Ok(ConsonantRrha),
            "ConsonantYa" => Ok(ConsonantYa),
            "Digit0" => Ok(Digit0),
            "Digit1" => Ok(Digit1),
            "Digit2" => Ok(Digit2),
            "Digit3" => Ok(Digit3),
            "Digit4" => Ok(Digit4),
            "Digit5" => Ok(Digit5),
            "Digit6" => Ok(Digit6),
            "Digit7" => Ok(Digit7),
            "Digit8" => Ok(Digit8),
            "Digit9" => Ok(Digit9),
            _ => Err(format!("Unknown AlphabetToken: {}", s)),
        }
    }
}