use regex::Regex; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ScriptureSection { pub verse: String, pub reference: String, } /// Format raw scripture text into structured sections with verses and references pub fn format_scripture_text(text: &str) -> Vec { // Handle single-line format where verse and reference are together if text.contains(" KJV") && !text.contains('\n') { // Single line format: "verse text. Book chapter:verse KJV" if let Some(kjv_pos) = text.rfind(" KJV") { let before_kjv = &text[..kjv_pos]; // Find the last period or other punctuation that separates verse from reference if let Some(last_period) = before_kjv.rfind('.') { if let Some(reference_start) = before_kjv[last_period..].find(char::is_alphabetic) { let actual_start = last_period + reference_start; let verse_text = format!("{}.", &before_kjv[..last_period]); let reference = format!("{} KJV", &before_kjv[actual_start..]); return vec![ScriptureSection { verse: verse_text.trim().to_string(), reference: reference.trim().to_string(), }]; } } } // Fallback: treat entire text as verse with no separate reference return vec![ScriptureSection { verse: text.to_string(), reference: String::new(), }]; } // Multi-line format (original logic) let sections: Vec<&str> = text.split('\n').collect(); let mut formatted_sections = Vec::new(); let mut current_verse = String::new(); for section in sections { let trimmed = section.trim(); if trimmed.is_empty() { continue; } // Check if this line is a reference (contains "KJV" at the end) if trimmed.ends_with("KJV") { // This is a reference for the verse we just accumulated if !current_verse.is_empty() { formatted_sections.push(ScriptureSection { verse: current_verse.clone(), reference: trimmed.to_string(), }); current_verse.clear(); // Reset for next verse } } else { // This is verse text if !current_verse.is_empty() { current_verse.push(' '); } current_verse.push_str(trimmed); } } // Add any remaining verse without a reference if !current_verse.is_empty() { formatted_sections.push(ScriptureSection { verse: current_verse, reference: String::new(), }); } formatted_sections } /// Extract scripture references from text (e.g., "Joel 2:28 KJV" patterns) pub fn extract_scripture_references(text: &str) -> String { let pattern = r"([1-3]?\s*[A-Za-z]+\s+\d+:\d+(?:-\d+)?)\s+KJV"; match Regex::new(pattern) { Ok(regex) => { let references: Vec = regex .captures_iter(text) .filter_map(|cap| cap.get(1).map(|m| m.as_str().trim().to_string())) .collect(); if references.is_empty() { "Scripture Reading".to_string() } else { references.join(", ") } } Err(_) => "Scripture Reading".to_string(), } } /// Create standardized share text for sermons pub fn create_sermon_share_text(title: &str, speaker: &str, video_url: Option<&str>, audio_url: Option<&str>) -> Vec { let mut items = Vec::new(); // Create share text let share_text = format!("Check out this sermon: \"{}\" by {}", title, speaker); items.push(share_text); // Add video URL if available, otherwise audio URL if let Some(url) = video_url { items.push(url.to_string()); } else if let Some(url) = audio_url { items.push(url.to_string()); } items } #[cfg(test)] mod tests { use super::*; #[test] fn test_single_line_scripture_format() { let input = "And it shall come to pass afterward, that I will pour out my spirit upon all flesh. Joel 2:28 KJV"; let result = format_scripture_text(input); assert_eq!(result.len(), 1); assert_eq!(result[0].verse, "And it shall come to pass afterward, that I will pour out my spirit upon all flesh."); assert_eq!(result[0].reference, "Joel 2:28 KJV"); } #[test] fn test_multi_line_scripture_format() { let input = "And it shall come to pass afterward, that I will pour out my spirit upon all flesh\nJoel 2:28 KJV\nQuench not the Spirit. Despise not prophesyings.\n1 Thessalonians 5:19-21 KJV"; let result = format_scripture_text(input); assert_eq!(result.len(), 2); assert_eq!(result[0].verse, "And it shall come to pass afterward, that I will pour out my spirit upon all flesh"); assert_eq!(result[0].reference, "Joel 2:28 KJV"); assert_eq!(result[1].verse, "Quench not the Spirit. Despise not prophesyings."); assert_eq!(result[1].reference, "1 Thessalonians 5:19-21 KJV"); } #[test] fn test_extract_scripture_references() { let input = "Some text with Joel 2:28 KJV and 1 Thessalonians 5:19-21 KJV references"; let result = extract_scripture_references(input); assert_eq!(result, "Joel 2:28, 1 Thessalonians 5:19-21"); } #[test] fn test_create_sermon_share_text() { let result = create_sermon_share_text( "Test Sermon", "John Doe", Some("https://example.com/video"), Some("https://example.com/audio") ); assert_eq!(result.len(), 2); assert_eq!(result[0], "Check out this sermon: \"Test Sermon\" by John Doe"); assert_eq!(result[1], "https://example.com/video"); } }