#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VideoPipeline {
    Copy,
    Encode(VideoEncoder),
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VideoEncoder {
    Libx264,
}

impl VideoPipeline {
    pub fn ffmpeg_args(self, segment_seconds: u8) -> Vec<String> {
        match self {
            Self::Copy => vec!["-c:v".into(), "copy".into()],
            Self::Encode(encoder) => encoder.ffmpeg_args(segment_seconds),
        }
    }
}

impl VideoEncoder {
    pub fn portable_software() -> Self {
        Self::Libx264
    }

    fn ffmpeg_args(self, segment_seconds: u8) -> Vec<String> {
        match self {
            Self::Libx264 => vec![
                "-c:v".into(),
                "libx264".into(),
                "-preset".into(),
                "veryfast".into(),
                "-crf".into(),
                "20".into(),
                "-vf".into(),
                "scale=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p".into(),
                "-force_key_frames".into(),
                format!("expr:gte(t,n_forced*{segment_seconds})"),
                "-sc_threshold".into(),
                "0".into(),
            ],
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{VideoEncoder, VideoPipeline};

    #[test]
    fn libx264_profile_is_browser_compatible_and_segment_aligned() {
        let args = VideoPipeline::Encode(VideoEncoder::Libx264).ffmpeg_args(2);
        assert!(args.windows(2).any(|pair| pair == ["-c:v", "libx264"]));
        assert!(args.windows(2).any(|pair| pair == ["-crf", "20"]));
        assert!(
            args.windows(2)
                .any(|pair| { pair == ["-force_key_frames", "expr:gte(t,n_forced*2)"] })
        );
        assert!(args.iter().any(|arg| arg.contains("format=yuv420p")));
    }
}
