use std::time::Duration;
use regex::Regex;
use lazy_static::lazy_static;

lazy_static! {
    // Regex pour parser la ligne de progression FFmpeg
    // frame=  123 fps=0.0 q=-1.0 size=    1024kB time=00:00:05.12 bitrate=1638.4kbits/s speed=10.2x
    static ref PROGRESS_REGEX: Regex = Regex::new(
        r"frame=\s*(\d+)\s+fps=\s*([\d.]+)\s+q=\s*([-]?[\d.]+)\s+size=\s*(\w+)\s+time=\s*(\d{2}:\d{2}:\d{2}\.\d{2})\s+bitrate=\s*([\d.]+\w+/s)\s+speed=\s*([\d.]+)x"
    ).unwrap();
    
    // Regex alternatif pour le temps seul (cas audio simple)
    // size=    1024kB time=00:00:05.12 bitrate=1638.4kbits/s speed=10.2x
    static ref TIME_REGEX: Regex = Regex::new(r"time=\s*(\d{2}:\d{2}:\d{2}\.\d{2})").unwrap();
}

#[derive(Debug, Clone, Default)]
pub struct FfmpegProgress {
    pub frame: Option<u64>,
    pub fps: Option<f32>,
    pub time: Option<Duration>,
    pub bitrate: Option<String>,
    pub speed: Option<f32>,
}

impl FfmpegProgress {
    pub fn parse(line: &str) -> Option<Self> {
        if let Some(caps) = PROGRESS_REGEX.captures(line) {
            return Some(Self {
                frame: caps.get(1).and_then(|m| m.as_str().parse().ok()),
                fps: caps.get(2).and_then(|m| m.as_str().parse().ok()),
                time: caps.get(5).and_then(|m| parse_duration(m.as_str())),
                bitrate: caps.get(6).map(|m| m.as_str().to_string()),
                speed: caps.get(7).and_then(|m| m.as_str().parse().ok()),
            });
        }
        
        // Fallback pour audio-only (pas de frame/fps parfois)
        if let Some(caps) = TIME_REGEX.captures(line) {
            return Some(Self {
                frame: None,
                fps: None,
                time: caps.get(1).and_then(|m| parse_duration(m.as_str())),
                bitrate: None, // On pourrait parser plus mais time est le plus important
                speed: None,
            });
        }

        None
    }
}

fn parse_duration(time_str: &str) -> Option<Duration> {
    // Format: HH:MM:SS.mm
    let parts: Vec<&str> = time_str.split(':').collect();
    if parts.len() != 3 {
        return None;
    }

    let hours: u64 = parts[0].parse().ok()?;
    let minutes: u64 = parts[1].parse().ok()?;
    let seconds_parts: Vec<&str> = parts[2].split('.').collect();
    let seconds: u64 = seconds_parts[0].parse().ok()?;
    let centis: u64 = if seconds_parts.len() > 1 {
        let s = seconds_parts[1];
        let mut s = s.to_string();
        while s.len() < 3 { s.push('0'); } // Normalize to ms
        s[..3].parse().ok()?
    } else {
        0
    };

    Some(Duration::from_millis(
        hours * 3600 * 1000 + minutes * 60 * 1000 + seconds * 1000 + centis
    ))
}

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

    #[test]
    fn test_parse_progress_full() {
        let line = "frame=  123 fps=0.0 q=-1.0 size=    1024kB time=00:00:05.12 bitrate=1638.4kbits/s speed=10.2x";
        let progress = FfmpegProgress::parse(line).unwrap();
        
        assert_eq!(progress.frame, Some(123));
        assert_eq!(progress.time, Some(Duration::from_millis(5120)));
        assert_eq!(progress.speed, Some(10.2));
    }

    #[test]
    fn test_parse_progress_audio() {
        let line = "size=    1024kB time=00:01:05.50 bitrate=128.0kbits/s speed=50.0x";
        let progress = FfmpegProgress::parse(line).unwrap();
        
        assert_eq!(progress.time, Some(Duration::from_secs(65) + Duration::from_millis(500)));
    }
}
