use serde::Deserialize;
use std::fs;
use std::process::exit;
use toml::from_str;

#[derive(Deserialize, Debug)]
#[allow(clippy::struct_field_names)]
#[allow(clippy::struct_excessive_bools)]
pub struct Config {
    // User toml configs
    #[serde(default)]
    pub branch: String,
    #[serde(default)]
    pub tag: String,
    #[serde(default)]
    pub arch: String,
    #[serde(default)]
    pub mirror: String,
    #[serde(default)]
    pub sbosrcarch_mirror: String,
    #[serde(default)]
    pub local_repo: String,
    #[serde(default)]
    pub rsync_args: Vec<String>,
    #[serde(default)]
    pub wget_args: Vec<String>,
    #[serde(default)]
    pub git_args: Vec<String>,
    #[serde(default)]
    pub build_path: String,
    #[serde(default)]
    pub installpkg: String,
    #[serde(default)]
    pub reinstall: String,
    #[serde(default)]
    pub removepkg: String,
    #[serde(default)]
    pub pkgtype: String,
    #[serde(default)]
    pub makeflags: String,
    #[serde(default)]
    pub checksum: bool,
    #[serde(default)]
    pub gpg_verify: bool,
    #[serde(default)]
    pub lock: bool,
    #[serde(default)]
    pub colors: bool,
    #[serde(default)]
    pub fetch_path: String,

    // Default configs
    #[serde(skip)]
    pub mirror_url: String,
    #[serde(skip)]
    pub repo_path: String,
    #[serde(skip)]
    pub data_json: String,
    #[serde(skip)]
    pub var_log_path: String,
    #[serde(skip)]
    pub build_log_file: String,
    #[serde(skip)]
    pub deps_log_file: String,
    #[serde(skip)]
    pub installed_packages: String,
    #[serde(skip)]
    pub changelog: String,
    #[serde(skip)]
    pub config_file: String,
    #[serde(skip)]
    pub blacklist_file: String,
    #[serde(skip)]
    pub tmp_sbpkg: String,
}

/// Reads `sbpkg.toml` from the current directory and returns a populated [`Config`].
///
/// Derived fields `mirror_url`, `repo_path`, and `data_json` are computed
/// from the raw values and attached before returning.
///
/// # Exits
///
/// Exits with code 1 if `sbpkg.toml` is missing or required fields are empty.
pub fn get_config() -> Config {
    let config_file = "/etc/sbpkg/sbpkg.toml";
    let content: String = fs::read_to_string(config_file).unwrap_or_else(|e| {
        eprintln!("Error: {config_file} not found: {e}");
        exit(1);
    });

    let mut cfg: Config = from_str(&content).unwrap_or_else(|e| {
        eprintln!("Error: Incorrect format in {config_file}: {e}");
        exit(1);
    });

    let required = [
        ("tag", &cfg.tag),
        ("mirror", &cfg.mirror),
        ("sbosrcarch_mirror", &cfg.sbosrcarch_mirror),
        ("branch", &cfg.branch),
        ("local_repo", &cfg.local_repo),
        ("build_path", &cfg.build_path),
        ("installpkg", &cfg.installpkg),
        ("reinstall", &cfg.reinstall),
        ("removepkg", &cfg.removepkg),
        ("pkgtype", &cfg.pkgtype),
        ("makeflags", &cfg.makeflags),
        ("fetch_path", &cfg.fetch_path),
    ];

    for (name, value) in &required {
        if value.is_empty() {
            eprintln!("Error: '{name}' is missing from {config_file}");
            exit(1);
        }
    }

    // Paths
    cfg.mirror_url = format!("{}{}", cfg.mirror, cfg.branch);
    cfg.repo_path = format!("{}{}", cfg.local_repo, cfg.branch);
    cfg.var_log_path = "/var/log/sbpkg/".to_string();
    cfg.installed_packages = "/var/log/packages/".to_string();
    cfg.tmp_sbpkg = "/tmp/sbpkg/".to_string();

    // File names
    cfg.build_log_file = "build.log".to_string();
    cfg.deps_log_file = "deps.log".to_string();
    cfg.changelog = "ChangeLog.txt".to_string();
    cfg.data_json = "data.json".to_string();
    cfg.config_file = "/etc/sbpkg/sbpkg.toml".to_string();
    cfg.blacklist_file = "/etc/sbpkg/blacklist.toml".to_string();

    for path in [&cfg.build_path, &cfg.var_log_path, &cfg.fetch_path] {
        if !std::path::Path::new(path).exists() {
            fs::create_dir_all(path).unwrap_or_else(|e| {
                eprintln!("Error: Failed to create {path}: {e}");
                exit(1);
            });
        }
    }

    cfg
}
