use chrono::NaiveDate;
use regex::Regex;

#[derive(Debug, Clone)]
pub struct ParsedMediaTitle {
    pub title: String,
    pub speaker: Option<String>,
    pub date: Option<NaiveDate>,
}

/// Parse media titles in the format: "Title - Speaker | Date" or similar variations
pub fn parse_media_title(input: &str) -> ParsedMediaTitle {
    // Remove common file extensions first
    let cleaned_input = input.trim()
        .trim_end_matches(".mp4")
        .trim_end_matches(".mkv")
        .trim_end_matches(".avi")
        .trim_end_matches(".mov")
        .trim_end_matches(".webm")
        .trim_end_matches(".mp3")
        .trim_end_matches(".m4a")
        .trim_end_matches(".flac")
        .trim_end_matches(".wav")
        .trim_end_matches(".ogg");
    
    // Try parsing with pipe separator first: "Title - Speaker | Date"
    if let Some((left_part, date_part)) = split_on_separator(cleaned_input, '|') {
        let date = parse_date(&date_part);
        
        // Now split the left part on " - " for title and speaker
        if let Some((title_part, speaker_part)) = split_on_separator(&left_part, '-') {
            return ParsedMediaTitle {
                title: title_part.trim().to_string(),
                speaker: if speaker_part.trim().is_empty() { 
                    None 
                } else { 
                    Some(speaker_part.trim().to_string()) 
                },
                date,
            };
        } else {
            // No speaker separator found, just title and date
            return ParsedMediaTitle {
                title: left_part.trim().to_string(),
                speaker: None,
                date,
            };
        }
    }
    
    // Try without pipe separator: "Title - Speaker Date"
    if let Some((title_part, rest)) = split_on_separator(cleaned_input, '-') {
        let rest = rest.trim();
        
        // Try to extract date from the end
        if let Some(extracted_date) = extract_date_from_end(rest) {
            let speaker_part = rest.trim_end_matches(&extracted_date.original_text).trim();
            
            return ParsedMediaTitle {
                title: title_part.trim().to_string(),
                speaker: if speaker_part.is_empty() { 
                    None 
                } else { 
                    Some(speaker_part.to_string()) 
                },
                date: extracted_date.date,
            };
        } else {
            // No date found, treat everything after dash as speaker
            return ParsedMediaTitle {
                title: title_part.trim().to_string(),
                speaker: if rest.is_empty() { 
                    None 
                } else { 
                    Some(rest.to_string()) 
                },
                date: None,
            };
        }
    }
    
    // No separators found, try to extract date from the end of the entire string
    if let Some(extracted_date) = extract_date_from_end(cleaned_input) {
        let title_part = cleaned_input.trim_end_matches(&extracted_date.original_text).trim();
        return ParsedMediaTitle {
            title: title_part.to_string(),
            speaker: None,
            date: extracted_date.date,
        };
    }
    
    // Fallback: treat entire string as title
    ParsedMediaTitle {
        title: cleaned_input.to_string(),
        speaker: None,
        date: None,
    }
}

fn split_on_separator(input: &str, separator: char) -> Option<(String, String)> {
    let separator_str = if separator == '-' { " - " } else { &format!(" {} ", separator) };
    
    if let Some(pos) = input.find(separator_str) {
        let left = input[..pos].trim().to_string();
        let right = input[pos + separator_str.len()..].trim().to_string();
        Some((left, right))
    } else {
        None
    }
}

struct ExtractedDate {
    date: Option<NaiveDate>,
    original_text: String,
}

fn extract_date_from_end(input: &str) -> Option<ExtractedDate> {
    // Common date patterns at the end of strings
    let patterns = [
        // "July 12 2025", "January 1 2024", etc.
        r"(?i)\b(January|February|March|April|May|June|July|August|September|October|November|December)\s+(\d{1,2})\s+(\d{4})\s*$",
        // "Jul 12 2025", "Jan 1 2024", etc.
        r"(?i)\b(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s+(\d{1,2})\s+(\d{4})\s*$",
        // "12-07-2025", "1-1-2024", etc.
        r"\b(\d{1,2})-(\d{1,2})-(\d{4})\s*$",
        // "2025-07-12", "2024-01-01", etc.
        r"\b(\d{4})-(\d{1,2})-(\d{1,2})\s*$",
        // "12/07/2025", "1/1/2024", etc.
        r"\b(\d{1,2})/(\d{1,2})/(\d{4})\s*$",
    ];
    
    for pattern in &patterns {
        let regex = Regex::new(pattern).unwrap();
        if let Some(captures) = regex.captures(input) {
            let full_match = captures.get(0).unwrap().as_str();
            let date = parse_date_from_captures(&captures);
            return Some(ExtractedDate {
                date,
                original_text: full_match.to_string(),
            });
        }
    }
    
    None
}

fn parse_date_from_captures(captures: &regex::Captures) -> Option<NaiveDate> {
    let full = captures.get(0)?.as_str();
    
    // Try multiple date formats
    let formats = [
        "%B %d %Y",    // "July 12 2025"
        "%b %d %Y",    // "Jul 12 2025"
        "%m-%d-%Y",    // "7-12-2025"
        "%Y-%m-%d",    // "2025-07-12"
        "%m/%d/%Y",    // "7/12/2025"
    ];
    
    for format in &formats {
        if let Ok(date) = NaiveDate::parse_from_str(full.trim(), format) {
            return Some(date);
        }
    }
    
    None
}

fn parse_date(date_str: &str) -> Option<NaiveDate> {
    let trimmed = date_str.trim();
    
    // Try multiple date formats
    let formats = [
        "%B %d %Y",    // "July 12 2025"
        "%b %d %Y",    // "Jul 12 2025"
        "%B %d, %Y",   // "July 12, 2025"
        "%b %d, %Y",   // "Jul 12, 2025"
        "%m-%d-%Y",    // "7-12-2025"
        "%d-%m-%Y",    // "12-7-2025"
        "%Y-%m-%d",    // "2025-07-12"
        "%m/%d/%Y",    // "7/12/2025"
        "%d/%m/%Y",    // "12/7/2025"
    ];
    
    for format in &formats {
        if let Ok(date) = NaiveDate::parse_from_str(trimmed, format) {
            return Some(date);
        }
    }
    
    None
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::NaiveDate;
    
    #[test]
    fn test_parse_full_format() {
        let result = parse_media_title("To Put On Christ - Pastor Joseph Piresson | July 12 2025");
        assert_eq!(result.title, "To Put On Christ");
        assert_eq!(result.speaker, Some("Pastor Joseph Piresson".to_string()));
        assert_eq!(result.date, Some(NaiveDate::from_ymd_opt(2025, 7, 12).unwrap()));
    }
    
    #[test]
    fn test_parse_no_pipe() {
        let result = parse_media_title("Sermon Title - John Doe January 15 2024");
        assert_eq!(result.title, "Sermon Title");
        assert_eq!(result.speaker, Some("John Doe".to_string()));
        assert_eq!(result.date, Some(NaiveDate::from_ymd_opt(2024, 1, 15).unwrap()));
    }
    
    #[test]
    fn test_parse_only_title() {
        let result = parse_media_title("Simple Title");
        assert_eq!(result.title, "Simple Title");
        assert_eq!(result.speaker, None);
        assert_eq!(result.date, None);
    }
    
    #[test]
    fn test_parse_with_extension() {
        let result = parse_media_title("My Sermon - Jane Smith | Dec 25 2023.mp4");
        assert_eq!(result.title, "My Sermon");
        assert_eq!(result.speaker, Some("Jane Smith".to_string()));
        assert_eq!(result.date, Some(NaiveDate::from_ymd_opt(2023, 12, 25).unwrap()));
    }
    
    #[test]
    fn test_parse_alternative_separators() {
        // Test without pipe (space-separated date) - more DaVinci Resolve friendly
        let result1 = parse_media_title("God's Love - Pastor Mary Smith January 20 2024");
        assert_eq!(result1.title, "God's Love");
        assert_eq!(result1.speaker, Some("Pastor Mary Smith".to_string()));
        assert_eq!(result1.date, Some(NaiveDate::from_ymd_opt(2024, 1, 20).unwrap()));
        
        // Test with different formatting
        let result2 = parse_media_title("Salvation Message - Elder Johnson December 15 2023");
        assert_eq!(result2.title, "Salvation Message");
        assert_eq!(result2.speaker, Some("Elder Johnson".to_string()));
        assert_eq!(result2.date, Some(NaiveDate::from_ymd_opt(2023, 12, 15).unwrap()));
    }
}