// Case transformation functions
//
// This module provides functions to transform word lists into various casing
// conventions (PascalCase, camelCase, snake_case, kebab-case, etc.).

/// Transform words to lowercase (concatenated)
/// Example: ["By", "Item"] → "byitem"
pub fn to_lowercase(words: &[String]) -> String {
    words
        .iter()
        .map(|w| w.to_lowercase())
        .collect::<Vec<_>>()
        .join("")
}

/// Transform words to UPPERCASE (concatenated)
/// Example: ["By", "Item"] → "BYITEM"
pub fn to_uppercase(words: &[String]) -> String {
    words
        .iter()
        .map(|w| w.to_uppercase())
        .collect::<Vec<_>>()
        .join("")
}

/// Transform words to PascalCase
/// Example: ["by", "item"] → "ByItem"
pub fn to_pascal_case(words: &[String]) -> String {
    words
        .iter()
        .map(|w| {
            let mut chars = w.chars();
            match chars.next() {
                None => String::new(),
                Some(first) => first.to_uppercase().chain(chars.as_str().to_lowercase().chars()).collect(),
            }
        })
        .collect()
}

/// Transform words to camelCase
/// Example: ["by", "item"] → "byItem"
pub fn to_camel_case(words: &[String]) -> String {
    if words.is_empty() {
        return String::new();
    }

    let mut result = words[0].to_lowercase();
    
    for word in &words[1..] {
        let mut chars = word.chars();
        match chars.next() {
            None => {}
            Some(first) => {
                result.push_str(&first.to_uppercase().to_string());
                result.push_str(&chars.as_str().to_lowercase());
            }
        }
    }

    result
}

/// Transform words to lower_snake_case
/// Example: ["By", "Item"] → "by_item"
pub fn to_lower_snake_case(words: &[String]) -> String {
    words
        .iter()
        .map(|w| w.to_lowercase())
        .collect::<Vec<_>>()
        .join("_")
}

/// Transform words to SCREAMING_SNAKE_CASE
/// Example: ["By", "Item"] → "BY_ITEM"
pub fn to_screaming_snake_case(words: &[String]) -> String {
    words
        .iter()
        .map(|w| w.to_uppercase())
        .collect::<Vec<_>>()
        .join("_")
}

/// Transform words to kebab-case
/// Example: ["By", "Item"] → "by-item"
pub fn to_kebab_case(words: &[String]) -> String {
    words
        .iter()
        .map(|w| w.to_lowercase())
        .collect::<Vec<_>>()
        .join("-")
}

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

    #[test]
    fn test_to_lowercase() {
        assert_eq!(to_lowercase(&["By".to_string(), "Item".to_string()]), "byitem");
        assert_eq!(
            to_lowercase(&["User".to_string(), "Email".to_string()]),
            "useremail"
        );
    }

    #[test]
    fn test_to_uppercase() {
        assert_eq!(to_uppercase(&["By".to_string(), "Item".to_string()]), "BYITEM");
        assert_eq!(
            to_uppercase(&["User".to_string(), "Email".to_string()]),
            "USEREMAIL"
        );
    }

    #[test]
    fn test_to_pascal_case() {
        assert_eq!(
            to_pascal_case(&["by".to_string(), "item".to_string()]),
            "ByItem"
        );
        assert_eq!(
            to_pascal_case(&["user".to_string(), "email".to_string()]),
            "UserEmail"
        );
        // Mixed case input
        assert_eq!(
            to_pascal_case(&["By".to_string(), "ITEM".to_string()]),
            "ByItem"
        );
    }

    #[test]
    fn test_to_camel_case() {
        assert_eq!(
            to_camel_case(&["by".to_string(), "item".to_string()]),
            "byItem"
        );
        assert_eq!(
            to_camel_case(&["user".to_string(), "email".to_string()]),
            "userEmail"
        );
        // Mixed case input
        assert_eq!(
            to_camel_case(&["By".to_string(), "ITEM".to_string()]),
            "byItem"
        );
    }

    #[test]
    fn test_to_lower_snake_case() {
        assert_eq!(
            to_lower_snake_case(&["By".to_string(), "Item".to_string()]),
            "by_item"
        );
        assert_eq!(
            to_lower_snake_case(&["User".to_string(), "Email".to_string()]),
            "user_email"
        );
    }

    #[test]
    fn test_to_screaming_snake_case() {
        assert_eq!(
            to_screaming_snake_case(&["By".to_string(), "Item".to_string()]),
            "BY_ITEM"
        );
        assert_eq!(
            to_screaming_snake_case(&["User".to_string(), "Email".to_string()]),
            "USER_EMAIL"
        );
    }

    #[test]
    fn test_to_kebab_case() {
        assert_eq!(
            to_kebab_case(&["By".to_string(), "Item".to_string()]),
            "by-item"
        );
        assert_eq!(
            to_kebab_case(&["Order".to_string(), "Processor".to_string()]),
            "order-processor"
        );
    }

    #[test]
    fn test_single_word() {
        assert_eq!(to_pascal_case(&["item".to_string()]), "Item");
        assert_eq!(to_camel_case(&["item".to_string()]), "item");
        assert_eq!(to_lowercase(&["Item".to_string()]), "item");
        assert_eq!(to_uppercase(&["item".to_string()]), "ITEM");
    }

    #[test]
    fn test_with_numbers() {
        assert_eq!(
            to_pascal_case(&["Item2".to_string()]),
            "Item2"
        );
        assert_eq!(
            to_lower_snake_case(&["Item".to_string(), "2".to_string()]),
            "item_2"
        );
    }
}
