use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
    #[serde(default = "default_show_help_hint")]
    pub show_help_hint: bool,
    #[serde(default = "Vec::new")]
    pub projects: Vec<String>,
    #[serde(default = "default_strict_projects")]
    pub strict_projects: bool,
    #[serde(default = "default_multi_column")]
    pub multi_column: bool,
    #[serde(default = "default_true")]
    pub show_permanent: bool,
    #[serde(default = "default_true")]
    pub show_recurring: bool,
    #[serde(default = "default_true")]
    pub show_recent: bool,
    #[serde(default = "default_true")]
    pub show_time_gaps: bool,
}

fn default_show_help_hint() -> bool {
    true
}

fn default_strict_projects() -> bool {
    false
}

fn default_multi_column() -> bool {
    true
}

fn default_true() -> bool {
    true
}

impl Default for Config {
    fn default() -> Self {
        Self {
            show_help_hint: default_show_help_hint(),
            projects: Vec::new(),
            strict_projects: default_strict_projects(),
            multi_column: default_multi_column(),
            show_permanent: default_true(),
            show_recurring: default_true(),
            show_recent: default_true(),
            show_time_gaps: default_true(),
        }
    }
}

impl Config {
    pub fn load() -> anyhow::Result<Self> {
        let path = Self::config_path()?;
        if !path.exists() {
            let config = Config::default();
            let yaml = serde_yaml::to_string(&config)?;
            std::fs::write(&path, yaml)?;
            return Ok(config);
        }
        let contents = std::fs::read_to_string(path)?;
        Ok(serde_yaml::from_str(&contents)?)
    }

    #[allow(dead_code)]
    pub fn save(&self) -> anyhow::Result<()> {
        let path = Self::config_path()?;
        let yaml = serde_yaml::to_string(&self)?;
        std::fs::write(path, yaml)?;
        Ok(())
    }

    pub fn config_path() -> anyhow::Result<PathBuf> {
        let mut path =
            dirs::config_dir().ok_or_else(|| anyhow::anyhow!("Could not find config directory"))?;
        path.push("wat");
        std::fs::create_dir_all(&path)?;
        path.push("config.yaml");
        Ok(path)
    }

    pub fn is_valid_project(&self, project: &str) -> bool {
        if !self.strict_projects {
            return true;
        }
        self.projects.contains(&project.to_string())
    }
}
