use crate::AppResult;
use anyhow::anyhow;
use config::{Config, File, Source};
use std::path::Path;

pub fn read_config_default<'de, T: serde::Deserialize<'de>>(cfg_file: &str) -> AppResult<T> {
    let (cfg, def) = read_config_with_required(cfg_file, false, &[])?;
    if def {
        log::warn!(
            "The configuration for  '{cfg_file}' does not exist, default values will be used!"
        );
    }
    Ok(cfg)
}

pub fn read_config_with<'de, T: serde::Deserialize<'de>>(
    cfg_file: &str,
    env_list_keys: &[&str],
) -> AppResult<T> {
    let (cfg, _) = read_config_with_required(cfg_file, true, env_list_keys)?;
    Ok(cfg)
}

pub fn read_config_default_with<'de, T: serde::Deserialize<'de>>(
    cfg_file: &str,
    env_list_keys: &[&str],
) -> AppResult<T> {
    let (cfg, def) = read_config_with_required(cfg_file, false, env_list_keys)?;
    if def {
        log::warn!(
            "The configuration for  '{cfg_file}' does not exist, default values will be used!"
        );
    }
    Ok(cfg)
}

pub fn read_config_with_required<'de, T: serde::Deserialize<'de>>(
    cfg_file: &str,
    required: bool,
    env_list_keys: &[&str],
) -> AppResult<(T, bool)> {
    let path = Path::new(cfg_file);
    if !path.is_file() {
        return Err(anyhow!(format!("not found: {cfg_file}")));
    }
    let builder = Config::builder().add_source(File::from(path).required(required));
    let mut env = config::Environment::with_prefix(&format!("gateway_"));
    if !env_list_keys.is_empty() {
        env = env.try_parsing(true).list_separator(" ");
        for key in env_list_keys {
            env = env.with_list_parse_key(key);
        }
    }

    let builder = builder.add_source(env);
    let s = builder.build()?;
    let count = s.collect()?.len();
    Ok((s.try_deserialize::<T>()?, count == 0))
}
