use super::config::AccountConfig;
use super::{Miniflux, MinifluxApi};
use crate::feed_api::{ApiMetadata, FeedApi, FeedApiErrorKind, FeedApiResult, Portal};
use crate::models::{LoginGUI, PasswordLoginGUI, PluginID, PluginIcon, PluginInfo, ServiceLicense, ServicePrice, ServiceType, Url, VectorIcon};
use failure::{Fail, ResultExt};
use miniflux_api::{ApiError as MinifluxError, ApiErrorKind as MinifluxErrorKind};
use rust_embed::RustEmbed;
use std::path::PathBuf;
use std::str;

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

pub struct MinifluxMetadata;

impl MinifluxMetadata {
    pub fn get_id() -> PluginID {
        PluginID::new("miniflux")
    }
}

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

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

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

        let login_gui = LoginGUI::Password(PasswordLoginGUI { url: true, http_auth: false });

        Ok(PluginInfo {
            id: self.id(),
            name: String::from("Miniflux"),
            icon: Some(icon),
            icon_symbolic: Some(symbolic_icon),
            website: match Url::parse("https://miniflux.app/") {
                Ok(website) => Some(website),
                Err(_) => None,
            },
            service_type: ServiceType::Remote { self_hosted: true },
            license_type: ServiceLicense::ApacheV2,
            service_price: ServicePrice::Free,
            login_gui,
        })
    }

    fn parse_error(&self, error: &dyn Fail) -> Option<String> {
        if let Some(error) = Fail::downcast_ref::<MinifluxError>(error) {
            if let MinifluxErrorKind::Miniflux(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 mut api: Option<MinifluxApi> = None;

        if let Some(url) = account_config.get_url() {
            if let Ok(url) = Url::parse(&url) {
                if let Some(username) = account_config.get_user_name() {
                    if let Some(password) = account_config.get_password() {
                        api = Some(MinifluxApi::new(&url.get(), username.clone(), password.clone()));
                    }
                }
            }
        }

        let logged_in = api.is_some();

        let miniflux = Miniflux {
            api,
            portal,
            logged_in,
            config: account_config,
        };
        let miniflux = Box::new(miniflux);
        Ok(miniflux)
    }
}
