use std::{
    fs,
    path::{Path, PathBuf},
};

use serde::{Deserialize, Serialize};

use crate::error_reporting::{report_serde_json_err, report_serde_ron_err};

use super::error::{self, Config};

#[derive(Debug, Serialize, Deserialize)]
pub struct Configs {
    #[serde(default = "default_example_value")]
    pub example_value: i32,
    #[serde(default)]
    pub no_startup_message: bool,
    pub evaluator: Option<eval::Available>,
}

/// what the fuck serde why do i need this
fn default_example_value() -> i32 {
    43
}

/// Find the location of a config file and check if there is, in fact, a file
pub(super) fn find_config_file() -> Result<PathBuf, Config> {
    let Some(config_path) = dirs::config_dir() else {
        return Err(Config::NoConfigDir);
    };

    let ron_path = config_path.with_file_name("config.ron");
    let json_path = config_path.with_file_name("config.json");

    if Path::new(&ron_path).exists() {
        Ok(ron_path)
    } else if Path::new(&json_path).exists() {
        Ok(json_path)
    } else {
        Err(Config::NoConfigFileFound)
    }
}

impl Configs {
    pub fn read(p: PathBuf) -> Result<Self, error::Config> {
        match p
            .extension()
            .map(|v| v.to_str().expect("config path to be UTF-8"))
        {
            Some("ron") => {
                let f = fs::read_to_string(p)?;
                ron::from_str(&f).or_else(|e| report_serde_ron_err(&f, &e))
            }
            Some("json") => {
                let f = fs::read_to_string(p)?;
                serde_json::from_str(&f).or_else(|e| report_serde_json_err(&f, &e))
            }
            e => Err(error::Config::UnknownExtension(e.map(str::to_owned))),
        }
    }
}
