use std::fs::{File, read};
use std::io::BufReader;
use std::path::Path;
use serde::Deserialize;
use serde_json::{from_reader, from_str};
use lazy_static::lazy_static;
use crate::auth::token::{fetch_token, write_token};

lazy_static! {
    pub static ref CONFIG_PATH: String = {
        format!("{}/.config/nslack.json", env!("HOME"))
    };
}

#[derive(Deserialize, Default)]
#[serde(default)]
pub struct UserConfig {
    pub token: String
}

impl UserConfig {
    pub fn new() -> Self {
        let config_file = match read(&*CONFIG_PATH) {
            Ok(file) => String::from_utf8_lossy(&file).to_string(),
            // Theoretically this should never match an error since
            // the existence of this file is handled at the start
            // of the program.
            Err(_) => panic!("User config file not found")
        };

        from_str(config_file.as_str()).unwrap()
    }
}

#[derive(Deserialize, Default, Clone)]
#[serde(default)]
pub struct ApiConfig {
    pub uri: String,
    pub redirect_uri: String,
    pub client_id: String,
    pub client_secret: String,
    pub scopes: Vec<String>
}

impl ApiConfig {
    pub fn new() -> Self {
        let file = File::open("./assets/config.json").unwrap();
        let reader = BufReader::new(file);

        from_reader(reader).unwrap()
    }
}

#[derive(Deserialize, Default)]
#[serde(default)]
pub struct Config {
    pub user: UserConfig,
    pub api: ApiConfig
}

impl Config {
    pub fn new() -> Self {
        let api_config = ApiConfig::new();
        let user_config = UserConfig::new();

        Self {
            api: api_config,
            user: user_config
        }
    }
}

pub async fn load_config() -> Config {
    let config_exists = Path::new(&*CONFIG_PATH).is_file();

    if !config_exists {
        write_token(fetch_token().await);
    }

    Config::new()
}
