use crate::structs::*;
use crate::utils::*;
use anyhow::Result;

use std::fs::File;
use std::io::{self, BufReader, Read, Write};
use std::process::Command;

use regex::Regex;
use rss::Channel;
use std::path::PathBuf;

fn launch_player(url: &str) -> Result<()> {
    if launch_mpv(url).is_err() {
        return launch_vlc(url);
    }
    Ok(())
}

fn launch_mpv(url: &str) -> Result<()> {
    if let Err(err) = Command::new("mpv")
        .args(&["--no-audio-display", "--ytdl=no", url])
        .status()
    {
        let stderr = io::stderr();
        let mut handle = stderr.lock();
        match err.kind() {
            io::ErrorKind::NotFound => {
                writeln!(&mut handle, "Couldn't open mpv\nTrying vlc...").ok()
            }
            _ => writeln!(&mut handle, "Error: {}", err).ok(),
        };
    }
    Ok(())
}

fn launch_vlc(url: &str) -> Result<()> {
    if let Err(err) = Command::new("vlc").args(&["-I ncurses", url]).status() {
        let stderr = io::stderr();
        let mut handle = stderr.lock();
        match err.kind() {
            io::ErrorKind::NotFound => writeln!(&mut handle, "Couldn't open vlc...aborting").ok(),
            _ => writeln!(&mut handle, "Error: {}", err).ok(),
        };
    }
    Ok(())
}

pub fn play_latest(state: &State, p_search: &str) -> Result<()> {
    let re_pod: Regex = Regex::new(&format!("(?i){}", &p_search))?;
    let mut path: PathBuf = get_xml_dir()?;
    for subscription in &state.subscriptions {
        if re_pod.is_match(&subscription.title) {
            let mut filename: String = subscription.title.clone();
            filename.push_str(".xml");
            path.push(filename);

            let file: File = File::open(&path)?;
            let podcast: Podcast = Podcast::from(Channel::read_from(BufReader::new(file))?);
            let episodes = podcast.episodes();
            let episode = episodes[0].clone();

            filename = episode.title().unwrap();
            filename.push_str(&episode.extension().unwrap());
            path = get_podcast_dir()?;
            path.push(podcast.title());
            path.push(filename);
            if path.exists() {
                launch_player(path.to_str().unwrap())?;
            } else {
                launch_player(episode.url().unwrap())?;
            }
            return Ok(());
        }
    }
    Ok(())
}

pub fn play_episode_by_num(state: &State, p_search: &str, ep_num_string: &str) -> Result<()> {
    let re_pod: Regex = Regex::new(&format!("(?i){}", &p_search))?;
    if let Ok(ep_num) = ep_num_string.parse::<usize>() {
        let mut path: PathBuf = get_xml_dir()?;
        for subscription in &state.subscriptions {
            if re_pod.is_match(&subscription.title) {
                let mut filename: String = subscription.title.clone();
                filename.push_str(".xml");
                path.push(filename);

                let file: File = File::open(&path).unwrap();
                let podcast = Podcast::from(Channel::read_from(BufReader::new(file)).unwrap());
                let episodes = podcast.episodes();
                let episode = episodes[episodes.len() - ep_num].clone();

                filename = episode.title().unwrap();
                filename.push_str(&episode.extension().unwrap());
                path = get_podcast_dir()?;
                path.push(podcast.title());
                path.push(filename);
                if path.exists() {
                    launch_player(path.to_str().unwrap())?;
                } else {
                    launch_player(episode.url().unwrap())?;
                }
                return Ok(());
            }
        }
    } else {
        {
            let stderr = io::stderr();
            let mut handle = stderr.lock();
            writeln!(&mut handle, "Failed to parse episode index number...").ok();
            writeln!(&mut handle, "Attempting to find episode by name...").ok();
        }
        play_episode_by_name(state, p_search, ep_num_string)?;
    }
    Ok(())
}

pub fn play_episode_by_name(state: &State, p_search: &str, ep_string: &str) -> Result<()> {
    let re_pod: Regex = Regex::new(&format!("(?i){}", &p_search))?;
    let mut path: PathBuf = get_xml_dir()?;
    for subscription in &state.subscriptions {
        if re_pod.is_match(&subscription.title) {
            let mut filename: String = subscription.title.clone();
            filename.push_str(".xml");
            path.push(filename);

            let mut file: File = File::open(&path).unwrap();
            let mut content: Vec<u8> = Vec::new();
            file.read_to_end(&mut content).unwrap();

            let podcast = Podcast::from(Channel::read_from(content.as_slice()).unwrap());
            let episodes = podcast.episodes();
            let filtered_episodes: Vec<&Episode> = episodes
                .iter()
                .filter(|ep| {
                    ep.title()
                        .unwrap_or_else(|| "".to_string())
                        .to_lowercase()
                        .contains(&ep_string.to_lowercase())
                })
                .collect();
            if let Some(episode) = filtered_episodes.first() {
                filename = episode.title().unwrap();
                filename.push_str(&episode.extension().unwrap());
                path = get_podcast_dir()?;
                path.push(podcast.title());
                path.push(filename);
                if path.exists() {
                    launch_player(path.to_str().unwrap())?;
                } else {
                    launch_player(episode.url().unwrap())?;
                }
            }
            return Ok(());
        }
    }
    Ok(())
}