use crate::feed_api::{FeedApiErrorKind, FeedApiResult};
use failure::ResultExt;
use serde_derive::{Deserialize, Serialize};
use std::fs::{self, File};
use std::io::Read;
use std::path::PathBuf;

static CONFIG_NAME: &'static str = "feedly.json";

#[derive(Debug, Serialize, Deserialize)]
pub struct AccountConfig {
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    access_token: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    refresh_token: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    user_name: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(default)]
    token_expires: Option<String>,
    #[serde(skip_serializing)]
    #[serde(skip_deserializing)]
    path: PathBuf,
}

impl AccountConfig {
    pub fn load(path: &PathBuf) -> FeedApiResult<Self> {
        let path = path.join(CONFIG_NAME);
        if path.as_path().exists() {
            let mut contents = String::new();
            let mut config = File::open(&path).context(FeedApiErrorKind::IO)?;
            config.read_to_string(&mut contents).context(FeedApiErrorKind::IO)?;
            let mut config: AccountConfig = serde_json::from_str(&contents).context(FeedApiErrorKind::Config)?;
            config.path = path.clone();
            return Ok(config);
        }

        Ok(AccountConfig {
            access_token: None,
            refresh_token: None,
            user_name: None,
            token_expires: None,
            path: path.clone(),
        })
    }

    pub fn write(&self) -> FeedApiResult<()> {
        let data = serde_json::to_string_pretty(self).context(FeedApiErrorKind::Config)?;
        fs::write(&self.path, data).context(FeedApiErrorKind::IO)?;
        Ok(())
    }

    pub fn delete(&self) -> FeedApiResult<()> {
        fs::remove_file(&self.path).context(FeedApiErrorKind::IO)?;
        Ok(())
    }

    pub fn get_access_token(&self) -> Option<String> {
        self.access_token.clone()
    }

    pub fn set_access_token(&mut self, access_token: &str) {
        self.access_token = Some(access_token.to_owned());
    }

    pub fn get_refresh_token(&self) -> Option<String> {
        self.refresh_token.clone()
    }

    pub fn set_refresh_token(&mut self, refresh_token: &str) {
        self.refresh_token = Some(refresh_token.to_owned());
    }

    pub fn get_user_name(&self) -> Option<String> {
        self.user_name.clone()
    }

    pub fn set_user_name(&mut self, user_name: &str) {
        self.user_name = Some(user_name.to_owned());
    }

    pub fn get_token_expires(&self) -> Option<String> {
        self.token_expires.clone()
    }

    pub fn set_token_expires(&mut self, token_expires: &str) {
        self.token_expires = Some(token_expires.to_owned());
    }
}
