use std::fs;
use async_trait::async_trait;
use error_chain::error_chain;
use futures::future::join_all;
use crate::api::{get_provider, ClientVersion};
use crate::providers::{DynProvider, Provider};
use crate::status::Channel;
use crate::util::cache::VideoCache;
use crate::util::interleave;
use crate::videos::{ServerOptions, VideoItem};
use crate::DbPool;

error_chain! {
    foreign_links {
        Io(std::io::Error);
        HttpRequest(wreq::Error);
    }
}


#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct AllProvider {
}

impl AllProvider {
    pub fn new() -> Self {
        AllProvider {}
    }
}

#[async_trait]
impl Provider for AllProvider {
    async fn get_videos(
        &self,
        cache: VideoCache,
        pool: DbPool,
        sort: String,
        query: Option<String>,
        page: String,
        per_page: String,
        options: ServerOptions,
    ) -> Vec<VideoItem> {
        let mut sites_str = options.clone().sites.unwrap();
        if sites_str.is_empty() {
            let files = fs::read_dir("./src/providers").unwrap();
            let providers = files.map(|entry| entry.unwrap().file_name())
                .filter(|name| name.to_str().unwrap().ends_with(".rs"))
                .filter(|name| !name.to_str().unwrap().contains("mod.rs") && !name.to_str().unwrap().contains("all.rs"))
                .map(|name| name.to_str().unwrap().replace(".rs", ""))
                .collect::<Vec<String>>();
            sites_str = providers.join(",");
        }
        let providers: Vec<DynProvider> = sites_str
            .split(',')
            .filter(|s| !s.is_empty())
            .filter_map(|s| get_provider(s)) // assumes get_provider -> Option<DynProvider>
            .collect();
       
        let futures = providers.iter().map(|provider| {
            provider.get_videos(
                cache.clone(),
                pool.clone(),
                sort.clone(),
                query.clone(),
                page.clone(),
                per_page.clone(),
                options.clone()
            )
        }).collect::<Vec<_>>();
        let results:Vec<Vec<VideoItem>> = join_all(futures).await;
        let video_items: Vec<VideoItem> = interleave(&results);
        

        return video_items;
    }
    
    fn get_channel(&self,clientversion:ClientVersion) -> Channel {
        println!("Getting channel for placeholder with client version: {:?}",clientversion);
        let _ = clientversion;
        Channel {
            id:"placeholder".to_string(),name:"PLACEHOLDER".to_string(),description:"PLACEHOLDER FOR PARENT CLASS".to_string(),premium:false,favicon:"https://www.google.com/s2/favicons?sz=64&domain=missav.ws".to_string(),status:"active".to_string(),categories:vec![],options:vec![],nsfw:true,cacheDuration:None,
        }
    }
}
