use super::VideoPipeline;

#[derive(Debug, Clone)]
pub struct PlaybackPlan {
    pub video_pipeline: VideoPipeline,
    pub audio_streams: Vec<u32>,
    pub duration_seconds: Option<f64>,
    pub segment_seconds: u8,
}

impl PlaybackPlan {
    pub fn live_dash(
        video_pipeline: VideoPipeline,
        audio_streams: Vec<u32>,
        duration_seconds: Option<f64>,
    ) -> Self {
        Self {
            video_pipeline,
            audio_streams,
            duration_seconds,
            segment_seconds: 2,
        }
    }

    pub fn audio_count(&self) -> usize {
        self.audio_streams.len()
    }

    pub fn ffmpeg_output_args(&self) -> Vec<String> {
        let mut args = vec!["-map".into(), "0:v:0".into()];
        args.extend(self.video_pipeline.ffmpeg_args(self.segment_seconds));
        for stream in &self.audio_streams {
            args.extend(["-map".into(), format!("0:{stream}")]);
        }
        if !self.audio_streams.is_empty() {
            args.extend([
                "-c:a".into(),
                "aac".into(),
                "-profile:a".into(),
                "aac_low".into(),
                "-b:a".into(),
                "192k".into(),
                "-ac".into(),
                "2".into(),
            ]);
        }
        let mut adaptation_sets = vec!["id=0,streams=0".to_owned()];
        adaptation_sets.extend(
            (1..=self.audio_streams.len()).map(|output| format!("id={output},streams={output}")),
        );
        args.extend([
            "-sn".into(),
            "-f".into(),
            "dash".into(),
            "-seg_duration".into(),
            self.segment_seconds.to_string(),
            "-update_period".into(),
            "1".into(),
            "-use_template".into(),
            "1".into(),
            "-use_timeline".into(),
            "1".into(),
            "-window_size".into(),
            "0".into(),
            "-extra_window_size".into(),
            "0".into(),
            "-adaptation_sets".into(),
            adaptation_sets.join(" "),
            "manifest.mpd".into(),
        ]);
        args
    }
}

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

    #[test]
    fn live_profile_copies_video_and_encodes_audio_to_aac() {
        let args = PlaybackPlan::live_dash(VideoPipeline::Copy, vec![1, 3], Some(120.0))
            .ffmpeg_output_args();
        assert!(args.windows(2).any(|pair| pair == ["-c:v", "copy"]));
        assert!(args.windows(2).any(|pair| pair == ["-c:a", "aac"]));
        assert!(args.windows(2).any(|pair| pair == ["-ac", "2"]));
        assert!(args.windows(2).any(|pair| pair == ["-map", "0:1"]));
        assert!(args.windows(2).any(|pair| pair == ["-map", "0:3"]));
        assert!(args.windows(2).any(|pair| {
            pair == [
                "-adaptation_sets",
                "id=0,streams=0 id=1,streams=1 id=2,streams=2",
            ]
        }));
    }
}
