use super::config::AccountConfig;
use super::feedly_secrets::FeedlySecrets;
use super::{Feedly, FeedlyApi};
use crate::feed_api::{ApiMetadata, FeedApi, FeedApiErrorKind, FeedApiResult, Portal};
use crate::models::{LoginGUI, OAuthLoginGUI, PluginID, PluginIcon, PluginInfo, ServiceLicense, ServicePrice, ServiceType, Url, VectorIcon};
use failure::{Fail, ResultExt};
use feedly_api::{ApiError as FeedlyApiError, ApiErrorKind as FeedlyApiErrorKind};
use parking_lot::RwLock;
use rust_embed::RustEmbed;
use std::path::PathBuf;
use std::str;
use std::sync::Arc;

#[derive(RustEmbed)]
#[folder = "src/feed_api_implementations/feedly/icons"]
struct FeedlyResources;

pub struct FeedlyMetadata;

impl FeedlyMetadata {
    pub fn get_id() -> PluginID {
        PluginID::new("feedly")
    }
}

impl ApiMetadata for FeedlyMetadata {
    fn id(&self) -> PluginID {
        Self::get_id()
    }

    fn info(&self) -> FeedApiResult<PluginInfo> {
        let icon_data = FeedlyResources::get("feed-service-feedly.svg").ok_or(FeedApiErrorKind::Resource)?;
        let icon = VectorIcon {
            data: icon_data.to_vec(),
            width: 48,
            height: 48,
        };
        let icon = PluginIcon::Vector(icon);

        let symbolic_icon_data = FeedlyResources::get("feed-service-feedly-symbolic.svg").ok_or(FeedApiErrorKind::Resource)?;
        let symbolic_icon = VectorIcon {
            data: symbolic_icon_data.to_vec(),
            width: 48,
            height: 48,
        };
        let symbolic_icon = PluginIcon::Vector(symbolic_icon);

        let secrets = FeedlySecrets::new();
        let login_url = FeedlyApi::login_url(&secrets.client_id, &secrets.client_secret).context(FeedApiErrorKind::Api)?;
        let redirect_url = FeedlyApi::redirect_uri().context(FeedApiErrorKind::Api)?;

        let login_gui = LoginGUI::OAuth(OAuthLoginGUI {
            login_website: Some(login_url),
            catch_redirect: Some(String::from(redirect_url.as_str())),
        });

        Ok(PluginInfo {
            id: self.id(),
            name: String::from("feedly"),
            icon: Some(icon),
            icon_symbolic: Some(symbolic_icon),
            website: match Url::parse("http://feedly.com/") {
                Ok(website) => Some(website),
                Err(_) => None,
            },
            service_type: ServiceType::Remote { self_hosted: false },
            license_type: ServiceLicense::GenericProprietary,
            service_price: ServicePrice::PaidPremimum,
            login_gui,
        })
    }

    fn parse_error(&self, error: &dyn Fail) -> Option<String> {
        if let Some(error) = Fail::downcast_ref::<FeedlyApiError>(error) {
            if let FeedlyApiErrorKind::Feedly(error) = error.kind() {
                return Some(error.error_message);
            }

            return Some(format!("{}", error));
        }
        None
    }

    fn get_instance(&self, path: &PathBuf, portal: Box<dyn Portal>) -> FeedApiResult<Box<dyn FeedApi>> {
        let account_config = AccountConfig::load(path).context(FeedApiErrorKind::Config)?;
        let secret_struct = FeedlySecrets::new();

        let mut api: Option<FeedlyApi> = None;
        let mut logged_in: bool = false;
        if let Some(access_token) = account_config.get_access_token() {
            if let Some(refresh_token) = account_config.get_refresh_token() {
                if let Some(token_expires) = account_config.get_token_expires() {
                    let token_expires = FeedlyApi::parse_expiration_date(&token_expires).context(FeedApiErrorKind::Config)?;
                    api = Some(
                        FeedlyApi::new(
                            secret_struct.client_id.clone(),
                            secret_struct.client_secret.clone(),
                            access_token.clone(),
                            refresh_token.clone(),
                            token_expires,
                        )
                        .context(FeedApiErrorKind::Api)?,
                    );

                    // FIXME: find more accurate way of figuring out if login is still valid
                    logged_in = true;
                }
            }
        }

        let feedly = Feedly {
            api,
            portal,
            logged_in,
            config: Arc::new(RwLock::new(account_config)),
        };
        let feedly = Box::new(feedly);

        Ok(feedly)
    }
}
