use std::fs;
use std::io::ErrorKind;
use std::path::PathBuf;
use std::sync::OnceLock;
use directories::ProjectDirs;
use serde_derive::{Deserialize, Serialize};

pub static CONFIG_DIR: OnceLock<PathBuf> = OnceLock::new();
pub static CONFIG_FILE: OnceLock<PathBuf> = OnceLock::new();


#[derive(Serialize, Deserialize)]
pub struct Paths {
    pub runelite_path: String,
    pub java_path: String,
}

#[derive(Serialize, Deserialize)]
pub struct Versions {
    pub runelite_version: String,
    pub runelite_hash: String,
}

#[derive(Serialize, Deserialize)]
pub struct Config {
    pub paths: Paths,
    pub versions: Versions,
}

impl Config {
    pub fn new() -> Config {
        let mut runelite_path = CONFIG_DIR.get().unwrap().clone();
        runelite_path.push("runelite.jar");

        let new_config = Config {
            paths: Paths { runelite_path: runelite_path.into_os_string().into_string().unwrap(), java_path: "java".to_string() },
            versions: Versions { runelite_version: "".to_string(), runelite_hash: "".to_string() },
        };

        new_config.save_config();

        new_config
    }

    pub fn get_config() -> Config {
        let binding = ProjectDirs::from("sex", "gaycatgirl", "osrs-luncher").expect("Could not generate config path");
        let expected_config_dir = binding.config_dir();
        CONFIG_DIR.set(expected_config_dir.to_path_buf()).expect("Failed to set config dir");
        
        let expected_config_file = expected_config_dir.join("config.toml");
        CONFIG_FILE.set(expected_config_file.to_path_buf()).expect("Failed to set config file");

        // check to see if a config already exists at the expected path
        match fs::read_to_string(&expected_config_file) {
            Ok(config_contents) => {
                toml::from_str::<Config>(&config_contents).unwrap_or_else(|_| Config::new())
            }
            Err(error) => {
                match error.kind() {
                    ErrorKind::NotFound => {
                        // config doesn't exist, create
                        Config::new()
                    }
                    _ => panic!("Could not read config file: {}", error),
                }
            }
        }
    }

    pub fn save_config(&self) {
        let file_path = CONFIG_FILE.get().unwrap().clone();

        fs::create_dir_all(file_path.parent().unwrap()).expect("Could not create config directory");
        fs::write(file_path, toml::to_string_pretty(self).expect("Failed to generate config string")).expect("Could not write config file");
    }
}