use anyhow::{Context, Result};
use dirs::config_dir;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;

#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Config {
    pub api_key: String,
    #[serde(default)]
    pub theme: Option<String>,
}

pub fn config_path() -> Result<PathBuf> {
    let base_dir = config_dir().context("could not determine your config directory")?;
    Ok(base_dir.join("hc-mail").join("config.toml"))
}

pub fn load_config() -> Result<Option<Config>> {
    let path = config_path()?;

    if !path.exists() {
        return Ok(None);
    }

    let contents = fs::read_to_string(&path)
        .with_context(|| format!("failed to read config file at {}", path.display()))?;
    let config = toml::from_str::<Config>(&contents)
        .with_context(|| format!("failed to parse config file at {}", path.display()))?;

    Ok(Some(config))
}

pub fn save_config(config: &Config) -> Result<PathBuf> {
    let path = config_path()?;

    if let Some(parent) = path.parent() {
        fs::create_dir_all(parent).with_context(|| {
            format!("failed to create config directory at {}", parent.display())
        })?;
    }

    let contents = toml::to_string(config).context("failed to serialize config")?;
    fs::write(&path, contents)
        .with_context(|| format!("failed to write config file at {}", path.display()))?;

    #[cfg(unix)]
    fs::set_permissions(&path, fs::Permissions::from_mode(0o600)).with_context(|| {
        format!(
            "failed to tighten permissions on config file at {}",
            path.display()
        )
    })?;

    Ok(path)
}

pub fn delete_config() -> Result<bool> {
    let Some(mut config) = load_config()? else {
        return Ok(false);
    };

    if config.theme.is_none() {
        let path = config_path()?;
        fs::remove_file(&path)
            .with_context(|| format!("failed to delete config file at {}", path.display()))?;
    } else {
        config.api_key.clear();
        save_config(&config)?;
    }

    Ok(true)
}
