//! Utility functions for string manipulation.

/// Truncate a string to a maximum byte length, respecting UTF-8 character boundaries.
///
/// If the string exceeds `max_len` bytes, it is truncated at the last valid
/// UTF-8 character boundary at or before `max_len` bytes, and "..." is appended.
///
/// # Examples
///
/// ```
/// use mi6_core::truncate_string;
///
/// // Short string is unchanged
/// assert_eq!(truncate_string("hello", 10), "hello");
///
/// // Long string is truncated with "..."
/// let long = "a".repeat(1500);
/// let truncated = truncate_string(&long, 1000);
/// assert!(truncated.ends_with("..."));
/// assert!(truncated.len() <= 1003);
/// ```
pub fn truncate_string(s: &str, max_len: usize) -> String {
    if s.len() <= max_len {
        s.to_string()
    } else {
        // Find a valid UTF-8 char boundary at or before max_len
        let mut end = max_len;
        while !s.is_char_boundary(end) && end > 0 {
            end -= 1;
        }
        format!("{}...", &s[..end])
    }
}

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

    #[test]
    fn test_truncate_string_short() {
        assert_eq!(truncate_string("hello", 10), "hello");
    }

    #[test]
    fn test_truncate_string_exact_length() {
        assert_eq!(truncate_string("hello", 5), "hello");
    }

    #[test]
    fn test_truncate_string_long() {
        let long = "a".repeat(1500);
        let truncated = truncate_string(&long, 1000);
        assert!(truncated.ends_with("..."));
        assert_eq!(truncated.len(), 1003); // 1000 + "..."
    }

    #[test]
    fn test_truncate_string_multibyte_utf8() {
        // "é" is 2 bytes in UTF-8, create string where byte 1000 is in middle of char
        let s = format!("{}{}", "a".repeat(999), "é"); // 999 + 2 = 1001 bytes
        let truncated = truncate_string(&s, 1000);
        assert!(truncated.ends_with("..."));
        // Should truncate at byte 999 (the last valid boundary before 1000)
        assert_eq!(truncated.len(), 1002); // 999 + "..."
    }

    #[test]
    fn test_truncate_string_empty() {
        assert_eq!(truncate_string("", 10), "");
    }

    #[test]
    fn test_truncate_string_zero_max() {
        assert_eq!(truncate_string("hello", 0), "...");
    }
}
