use anyhow::anyhow;
use std::collections::HashMap;
use std::io::Read;
use std::path::Path;
use std::process::Command;

use anyhow::Result;

use super::Previewable;

pub struct AudioPath<'a>(pub &'a Path);

const COLOR: &str = "#dc322f"; // solarized red

impl<'a> Previewable for AudioPath<'a> {
    fn get_thumbnail(&self, options: HashMap<String, String>) -> Result<Option<Vec<u8>>> {
        match options.get("type").map(|x| x.as_str()) {
            Some("json") => {
                let outfile = tempfile::Builder::new().suffix(".json").tempfile()?;

                // -i long_clip.mp3 -o long_clip.json --pixels-per-second 20 --bits 8
                let audiowaveform_cmd = Command::new("audiowaveform")
                    .args(["-i", &self.0.to_string_lossy()])
                    .args(["-o", &*outfile.path().to_string_lossy()])
                    .args(["--pixels-per-second", "20"])
                    .args(["--bits", "8"])
                    .output()?;

                if !audiowaveform_cmd.status.success() {
                    return Err(anyhow!(
                        "Failed to retrieve audiofile peaks: {:?}",
                        String::from_utf8_lossy(&audiowaveform_cmd.stderr)
                    ));
                }

                let mut buffer = Vec::new();
                outfile.as_file().read_to_end(&mut buffer)?;
                Ok(Some(buffer))
            }
            Some("image") | None => {
                let outfile = tempfile::Builder::new().suffix(".webp").tempfile()?;

                let color = options
                    .get("color")
                    .map(String::to_owned)
                    .unwrap_or_else(|| COLOR.into());
                let dimensions = options
                    .get("dimensions")
                    .map(String::to_owned)
                    .unwrap_or_else(|| "860x256".into());

                let thumbnail_cmd = Command::new("ffmpeg")
                    .args(["-i", &self.0.to_string_lossy()])
                    .args([
                        "-filter_complex",
                        &format!(
                            "[0:a]aformat=channel_layouts=mono, compand=gain=-2,
                             showwavespic=s={dimensions}:colors={color},
                             drawbox=x=(iw-w)/2:y=(ih-h)/2:w=iw:h=1:color={color}"
                        ),
                    ])
                    .args(["-vframes", "1"])
                    .arg(&*outfile.path().to_string_lossy())
                    .arg("-y")
                    .output()?;

                if !thumbnail_cmd.status.success() {
                    return Err(anyhow!(
                        "Failed to render thumbnail: {:?}",
                        String::from_utf8_lossy(&thumbnail_cmd.stderr)
                    ));
                }

                let mut buffer = Vec::new();
                outfile.as_file().read_to_end(&mut buffer)?;
                Ok(Some(buffer))
            }
            Some(_) => Err(anyhow!("type has to be one of: image, json")),
        }
    }
}
