use std::collections::HashMap;

use oiseau::config::{Configuration, DatabaseConfig};
use pathbufd::PathBufD;
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Config {
    /// The directory files are stored in (relative to cwd).
    #[serde(default = "default_directory")]
    pub directory: String,
    /// The path to the default image to be served for the given buckets.
    #[serde(default = "default_bucket_defaults")]
    pub bucket_defaults: HashMap<String, (String, String)>,
    /// Database configuration.
    #[serde(default = "default_database")]
    pub database: DatabaseConfig,
}

fn default_directory() -> String {
    "buckets".to_string()
}

fn default_bucket_defaults() -> HashMap<String, (String, String)> {
    HashMap::new()
}

fn default_database() -> DatabaseConfig {
    DatabaseConfig::default()
}

impl Configuration for Config {
    fn db_config(&self) -> DatabaseConfig {
        self.database.to_owned()
    }
}

impl Default for Config {
    fn default() -> Self {
        Self {
            directory: default_directory(),
            bucket_defaults: default_bucket_defaults(),
            database: default_database(),
        }
    }
}

impl Config {
    /// Read the configuration file.
    pub fn read() -> Self {
        toml::from_str(
            &match std::fs::read_to_string(PathBufD::current().join("app.toml")) {
                Ok(x) => x,
                Err(_) => {
                    let x = Config::default();

                    std::fs::write(
                        PathBufD::current().join("app.toml"),
                        &toml::to_string_pretty(&x).expect("failed to serialize config"),
                    )
                    .expect("failed to write config");

                    return x;
                }
            },
        )
        .expect("failed to deserialize config")
    }
}
