use rand::distr::Alphanumeric;
use rand::{rng, Rng};
use serde::{Deserialize, Serialize};
use std::{
    path::{Path, PathBuf},
    str::FromStr,
    sync::Mutex,
};
use tauri::Manager;
#[derive(Default, Serialize, Deserialize, Debug, Clone)]
pub struct Config {
    pub core_cfg: CoreCFG,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CoreCFG {
    pub home_path: Option<PathBuf>,
    #[serde(skip_serializing)]
    pub current_file: Option<PathBuf>,
    pub client_id: String,
}
impl Default for CoreCFG {
    fn default() -> Self {
        CoreCFG {
            home_path: None,
            current_file: None,
            client_id: rng()
                .sample_iter(&Alphanumeric)
                .take(30)
                .map(char::from)
                .collect(),
        }
    }
}

pub fn load_config(path: Option<PathBuf>) -> Config {
    match path {
        Some(p) => confy::load_path(p).expect("Configuration could not be loaded"),
        None => confy::load("apograph", Some("config"))
            .ok()
            .unwrap_or_else(|| {
                let config: Config = Config::default();
                let _ = confy::store("apograph", Some("config"), Config::default());
                config
            }),
    }
}

#[tauri::command]
pub fn get_basepath(app_handle: tauri::AppHandle) -> Option<String> {
    let config = app_handle.state::<Mutex<Config>>();

    // Lock the mutex to get mutable access:
    let config = config.lock().unwrap();
    let base_path = config.core_cfg.home_path.clone();
    return base_path.map(|p| p.to_string_lossy().into_owned());
}

pub fn _get_client_id(app_handle: &tauri::AppHandle) -> String {
    let config = app_handle.state::<Mutex<Config>>();

    // Lock the mutex to get mutable access:
    let config = config.lock().unwrap();
    let client_id = config.core_cfg.client_id.clone();
    return client_id;
}
#[tauri::command]
pub fn set_basepath(app_handle: tauri::AppHandle, path: String) -> bool {
    if let Ok(resolved_path) = shellexpand::full(&path) {
        let basepath = Path::new(&resolved_path.to_string()).to_path_buf();
        if !basepath.is_dir() {
            println!("{:?}", basepath);
            return false;
        }

        let config = app_handle.state::<Mutex<Config>>();
        // Lock the mutex to get mutable access:
        let mut config = config.lock().unwrap();
        config.core_cfg.home_path = Some(basepath);
        let _ = confy::store("apograph", Some("config"), config.clone());
        return true;
    } else {
        return false;
    };
}
// TODO error handling
pub fn get_open_file_path(app_handle: tauri::AppHandle) -> Option<String> {
    let config = app_handle.state::<Mutex<Config>>();

    // Lock the mutex to get mutable access:
    let config = config.lock().unwrap();
    let open_file_path = config.core_cfg.current_file.clone();
    return open_file_path.map(|p| p.to_string_lossy().into_owned());
}
pub fn set_open_file_path(app_handle: tauri::AppHandle, path: &str) {
    let mut config = app_handle.state::<Mutex<Config>>();

    // Lock the mutex to get mutable access:
    let mut config = config.lock().unwrap();
    config.core_cfg.current_file = Some(PathBuf::from_str(path).unwrap_or_default());
}
