pub fn to_pascal_case(input: &str) -> String {
    input
        .split(['-', '_', ' '])
        .map(|word| {
            let mut chars = word.chars();
            match chars.next() {
                None => String::new(),
                Some(c) => c.to_uppercase().to_string() + chars.as_str(),
            }
        })
        .collect()
}

pub fn to_kebab_case(pascal: &str) -> String {
    let mut out = String::new();
    for (i, c) in pascal.chars().enumerate() {
        if c.is_uppercase() && i != 0 {
            out.push('-');
        }
        out.extend(c.to_lowercase());
    }
    out
}

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

    #[test]
    fn pascal_from_kebab() {
        assert_eq!(to_pascal_case("hero-section"), "HeroSection");
    }

    #[test]
    fn pascal_from_snake() {
        assert_eq!(to_pascal_case("my_card"), "MyCard");
    }

    #[test]
    fn pascal_from_already_pascal() {
        assert_eq!(to_pascal_case("HeroSection"), "HeroSection");
    }

    #[test]
    fn pascal_from_single_word() {
        assert_eq!(to_pascal_case("navbar"), "Navbar");
    }

    #[test]
    fn kebab_from_pascal() {
        assert_eq!(to_kebab_case("HeroSection"), "hero-section");
    }

    #[test]
    fn kebab_from_single_word() {
        assert_eq!(to_kebab_case("Navbar"), "navbar");
    }

    #[test]
    fn kebab_from_multi_word() {
        assert_eq!(to_kebab_case("DataTableHeader"), "data-table-header");
    }

    #[test]
    fn roundtrip_kebab_to_pascal_to_kebab() {
        let input = "feature-card";
        assert_eq!(to_kebab_case(&to_pascal_case(input)), input);
    }
}
