use std::process::{Command, Output, Stdio};
use std::str::from_utf8;

use super::prelude::*;

const FIRST_LOAD_PREFIX: &str = "[download] Destination:";
const RELOAD_SUFFIX: &str = " has already been downloaded";
const PREFIX: &str = "[download] ";

fn convert_output(out: &Output) -> Result<Vec<String>, String> {
    match from_utf8(out.stdout.as_slice()) {
        Ok(string) => {
            let lines = string.split("\n");

            let mut files = Vec::new();

            for line in lines {
                if !line.is_empty() {
                    let mut line = line.to_string();
                    let line_len = line.len();

                    if line.starts_with(FIRST_LOAD_PREFIX) {
                        let file_name = line.split_off(FIRST_LOAD_PREFIX.len());
                        files.push(file_name.trim().to_string());
                    } else if line.ends_with(RELOAD_SUFFIX) {
                        line.split_off(line_len - RELOAD_SUFFIX.len());
                        let file_name = line.split_off(PREFIX.len());
                        files.push(file_name.trim().to_string());
                    }
                }
            }

            let mut mp3s = Vec::new();

            for file in files {
                mp3s.push(str::replace(file.as_str(), ".webm", ".mp3").to_string());
            }

            Ok(mp3s)
        }

        Err(_) => Err("error converting output".to_string()),
    }
}

pub fn youtube_dl(uri: &str) -> Result<Vec<Song>, String> {
    let args = ["-f", "bestaudio/best", "-o", "%(title)s", uri];

    let out = match Command::new("youtube-dl")
        .args(&args)
        .stdin(Stdio::null())
        .output()
    {
        Ok(out) => out,
        Err(why) => return Err(format!("youtube-dl error {:?}", why)),
    };

    if !out.status.success() {
        let stdout = match String::from_utf8(out.stdout) {
            Ok(string) => string,
            Err(_) => String::new(),
        };

        let stderr = match String::from_utf8(out.stderr) {
            Ok(string) => string,
            Err(_) => String::new(),
        };

        return Err(format!(
            "Shell error\nstdout: {}\nstderr: {}",
            stdout, stderr
        ));
    }

    let files = convert_output(&out)?;

    for file in &files {
        println!("file: {}", file);
    }

    let mut songs = Vec::new();

    for file in files {
        songs.push(Song { name: file })
    }

    Ok(songs)
}
